2 // "$Id: fl_font_xft.cxx 8442 2011-02-18 13:39:48Z manolo $"
4 // Xft font code for the Fast Light Tool Kit (FLTK).
6 // Copyright 2001-2011 Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 // Draw fonts using Keith Packard's Xft library to provide anti-
32 // Many thanks to Carl for making the original version of this.
34 // This font code only requires libXft to work. Contrary to popular
35 // belief there is no need to have FreeType, or the Xrender extension
36 // available to use this code. You will just get normal Xlib fonts
37 // (Xft calls them "core" fonts) The Xft algorithms for choosing
38 // these is about as good as the FLTK ones (I hope to fix it so it is
39 // exactly as good...), plus it can cache its results and share them
40 // between programs, so using this should be a win in all cases. Also
41 // it should be obvious by comparing this file and fl_font_x.cxx that
42 // it is a lot easier to program with Xft than with Xlib.
44 // Also, Xft supports UTF-8 text rendering directly, which will allow
45 // us to support UTF-8 on all platforms more easily.
47 // To actually get antialiasing you need the following:
49 // 1. You have XFree86 4
50 // 2. You have the XRender extension
51 // 3. Your X device driver supports the render extension
53 // 5. Your libXft has FreeType2 support compiled in
54 // 6. You have the FreeType2 library
56 // Distributions that have XFree86 4.0.3 or later should have all of this...
58 // Unlike some other Xft packages, I tried to keep this simple and not
59 // to work around the current problems in Xft by making the "patterns"
60 // complicated. I believe doing this defeats our ability to improve Xft
61 // itself. You should edit the ~/.xftconfig file to "fix" things, there
62 // are several web pages of information on how to do this.
66 #include <X11/Xft/Xft.h>
70 // The predefined fonts that FLTK has:
71 static Fl_Fontdesc built_in_table
[] = {
103 {" lucidatypewriter"},
104 {"Blucidatypewriter"},
109 Fl_Fontdesc
* fl_fonts
= built_in_table
;
111 Fl_XFont_On_Demand fl_xfont
;
112 void *fl_xftfont
= 0;
113 //const char* fl_encoding_ = "iso8859-1";
114 const char* fl_encoding_
= "iso10646-1";
116 extern Region
XRegionFromRectangle ( Fl_Rectangle
*rg
);
118 static void fl_xft_font(Fl_Xlib_Graphics_Driver
*driver
, Fl_Font fnum
, Fl_Fontsize size
, int angle
) {
119 if (fnum
==-1) { // special case to stop font caching
120 driver
->Fl_Graphics_Driver::font(0, 0);
123 Fl_Font_Descriptor
* f
= driver
->font_descriptor();
124 if (fnum
== driver
->Fl_Graphics_Driver::font() && size
== driver
->size() && f
&& f
->angle
== angle
)
126 driver
->Fl_Graphics_Driver::font(fnum
, size
);
127 Fl_Fontdesc
*font
= fl_fonts
+ fnum
;
128 // search the fontsizes we have generated already
129 for (f
= font
->first
; f
; f
= f
->next
) {
130 if (f
->size
== size
&& f
->angle
== angle
)// && !strcasecmp(f->encoding, fl_encoding_))
134 f
= new Fl_Font_Descriptor(font
->name
, size
, angle
);
135 f
->next
= font
->first
;
138 driver
->font_descriptor(f
);
140 fl_xfont
= f
->font
->u
.core
.font
;
142 fl_xfont
= NULL
; // invalidate
143 #endif // XFT_MAJOR < 2
144 fl_xftfont
= (void*)f
->font
;
147 void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum
, Fl_Fontsize size
) {
148 fl_xft_font(this,fnum
,size
,0);
151 static XftFont
* fontopen(const char* name
, Fl_Fontsize size
, bool core
, int angle
) {
152 // Check: does it look like we have been passed an old-school XLFD fontname?
153 bool is_xlfd
= false;
154 int hyphen_count
= 0;
156 unsigned len
= strlen(name
);
157 if (len
> 512) len
= 512; // ensure we are not passed an unbounded font name
158 for(unsigned idx
= 0; idx
< len
; idx
++) {
159 if(name
[idx
] == '-') hyphen_count
++; // check for XLFD hyphens
160 if(name
[idx
] == ',') comma_count
++; // are there multiple names?
162 if(hyphen_count
>= 14) is_xlfd
= true; // Not a robust check, but good enough?
166 if(!is_xlfd
) { // Not an XLFD - open as a XFT style name
167 XftFont
*the_font
; // the font we will return;
168 XftPattern
*fnt_pat
= XftPatternCreate(); // the pattern we will use for matching
169 int slant
= XFT_SLANT_ROMAN
;
170 int weight
= XFT_WEIGHT_MEDIUM
;
172 /* This "converts" FLTK-style font names back into "regular" names, extracting
173 * the BOLD and ITALIC codes as it does so - all FLTK font names are prefixed
174 * by 'I' (italic) 'B' (bold) 'P' (bold italic) or ' ' (regular) modifiers.
175 * This gives a fairly limited font selection ability, but is retained for
176 * compatibility reasons. If you really need a more complex choice, you are best
177 * calling Fl::set_fonts(*) then selecting the font by font-index rather than by
178 * name anyway. Probably.
179 * If you want to load a font who's name does actually begin with I, B or P, you
180 * MUST use a leading space OR simply use lowercase for the name...
182 /* This may be efficient, but it is non-obvious. */
184 case 'I': slant
= XFT_SLANT_ITALIC
; break; // italic
185 case 'P': slant
= XFT_SLANT_ITALIC
; // bold-italic (falls-through)
186 case 'B': weight
= XFT_WEIGHT_BOLD
; break; // bold
187 case ' ': break; // regular
188 default: name
--; // no prefix, restore name
191 if(comma_count
) { // multiple comma-separated names were passed
192 char *local_name
= strdup(name
); // duplicate the full name so we can edit the copy
193 char *curr
= local_name
; // points to first name in string
194 char *nxt
; // next name in string
196 nxt
= strchr(curr
, ','); // find comma separator
198 *nxt
= 0; // terminate first name
199 nxt
++; // first char of next name
202 // Add the current name to the match pattern
203 XftPatternAddString(fnt_pat
, XFT_FAMILY
, curr
);
205 if(nxt
) curr
= nxt
; // move onto next name (if it exists)
206 // Now do a cut-down version of the FLTK name conversion.
207 // NOTE: we only use the slant and weight of the first name,
208 // subsequent names we ignore this for... But we still need to do the check.
210 case 'I': break; // italic
211 case 'P': // bold-italic (falls-through)
212 case 'B': break; // bold
213 case ' ': break; // regular
214 default: curr
--; // no prefix, restore name
217 comma_count
--; // decrement name sections count
218 } while (comma_count
>= 0);
219 free(local_name
); // release our local copy of font names
221 else { // single name was passed - add it directly
222 XftPatternAddString(fnt_pat
, XFT_FAMILY
, name
);
225 // Construct a match pattern for the font we want...
226 XftPatternAddInteger(fnt_pat
, XFT_WEIGHT
, weight
);
227 XftPatternAddInteger(fnt_pat
, XFT_SLANT
, slant
);
228 XftPatternAddDouble (fnt_pat
, XFT_PIXEL_SIZE
, (double)size
);
229 XftPatternAddString (fnt_pat
, XFT_ENCODING
, fl_encoding_
);
231 // rotate font if angle!=0
235 XftMatrixRotate(&m
,cos(M_PI
*angle
/180.),sin(M_PI
*angle
/180.));
236 XftPatternAddMatrix (fnt_pat
, XFT_MATRIX
,&m
);
240 XftPatternAddBool(fnt_pat
, XFT_CORE
, FcTrue
);
241 XftPatternAddBool(fnt_pat
, XFT_RENDER
, FcFalse
);
244 XftPattern
*match_pat
; // the best available match on the system
245 XftResult match_result
; // the result of our matching attempt
247 // query the system to find a match for this font
248 match_pat
= XftFontMatch(fl_display
, fl_screen
, fnt_pat
, &match_result
);
250 #if 0 // the XftResult never seems to get set to anything... abandon this code?
251 switch(match_result
) { // how good a match is this font for our request?
253 puts("Object exists with the specified ID");
256 case XftResultTypeMismatch
:
257 puts("Object exists, but the type does not match");
261 puts("Object exists, but has fewer values than specified");
264 case FcResultOutOfMemory
:
265 puts("FcResult: Malloc failed");
268 case XftResultNoMatch
:
269 puts("Object does not exist at all");
273 printf("Invalid XftResult status %d \n", match_result
);
278 #if 0 // diagnostic to print the "full name" of the font we matched. This works.
279 FcChar8
*picked_name
= FcNameUnparse(match_pat
);
280 printf("Match: %s\n", picked_name
);
285 // last chance, just open any font in the right size
286 the_font
= XftFontOpen (fl_display
, fl_screen
,
287 XFT_FAMILY
, XftTypeString
, "sans",
288 XFT_SIZE
, XftTypeDouble
, (double)size
,
290 XftPatternDestroy(fnt_pat
);
292 Fl::error("Unable to find fonts. Check your FontConfig configuration.\n");
298 // open the matched font
299 the_font
= XftFontOpenPattern(fl_display
, match_pat
);
301 #if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
302 FcChar8
*picked_name2
= FcNameUnparse(the_font
->pattern
);
303 printf("Open : %s\n", picked_name2
);
307 XftPatternDestroy(fnt_pat
);
308 // XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not!
312 else { // We were passed a font name in XLFD format
313 /* OksiD's X font code could handle being passed a comma separated list
314 * of XLFD's. It then attempted to find which font was "best" from this list.
315 * But XftFontOpenXlfd can not do this, so if a list is passed, we just
316 * terminate it at the first comma.
317 * A "better" solution might be to use XftXlfdParse() on each of the passed
318 * XLFD's to construct a "super-pattern" that incorporates attributes from all
319 * XLFD's and use that to perform a XftFontMatch(). Maybe...
321 char *local_name
= strdup(name
);
322 if(comma_count
) { // This means we were passed multiple XLFD's
323 char *pc
= strchr(local_name
, ',');
324 *pc
= 0; // terminate the XLFD at the first comma
326 XftFont
*the_font
= XftFontOpenXlfd(fl_display
, fl_screen
, local_name
);
328 #if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
329 puts("Font Opened"); fflush(stdout
);
330 FcChar8
*picked_name2
= FcNameUnparse(the_font
->pattern
);
331 printf("Open : %s\n", picked_name2
); fflush(stdout
);
338 Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name
, Fl_Fontsize fsize
, int fangle
) {
339 // encoding = fl_encoding_;
345 font
= fontopen(name
, fsize
, false, angle
);
348 Fl_Font_Descriptor::~Fl_Font_Descriptor() {
349 if (this == fl_graphics_driver
->font_descriptor()) fl_graphics_driver
->font_descriptor(NULL
);
350 // XftFontClose(fl_display, font);
353 /* decodes the input UTF-8 string into a series of wchar_t characters.
354 n is set upon return to the number of characters.
355 Don't deallocate the returned memory.
357 static const wchar_t *utf8reformat(const char *str
, int& n
)
359 static const wchar_t empty
[] = {0};
360 static wchar_t *buffer
;
363 if (n
== 0) return empty
;
364 newn
= fl_utf8towc(str
, n
, (wchar_t*)buffer
, lbuf
);
367 if (buffer
) free(buffer
);
368 buffer
= (wchar_t*)malloc(lbuf
* sizeof(wchar_t));
369 n
= fl_utf8towc(str
, n
, (wchar_t*)buffer
, lbuf
);
376 static void utf8extents(Fl_Font_Descriptor
*desc
, const char *str
, int n
, XGlyphInfo
*extents
)
378 memset(extents
, 0, sizeof(XGlyphInfo
));
379 const wchar_t *buffer
= utf8reformat(str
, n
);
381 XftTextExtents16(fl_display
, desc
->font
, (XftChar16
*)buffer
, n
, extents
);
383 XftTextExtents32(fl_display
, desc
->font
, (XftChar32
*)buffer
, n
, extents
);
387 int Fl_Xlib_Graphics_Driver::height() {
388 if (font_descriptor()) return font_descriptor()->font
->ascent
+ font_descriptor()->font
->descent
;
392 int Fl_Xlib_Graphics_Driver::descent() {
393 if (font_descriptor()) return font_descriptor()->font
->descent
;
397 double Fl_Xlib_Graphics_Driver::width(const char* str
, int n
) {
398 if (!font_descriptor()) return -1.0;
400 utf8extents(font_descriptor(), str
, n
, &i
);
404 /*double fl_width(uchar c) {
405 return fl_graphics_driver->width((const char *)(&c), 1);
408 static double fl_xft_width(Fl_Font_Descriptor
*desc
, FcChar32
*str
, int n
) {
409 if (!desc
) return -1.0;
411 XftTextExtents32(fl_display
, desc
->font
, str
, n
, &i
);
415 double Fl_Xlib_Graphics_Driver::width(unsigned int c
) {
416 return fl_xft_width(font_descriptor(), (FcChar32
*)(&c
), 1);
419 void Fl_Xlib_Graphics_Driver::text_extents(const char *c
, int n
, int &dx
, int &dy
, int &w
, int &h
) {
420 if (!font_descriptor()) {
426 utf8extents(font_descriptor(), c
, n
, &gi
);
435 /* This code is used (mainly by opengl) to get a bitmapped font. The
436 * original XFT-1 code used XFT's "core" fonts methods to load an XFT
437 * font that was actually a X-bitmap font, that could then be readily
438 * used with GL. But XFT-2 does not provide that ability, and there
439 * is no easy method to use an XFT font directly with GL. So...
443 // This function attempts, on XFT2 systems, to find a suitable "core" Xfont
444 // for GL or other bitmap font needs (we dont have an XglUseXftFont(...) function.)
445 // There's probably a better way to do this. I can't believe it is this hard...
446 // Anyway... This code attempts to make an XLFD out of the fltk-style font
447 // name it is passed, then tries to load that font. Surprisingly, this quite
448 // often works - boxes that have XFT generally also have a fontserver that
449 // can serve TTF and other fonts to X, and so the font name that fltk makes
450 // from the XFT name often also "exists" as an "core" X font...
451 // If this code fails to load the requested font, it falls back through a
452 // series of tried 'n tested alternatives, ultimately resorting to what the
453 // original fltk code did.
454 // NOTE: On my test boxes (FC6, FC7, FC8, ubuntu8.04, 9.04, 9.10) this works
455 // well for the fltk "built-in" font names.
456 static XFontStruct
* load_xfont_for_xft2(Fl_Graphics_Driver
*driver
) {
457 XFontStruct
* xgl_font
= 0;
458 int size
= driver
->size();
459 int fnum
= driver
->font();
460 const char *wt_med
= "medium";
461 const char *wt_bold
= "bold";
462 const char *weight
= wt_med
; // no specifc weight requested - accept any
463 char slant
= 'r'; // regular non-italic by default
464 char xlfd
[128]; // we will put our synthetic XLFD in here
465 char *pc
= strdup(fl_fonts
[fnum
].name
); // what font were we asked for?
466 const char *name
= pc
; // keep a handle to the original name for freeing later
467 // Parse the "fltk-name" of the font
469 case 'I': slant
= 'i'; break; // italic
470 case 'P': slant
= 'i'; // bold-italic (falls-through)
471 case 'B': weight
= wt_bold
; break; // bold
472 case ' ': break; // regular
473 default: name
--; // no prefix, restore name
476 // first, we do a query with no prefered size, to see if the font exists at all
477 snprintf(xlfd
, 128, "-*-%s-%s-%c-*--*-*-*-*-*-*-*-*", name
, weight
, slant
); // make up xlfd style name
478 xgl_font
= XLoadQueryFont(fl_display
, xlfd
);
479 if(xgl_font
) { // the face exists, but can we get it in a suitable size?
480 XFreeFont(fl_display
, xgl_font
); // release the non-sized version
481 snprintf(xlfd
, 128, "-*-%s-%s-%c-*--*-%d-*-*-*-*-*-*", name
, weight
, slant
, (size
*10));
482 xgl_font
= XLoadQueryFont(fl_display
, xlfd
); // attempt to load the font at the right size
486 // try alternative names
488 if (!strcmp(name
, "sans")) {
490 } else if (!strcmp(name
, "mono")) {
492 } else if (!strcmp(name
, "serif")) {
494 } else if (!strcmp(name
, "screen")) {
495 name
= "lucidatypewriter";
496 } else if (!strcmp(name
, "dingbats")) {
497 name
= "zapf dingbats";
499 snprintf(xlfd
, 128, "-*-*%s*-%s-%c-*--*-%d-*-*-*-*-*-*", name
, weight
, slant
, (size
*10));
500 xgl_font
= XLoadQueryFont(fl_display
, xlfd
);
502 free(pc
); // release our copy of the font name
504 // if we have nothing loaded, try a generic proportional font
506 snprintf(xlfd
, 128, "-*-helvetica-*-%c-*--*-%d-*-*-*-*-*-*", slant
, (size
*10));
507 xgl_font
= XLoadQueryFont(fl_display
, xlfd
);
509 // If that still didn't work, try this instead
511 snprintf(xlfd
, 128, "-*-courier-medium-%c-*--*-%d-*-*-*-*-*-*", slant
, (size
*10));
512 xgl_font
= XLoadQueryFont(fl_display
, xlfd
);
514 //printf("glf: %d\n%s\n%s\n", size, xlfd, fl_fonts[fl_font_].name);
515 //if(xgl_font) puts("ok");
517 // Last chance fallback - this usually loads something...
518 if (!xgl_font
) xgl_font
= XLoadQueryFont(fl_display
, "fixed");
521 } // end of load_xfont_for_xft2
524 static XFontStruct
* fl_xxfont(Fl_Graphics_Driver
*driver
) {
526 // kludge! XFT 2 and later does not provide core fonts for us to use with GL
527 // try to load a bitmap X font instead
528 static XFontStruct
* xgl_font
= 0;
529 static int glsize
= 0;
530 static int glfont
= -1;
531 // Do we need to load a new font?
532 if ((!xgl_font
) || (glsize
!= driver
->size()) || (glfont
!= driver
->font())) {
533 // create a dummy XLFD for some font of the appropriate size...
534 if (xgl_font
) XFreeFont(fl_display
, xgl_font
); // font already loaded, free it - this *might* be a Bad Idea
535 glsize
= driver
->size(); // record current font size
536 glfont
= driver
->font(); // and face
537 xgl_font
= load_xfont_for_xft2(driver
);
540 # else // XFT-1 provides a means to load a "core" font directly
541 if (driver
->font_descriptor()->font
->core
) {
542 return driver
->font_descriptor()->font
->u
.core
.font
; // is the current font a "core" font? If so, use it.
544 static XftFont
* xftfont
;
545 if (xftfont
) XftFontClose (fl_display
, xftfont
);
546 xftfont
= fontopen(fl_fonts
[driver
->font()].name
, driver
->size(), true, 0); // else request XFT to load a suitable "core" font instead.
547 return xftfont
->u
.core
.font
;
548 # endif // XFT_MAJOR > 1
551 XFontStruct
* Fl_XFont_On_Demand::value() {
552 if (!ptr
) ptr
= fl_xxfont(fl_graphics_driver
);
557 // Currently Xft does not work with colormapped visuals, so this probably
558 // does not work unless you have a true-color overlay.
559 extern bool fl_overlay
;
560 extern Colormap fl_overlay_colormap
;
561 extern XVisualInfo
* fl_overlay_visual
;
564 // For some reason Xft produces errors if you destroy a window whose id
565 // still exists in an XftDraw structure. It would be nice if this is not
566 // true, a lot of junk is needed to try to stop this:
568 static XftDraw
* draw_
;
569 static Window draw_window
;
571 static XftDraw
* draw_overlay
;
572 static Window draw_overlay_window
;
575 void fl_destroy_xft_draw(Window id
) {
576 if (id
== draw_window
)
577 XftDrawChange(draw_
, draw_window
= fl_message_window
);
579 if (id
== draw_overlay_window
)
580 XftDrawChange(draw_overlay
, draw_overlay_window
= fl_message_window
);
584 void Fl_Xlib_Graphics_Driver::draw(const char *str
, int n
, int x
, int y
) {
585 if ( !this->font_descriptor() ) {
586 this->font(FL_HELVETICA
, FL_NORMAL_SIZE
);
589 XftDraw
*& draw_
= fl_overlay
? draw_overlay
: ::draw_
;
592 draw_
= XftDrawCreate(fl_display
, draw_overlay_window
= fl_window
,
593 fl_overlay_visual
->visual
, fl_overlay_colormap
);
594 else //if (draw_overlay_window != fl_window)
595 XftDrawChange(draw_
, draw_overlay_window
= fl_window
);
599 draw_
= XftDrawCreate(fl_display
, draw_window
= fl_window
,
600 fl_visual
->visual
, fl_colormap
);
601 else //if (draw_window != fl_window)
602 XftDrawChange(draw_
, draw_window
= fl_window
);
604 Region region
= XRegionFromRectangle( fl_clip_region() );
606 if (region
&& XEmptyRegion(region
))
608 XDestroyRegion( region
);
612 XftDrawSetClip(draw_
, region
);
614 // Use fltk's color allocator, copy the results to match what
615 // XftCollorAllocValue returns:
617 color
.pixel
= fl_xpixel(Fl_Graphics_Driver::color());
618 uchar r
,g
,b
; Fl::get_color(Fl_Graphics_Driver::color(), r
,g
,b
);
619 color
.color
.red
= ((int)r
)*0x101;
620 color
.color
.green
= ((int)g
)*0x101;
621 color
.color
.blue
= ((int)b
)*0x101;
622 color
.color
.alpha
= 0xffff;
624 const wchar_t *buffer
= utf8reformat(str
, n
);
626 XftDrawString16(draw_
, &color
, font_descriptor()->font
, x
, y
, (XftChar16
*)buffer
, n
);
628 XftDrawString32(draw_
, &color
, font_descriptor()->font
, x
, y
, (XftChar32
*)buffer
, n
);
631 if ( region
) XDestroyRegion( region
);
634 void Fl_Xlib_Graphics_Driver::draw(int angle
, const char *str
, int n
, int x
, int y
) {
635 fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), angle
);
636 this->draw(str
, n
, (int)x
, (int)y
);
637 fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), 0);
640 static void fl_drawUCS4(Fl_Graphics_Driver
*driver
, const FcChar32
*str
, int n
, int x
, int y
) {
642 XftDraw
*& draw_
= fl_overlay
? draw_overlay
: ::draw_
;
645 draw_
= XftDrawCreate(fl_display
, draw_overlay_window
= fl_window
,
646 fl_overlay_visual
->visual
, fl_overlay_colormap
);
647 else //if (draw_overlay_window != fl_window)
648 XftDrawChange(draw_
, draw_overlay_window
= fl_window
);
652 draw_
= XftDrawCreate(fl_display
, draw_window
= fl_window
,
653 fl_visual
->visual
, fl_colormap
);
654 else //if (draw_window != fl_window)
655 XftDrawChange(draw_
, draw_window
= fl_window
);
658 Region region
= XRegionFromRectangle( fl_clip_region() );
660 if (region
&& XEmptyRegion(region
))
662 XDestroyRegion( region
);
666 XftDrawSetClip(draw_
, region
);
668 // Use fltk's color allocator, copy the results to match what
669 // XftCollorAllocValue returns:
671 color
.pixel
= fl_xpixel(driver
->color());
672 uchar r
,g
,b
; Fl::get_color(driver
->color(), r
,g
,b
);
673 color
.color
.red
= ((int)r
)*0x101;
674 color
.color
.green
= ((int)g
)*0x101;
675 color
.color
.blue
= ((int)b
)*0x101;
676 color
.color
.alpha
= 0xffff;
678 XftDrawString32(draw_
, &color
, driver
->font_descriptor()->font
, x
, y
, (FcChar32
*)str
, n
);
680 if ( region
) XDestroyRegion( region
);
684 void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c
, int n
, int x
, int y
) {
686 #if defined(__GNUC__)
687 // FIXME: warning Need to improve this XFT right to left draw function
690 // This actually draws LtoR, but aligned to R edge with the glyph order reversed...
691 // but you can't just byte-rev a UTF-8 string, that isn't valid.
692 // You can reverse a UCS4 string though...
693 int num_chars
, wid
, utf_len
= strlen(c
);
694 FcChar8
*u8
= (FcChar8
*)c
;
695 FcBool valid
= FcUtf8Len(u8
, utf_len
, &num_chars
, &wid
);
698 // badly formed Utf-8 input string
701 if (num_chars
< n
) n
= num_chars
; // limit drawing to usable characters in input array
702 FcChar32
*ucs_txt
= new FcChar32
[n
+1];
707 while ((out
>= 0) && (utf_len
> 0))
710 sz
= FcUtf8ToUcs4(u8
, pu
, utf_len
);
711 utf_len
= utf_len
- sz
;
715 // Now we have a UCS4 version of the input text, reversed, in ucs_txt
716 int offs
= (int)fl_xft_width(font_descriptor(), ucs_txt
, n
);
717 fl_drawUCS4(this, ucs_txt
, n
, (x
-offs
), y
);
724 // End of "$Id: fl_font_xft.cxx 8442 2011-02-18 13:39:48Z manolo $"