26 # include <ft2build.h>
27 # include FT_FREETYPE_H
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
36 #include <X11/cursorfont.h>
37 #include <X11/keysym.h>
40 struct RXColor:XColor{};
41 struct RVisual:Visual{};
42 struct RXImage:XImage{};
48 #include <X11/Xft/Xft.h>
51 class TXftFontData :
public TNamed,
public TRefCnt {
56 TXftFontData(GContext_t gc, XftFont *xftfont,
const char *name) :
57 TNamed(name,
""), TRefCnt(), fXftFont(xftfont)
63 void MapGCFont(GContext_t gc, FontStruct_t font)
65 fGC = gc; fXftFont = (XftFont *)font;
70 if (References() == 1) {
71 if (fXftFont) XftFontClose((Display*)gVirtualX->GetDisplay(), fXftFont);
81 TXftFontHash() { fList =
new THashTable(50); }
83 TXftFontData *FindByName(
const char *name)
85 return (TXftFontData*)fList->FindObject(name);
88 TXftFontData *FindByFont(FontStruct_t font)
93 while ((d = (TXftFontData*) next())) {
94 if (d->fXftFont == (XftFont *)font) {
101 TXftFontData *FindByGC(GContext_t gc)
106 while ((d = (TXftFontData*) next())) {
114 void AddFont(TXftFontData *data)
122 while ((d = (TXftFontData*) next())) {
123 if (d->fXftFont == data->fXftFont) {
124 data->AddReference();
131 void FreeFont(TXftFontData *data)
149 TTFX11Init() { TGX11TTF::Activate(); }
151 static TTFX11Init gTTFX11Init;
159 TGX11TTF::TGX11TTF(
const TGX11 &org) : TGX11(org)
162 SetTitle(
"ROOT interface to X11 with TrueType fonts");
164 if (!TTF::fgInit) TTF::Init();
179 void TGX11TTF::Activate()
181 if (gVirtualX && dynamic_cast<TGX11*>(gVirtualX)) {
182 TGX11 *oldg = (TGX11 *) gVirtualX;
183 gVirtualX =
new TGX11TTF(*oldg);
191 Bool_t TGX11TTF::Init(
void *display)
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)) {
201 fXftFontHash =
new TXftFontHash();
204 Bool_t r = TGX11::Init(display);
207 TTF::SetSmoothing(kTRUE);
209 TTF::SetSmoothing(kFALSE);
220 void TGX11TTF::Align(
void)
222 EAlign align = (EAlign) fTextAlign;
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;
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;
242 FT_Vector_Transform(&fAlign, TTF::fgRotMatrix);
243 fAlign.x = fAlign.x >> 6;
244 fAlign.y = fAlign.y >> 6;
251 void TGX11TTF::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back,
252 RXImage *xim, Int_t bx, Int_t by)
254 UChar_t d = 0, *s = source->buffer;
256 if (TTF::fgSmoothing) {
258 static RXColor col[5];
265 if (back == (ULong_t) -1 && (UInt_t)source->width) {
268 const Int_t maxdots = 50000;
270 dots = Int_t(source->width * source->rows);
271 dots = dots > maxdots ? maxdots : dots;
272 bcol =
new RXColor[dots];
276 for (y = 0; y < (int) source->rows; y++) {
277 for (x = 0; x < (int) source->width; x++, bc++) {
279 bc->pixel = XGetPixel(xim, bx + x, by + y);
280 bc->flags = DoRed | DoGreen | DoBlue;
281 if (++dotcnt >= maxdots)
break;
284 QueryColors(fColormap, bcol, dots);
288 for (y = 0; y < (int) source->rows; y++) {
289 for (x = 0; x < (int) source->width; x++, bc++) {
293 if (++dotcnt >= maxdots)
break;
302 if (bc->red == r && bc->green == g && bc->blue == b)
306 bc->red = (UShort_t) r;
307 bc->green = (UShort_t) g;
308 bc->blue = (UShort_t) b;
316 if (fore != col[4].pixel || back != col[0].pixel) {
318 col[4].flags = DoRed|DoGreen|DoBlue;
319 if (back != (ULong_t) -1) {
321 col[3].flags = DoRed | DoGreen | DoBlue;
322 QueryColors(fColormap, &col[3], 2);
325 QueryColors(fColormap, &col[4], 1);
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;
342 for (y = 0; y < (int) source->rows; y++) {
343 for (x = 0; x < (int) source->width; x++) {
345 d = ((d + 10) * 5) / 256;
347 if (d && x < (
int) source->width) {
348 ULong_t p = col[d].pixel;
349 XPutPixel(xim, bx + x, by + y, p);
356 for (
int y = 0; y < (int) source->rows; y++) {
359 for (
int x = 0; x < (int) source->width; x++) {
360 if (n == 0) d = *s++;
362 XPutPixel(xim, bx + x, by + y, fore);
363 if (++n == (
int) kBitsPerByte) n = 0;
365 row += source->pitch;
374 void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
375 const char *text, ETextMode mode)
378 TGX11::DrawText(x, y, angle, mgn, text, mode);
380 if (!TTF::fgInit) TTF::Init();
381 TTF::SetRotationMatrix(angle);
382 TTF::PrepareString(text);
385 RenderString(x, y, mode);
393 void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
394 const wchar_t *text, ETextMode mode)
397 TGX11::DrawText(x, y, angle, mgn, text, mode);
399 if (!TTF::fgInit) TTF::Init();
400 TTF::SetRotationMatrix(angle);
401 TTF::PrepareString(text);
404 RenderString(x, y, mode);
411 RXImage *TGX11TTF::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h)
413 Window_t cws = GetCurrentWindow();
417 gVirtualX->GetWindowSize(cws, xy, xy, width, height);
428 if (x+w > width) w = width - x;
429 if (y+h > height) h = height - y;
431 return (RXImage*)XGetImage((Display*)fDisplay, cws, x, y, w, h, AllPlanes, ZPixmap);
437 Bool_t TGX11TTF::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h)
439 Window_t cws = GetCurrentWindow();
443 gVirtualX->GetWindowSize(cws, xy, xy, width, height);
446 if ((
int)w == 0 || (
int)h == 0)
return kFALSE;
449 if (x + (
int)w <= 0 || x >= (
int)width)
return kFALSE;
450 if (y + (
int)h <= 0 || y >= (
int)height)
return kFALSE;
455 if (w > 10*width)
return kFALSE;
456 if (h > 10*height)
return kFALSE;
465 void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode)
467 TTF::TTGlyph* glyph = TTF::fgGlyphs;
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;
478 if (!IsVisible(x1, y1, w, h))
return;
481 UInt_t depth = fDepth;
483 xim = XCreateImage((Display*)fDisplay, fVisual,
484 depth, ZPixmap, 0, 0, w, h,
485 depth == 24 ? 32 : (depth==15?16:depth), 0);
489 xim->data = (
char *) malloc(xim->bytes_per_line * h);
490 memset(xim->data, 0, xim->bytes_per_line * h);
496 Error(
"DrawText",
"error getting Graphics Context");
499 XGetGCValues((Display*)fDisplay, *gc, GCForeground | GCBackground, &values);
502 if (mode == kClear) {
504 XImage *bim = GetBackground(x1, y1, w, h);
506 Error(
"DrawText",
"error getting background image");
511 Int_t xo = 0, yo = 0;
512 if (x1 < 0) xo = -x1;
513 if (y1 < 0) yo = -y1;
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);
525 XAddPixel(xim, values.background);
526 bg = values.background;
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,
536 FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
537 FT_Bitmap* source = &bitmap->bitmap;
540 bx = bitmap->left+Xoff;
541 by = h - bitmap->top-Yoff;
542 DrawImage(source, values.foreground, bg, (RXImage*)xim, bx, by);
546 Window_t cws = GetCurrentWindow();
548 if (gc) XPutImage((Display*)fDisplay, cws, *gc, xim, 0, 0, x1, y1, w, h);
555 void TGX11TTF::SetTextFont(Font_t fontnumber)
557 fTextFont = fontnumber;
559 TGX11::SetTextFont(fontnumber);
561 TTF::SetTextFont(fontnumber);
575 Int_t TGX11TTF::SetTextFont(
char *fontname, ETextSetMode mode)
578 return TGX11::SetTextFont(fontname, mode);
580 return TTF::SetTextFont(fontname);
587 void TGX11TTF::SetTextSize(Float_t textsize)
589 fTextSize = textsize;
591 TGX11::SetTextSize(textsize);
593 TTF::SetTextSize(textsize);
603 FontStruct_t TGX11TTF::LoadQueryFont(
const char *font_name)
606 return TGX11::LoadQueryFont(font_name);
609 TXftFontData *data = fXftFontHash->FindByName(font_name);
613 return (FontStruct_t)data->fXftFont;
616 XftFont *xftfont = XftFontOpenXlfd((Display*)fDisplay, fScreenNumber, font_name);
618 data =
new TXftFontData(0, xftfont, font_name);
619 fXftFontHash->AddFont(data);
621 return (FontStruct_t)xftfont;
627 void TGX11TTF::DeleteFont(FontStruct_t fs)
630 TGX11::DeleteFont(fs);
634 TXftFontData *data = fXftFontHash->FindByFont(fs);
637 fXftFontHash->FreeFont(data);
643 void TGX11TTF::DeleteGC(GContext_t gc)
650 TXftFontData *gcdata = fXftFontHash->FindByGC(gc);
651 if (gcdata) fXftFontHash->FreeFont(gcdata);
658 FontH_t TGX11TTF::GetFontHandle(FontStruct_t fs)
661 return TGX11::GetFontHandle(fs);
670 FontStruct_t TGX11TTF::GetGCFont(GContext_t gc)
676 TXftFontData *data = fXftFontHash->FindByGC(gc);
681 return (FontStruct_t)data->fXftFont;
687 void TGX11TTF::MapGCFont(GContext_t gc, FontStruct_t font)
692 TXftFontData *gcdata = fXftFontHash->FindByGC(gc);
693 TXftFontData *fontdata = fXftFontHash->FindByFont(font);
696 gcdata->fXftFont = (XftFont *)font;
699 TXftFontData *data =
new TXftFontData(gc, (XftFont *)font, fontdata->GetName());
700 fXftFontHash->AddFont(data);
707 Int_t TGX11TTF::TextWidth(FontStruct_t font,
const char *s, Int_t len)
710 return TGX11::TextWidth(font, s, len);
713 TXftFontData *data = fXftFontHash->FindByFont(font);
717 XftFont *xftfont = data->fXftFont;
720 XGlyphInfo glyph_info;
721 XftTextExtents8((Display *)fDisplay, xftfont, (XftChar8 *)s, len, &glyph_info);
722 return glyph_info.xOff;
730 void TGX11TTF::GetFontProperties(FontStruct_t font, Int_t &max_ascent, Int_t &max_descent)
733 TGX11::GetFontProperties(font, max_ascent, max_descent);
737 TXftFontData *data = fXftFontHash->FindByFont(font);
740 TGX11::GetFontProperties(font, max_ascent, max_descent);
744 XftFont *xftfont = data->fXftFont;
747 TGX11::GetFontProperties(font, max_ascent, max_descent);
751 max_ascent = xftfont->ascent;
752 max_descent = xftfont->descent;
758 void TGX11TTF::DrawString(Drawable_t xwindow, GContext_t gc, Int_t x, Int_t y,
759 const char *text, Int_t len)
774 if (!text || (len < 1) || !text[0]) {
779 TGX11::DrawString(xwindow, gc, x, y, text, len);
784 gval.fMask = kGCForeground | kGCBackground;
785 GetGCValues(gc, gval);
787 TXftFontData *data = fXftFontHash->FindByGC(gc);
791 TGX11::DrawString(xwindow, gc, x, y, text, len);
795 xftfont = data->fXftFont;
799 TGX11::DrawString(xwindow, gc, x, y, text, len);
806 UInt_t bwidth, width, height, depth;
809 XGetGeometry((Display*)fDisplay, (Drawable)xwindow, &droot, &dx, &dy,
810 &width, &height, &bwidth, &depth);
813 TGX11::DrawString(xwindow, gc, x, y, text, len);
817 memset(&xcolor, 0,
sizeof(xcolor));
818 xcolor.pixel = gval.fForeground;
820 XQueryColor((Display*)fDisplay, fColormap, &xcolor);
823 xftdraw = XftDrawCreate((Display*)fDisplay, (Drawable)xwindow, fVisual, fColormap);
827 TGX11::DrawString(xwindow, gc, x, y, text, len);
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;
837 XftDrawString8(xftdraw, &xftcolor, xftfont, x, y, (XftChar8 *)text, len);
840 XftDrawDestroy(xftdraw);