00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdlib.h>
00027
00028 #include "TGX11TTF.h"
00029 #include "TClass.h"
00030 #include "TEnv.h"
00031
00032 #ifdef R__HAS_XFT
00033
00034 #include "THashTable.h"
00035 #include "TRefCnt.h"
00036 #include <X11/Xft/Xft.h>
00037
00038
00039 class TXftFontData : public TNamed, public TRefCnt {
00040 public:
00041 XFontStruct *fFontStruct;
00042 XftFont *fXftFont;
00043
00044 TXftFontData(FontStruct_t font, XftFont *xftfont, const char *name) :
00045 TNamed(name, ""), TRefCnt(), fXftFont(xftfont)
00046 {
00047 SetRefCount(1);
00048 fFontStruct = (XFontStruct*)font;
00049 }
00050
00051 ~TXftFontData()
00052 {
00053 if (fFontStruct) ((TGX11*)gVirtualX)->DeleteFont((FontStruct_t)fFontStruct);
00054 if (fXftFont) XftFontClose((Display*)gVirtualX->GetDisplay(), fXftFont);
00055 }
00056 };
00057
00058
00059
00060 class TXftFontHash {
00061 public:
00062 THashTable *fList;
00063
00064 TXftFontHash() { fList = new THashTable(50); }
00065
00066 TXftFontData *FindByName(const char *name)
00067 {
00068 return (TXftFontData*)fList->FindObject(name);
00069 }
00070
00071 TXftFontData *FindByStruct(FontStruct_t font)
00072 {
00073 TIter next(fList);
00074 TXftFontData *d = 0;
00075
00076 while ((d = (TXftFontData*) next())) {
00077 if (d->fFontStruct == (XFontStruct*)font) {
00078 return d;
00079 }
00080 }
00081 return 0;
00082 }
00083
00084 TXftFontData *FindByHandle(FontH_t id)
00085 {
00086 TIter next(fList);
00087 TXftFontData *d = 0;
00088
00089 while ((d = (TXftFontData*) next())) {
00090 if (d->fFontStruct->fid == id) {
00091 return d;
00092 }
00093 }
00094 return 0;
00095 }
00096
00097 void AddFont(TXftFontData *data)
00098 {
00099 fList->Add(data);
00100 }
00101
00102 void FreeFont(TXftFontData *data)
00103 {
00104 if (data->RemoveReference() > 0) return;
00105 fList->Remove(data);
00106 delete data;
00107 }
00108 };
00109 #endif // R__HAS_XFT
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 class TTFX11Init {
00122 public:
00123 TTFX11Init() { TGX11TTF::Activate(); }
00124 };
00125 static TTFX11Init gTTFX11Init;
00126
00127
00128 ClassImp(TGX11TTF)
00129
00130
00131 TGX11TTF::TGX11TTF(const TGX11 &org) : TGX11(org)
00132 {
00133
00134
00135 SetName("X11TTF");
00136 SetTitle("ROOT interface to X11 with TrueType fonts");
00137
00138 if (!TTF::fgInit) TTF::Init();
00139
00140 fHasTTFonts = kTRUE;
00141 fAlign.x = 0;
00142 fAlign.y = 0;
00143
00144 #ifdef R__HAS_XFT
00145 fXftFontHash = 0;
00146 if (gEnv->GetValue("X11.UseXft", 0)) {
00147 fXftFontHash = new TXftFontHash();
00148 }
00149 #endif
00150 }
00151
00152
00153 void TGX11TTF::Activate()
00154 {
00155
00156
00157 if (gVirtualX && !strcmp(gVirtualX->IsA()->GetName(), "TGX11")) {
00158 TGX11 *oldg = (TGX11 *) gVirtualX;
00159 gVirtualX = new TGX11TTF(*oldg);
00160 delete oldg;
00161 }
00162 }
00163
00164
00165 Bool_t TGX11TTF::Init(void *display)
00166 {
00167
00168
00169 Bool_t r = TGX11::Init(display);
00170
00171 if (fDepth > 8) {
00172 TTF::SetSmoothing(kTRUE);
00173 } else {
00174 TTF::SetSmoothing(kFALSE);
00175 }
00176
00177 return r;
00178 }
00179
00180
00181 void TGX11TTF::Align(void)
00182 {
00183
00184
00185
00186
00187 EAlign align = (EAlign) fTextAlign;
00188
00189
00190 if (align == kTLeft || align == kTCenter || align == kTRight) {
00191 fAlign.y = TTF::fgAscent;
00192 } else if (align == kMLeft || align == kMCenter || align == kMRight) {
00193 fAlign.y = TTF::fgAscent/2;
00194 } else {
00195 fAlign.y = 0;
00196 }
00197
00198
00199 if (align == kTRight || align == kMRight || align == kBRight) {
00200 fAlign.x = TTF::fgWidth;
00201 } else if (align == kTCenter || align == kMCenter || align == kBCenter) {
00202 fAlign.x = TTF::fgWidth/2;
00203 } else {
00204 fAlign.x = 0;
00205 }
00206
00207 FT_Vector_Transform(&fAlign, TTF::fgRotMatrix);
00208 fAlign.x = fAlign.x >> 6;
00209 fAlign.y = fAlign.y >> 6;
00210 }
00211
00212
00213 void TGX11TTF::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back,
00214 XImage *xim, Int_t bx, Int_t by)
00215 {
00216
00217
00218
00219 UChar_t d = 0, *s = source->buffer;
00220
00221 if (TTF::fgSmoothing) {
00222
00223 static XColor col[5];
00224 XColor *bcol = 0, *bc;
00225 Int_t x, y;
00226
00227
00228
00229 if (back == (ULong_t) -1 && (UInt_t)source->width) {
00230 ULong_t r, g, b;
00231 Int_t dots, dotcnt;
00232 const Int_t maxdots = 50000;
00233
00234 dots = Int_t(source->width * source->rows);
00235 dots = dots > maxdots ? maxdots : dots;
00236 bcol = new XColor[dots];
00237 if (!bcol) return;
00238 bc = bcol;
00239 dotcnt = 0;
00240 for (y = 0; y < (int) source->rows; y++) {
00241 for (x = 0; x < (int) source->width; x++, bc++) {
00242
00243 bc->pixel = XGetPixel(xim, bx + x, by + y);
00244 bc->flags = DoRed | DoGreen | DoBlue;
00245 if (++dotcnt >= maxdots) break;
00246 }
00247 }
00248 QueryColors(fColormap, bcol, dots);
00249 r = g = b = 0;
00250 bc = bcol;
00251 dotcnt = 0;
00252 for (y = 0; y < (int) source->rows; y++) {
00253 for (x = 0; x < (int) source->width; x++, bc++) {
00254 r += bc->red;
00255 g += bc->green;
00256 b += bc->blue;
00257 if (++dotcnt >= maxdots) break;
00258 }
00259 }
00260 if (dots != 0) {
00261 r /= dots;
00262 g /= dots;
00263 b /= dots;
00264 }
00265 bc = &col[0];
00266 if (bc->red == r && bc->green == g && bc->blue == b)
00267 bc->pixel = back;
00268 else {
00269 bc->pixel = ~back;
00270 bc->red = (UShort_t) r;
00271 bc->green = (UShort_t) g;
00272 bc->blue = (UShort_t) b;
00273 }
00274 }
00275 delete [] bcol;
00276
00277
00278
00279
00280 if (fore != col[4].pixel || back != col[0].pixel) {
00281 col[4].pixel = fore;
00282 col[4].flags = DoRed|DoGreen|DoBlue;
00283 if (back != (ULong_t) -1) {
00284 col[3].pixel = back;
00285 col[3].flags = DoRed | DoGreen | DoBlue;
00286 QueryColors(fColormap, &col[3], 2);
00287 col[0] = col[3];
00288 } else {
00289 QueryColors(fColormap, &col[4], 1);
00290 }
00291
00292
00293 for (x = 3; x > 0; x--) {
00294 col[x].red = (col[4].red *x + col[0].red *(4-x)) /4;
00295 col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
00296 col[x].blue = (col[4].blue *x + col[0].blue *(4-x)) /4;
00297 if (!AllocColor(fColormap, &col[x])) {
00298 Warning("DrawImage", "cannot allocate smoothing color");
00299 col[x].pixel = col[x+1].pixel;
00300 }
00301 }
00302 }
00303
00304
00305
00306 for (y = 0; y < (int) source->rows; y++) {
00307 for (x = 0; x < (int) source->width; x++) {
00308 d = *s++ & 0xff;
00309 d = ((d + 10) * 5) / 256;
00310 if (d > 4) d = 4;
00311 if (d && x < (int) source->width) {
00312 ULong_t p = col[d].pixel;
00313 XPutPixel(xim, bx + x, by + y, p);
00314 }
00315 }
00316 }
00317 } else {
00318
00319 UChar_t* row=s;
00320 for (int y = 0; y < (int) source->rows; y++) {
00321 int n = 0;
00322 s = row;
00323 for (int x = 0; x < (int) source->width; x++) {
00324 if (n == 0) d = *s++;
00325 if (TESTBIT(d,7-n))
00326 XPutPixel(xim, bx + x, by + y, fore);
00327 if (++n == (int) kBitsPerByte) n = 0;
00328 }
00329 row += source->pitch;
00330 }
00331 }
00332 }
00333
00334
00335 void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
00336 const char *text, ETextMode mode)
00337 {
00338
00339
00340
00341 if (!fHasTTFonts) {
00342 TGX11::DrawText(x, y, angle, mgn, text, mode);
00343 } else {
00344 if (!TTF::fgInit) TTF::Init();
00345 TTF::SetRotationMatrix(angle);
00346 TTF::PrepareString(text);
00347 TTF::LayoutGlyphs();
00348 Align();
00349 RenderString(x, y, mode);
00350 }
00351 }
00352
00353
00354 XImage *TGX11TTF::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h)
00355 {
00356
00357
00358 Window_t cws = GetCurrentWindow();
00359 UInt_t width;
00360 UInt_t height;
00361 Int_t xy;
00362 gVirtualX->GetWindowSize(cws, xy, xy, width, height);
00363
00364 if (x < 0) {
00365 w += x;
00366 x = 0;
00367 }
00368 if (y < 0) {
00369 h += y;
00370 y = 0;
00371 }
00372
00373 if (x+w > width) w = width - x;
00374 if (y+h > height) h = height - y;
00375
00376 return XGetImage(fDisplay, cws, x, y, w, h, AllPlanes, ZPixmap);
00377 }
00378
00379
00380 Bool_t TGX11TTF::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h)
00381 {
00382
00383
00384 Window_t cws = GetCurrentWindow();
00385 UInt_t width;
00386 UInt_t height;
00387 Int_t xy;
00388 gVirtualX->GetWindowSize(cws, xy, xy, width, height);
00389
00390
00391 if ((int)w == 0 || (int)h == 0) return kFALSE;
00392
00393
00394 if (x + (int)w <= 0 || x >= (int)width) return kFALSE;
00395 if (y + (int)h <= 0 || y >= (int)height) return kFALSE;
00396
00397 return kTRUE;
00398 }
00399
00400
00401 void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode)
00402 {
00403
00404
00405
00406 TTGlyph* glyph = TTF::fgGlyphs;
00407
00408
00409 Int_t Xoff = 0; if (TTF::GetBox().xMin < 0) Xoff = -TTF::GetBox().xMin;
00410 Int_t Yoff = 0; if (TTF::GetBox().yMin < 0) Yoff = -TTF::GetBox().yMin;
00411 Int_t w = TTF::GetBox().xMax + Xoff;
00412 Int_t h = TTF::GetBox().yMax + Yoff;
00413 Int_t x1 = x-Xoff-fAlign.x;
00414 Int_t y1 = y+Yoff+fAlign.y-h;
00415
00416 if (!IsVisible(x1, y1, w, h)) return;
00417
00418
00419 UInt_t depth = fDepth;
00420 XImage *xim = 0;
00421 xim = XCreateImage(fDisplay, fVisual,
00422 depth, ZPixmap, 0, 0, w, h,
00423 depth == 24 ? 32 : (depth==15?16:depth), 0);
00424
00425
00426 xim->data = (char *) malloc(xim->bytes_per_line * h);
00427 memset(xim->data, 0, xim->bytes_per_line * h);
00428
00429 ULong_t bg;
00430 XGCValues values;
00431 XGetGCValues(fDisplay, *GetGC(3), GCForeground | GCBackground, &values);
00432
00433
00434 if (mode == kClear) {
00435
00436 XImage *bim = GetBackground(x1, y1, w, h);
00437 if (!bim) {
00438 Error("DrawText", "error getting background image");
00439 return;
00440 }
00441
00442
00443 Int_t xo = 0, yo = 0;
00444 if (x1 < 0) xo = -x1;
00445 if (y1 < 0) yo = -y1;
00446
00447 for (int yp = 0; yp < (int) bim->height; yp++) {
00448 for (int xp = 0; xp < (int) bim->width; xp++) {
00449 ULong_t pixel = XGetPixel(bim, xp, yp);
00450 XPutPixel(xim, xo+xp, yo+yp, pixel);
00451 }
00452 }
00453 XDestroyImage(bim);
00454 bg = (ULong_t) -1;
00455 } else {
00456
00457 XAddPixel(xim, values.background);
00458 bg = values.background;
00459 }
00460
00461
00462 glyph = TTF::fgGlyphs;
00463 for (int n = 0; n < TTF::fgNumGlyphs; n++, glyph++) {
00464 if (FT_Glyph_To_Bitmap(&glyph->fImage,
00465 TTF::fgSmoothing ? ft_render_mode_normal
00466 : ft_render_mode_mono,
00467 0, 1 )) continue;
00468 FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage;
00469 FT_Bitmap* source = &bitmap->bitmap;
00470 Int_t bx, by;
00471
00472 bx = bitmap->left+Xoff;
00473 by = h - bitmap->top-Yoff;
00474 DrawImage(source, values.foreground, bg, xim, bx, by);
00475 }
00476
00477
00478 Window_t cws = GetCurrentWindow();
00479 GC *gc = GetGC(6);
00480 XPutImage(fDisplay, cws, *gc, xim, 0, 0, x1, y1, w, h);
00481 XDestroyImage(xim);
00482 }
00483
00484
00485 void TGX11TTF::SetTextFont(Font_t fontnumber)
00486 {
00487
00488
00489 fTextFont = fontnumber;
00490 if (!fHasTTFonts) {
00491 TGX11::SetTextFont(fontnumber);
00492 } else {
00493 TTF::SetTextFont(fontnumber);
00494 }
00495 }
00496
00497
00498 Int_t TGX11TTF::SetTextFont(char *fontname, ETextSetMode mode)
00499 {
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509 if (!fHasTTFonts) {
00510 return TGX11::SetTextFont(fontname, mode);
00511 } else {
00512 return TTF::SetTextFont(fontname);
00513 }
00514 }
00515
00516
00517 void TGX11TTF::SetTextSize(Float_t textsize)
00518 {
00519
00520
00521 fTextSize = textsize;
00522 if (!fHasTTFonts) {
00523 TGX11::SetTextSize(textsize);
00524 } else {
00525 TTF::SetTextSize(textsize);
00526 }
00527 }
00528
00529 #ifdef R__HAS_XFT
00530
00531
00532
00533 FontStruct_t TGX11TTF::LoadQueryFont(const char *font_name)
00534 {
00535
00536
00537 if (!fXftFontHash) {
00538 return TGX11::LoadQueryFont(font_name);
00539 }
00540
00541 TXftFontData *data = fXftFontHash->FindByName(font_name);
00542
00543
00544 if (data) {
00545 data->AddReference();
00546 return (FontStruct_t)data->fFontStruct;
00547 }
00548
00549
00550 FontStruct_t font = TGX11::LoadQueryFont(font_name);
00551
00552 if (!font) {
00553 return font;
00554 }
00555
00556 XftFont *xftfont = XftFontOpenXlfd(fDisplay, fScreenNumber, font_name);
00557
00558 data = new TXftFontData(font, xftfont, font_name);
00559 fXftFontHash->AddFont(data);
00560
00561 return font;
00562 }
00563
00564
00565 void TGX11TTF::DeleteFont(FontStruct_t fs)
00566 {
00567
00568
00569 if (!fXftFontHash) {
00570 TGX11::DeleteFont(fs);
00571 return;
00572 }
00573
00574 TXftFontData *data = fXftFontHash->FindByStruct(fs);
00575
00576 if (!data) {
00577 TGX11::DeleteFont(fs);
00578 return;
00579 }
00580
00581 fXftFontHash->FreeFont(data);
00582 }
00583
00584
00585 Int_t TGX11TTF::TextWidth(FontStruct_t font, const char *s, Int_t len)
00586 {
00587
00588
00589 if (!fXftFontHash) {
00590 return TGX11::TextWidth(font, s, len);
00591 }
00592
00593 TXftFontData *data = fXftFontHash->FindByStruct(font);
00594
00595 if (!data) {
00596 return TGX11::TextWidth(font, s, len);
00597 }
00598
00599 XftFont *xftfont = data->fXftFont;
00600
00601 if (!xftfont) {
00602 return TGX11::TextWidth(font, s, len);
00603 }
00604
00605 XGlyphInfo glyph_info;
00606 XftTextExtents8(fDisplay, xftfont, (XftChar8 *)s, len, &glyph_info);
00607
00608 return glyph_info.xOff;
00609 }
00610
00611
00612 void TGX11TTF::GetFontProperties(FontStruct_t font, Int_t &max_ascent, Int_t &max_descent)
00613 {
00614
00615
00616 if (!fXftFontHash) {
00617 TGX11::GetFontProperties(font, max_ascent, max_descent);
00618 return;
00619 }
00620
00621 TXftFontData *data = fXftFontHash->FindByStruct(font);
00622
00623 if (!data) {
00624 TGX11::GetFontProperties(font, max_ascent, max_descent);
00625 return;
00626 }
00627
00628 XftFont *xftfont = data->fXftFont;
00629
00630 if (!xftfont) {
00631 TGX11::GetFontProperties(font, max_ascent, max_descent);
00632 return;
00633 }
00634
00635 max_ascent = xftfont->ascent;
00636 max_descent = xftfont->descent;
00637 }
00638
00639
00640 void TGX11TTF::DrawString(Drawable_t xwindow, GContext_t gc, Int_t x, Int_t y,
00641 const char *text, Int_t len)
00642 {
00643
00644
00645 XftDraw *xftdraw;
00646 XftColor xftcolor;
00647 XColor xcolor;
00648 XftFont *xftfont;
00649
00650 if (!xwindow) {
00651 return;
00652 }
00653
00654 if (!gc) {
00655 return;
00656 }
00657
00658 if (!text || (len < 1) || !strlen(text)) {
00659 return;
00660 }
00661
00662 if (!fXftFontHash) {
00663 TGX11::DrawString(xwindow, gc, x, y, text, len);
00664 return;
00665 }
00666
00667 GCValues_t gval;
00668 gval.fMask = kGCForeground | kGCBackground | kGCFont;
00669 GetGCValues(gc, gval);
00670
00671 TXftFontData *data = fXftFontHash->FindByHandle(gval.fFont);
00672
00673
00674 if (!data) {
00675 TGX11::DrawString(xwindow, gc, x, y, text, len);
00676 return;
00677 }
00678
00679 xftfont = data->fXftFont;
00680
00681
00682 if (!xftfont) {
00683 TGX11::DrawString(xwindow, gc, x, y, text, len);
00684 return;
00685 }
00686
00687
00688 Window droot;
00689 Int_t dx,dy;
00690 UInt_t bwidth, width, height, depth;
00691
00692
00693 XGetGeometry(fDisplay, (Drawable)xwindow, &droot, &dx, &dy,
00694 &width, &height, &bwidth, &depth);
00695
00696 if (depth <= 1) {
00697 TGX11::DrawString(xwindow, gc, x, y, text, len);
00698 return;
00699 }
00700
00701 memset(&xcolor, 0, sizeof(xcolor));
00702 xcolor.pixel = gval.fForeground;
00703
00704 XQueryColor(fDisplay, fColormap, &xcolor);
00705
00706
00707 xftdraw = XftDrawCreate(fDisplay, (Drawable)xwindow, fVisual, fColormap);
00708
00709 if (!xftdraw) {
00710
00711 TGX11::DrawString(xwindow, gc, x, y, text, len);
00712 return;
00713 }
00714
00715 xftcolor.color.red = xcolor.red;
00716 xftcolor.color.green = xcolor.green;
00717 xftcolor.color.blue = xcolor.blue;
00718 xftcolor.color.alpha = 0xffff;
00719 xftcolor.pixel = gval.fForeground;
00720
00721 XftDrawString8(xftdraw, &xftcolor, xftfont, x, y, (XftChar8 *)text, len);
00722
00723
00724 XftDrawDestroy(xftdraw);
00725 }
00726
00727 #endif // R__HAS_XFT