fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_font_xft.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_font_xft.cxx 8211 2011-01-07 13:28:42Z AlbrechtS $"
00003 //
00004 // Xft font code for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 2001-2010 Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 //
00029 // Draw fonts using Keith Packard's Xft library to provide anti-
00030 // aliased text. Yow!
00031 //
00032 // Many thanks to Carl for making the original version of this.
00033 //
00034 // This font code only requires libXft to work.  Contrary to popular
00035 // belief there is no need to have FreeType, or the Xrender extension
00036 // available to use this code.  You will just get normal Xlib fonts
00037 // (Xft calls them "core" fonts) The Xft algorithms for choosing
00038 // these is about as good as the FLTK ones (I hope to fix it so it is
00039 // exactly as good...), plus it can cache its results and share them
00040 // between programs, so using this should be a win in all cases. Also
00041 // it should be obvious by comparing this file and fl_font_x.cxx that
00042 // it is a lot easier to program with Xft than with Xlib.
00043 //
00044 // Also, Xft supports UTF-8 text rendering directly, which will allow
00045 // us to support UTF-8 on all platforms more easily.
00046 //
00047 // To actually get antialiasing you need the following:
00048 //
00049 //     1. You have XFree86 4
00050 //     2. You have the XRender extension
00051 //     3. Your X device driver supports the render extension
00052 //     4. You have libXft
00053 //     5. Your libXft has FreeType2 support compiled in
00054 //     6. You have the FreeType2 library
00055 //
00056 // Distributions that have XFree86 4.0.3 or later should have all of this...
00057 //
00058 // Unlike some other Xft packages, I tried to keep this simple and not
00059 // to work around the current problems in Xft by making the "patterns"
00060 // complicated. I believe doing this defeats our ability to improve Xft
00061 // itself. You should edit the ~/.xftconfig file to "fix" things, there
00062 // are several web pages of information on how to do this.
00063 //
00064 #ifndef FL_DOXYGEN
00065 
00066 #include <X11/Xft/Xft.h>
00067 
00068 #include <math.h>
00069 
00070 // The predefined fonts that FLTK has:
00071 static Fl_Fontdesc built_in_table[] = {
00072 #if 1
00073 {" sans"},
00074 {"Bsans"},
00075 {"Isans"},
00076 {"Psans"},
00077 {" mono"},
00078 {"Bmono"},
00079 {"Imono"},
00080 {"Pmono"},
00081 {" serif"},
00082 {"Bserif"},
00083 {"Iserif"},
00084 {"Pserif"},
00085 {" symbol"},
00086 {" screen"},
00087 {"Bscreen"},
00088 {" zapf dingbats"},
00089 #else
00090 {" helvetica"},
00091 {"Bhelvetica"},
00092 {"Ihelvetica"},
00093 {"Phelvetica"},
00094 {" courier"},
00095 {"Bcourier"},
00096 {"Icourier"},
00097 {"Pcourier"},
00098 {" times"},
00099 {"Btimes"},
00100 {"Itimes"},
00101 {"Ptimes"},
00102 {" symbol"},
00103 {" lucidatypewriter"},
00104 {"Blucidatypewriter"},
00105 {" zapf dingbats"},
00106 #endif
00107 };
00108 
00109 Fl_Fontdesc* fl_fonts = built_in_table;
00110 
00111 #define current_font (fl_fontsize->font)
00112 
00113 Fl_Font fl_font_ = 0;
00114 Fl_Fontsize fl_size_ = 0;
00115 int fl_angle_ = 0; // internal for rotating text support
00116 Fl_XFont_On_Demand fl_xfont;
00117 void *fl_xftfont = 0;
00118 //const char* fl_encoding_ = "iso8859-1";
00119 const char* fl_encoding_ = "iso10646-1";
00120 Fl_Font_Descriptor* fl_fontsize = 0;
00121 
00122 
00123 
00124 void fl_font(Fl_Font fnum, Fl_Fontsize size, int angle) {
00125   if (fnum==-1) { // special case to stop font caching
00126     fl_font_ = 0; fl_size_ = 0; fl_angle_ = 0;
00127     return;
00128   }
00129   if (fnum == fl_font_ && size == fl_size_ && angle == fl_angle_
00130       && fl_fontsize)
00131 //      && !strcasecmp(fl_fontsize->encoding, fl_encoding_))
00132     return;
00133   fl_font_ = fnum; fl_size_ = size; fl_angle_ = angle;
00134   Fl_Fontdesc *font = fl_fonts + fnum;
00135   Fl_Font_Descriptor* f;
00136   // search the fontsizes we have generated already
00137   for (f = font->first; f; f = f->next) {
00138     if (f->size == size && f->angle == angle)// && !strcasecmp(f->encoding, fl_encoding_))
00139       break;
00140   }
00141   if (!f) {
00142     f = new Fl_Font_Descriptor(font->name);
00143     f->next = font->first;
00144     font->first = f;
00145   }
00146   fl_fontsize = f;
00147 #if XFT_MAJOR < 2
00148   fl_xfont    = f->font->u.core.font;
00149 #else
00150   fl_xfont    = NULL; // invalidate
00151 #endif // XFT_MAJOR < 2
00152   fl_xftfont = (void*)f->font;
00153 }
00154 
00155 void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
00156   fl_font(fnum,size,0);
00157 }
00158 
00159 static XftFont* fontopen(const char* name, bool core, int angle) {
00160   // Check: does it look like we have been passed an old-school XLFD fontname?
00161   bool is_xlfd = false;
00162   int hyphen_count = 0;
00163   int comma_count = 0;
00164   unsigned len = strlen(name);
00165   if (len > 512) len = 512; // ensure we are not passed an unbounded font name
00166   for(unsigned idx = 0; idx < len; idx++) {
00167     if(name[idx] == '-') hyphen_count++; // check for XLFD hyphens
00168     if(name[idx] == ',') comma_count++;  // are there multiple names?
00169   }
00170   if(hyphen_count >= 14) is_xlfd = true; // Not a robust check, but good enough?
00171 
00172   fl_open_display();
00173 
00174   if(!is_xlfd) { // Not an XLFD - open as a XFT style name
00175     XftFont *the_font; // the font we will return;
00176     XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching
00177     int slant = XFT_SLANT_ROMAN;
00178     int weight = XFT_WEIGHT_MEDIUM;
00179 
00180     /* This "converts" FLTK-style font names back into "regular" names, extracting
00181      * the BOLD and ITALIC codes as it does so - all FLTK font names are prefixed
00182      * by 'I' (italic) 'B' (bold) 'P' (bold italic) or ' ' (regular) modifiers.
00183      * This gives a fairly limited font selection ability, but is retained for
00184      * compatibility reasons. If you really need a more complex choice, you are best
00185      * calling Fl::set_fonts(*) then selecting the font by font-index rather than by
00186      * name anyway. Probably.
00187      * If you want to load a font who's name does actually begin with I, B or P, you
00188      * MUST use a leading space OR simply use lowercase for the name...
00189      */
00190     /* This may be efficient, but it is non-obvious. */
00191     switch (*name++) {
00192     case 'I': slant = XFT_SLANT_ITALIC; break; // italic
00193     case 'P': slant = XFT_SLANT_ITALIC;        // bold-italic (falls-through)
00194     case 'B': weight = XFT_WEIGHT_BOLD; break; // bold
00195     case ' ': break;                           // regular
00196     default: name--;                           // no prefix, restore name
00197     }
00198 
00199     if(comma_count) { // multiple comma-separated names were passed
00200       char *local_name = strdup(name); // duplicate the full name so we can edit the copy
00201       char *curr = local_name; // points to first name in string
00202       char *nxt; // next name in string
00203       do {
00204         nxt = strchr(curr, ','); // find comma separator
00205         if (nxt) {
00206           *nxt = 0; // terminate first name
00207           nxt++; // first char of next name
00208         }
00209 
00210         // Add the current name to the match pattern
00211         XftPatternAddString(fnt_pat, XFT_FAMILY, curr);
00212 
00213         if(nxt) curr = nxt; // move onto next name (if it exists)
00214         // Now do a cut-down version of the FLTK name conversion.
00215         // NOTE: we only use the slant and weight of the first name,
00216         // subsequent names we ignore this for... But we still need to do the check.
00217         switch (*curr++) {
00218         case 'I': break; // italic
00219         case 'P':        // bold-italic (falls-through)
00220         case 'B': break; // bold
00221         case ' ': break; // regular
00222         default: curr--; // no prefix, restore name
00223         }
00224 
00225         comma_count--; // decrement name sections count
00226       } while (comma_count >= 0);
00227       free(local_name); // release our local copy of font names
00228     }
00229     else { // single name was passed - add it directly
00230       XftPatternAddString(fnt_pat, XFT_FAMILY, name);
00231     }
00232 
00233     // Construct a match pattern for the font we want...
00234     XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight);
00235     XftPatternAddInteger(fnt_pat, XFT_SLANT, slant);
00236     XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)fl_size_);
00237     XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_);
00238 
00239     // rotate font if fl_angle_!=0
00240     if (fl_angle_ !=0) {
00241       XftMatrix m;
00242       XftMatrixInit(&m);
00243       XftMatrixRotate(&m,cos(M_PI*fl_angle_/180.),sin(M_PI*fl_angle_/180.));
00244       XftPatternAddMatrix (fnt_pat, XFT_MATRIX,&m);
00245     }
00246 
00247     if (core) {
00248       XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue);
00249       XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse);
00250     }
00251 
00252     XftPattern *match_pat;  // the best available match on the system
00253     XftResult match_result; // the result of our matching attempt
00254 
00255     // query the system to find a match for this font
00256     match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result);
00257 
00258 #if 0 // the XftResult never seems to get set to anything... abandon this code?
00259     switch(match_result) { // how good a match is this font for our request?
00260       case XftResultMatch:
00261         puts("Object exists with the specified ID");
00262         break;
00263 
00264       case XftResultTypeMismatch:
00265         puts("Object exists, but the type does not match");
00266         break;
00267 
00268       case XftResultNoId:
00269         puts("Object exists, but has fewer values than specified");
00270         break;
00271 
00272       case FcResultOutOfMemory:
00273         puts("FcResult: Malloc failed");
00274         break;
00275 
00276       case XftResultNoMatch:
00277         puts("Object does not exist at all");
00278         break;
00279 
00280       default:
00281         printf("Invalid XftResult status %d \n", match_result);
00282         break;
00283     }
00284 #endif
00285 
00286 #if 0 // diagnostic to print the "full name" of the font we matched. This works.
00287     FcChar8 *picked_name =  FcNameUnparse(match_pat);
00288     printf("Match: %s\n", picked_name);
00289     free(picked_name);
00290 #endif
00291 
00292     if (!match_pat) {
00293       // last chance, just open any font in the right size
00294       the_font = XftFontOpen (fl_display, fl_screen,
00295                         XFT_FAMILY, XftTypeString, "sans",
00296                         XFT_SIZE, XftTypeDouble, (double)fl_size_,
00297                         NULL);
00298       XftPatternDestroy(fnt_pat);
00299       if (!the_font) {
00300         Fl::error("Unable to find fonts. Check your FontConfig configuration.\n");
00301         exit(1);
00302       }
00303       return the_font;
00304     }
00305 
00306     // open the matched font
00307     the_font = XftFontOpenPattern(fl_display, match_pat);
00308 
00309 #if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
00310     FcChar8 *picked_name2 =  FcNameUnparse(the_font->pattern);
00311     printf("Open : %s\n", picked_name2);
00312     free(picked_name2);
00313 #endif
00314 
00315     XftPatternDestroy(fnt_pat);
00316 //  XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not!
00317 
00318     return the_font;
00319   }
00320   else { // We were passed a font name in XLFD format
00321     /* OksiD's X font code could handle being passed a comma separated list
00322      * of XLFD's. It then attempted to find which font was "best" from this list.
00323      * But XftFontOpenXlfd can not do this, so if a list is passed, we just
00324      * terminate it at the first comma.
00325      * A "better" solution might be to use XftXlfdParse() on each of the passed
00326      * XLFD's to construct a "super-pattern" that incorporates attributes from all
00327      * XLFD's and use that to perform a XftFontMatch(). Maybe...
00328      */
00329     char *local_name = strdup(name);
00330     if(comma_count) { // This means we were passed multiple XLFD's
00331       char *pc = strchr(local_name, ',');
00332       *pc = 0; // terminate the XLFD at the first comma
00333     }
00334     XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name);
00335     free(local_name);
00336 #if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
00337 puts("Font Opened"); fflush(stdout);
00338     FcChar8 *picked_name2 =  FcNameUnparse(the_font->pattern);
00339     printf("Open : %s\n", picked_name2); fflush(stdout);
00340     free(picked_name2);
00341 #endif
00342    return the_font;
00343   }
00344 } // end of fontopen
00345 
00346 Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name) {
00347 //  encoding = fl_encoding_;
00348   size = fl_size_;
00349   angle = fl_angle_;
00350 #if HAVE_GL
00351   listbase = 0;
00352 #endif // HAVE_GL
00353   font = fontopen(name, false, angle);
00354 }
00355 
00356 Fl_Font_Descriptor::~Fl_Font_Descriptor() {
00357   if (this == fl_fontsize) fl_fontsize = 0;
00358 //  XftFontClose(fl_display, font);
00359 }
00360 
00361 /* decodes the input UTF-8 string into a series of wchar_t characters.
00362  n is set upon return to the number of characters.
00363  Don't deallocate the returned memory.
00364  */
00365 static const wchar_t *utf8reformat(const char *str, int& n)
00366 {
00367   static const wchar_t empty[] = {0};
00368   static wchar_t *buffer;
00369   static int lbuf = 0;
00370   int newn;
00371   if (n == 0) return empty;
00372   newn = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf);
00373   if (newn >= lbuf) {
00374     lbuf = newn + 100;
00375     if (buffer) free(buffer);
00376     buffer = (wchar_t*)malloc(lbuf * sizeof(wchar_t));
00377     n = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf);
00378   } else {
00379     n = newn;
00380   }
00381   return buffer;
00382 }
00383 
00384 static void utf8extents(const char *str, int n, XGlyphInfo *extents)
00385 {
00386   memset(extents, 0, sizeof(XGlyphInfo));
00387   const wchar_t *buffer = utf8reformat(str, n);
00388 #ifdef __CYGWIN__
00389     XftTextExtents16(fl_display, current_font, (XftChar16 *)buffer, n, extents);
00390 #else
00391     XftTextExtents32(fl_display, current_font, (XftChar32 *)buffer, n, extents);
00392 #endif
00393 }
00394 
00395 int fl_height() {
00396   if (current_font) return current_font->ascent + current_font->descent;
00397   else return -1;
00398 }
00399 
00400 int fl_descent() {
00401   if (current_font) return current_font->descent;
00402   else return -1;
00403 }
00404 
00405 double fl_width(const char *str, int n) {
00406   if (!current_font) return -1.0;
00407   XGlyphInfo i;
00408   utf8extents(str, n, &i);
00409   return i.xOff;
00410 }
00411 
00412 double fl_width(uchar c) {
00413   return fl_width((const char *)(&c), 1);
00414 }
00415 
00416 double fl_width(FcChar32 *str, int n) {
00417   if (!current_font) return -1.0;
00418   XGlyphInfo i;
00419   XftTextExtents32(fl_display, current_font, str, n, &i);
00420   return i.xOff;
00421 }
00422 
00423 double fl_width(unsigned int c) {
00424   return fl_width((FcChar32 *)(&c), 1);
00425 }
00426 
00427 void fl_text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
00428   if (!current_font) {
00429     w = h = 0;
00430     dx = dy = 0;
00431     return;
00432   }
00433   XGlyphInfo gi;
00434   utf8extents(c, n, &gi);
00435 
00436   w = gi.width;
00437   h = gi.height;
00438   dx = -gi.x;
00439   dy = -gi.y;
00440 } // fl_text_extents
00441 
00442 
00443 /* This code is used (mainly by opengl) to get a bitmapped font. The
00444  * original XFT-1 code used XFT's "core" fonts methods to load an XFT
00445  * font that was actually a X-bitmap font, that could then be readily
00446  * used with GL.  But XFT-2 does not provide that ability, and there
00447  * is no easy method to use an XFT font directly with GL. So...
00448 */
00449 
00450 #  if XFT_MAJOR > 1
00451 // This function attempts, on XFT2 systems, to find a suitable "core" Xfont
00452 // for GL or other bitmap font needs (we dont have an XglUseXftFont(...) function.)
00453 // There's probably a better way to do this. I can't believe it is this hard...
00454 // Anyway... This code attempts to make an XLFD out of the fltk-style font
00455 // name it is passed, then tries to load that font. Surprisingly, this quite
00456 // often works - boxes that have XFT generally also have a fontserver that
00457 // can serve TTF and other fonts to X, and so the font name that fltk makes
00458 // from the XFT name often also "exists" as an "core" X font...
00459 // If this code fails to load the requested font, it falls back through a
00460 // series of tried 'n tested alternatives, ultimately resorting to what the
00461 // original fltk code did.
00462 // NOTE: On my test boxes (FC6, FC7, FC8, ubuntu8.04, 9.04, 9.10) this works 
00463 //       well for the fltk "built-in" font names.
00464 static XFontStruct* load_xfont_for_xft2(void) {
00465   XFontStruct* xgl_font = 0;
00466   int size = fl_size_;
00467   const char *wt_med = "medium";
00468   const char *wt_bold = "bold";
00469   const char *weight = wt_med; // no specifc weight requested - accept any
00470   char slant = 'r';   // regular non-italic by default
00471   char xlfd[128];     // we will put our synthetic XLFD in here
00472   char *pc = strdup(fl_fonts[fl_font_].name); // what font were we asked for?
00473   const char *name = pc;    // keep a handle to the original name for freeing later
00474   // Parse the "fltk-name" of the font
00475   switch (*name++) {
00476   case 'I': slant = 'i'; break;       // italic
00477   case 'P': slant = 'i';              // bold-italic (falls-through)
00478   case 'B': weight = wt_bold; break;  // bold
00479   case ' ': break;                    // regular
00480   default: name--;                    // no prefix, restore name
00481   }
00482 
00483   // first, we do a query with no prefered size, to see if the font exists at all
00484   snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-*-*-*-*-*-*-*", name, weight, slant); // make up xlfd style name
00485   xgl_font = XLoadQueryFont(fl_display, xlfd);
00486   if(xgl_font) { // the face exists, but can we get it in a suitable size?
00487     XFreeFont(fl_display, xgl_font); // release the non-sized version
00488     snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10));
00489     xgl_font = XLoadQueryFont(fl_display, xlfd); // attempt to load the font at the right size
00490   }
00491 //puts(xlfd);
00492 
00493   // try alternative names
00494   if (!xgl_font) {
00495     if (!strcmp(name, "sans")) {
00496       name = "helvetica";
00497     } else if (!strcmp(name, "mono")) {
00498       name = "courier";
00499     } else if (!strcmp(name, "serif")) {
00500       name = "times";
00501     } else if (!strcmp(name, "screen")) {
00502       name = "lucidatypewriter";
00503     } else if (!strcmp(name, "dingbats")) {
00504       name = "zapf dingbats";
00505     }
00506     snprintf(xlfd, 128, "-*-*%s*-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10));
00507     xgl_font = XLoadQueryFont(fl_display, xlfd);
00508   }  
00509   free(pc); // release our copy of the font name
00510   
00511   // if we have nothing loaded, try a generic proportional font
00512   if(!xgl_font) {
00513     snprintf(xlfd, 128, "-*-helvetica-*-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10));
00514     xgl_font = XLoadQueryFont(fl_display, xlfd);
00515   }
00516   // If that still didn't work, try this instead
00517   if(!xgl_font) {
00518     snprintf(xlfd, 128, "-*-courier-medium-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10));
00519     xgl_font = XLoadQueryFont(fl_display, xlfd);
00520   }
00521 //printf("glf: %d\n%s\n%s\n", size, xlfd, fl_fonts[fl_font_].name);
00522 //if(xgl_font) puts("ok");
00523 
00524   // Last chance fallback - this usually loads something...
00525   if (!xgl_font) xgl_font = XLoadQueryFont(fl_display, "fixed");
00526 
00527   return xgl_font;
00528 } // end of load_xfont_for_xft2
00529 #  endif
00530 
00531 XFontStruct* fl_xxfont() {
00532 #  if XFT_MAJOR > 1
00533   // kludge! XFT 2 and later does not provide core fonts for us to use with GL
00534   // try to load a bitmap X font instead
00535   static XFontStruct* xgl_font = 0;
00536   static int glsize = 0;
00537   static int glfont = -1;
00538   // Do we need to load a new font?
00539   if ((!xgl_font) || (glsize != fl_size_) || (glfont != fl_font_)) {
00540     // create a dummy XLFD for some font of the appropriate size...
00541     if (xgl_font) XFreeFont(fl_display, xgl_font); // font already loaded, free it - this *might* be a Bad Idea
00542     glsize = fl_size_; // record current font size
00543     glfont = fl_font_; // and face
00544     xgl_font = load_xfont_for_xft2();
00545   }
00546   return xgl_font;
00547 #  else // XFT-1 provides a means to load a "core" font directly
00548   if (current_font->core) return current_font->u.core.font; // is the current font a "core" font? If so, use it.
00549   static XftFont* xftfont;
00550   if (xftfont) XftFontClose (fl_display, xftfont);
00551   xftfont = fontopen(fl_fonts[fl_font_].name, true); // else request XFT to load a suitable "core" font instead.
00552   return xftfont->u.core.font;
00553 #  endif // XFT_MAJOR > 1
00554 }
00555 
00556 XFontStruct* Fl_XFont_On_Demand::value() {
00557   if (!ptr) ptr = fl_xxfont();
00558   return ptr;
00559 }
00560 
00561 #if USE_OVERLAY
00562 // Currently Xft does not work with colormapped visuals, so this probably
00563 // does not work unless you have a true-color overlay.
00564 extern bool fl_overlay;
00565 extern Colormap fl_overlay_colormap;
00566 extern XVisualInfo* fl_overlay_visual;
00567 #endif
00568 
00569 // For some reason Xft produces errors if you destroy a window whose id
00570 // still exists in an XftDraw structure. It would be nice if this is not
00571 // true, a lot of junk is needed to try to stop this:
00572 
00573 static XftDraw* draw_;
00574 static Window draw_window;
00575 #if USE_OVERLAY
00576 static XftDraw* draw_overlay;
00577 static Window draw_overlay_window;
00578 #endif
00579 
00580 void fl_destroy_xft_draw(Window id) {
00581   if (id == draw_window)
00582     XftDrawChange(draw_, draw_window = fl_message_window);
00583 #if USE_OVERLAY
00584   if (id == draw_overlay_window)
00585     XftDrawChange(draw_overlay, draw_overlay_window = fl_message_window);
00586 #endif
00587 }
00588 
00589 void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) {
00590   if ( !current_font ) {
00591     fl_font(FL_HELVETICA, 14);
00592   }
00593 #if USE_OVERLAY
00594   XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_;
00595   if (fl_overlay) {
00596     if (!draw_)
00597       draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window,
00598                            fl_overlay_visual->visual, fl_overlay_colormap);
00599     else //if (draw_overlay_window != fl_window)
00600       XftDrawChange(draw_, draw_overlay_window = fl_window);
00601   } else
00602 #endif
00603   if (!draw_)
00604     draw_ = XftDrawCreate(fl_display, draw_window = fl_window,
00605                          fl_visual->visual, fl_colormap);
00606   else //if (draw_window != fl_window)
00607     XftDrawChange(draw_, draw_window = fl_window);
00608 
00609   Region region = fl_clip_region();
00610   if (region && XEmptyRegion(region)) return;
00611   XftDrawSetClip(draw_, region);
00612 
00613   // Use fltk's color allocator, copy the results to match what
00614   // XftCollorAllocValue returns:
00615   XftColor color;
00616   color.pixel = fl_xpixel(fl_color_);
00617   uchar r,g,b; Fl::get_color(fl_color_, r,g,b);
00618   color.color.red   = ((int)r)*0x101;
00619   color.color.green = ((int)g)*0x101;
00620   color.color.blue  = ((int)b)*0x101;
00621   color.color.alpha = 0xffff;
00622   
00623   const wchar_t *buffer = utf8reformat(str, n);
00624 #ifdef __CYGWIN__
00625   XftDrawString16(draw_, &color, current_font, x, y, (XftChar16 *)buffer, n);
00626 #else
00627   XftDrawString32(draw_, &color, current_font, x, y, (XftChar32 *)buffer, n);
00628 #endif
00629 }
00630 
00631 void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
00632   fl_font(fl_font_, fl_size_, angle);
00633   fl_draw(str, n, (int)x, (int)y);
00634   fl_font(fl_font_, fl_size_);
00635 }
00636 
00637 static void fl_drawUCS4(const FcChar32 *str, int n, int x, int y) {
00638 #if USE_OVERLAY
00639   XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_;
00640   if (fl_overlay) {
00641     if (!draw_)
00642       draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window,
00643                            fl_overlay_visual->visual, fl_overlay_colormap);
00644     else //if (draw_overlay_window != fl_window)
00645       XftDrawChange(draw_, draw_overlay_window = fl_window);
00646   } else
00647 #endif
00648   if (!draw_)
00649     draw_ = XftDrawCreate(fl_display, draw_window = fl_window,
00650                          fl_visual->visual, fl_colormap);
00651   else //if (draw_window != fl_window)
00652     XftDrawChange(draw_, draw_window = fl_window);
00653 
00654   Region region = fl_clip_region();
00655   if (region && XEmptyRegion(region)) return;
00656   XftDrawSetClip(draw_, region);
00657 
00658   // Use fltk's color allocator, copy the results to match what
00659   // XftCollorAllocValue returns:
00660   XftColor color;
00661   color.pixel = fl_xpixel(fl_color_);
00662   uchar r,g,b; Fl::get_color(fl_color_, r,g,b);
00663   color.color.red   = ((int)r)*0x101;
00664   color.color.green = ((int)g)*0x101;
00665   color.color.blue  = ((int)b)*0x101;
00666   color.color.alpha = 0xffff;
00667 
00668   XftDrawString32(draw_, &color, current_font, x, y, (FcChar32 *)str, n);
00669 }
00670 
00671 
00672 void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
00673 
00674 #if defined(__GNUC__)
00675 // FIXME: warning Need to improve this XFT right to left draw function
00676 #endif /*__GNUC__*/
00677 
00678 // This actually draws LtoR, but aligned to R edge with the glyph order reversed...
00679 // but you can't just byte-rev a UTF-8 string, that isn't valid.
00680 // You can reverse a UCS4 string though...
00681   int num_chars, wid, utf_len = strlen(c);
00682   FcChar8 *u8 = (FcChar8 *)c;
00683   FcBool valid = FcUtf8Len(u8, utf_len, &num_chars, &wid);
00684   if (!valid)
00685   {
00686     // badly formed Utf-8 input string
00687     return;
00688   }
00689   if (num_chars < n) n = num_chars; // limit drawing to usable characters in input array
00690   FcChar32 *ucs_txt = new FcChar32[n+1];
00691   FcChar32* pu;
00692   int in, out, sz;
00693   ucs_txt[n] = 0;
00694   in = 0; out = n-1;
00695   while ((out >= 0) && (utf_len > 0))
00696   {
00697     pu = &ucs_txt[out];
00698     sz = FcUtf8ToUcs4(u8, pu, utf_len);
00699     utf_len = utf_len - sz;
00700     u8 = u8 + sz;
00701     out = out - 1;
00702   }
00703   // Now we have a UCS4 version of the input text, reversed, in ucs_txt
00704   int offs = (int)fl_width(ucs_txt, n);
00705   fl_drawUCS4(ucs_txt, n, (x-offs), y);
00706 
00707   delete[] ucs_txt;
00708 }
00709 #endif
00710 
00711 //
00712 // End of "$Id: fl_font_xft.cxx 8211 2011-01-07 13:28:42Z AlbrechtS $"
00713 //