|
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) ![]() |
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 //