Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGX11TTF.cxx
Go to the documentation of this file.
1 // @(#)root/x11ttf:$Id: 80028b538e60290371c1c5d73728f78b1c32f09a $
2 // Author: Valeriy Onuchin (Xft support) 02/10/07
3 // Author: Olivier Couet 01/10/02
4 // Author: Fons Rademakers 21/11/98
5 
6 /*************************************************************************
7  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
8  * All rights reserved. *
9  * *
10  * For the licensing terms see $ROOTSYS/LICENSE. *
11  * For the list of contributors see $ROOTSYS/README/CREDITS. *
12  *************************************************************************/
13 
14 /** \class TGX11TTF
15 \ingroup x11
16 
17 Interface to low level X11 (Xlib). This class gives access to basic
18 X11 graphics via the parent class TGX11. However, all text and font
19 handling is done via the Freetype TrueType library. When the
20 shared library containing this class is loaded the global gVirtualX
21 is redirected to point to this class.
22 */
23 
24 #include <stdlib.h>
25 
26 # include <ft2build.h>
27 # include FT_FREETYPE_H
28 # include FT_GLYPH_H
29 #include "TGX11TTF.h"
30 #include "TClass.h"
31 #include "TEnv.h"
32 
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
36 #include <X11/cursorfont.h>
37 #include <X11/keysym.h>
38 #include <X11/xpm.h>
39 
40 struct RXColor:XColor{};
41 struct RVisual:Visual{};
42 struct RXImage:XImage{};
43 
44 #ifdef R__HAS_XFT
45 
46 #include "THashTable.h"
47 #include "TRefCnt.h"
48 #include <X11/Xft/Xft.h>
49 
50 ///////////////////////// xft font data //////////////////////////////////////
51 class TXftFontData : public TNamed, public TRefCnt {
52 public:
53  GContext_t fGC; // graphics context
54  XftFont *fXftFont; // xft font
55 
56  TXftFontData(GContext_t gc, XftFont *xftfont, const char *name) :
57  TNamed(name, ""), TRefCnt(), fXftFont(xftfont)
58  {
59  SetRefCount(1);
60  fGC = gc;
61  }
62 
63  void MapGCFont(GContext_t gc, FontStruct_t font)
64  {
65  fGC = gc; fXftFont = (XftFont *)font;
66  }
67 
68  ~TXftFontData()
69  {
70  if (References() == 1) {
71  if (fXftFont) XftFontClose((Display*)gVirtualX->GetDisplay(), fXftFont);
72  }
73  }
74 };
75 
76 /////////////////// hash table //////////////////////////////////////////////
77 class TXftFontHash {
78 public:
79  THashTable *fList; // hash table
80 
81  TXftFontHash() { fList = new THashTable(50); }
82 
83  TXftFontData *FindByName(const char *name)
84  {
85  return (TXftFontData*)fList->FindObject(name);
86  }
87 
88  TXftFontData *FindByFont(FontStruct_t font)
89  {
90  TIter next(fList);
91  TXftFontData *d = 0;
92 
93  while ((d = (TXftFontData*) next())) {
94  if (d->fXftFont == (XftFont *)font) {
95  return d;
96  }
97  }
98  return 0;
99  }
100 
101  TXftFontData *FindByGC(GContext_t gc)
102  {
103  TIter next(fList);
104  TXftFontData *d = 0;
105 
106  while ((d = (TXftFontData*) next())) {
107  if (d->fGC == gc) {
108  return d;
109  }
110  }
111  return 0;
112  }
113 
114  void AddFont(TXftFontData *data)
115  {
116  // Loop over all existing TXftFontData, if we already have one with the same
117  // font data, set the reference counter of this one beyond 1 so it does
118  // delete the font pointer
119  TIter next(fList);
120  TXftFontData *d = 0;
121 
122  while ((d = (TXftFontData*) next())) {
123  if (d->fXftFont == data->fXftFont) {
124  data->AddReference();
125  }
126  }
127 
128  fList->Add(data);
129  }
130 
131  void FreeFont(TXftFontData *data)
132  {
133  fList->Remove(data);
134  delete data;
135  }
136 };
137 #endif // R__HAS_XFT
138 
139 /** \class TTFX11Init
140 \ingroup GraphicsBackends
141 
142 Small utility class that takes care of switching the current
143 gVirtualX to the new TGX11TTF class as soon as the shared library
144 containing this class is loaded.
145 */
146 
147 class TTFX11Init {
148 public:
149  TTFX11Init() { TGX11TTF::Activate(); }
150 };
151 static TTFX11Init gTTFX11Init;
152 
153 
154 ClassImp(TGX11TTF);
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 /// Create copy of TGX11 but now use TrueType fonts.
158 
159 TGX11TTF::TGX11TTF(const TGX11 &org) : TGX11(org)
160 {
161  SetName("X11TTF");
162  SetTitle("ROOT interface to X11 with TrueType fonts");
163 
164  if (!TTF::fgInit) TTF::Init();
165 
166  fHasTTFonts = kTRUE;
167  fHasXft = kFALSE;
168  fAlign.x = 0;
169  fAlign.y = 0;
170 
171 #ifdef R__HAS_XFT
172  fXftFontHash = 0;
173 #endif
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Static method setting TGX11TTF as the acting gVirtualX.
178 
179 void TGX11TTF::Activate()
180 {
181  if (gVirtualX && dynamic_cast<TGX11*>(gVirtualX)) {
182  TGX11 *oldg = (TGX11 *) gVirtualX;
183  gVirtualX = new TGX11TTF(*oldg);
184  delete oldg;
185  }
186 }
187 
188 ////////////////////////////////////////////////////////////////////////////////
189 /// Initialize X11 system. Returns kFALSE in case of failure.
190 
191 Bool_t TGX11TTF::Init(void *display)
192 {
193 #ifdef R__HAS_XFT
194  fXftFontHash = 0;
195  XFontStruct *fs = 0;
196  if (display) fs = XLoadQueryFont((Display *)display, "-*-helvetica-*-r-*-*-14-*-*-*-*-*-*-*");
197  if (!fs) gEnv->SetValue("X11.UseXft", 1);
198  if (display && fs) XFreeFont((Display *)display, fs);
199  if (gEnv->GetValue("X11.UseXft", 0)) {
200  fHasXft = kTRUE;
201  fXftFontHash = new TXftFontHash();
202  }
203 #endif
204  Bool_t r = TGX11::Init(display);
205 
206  if (fDepth > 8) {
207  TTF::SetSmoothing(kTRUE);
208  } else {
209  TTF::SetSmoothing(kFALSE);
210  }
211 
212  return r;
213 }
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Compute alignment variables. The alignment is done on the horizontal string
217 /// then the rotation is applied on the alignment variables.
218 /// SetRotation and LayoutGlyphs should have been called before.
219 
220 void TGX11TTF::Align(void)
221 {
222  EAlign align = (EAlign) fTextAlign;
223 
224  // vertical alignment
225  if (align == kTLeft || align == kTCenter || align == kTRight) {
226  fAlign.y = TTF::fgAscent;
227  } else if (align == kMLeft || align == kMCenter || align == kMRight) {
228  fAlign.y = TTF::fgAscent/2;
229  } else {
230  fAlign.y = 0;
231  }
232 
233  // horizontal alignment
234  if (align == kTRight || align == kMRight || align == kBRight) {
235  fAlign.x = TTF::fgWidth;
236  } else if (align == kTCenter || align == kMCenter || align == kBCenter) {
237  fAlign.x = TTF::fgWidth/2;
238  } else {
239  fAlign.x = 0;
240  }
241 
242  FT_Vector_Transform(&fAlign, TTF::fgRotMatrix);
243  fAlign.x = fAlign.x >> 6;
244  fAlign.y = fAlign.y >> 6;
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Draw FT_Bitmap bitmap to xim image at position bx,by using specified
249 /// foreground color.
250 
251 void TGX11TTF::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back,
252  RXImage *xim, Int_t bx, Int_t by)
253 {
254  UChar_t d = 0, *s = source->buffer;
255 
256  if (TTF::fgSmoothing) {
257 
258  static RXColor col[5];
259  RXColor *bcol = 0;
260  XColor *bc;
261  Int_t x, y;
262 
263  // background kClear, i.e. transparent, we take as background color
264  // the average of the rgb values of all pixels covered by this character
265  if (back == (ULong_t) -1 && (UInt_t)source->width) {
266  ULong_t r, g, b;
267  Int_t dots, dotcnt;
268  const Int_t maxdots = 50000;
269 
270  dots = Int_t(source->width * source->rows);
271  dots = dots > maxdots ? maxdots : dots;
272  bcol = new RXColor[dots];
273  if (!bcol) return;
274  bc = bcol;
275  dotcnt = 0;
276  for (y = 0; y < (int) source->rows; y++) {
277  for (x = 0; x < (int) source->width; x++, bc++) {
278 /// bc->pixel = XGetPixel(xim, bx + x, by - c->TTF::fgAscent + y);
279  bc->pixel = XGetPixel(xim, bx + x, by + y);
280  bc->flags = DoRed | DoGreen | DoBlue;
281  if (++dotcnt >= maxdots) break;
282  }
283  }
284  QueryColors(fColormap, bcol, dots);
285  r = g = b = 0;
286  bc = bcol;
287  dotcnt = 0;
288  for (y = 0; y < (int) source->rows; y++) {
289  for (x = 0; x < (int) source->width; x++, bc++) {
290  r += bc->red;
291  g += bc->green;
292  b += bc->blue;
293  if (++dotcnt >= maxdots) break;
294  }
295  }
296  if (dots != 0) {
297  r /= dots;
298  g /= dots;
299  b /= dots;
300  }
301  bc = &col[0];
302  if (bc->red == r && bc->green == g && bc->blue == b)
303  bc->pixel = back;
304  else {
305  bc->pixel = ~back;
306  bc->red = (UShort_t) r;
307  bc->green = (UShort_t) g;
308  bc->blue = (UShort_t) b;
309  }
310  }
311  delete [] bcol;
312 
313  // if fore or background have changed from previous character
314  // recalculate the 3 smoothing colors (interpolation between fore-
315  // and background colors)
316  if (fore != col[4].pixel || back != col[0].pixel) {
317  col[4].pixel = fore;
318  col[4].flags = DoRed|DoGreen|DoBlue;
319  if (back != (ULong_t) -1) {
320  col[3].pixel = back;
321  col[3].flags = DoRed | DoGreen | DoBlue;
322  QueryColors(fColormap, &col[3], 2);
323  col[0] = col[3];
324  } else {
325  QueryColors(fColormap, &col[4], 1);
326  }
327 
328  // interpolate between fore and background colors
329  for (x = 3; x > 0; x--) {
330  col[x].red = (col[4].red *x + col[0].red *(4-x)) /4;
331  col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
332  col[x].blue = (col[4].blue *x + col[0].blue *(4-x)) /4;
333  if (!AllocColor(fColormap, &col[x])) {
334  Warning("DrawImage", "cannot allocate smoothing color");
335  col[x].pixel = col[x+1].pixel;
336  }
337  }
338  }
339 
340  // put smoothed character, character pixmap values are an index
341  // into the 5 colors used for aliasing (4 = foreground, 0 = background)
342  for (y = 0; y < (int) source->rows; y++) {
343  for (x = 0; x < (int) source->width; x++) {
344  d = *s++ & 0xff;
345  d = ((d + 10) * 5) / 256;
346  if (d > 4) d = 4;
347  if (d && x < (int) source->width) {
348  ULong_t p = col[d].pixel;
349  XPutPixel(xim, bx + x, by + y, p);
350  }
351  }
352  }
353  } else {
354  // no smoothing, just put character using foreground color
355  UChar_t* row=s;
356  for (int y = 0; y < (int) source->rows; y++) {
357  int n = 0;
358  s = row;
359  for (int x = 0; x < (int) source->width; x++) {
360  if (n == 0) d = *s++;
361  if (TESTBIT(d,7-n))
362  XPutPixel(xim, bx + x, by + y, fore);
363  if (++n == (int) kBitsPerByte) n = 0;
364  }
365  row += source->pitch;
366  }
367  }
368 }
369 
370 ////////////////////////////////////////////////////////////////////////////////
371 /// Draw text using TrueType fonts. If TrueType fonts are not available the
372 /// text is drawn with TGX11::DrawText.
373 
374 void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
375  const char *text, ETextMode mode)
376 {
377  if (!fHasTTFonts) {
378  TGX11::DrawText(x, y, angle, mgn, text, mode);
379  } else {
380  if (!TTF::fgInit) TTF::Init();
381  TTF::SetRotationMatrix(angle);
382  TTF::PrepareString(text);
383  TTF::LayoutGlyphs();
384  Align();
385  RenderString(x, y, mode);
386  }
387 }
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 /// Draw text using TrueType fonts. If TrueType fonts are not available the
391 /// text is drawn with TGX11::DrawText.
392 
393 void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
394  const wchar_t *text, ETextMode mode)
395 {
396  if (!fHasTTFonts) {
397  TGX11::DrawText(x, y, angle, mgn, text, mode);
398  } else {
399  if (!TTF::fgInit) TTF::Init();
400  TTF::SetRotationMatrix(angle);
401  TTF::PrepareString(text);
402  TTF::LayoutGlyphs();
403  Align();
404  RenderString(x, y, mode);
405  }
406 }
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// Get the background of the current window in an XImage.
410 
411 RXImage *TGX11TTF::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h)
412 {
413  Window_t cws = GetCurrentWindow();
414  UInt_t width;
415  UInt_t height;
416  Int_t xy;
417  gVirtualX->GetWindowSize(cws, xy, xy, width, height);
418 
419  if (x < 0) {
420  w += x;
421  x = 0;
422  }
423  if (y < 0) {
424  h += y;
425  y = 0;
426  }
427 
428  if (x+w > width) w = width - x;
429  if (y+h > height) h = height - y;
430 
431  return (RXImage*)XGetImage((Display*)fDisplay, cws, x, y, w, h, AllPlanes, ZPixmap);
432 }
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Test if there is really something to render.
436 
437 Bool_t TGX11TTF::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h)
438 {
439  Window_t cws = GetCurrentWindow();
440  UInt_t width;
441  UInt_t height;
442  Int_t xy;
443  gVirtualX->GetWindowSize(cws, xy, xy, width, height);
444 
445  // If w or h is 0, very likely the string is only blank characters
446  if ((int)w == 0 || (int)h == 0) return kFALSE;
447 
448  // If string falls outside window, there is probably no need to draw it.
449  if (x + (int)w <= 0 || x >= (int)width) return kFALSE;
450  if (y + (int)h <= 0 || y >= (int)height) return kFALSE;
451 
452  // If w or h are much larger than the window size, there is probably no need
453  // to draw it. Moreover a to large text size may produce a Seg Fault in
454  // malloc in RenderString.
455  if (w > 10*width) return kFALSE;
456  if (h > 10*height) return kFALSE;
457 
458  return kTRUE;
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Perform the string rendering in the pad.
463 /// LayoutGlyphs should have been called before.
464 
465 void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode)
466 {
467  TTF::TTGlyph* glyph = TTF::fgGlyphs;
468  GC *gc;
469 
470  // compute the size and position of the XImage that will contain the text
471  Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin;
472  Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin;
473  Int_t w = TTF::GetBox().xMax + Xoff;
474  Int_t h = TTF::GetBox().yMax + Yoff;
475  Int_t x1 = x-Xoff-fAlign.x;
476  Int_t y1 = y+Yoff+fAlign.y-h;
477 
478  if (!IsVisible(x1, y1, w, h)) return;
479 
480  // create the XImage that will contain the text
481  UInt_t depth = fDepth;
482  XImage *xim = 0;
483  xim = XCreateImage((Display*)fDisplay, fVisual,
484  depth, ZPixmap, 0, 0, w, h,
485  depth == 24 ? 32 : (depth==15?16:depth), 0);
486  if (!xim) return;
487 
488  // use malloc since Xlib will use free() in XDestroyImage
489  xim->data = (char *) malloc(xim->bytes_per_line * h);
490  memset(xim->data, 0, xim->bytes_per_line * h);
491 
492  ULong_t bg;
493  XGCValues values;
494  gc = (GC*)GetGC(3);
495  if (!gc) {
496  Error("DrawText", "error getting Graphics Context");
497  return;
498  }
499  XGetGCValues((Display*)fDisplay, *gc, GCForeground | GCBackground, &values);
500 
501  // get the background
502  if (mode == kClear) {
503  // if mode == kClear we need to get an image of the background
504  XImage *bim = GetBackground(x1, y1, w, h);
505  if (!bim) {
506  Error("DrawText", "error getting background image");
507  return;
508  }
509 
510  // and copy it into the text image
511  Int_t xo = 0, yo = 0;
512  if (x1 < 0) xo = -x1;
513  if (y1 < 0) yo = -y1;
514 
515  for (int yp = 0; yp < (int) bim->height; yp++) {
516  for (int xp = 0; xp < (int) bim->width; xp++) {
517  ULong_t pixel = XGetPixel(bim, xp, yp);
518  XPutPixel(xim, xo+xp, yo+yp, pixel);
519  }
520  }
521  XDestroyImage(bim);
522  bg = (ULong_t) -1;
523  } else {
524  // if mode == kOpaque its simple, we just draw the background
525  XAddPixel(xim, values.background);
526  bg = values.background;
527  }
528 
529  // paint the glyphs in the XImage
530  glyph = TTF::fgGlyphs;
531  for (int n = 0; n < TTF::fgNumGlyphs; n++, glyph++) {
532  if (FT_Glyph_To_Bitmap(&glyph->fImage,
533  TTF::fgSmoothing ? ft_render_mode_normal
534  : ft_render_mode_mono,
535  0, 1 )) continue;
536  FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
537  FT_Bitmap* source = &bitmap->bitmap;
538  Int_t bx, by;
539 
540  bx = bitmap->left+Xoff;
541  by = h - bitmap->top-Yoff;
542  DrawImage(source, values.foreground, bg, (RXImage*)xim, bx, by);
543  }
544 
545  // put the Ximage on the screen
546  Window_t cws = GetCurrentWindow();
547  gc = (GC*)GetGC(6);
548  if (gc) XPutImage((Display*)fDisplay, cws, *gc, xim, 0, 0, x1, y1, w, h);
549  XDestroyImage(xim);
550 }
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 /// Set specified font.
554 
555 void TGX11TTF::SetTextFont(Font_t fontnumber)
556 {
557  fTextFont = fontnumber;
558  if (!fHasTTFonts) {
559  TGX11::SetTextFont(fontnumber);
560  } else {
561  TTF::SetTextFont(fontnumber);
562  }
563 }
564 
565 ////////////////////////////////////////////////////////////////////////////////
566 /// Set text font to specified name.
567 /// mode : loading flag
568 /// mode=0 : search if the font exist (kCheck)
569 /// mode=1 : search the font and load it if it exists (kLoad)
570 /// font : font name
571 ///
572 /// Set text font to specified name. This function returns 0 if
573 /// the specified font is found, 1 if not.
574 
575 Int_t TGX11TTF::SetTextFont(char *fontname, ETextSetMode mode)
576 {
577  if (!fHasTTFonts) {
578  return TGX11::SetTextFont(fontname, mode);
579  } else {
580  return TTF::SetTextFont(fontname);
581  }
582 }
583 
584 ////////////////////////////////////////////////////////////////////////////////
585 /// Set current text size.
586 
587 void TGX11TTF::SetTextSize(Float_t textsize)
588 {
589  fTextSize = textsize;
590  if (!fHasTTFonts) {
591  TGX11::SetTextSize(textsize);
592  } else {
593  TTF::SetTextSize(textsize);
594  }
595 }
596 
597 #ifdef R__HAS_XFT
598 
599 ///////////////////////////// Xft font methods /////////////////////////////////
600 ////////////////////////////////////////////////////////////////////////////////
601 /// Parses an XLFD name and opens a font.
602 
603 FontStruct_t TGX11TTF::LoadQueryFont(const char *font_name)
604 {
605  if (!fXftFontHash) {
606  return TGX11::LoadQueryFont(font_name);
607  }
608 
609  TXftFontData *data = fXftFontHash->FindByName(font_name);
610 
611  // already loaded
612  if (data) {
613  return (FontStruct_t)data->fXftFont;
614  }
615 
616  XftFont *xftfont = XftFontOpenXlfd((Display*)fDisplay, fScreenNumber, font_name);
617 
618  data = new TXftFontData(0, xftfont, font_name);
619  fXftFontHash->AddFont(data);
620 
621  return (FontStruct_t)xftfont;
622 }
623 
624 ////////////////////////////////////////////////////////////////////////////////
625 /// Explicitly delete font structure obtained with LoadQueryFont().
626 
627 void TGX11TTF::DeleteFont(FontStruct_t fs)
628 {
629  if (!fXftFontHash) {
630  TGX11::DeleteFont(fs);
631  return;
632  }
633 
634  TXftFontData *data = fXftFontHash->FindByFont(fs);
635 
636  if (data)
637  fXftFontHash->FreeFont(data);
638 }
639 
640 ////////////////////////////////////////////////////////////////////////////////
641 /// Explicitly delete a graphics context.
642 
643 void TGX11TTF::DeleteGC(GContext_t gc)
644 {
645  if (!fXftFontHash) {
646  TGX11::DeleteGC(gc);
647  return;
648  }
649 
650  TXftFontData *gcdata = fXftFontHash->FindByGC(gc);
651  if (gcdata) fXftFontHash->FreeFont(gcdata);
652  TGX11::DeleteGC(gc);
653 }
654 
655 ////////////////////////////////////////////////////////////////////////////////
656 /// Return handle to font described by font structure.
657 
658 FontH_t TGX11TTF::GetFontHandle(FontStruct_t fs)
659 {
660  if (!fXftFontHash) {
661  return TGX11::GetFontHandle(fs);
662  }
663 
664  return (FontH_t)fs;
665 }
666 
667 ////////////////////////////////////////////////////////////////////////////////
668 /// Return the font associated with the graphics context gc
669 
670 FontStruct_t TGX11TTF::GetGCFont(GContext_t gc)
671 {
672  if (!fXftFontHash) {
673  return 0;
674  }
675 
676  TXftFontData *data = fXftFontHash->FindByGC(gc);
677 
678  // no XftFont data
679  if (!data) return 0;
680 
681  return (FontStruct_t)data->fXftFont;
682 }
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 /// Map the XftFont with the Graphics Context using it.
686 
687 void TGX11TTF::MapGCFont(GContext_t gc, FontStruct_t font)
688 {
689  if (!fXftFontHash)
690  return;
691 
692  TXftFontData *gcdata = fXftFontHash->FindByGC(gc);
693  TXftFontData *fontdata = fXftFontHash->FindByFont(font);
694 
695  if (gcdata) { // && (gcdata->fXftFont == 0)) {
696  gcdata->fXftFont = (XftFont *)font;
697  }
698  else if (fontdata) {
699  TXftFontData *data = new TXftFontData(gc, (XftFont *)font, fontdata->GetName());
700  fXftFontHash->AddFont(data);
701  }
702 }
703 
704 ////////////////////////////////////////////////////////////////////////////////
705 /// Return length of string in pixels. Size depends on font
706 
707 Int_t TGX11TTF::TextWidth(FontStruct_t font, const char *s, Int_t len)
708 {
709  if (!fXftFontHash) {
710  return TGX11::TextWidth(font, s, len);
711  }
712 
713  TXftFontData *data = fXftFontHash->FindByFont(font);
714 
715  if (!data) return 0;
716 
717  XftFont *xftfont = data->fXftFont;
718 
719  if (xftfont) {
720  XGlyphInfo glyph_info;
721  XftTextExtents8((Display *)fDisplay, xftfont, (XftChar8 *)s, len, &glyph_info);
722  return glyph_info.xOff;
723  }
724  return 0;
725 }
726 
727 ////////////////////////////////////////////////////////////////////////////////
728 /// Return some font properties
729 
730 void TGX11TTF::GetFontProperties(FontStruct_t font, Int_t &max_ascent, Int_t &max_descent)
731 {
732  if (!fXftFontHash) {
733  TGX11::GetFontProperties(font, max_ascent, max_descent);
734  return;
735  }
736 
737  TXftFontData *data = fXftFontHash->FindByFont(font);
738 
739  if (!data) {
740  TGX11::GetFontProperties(font, max_ascent, max_descent);
741  return;
742  }
743 
744  XftFont *xftfont = data->fXftFont;
745 
746  if (!xftfont) {
747  TGX11::GetFontProperties(font, max_ascent, max_descent);
748  return;
749  }
750 
751  max_ascent = xftfont->ascent;
752  max_descent = xftfont->descent;
753 }
754 
755 ////////////////////////////////////////////////////////////////////////////////
756 /// Draw text string
757 
758 void TGX11TTF::DrawString(Drawable_t xwindow, GContext_t gc, Int_t x, Int_t y,
759  const char *text, Int_t len)
760 {
761  XftDraw *xftdraw;
762  XftColor xftcolor;
763  XColor xcolor;
764  XftFont *xftfont;
765 
766  if (!xwindow) {
767  return;
768  }
769 
770  if (!gc) {
771  return;
772  }
773 
774  if (!text || (len < 1) || !text[0]) {
775  return;
776  }
777 
778  if (!fXftFontHash) {
779  TGX11::DrawString(xwindow, gc, x, y, text, len);
780  return;
781  }
782 
783  GCValues_t gval;
784  gval.fMask = kGCForeground | kGCBackground; // retrieve GC values
785  GetGCValues(gc, gval);
786 
787  TXftFontData *data = fXftFontHash->FindByGC(gc);
788 
789  // no XftFont data
790  if (!data) {
791  TGX11::DrawString(xwindow, gc, x, y, text, len);
792  return;
793  }
794 
795  xftfont = data->fXftFont;
796 
797  // no Xft font
798  if (!xftfont) {
799  TGX11::DrawString(xwindow, gc, x, y, text, len);
800  return;
801  }
802 
803  // dummies
804  Window droot;
805  Int_t dx,dy;
806  UInt_t bwidth, width, height, depth;
807 
808  // check if drawable is bitmap
809  XGetGeometry((Display*)fDisplay, (Drawable)xwindow, &droot, &dx, &dy,
810  &width, &height, &bwidth, &depth);
811 
812  if (depth <= 1) {
813  TGX11::DrawString(xwindow, gc, x, y, text, len);
814  return;
815  }
816 
817  memset(&xcolor, 0, sizeof(xcolor));
818  xcolor.pixel = gval.fForeground;
819 
820  XQueryColor((Display*)fDisplay, fColormap, &xcolor);
821 
822  // create XftDraw
823  xftdraw = XftDrawCreate((Display*)fDisplay, (Drawable)xwindow, fVisual, fColormap);
824 
825  if (!xftdraw) {
826  //Warning("could not create an XftDraw");
827  TGX11::DrawString(xwindow, gc, x, y, text, len);
828  return;
829  }
830 
831  xftcolor.color.red = xcolor.red;
832  xftcolor.color.green = xcolor.green;
833  xftcolor.color.blue = xcolor.blue;
834  xftcolor.color.alpha = 0xffff;
835  xftcolor.pixel = gval.fForeground;
836 
837  XftDrawString8(xftdraw, &xftcolor, xftfont, x, y, (XftChar8 *)text, len);
838 
839  // cleanup
840  XftDrawDestroy(xftdraw);
841 }
842 
843 #endif // R__HAS_XFT
844