// @(#)root/x11ttf:$Name: $:$Id: TGX11TTF.cxx,v 1.2 2000/06/05 07:31:22 brun Exp $
// Author: Fons Rademakers 21/11/98
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TGX11TTF //
// //
// Interface to low level X11 (Xlib). This class gives access to basic //
// X11 graphics via the parent class TGX11. However, all text and font //
// handling is done via the Freetype TrueType library. When the //
// shared library containing this class is loaded the global gVirtualX is //
// redirected to point to this class. //
// //
//////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG
#include "config.h"
#endif
#include "TGX11TTF.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TList.h"
#include "THashTable.h"
#include "TMath.h"
ClassImp(TGX11TTF)
// to scale TT fonts to same size as X11 fonts
const Float_t kScale = 0.7;
//////////////////////////////////////////////////////////////////////////
// //
// TTFInit //
// //
// Small utility class that takes care of switching the current gVirtualX //
// to the new TGX11TTF class as soon as the shared library containing //
// this class is loaded. //
// //
//////////////////////////////////////////////////////////////////////////
class TTFInit {
public:
TTFInit();
};
TTFInit::TTFInit()
{
if (gVirtualX->IsA() == TGX11::Class()) {
TGX11 *oldg = (TGX11 *) gVirtualX;
gVirtualX = new TGX11TTF(*oldg);
delete oldg;
}
}
static TTFInit gTTFInit;
// Class (actually structure) containing character description
class TTChar : public TObject {
public:
UInt_t fSize; // char size (= nint(fTextSize*kScale))
UInt_t fWidth; // bitmap width
UInt_t fBwidth; // bitmap width, byte boundary
UInt_t fHeight; // bitmap height
UInt_t fCode; // actual char code
UInt_t fCharlen; // origin x axis advance width
Float_t fAngle; // rotation angle in degrees
Int_t fAscent; // (top of bitmap) - (origin y axis)
Int_t fDescent; // (origin y axis) - (bottom of bitmap)
Int_t fXoff; // (left of bitmap) - (origin x axis)
const char *fFontName; // font name (pointer to, not a copy)
UChar_t *fBitmap; // bitmap representing character
TObjLink *fLink; // keep track where in LRU list we are stored
TTChar();
~TTChar();
Bool_t IsEqual(TObject *obj);
ULong_t Hash();
};
TTChar::TTChar()
{
fFontName = 0;
fBitmap = 0;
}
TTChar::~TTChar()
{
delete [] fBitmap;
}
Bool_t TTChar::IsEqual(TObject *obj)
{
TTChar *c = (TTChar *) obj;
if (fCode == c->fCode && fSize == c->fSize && fAngle == c->fAngle &&
!strcmp(fFontName, c->fFontName)) return kTRUE;
return kFALSE;
}
ULong_t TTChar::Hash()
{
return fCode ^ fSize;
}
inline Long_t TTFloor(Long_t x) { return x & -64; }
inline Long_t TTCeil(Long_t x) { return (x + 63) & -64; }
//______________________________________________________________________________
TGX11TTF::TGX11TTF(const TGX11 &org) : TGX11(org)
{
// Create copy of TGX11 but now use TrueType fonts.
SetName("X11TTF");
SetTitle("ROOT interface to X11 with TrueType fonts");
fFontCount = 0;
fCurFontIdx = -1;
fCacheCount = 0;
fCacheHits = 0;
fCacheMisses = 0;
fRotMatrix = 0;
fHinting = kTRUE;
fSmoothing = kFALSE;
if (DefaultDepth(fDisplay,fScreenNumber) > 8)
fSmoothing = kTRUE;
TT_Error error;
// Initialize TTF engine
fEngine = new TT_Engine;
if ((error = TT_Init_FreeType(fEngine))) {
Error("TGX11TTF", "error initializing engine, code = %d", (int)error);
return;
}
fHasTTFonts = kTRUE;
// load default font (arialbd), if this fails we'll continue
// using X11 fonts (SetTextFont will turn off fHasTTFonts)
SetTextFont(62);
fCharCache = new THashTable(kHashSize);
fLRU = new TList;
}
//______________________________________________________________________________
TGX11TTF::~TGX11TTF()
{
// Cleanup.
for (int i = 0; i < fFontCount; i++) {
delete fCharMap[i];
delete fProperties[i];
TT_Close_Face(*fFace[i]);
delete fFace[i];
delete fGlyph[i];
delete fInstance[i];
delete [] fFontName[i];
}
delete fRotMatrix;
TT_Done_FreeType(*fEngine);
delete fEngine;
ClearCache();
delete fCharCache;
delete fLRU;
}
//______________________________________________________________________________
void TGX11TTF::ClearCache()
{
// Clear TTChar cache.
fLRU->Clear(); // must be before the cache delete, or use option "nodelete"
fCharCache->Delete();
fCacheCount = 0;
fCacheHits = 0;
fCacheMisses = 0;
}
//______________________________________________________________________________
void TGX11TTF::Align(UInt_t w, UInt_t, Int_t ascent, Int_t &x, Int_t &y)
{
// Change x,y position depending on required alignment.
EAlign align = (EAlign) fTextAlign;
Int_t nl = 1; // number of lines
if (align == kTLeft || align == kTCenter || align == kTRight)
y += ascent;
else if (align == kMLeft || align == kMCenter || align == kMRight)
y = y - nl*ascent/2 + ascent;
else if (align == kBLeft || align == kBCenter || align == kBRight)
y = y - nl*ascent + ascent;
else // kNone
y = y;
if (align == kTLeft || align == kMLeft || align == kBLeft || align == kNone)
x = x;
else if (align == kTCenter || align == kMCenter || align == kBCenter)
x -= (Int_t) w / 2;
else
x -= w;
}
//______________________________________________________________________________
void TGX11TTF::AlignRotated(UInt_t w, UInt_t, Int_t, Int_t yoff,
Int_t &x, Int_t &y)
{
// Change x,y position or rotated text depending on required alignment.
EAlign align = (EAlign) fTextAlign;
Int_t nl = 1; // number of lines
if (align == kTLeft || align == kTCenter || align == kTRight)
y += yoff;
else if (align == kMLeft || align == kMCenter || align == kMRight)
y = y - nl*yoff/2 + yoff;
else if (align == kBLeft || align == kBCenter || align == kBRight)
y = y - nl*yoff + yoff;
else // kNone
y = y;
if (align == kTLeft || align == kMLeft || align == kBLeft || align == kNone)
x = x;
else if (align == kTCenter || align == kMCenter || align == kBCenter)
x -= (Int_t) w / 2;
else
x -= w;
}
//______________________________________________________________________________
void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn,
const char *text, ETextMode mode)
{
// Draw text using TrueType fonts.
#ifndef R__TTFROT
if (!fHasTTFonts || angle != 0.) {
#else
if (!fHasTTFonts) {
#endif
TGX11::DrawText(x, y, angle, mgn, text, mode);
return;
}
if (!text || !*text) return;
// angles are between 0<=angle<360 degrees
while (angle < 0.)
angle += 360.;
while (angle >= 360.)
angle -= 360.;
// FreeType rotates clockwise
if (angle > 0)
angle = 360 - angle;
angle = (Float_t)TMath::Nint(angle); // steps of 1 degree
if (angle != 0.) {
DrawRotatedText(x, y, angle, text, mode);
return;
}
if (gDebug > 0)
printf("TGX11TTF::DrawText: (x=%d,y=%d,ang=%f,mgn=%f,size=%f,mode=%s) %sn",
x, y, angle, mgn, fTextSize, mode==0 ? "kClear" : "kOpaque", text);
// get size of string so we can create an XImage for it
UInt_t w, h;
Int_t maxa; // maximum ascent
GetTextExtent(w, h, maxa, text);
if (w == 0) {
if (gDebug > 0)
Error("DrawText", "text width is 0, something went very wrong");
return;
}
Align(w, h, maxa, x, y);
Int_t y1 = y - maxa; // top of image (while y is the text baseline)
if (!IsVisible(x, y1, w, h)) return;
// create image that will contain the text
UInt_t depth = DefaultDepth(fDisplay, fScreenNumber);
XImage *xim = XCreateImage(fDisplay, DefaultVisual(fDisplay, fScreenNumber),
depth, ZPixmap, 0, 0, w, h,
depth == 24 ? 32 : (depth==15?16:depth), 0);
// use malloc since Xlib will use free() in XDestroyImage
xim->data = (char *) malloc(xim->bytes_per_line * h);
memset(xim->data, 0, xim->bytes_per_line * h);
ULong_t bg;
XGCValues values;
XGetGCValues(fDisplay, *GetGC(3), GCForeground | GCBackground, &values);
if (mode == kClear) {
// if mode == kClear we need to get an image of the background
XImage *bim = GetBackground(x, y1, w, h);
if (!bim) {
Error("DrawText", "error getting background image");
return;
}
// and copy it into the text image
Int_t xoff = 0, yoff = 0;
if (x < 0) xoff = -x;
if (y1 < 0) yoff = -y1;
for (int yp = 0; yp < (int) bim->height; yp++) {
for (int xp = 0; xp < (int) bim->width; xp++) {
ULong_t pixel = XGetPixel(bim, xp, yp);
XPutPixel(xim, xoff+xp, yoff+yp, pixel);
}
}
XDestroyImage(bim);
bg = (ULong_t) -1;
} else {
// if mode == kOpaque its simple, we just draw the background
XAddPixel(xim, values.background);
bg = values.background;
}
// loop over all characters and draw them in the xim image
Int_t bx = 0;
const char *s = text;
while (s && *s) {
UInt_t code = (UChar_t) *s++;
TTChar *c = GetChar(code, TMath::Nint(fTextSize * kScale), 0.);
if (!c) continue;
DrawImage(c, values.foreground, bg, xim, bx, maxa);
bx += c->fCharlen;
}
// put image back to pixmap on X server
XWindow_t *cws = GetCurrentWindow();
GC *gc = GetGC(6); // gGCpxmp
XPutImage(fDisplay, cws->drawing, *gc, xim, 0, 0, x, y1, w, h);
// cleanup
XDestroyImage(xim);
}
//______________________________________________________________________________
void TGX11TTF::DrawRotatedText(Int_t x, Int_t y, Float_t angle, const char *text,
ETextMode mode)
{
// Draw rotated text using TrueType fonts.
if (gDebug > 0)
printf("TGX11TTF::DrawRotatedText: (x=%d,y=%d,ang=%f,size=%f,mode=%s) %sn",
x, y, angle, fTextSize, mode==0 ? "kClear" : "kOpaque", text);
SetRotationMatrix(angle);
// get size of string so we can create an XImage for it
UInt_t w, h;
Int_t xoff, yoff; // offsets from desired x and y position
GetRotatedTextExtent(w, h, xoff, yoff, angle, text);
printf("GetRotatedTextExtent: angle = %f, width = %d, height = %d, xoff = %d, yoff = %dn",
angle,w,h,xoff,yoff);
if (w == 0) {
if (gDebug > 0)
Error("DrawText", "text width is 0, something went very wrong");
return;
}
AlignRotated(w, h, xoff, yoff, x, y);
Int_t y1 = y - yoff; // top of image (while y is the text baseline)
Int_t x1 = x + xoff;
if (!IsVisible(x1, y1, w, h)) return;
// create image that will contain the text
UInt_t depth = DefaultDepth(fDisplay, fScreenNumber);
XImage *xim = XCreateImage(fDisplay, DefaultVisual(fDisplay, fScreenNumber),
depth, ZPixmap, 0, 0, w, h,
depth == 24 ? 32 : (depth==15?16:depth), 0);
// use malloc since Xlib will use free() in XDestroyImage
xim->data = (char *) malloc(xim->bytes_per_line * h);
memset(xim->data, 0, xim->bytes_per_line * h);
ULong_t bg;
XGCValues values;
XGetGCValues(fDisplay, *GetGC(3), GCForeground | GCBackground, &values);
if (mode == kClear) {
// if mode == kClear we need to get an image of the background
XImage *bim = GetBackground(x1, y1, w, h);
if (!bim) {
Error("DrawText", "error getting background image");
return;
}
// and copy it into the text image
Int_t xoff1 = 0, yoff1 = 0;
if (x1 < 0) xoff1 = -x1;
if (y1 < 0) yoff1 = -y1;
for (int yp = 0; yp < (int) bim->height; yp++) {
for (int xp = 0; xp < (int) bim->width; xp++) {
ULong_t pixel = XGetPixel(bim, xp, yp);
XPutPixel(xim, xoff1+xp, yoff1+yp, pixel);
}
}
XDestroyImage(bim);
bg = (ULong_t) -1;
} else {
// if mode == kOpaque its simple, we just draw the background
XAddPixel(xim, values.background);
bg = values.background;
}
// loop over all characters and draw them in the xim image
Int_t bx = 0, by = 0;
if (angle > 180.) by = h;
const char *s = text;
while (s && *s) {
UInt_t code = (UChar_t) *s++;
TTChar *c = GetChar(code, TMath::Nint(fTextSize * kScale), angle);
if (!c) continue;
//DrawImage(c, values.foreground, bg, xim, bx, by+c->fAscent);
DrawImage(c, values.foreground, bg, xim, bx, by);
TT_Pos vec_x, vec_y;
vec_x = c->fCharlen << 6;
vec_y = 0;
TT_Transform_Vector(&vec_x, &vec_y, fRotMatrix);
bx += Int_t(vec_x >> 6);
if (angle > 180.)
by -= Int_t(vec_y >> 6);
else
by += Int_t(vec_y >> 6);
}
// put image back to pixmap on X server
XWindow_t *cws = GetCurrentWindow();
GC *gc = GetGC(6); // gGCpxmp
XPutImage(fDisplay, cws->drawing, *gc, xim, 0, 0, x1, y1, w, h);
// cleanup
XDestroyImage(xim);
}
//______________________________________________________________________________
void TGX11TTF::GetTextExtent(UInt_t &w, UInt_t &h, Int_t &maxAscent, const char *text)
{
// Get bounding box of text, returns also the maximum ascent
// in the string. This is used to position the string (at y-maxAscent).
// Private interface.
w = h = 0;
maxAscent = 0;
const char *s = text;
int maxa = 0, maxd = 0, extra = 0;
// loop over all characters in the string and calculate length + height
while (s && *s) {
UInt_t code = (UChar_t) *s++;
TTChar *c = GetChar(code, TMath::Nint(fTextSize * kScale), 0.);
if (!c) continue;
w += c->fCharlen;
extra = c->fXoff + c->fWidth - c->fCharlen;
maxa = TMath::Max(maxa, c->fAscent);
maxd = TMath::Max(maxd, c->fDescent);
if (gDebug > 1)
printf("char %c: a = %d, d = %d, w = %dn", code, c->fAscent, c->fDescent, c->fCharlen);
}
if (extra > 0) w += extra;
h = maxa + maxd;
maxAscent = maxa;
if (gDebug > 0)
printf("TGX11TTF::GetTextExtent: %d, %d, %d, %sn", w, h, maxa, text);
}
//______________________________________________________________________________
void TGX11TTF::GetRotatedTextExtent(UInt_t &w, UInt_t &h, Int_t &xoff, Int_t &yoff,
Float_t angle, const char *text)
{
// Get bounding box of rotated text, returns also the maximum descent
// in the string. This is used to position the string. Private interface.
w = h = 0;
xoff = yoff = 0;
const char *s = text;
int x = 0, y = 0, maxx = 0, maxy = 0, minx = 9999, miny = 9999;
// loop over all characters in the string and calculate length + height
while (s && *s) {
UInt_t code = (UChar_t) *s++;
TTChar *c = GetChar(code, TMath::Nint(fTextSize * kScale), angle);
if (!c) continue;
minx = TMath::Min(minx, x+c->fXoff);
miny = TMath::Min(miny, y+c->fDescent);
maxx = TMath::Max(maxx, int(x+c->fXoff+c->fWidth));
maxy = TMath::Max(maxy, int(y+c->fDescent+c->fHeight));
TT_Pos vec_x, vec_y;
vec_x = c->fCharlen << 6;
vec_y = 0;
TT_Transform_Vector(&vec_x, &vec_y, fRotMatrix);
x += Int_t(vec_x >> 6);
y += Int_t(vec_y >> 6);
if (gDebug > 1)
printf("char %c: a = %d, d = %d, w = %dn", code, c->fAscent, c->fDescent, c->fCharlen);
}
w = maxx - minx;
h = maxy - miny;
xoff = TMath::Min(minx, maxx);
yoff = TMath::Max(miny, maxy);
if (gDebug > 0)
printf("TGX11TTF::GetRotatedTextExtent: %d, %d, %d, %d, %sn", w, h, xoff, yoff, text);
}
//______________________________________________________________________________
void TGX11TTF::GetTextExtent(UInt_t &w, UInt_t &h, char *text)
{
// Get bounding box of text.
#ifndef R__TTFROT
if (!fHasTTFonts || fTextAngle != 0.) {
#else
if (!fHasTTFonts) {
#endif
TGX11::GetTextExtent(w, h, text);
return;
}
Int_t maxa;
GetTextExtent(w, h, maxa, text);
}
//______________________________________________________________________________
Int_t TGX11TTF::SetTextFont(char *fontname, ETextSetMode mode)
{
// Set text font to specified name.
// mode : loading flag
// mode=0 : search if the font exist (kCheck)
// mode=1 : search the font and load it if it exists (kLoad)
// font : font name
//
// Set text font to specified name. This function returns 0 if
// the specified font is found, 1 if not.
#ifndef R__TTFROT
if (!fHasTTFonts || fTextAngle != 0.)
#else
if (!fHasTTFonts)
#endif
return TGX11::SetTextFont(fontname, mode);
if (gDebug > 0)
printf("SetTextFont: %s (%s)\n", fontname, mode==kLoad?"kLoad":"kCheck");
if (!fontname || !fontname[0]) {
Error("SetTextFont", "no font name specified");
if (mode == kCheck) return 1;
Warning("SetTextFont", "using default font %s", fFontName[0]);
fCurFontIdx = 0; // use font 0 (default font, set in ctor)
return 0;
}
const char *basename = gSystem->BaseName(fontname);
// check if font is in cache
int i;
for (i = 0; i < fFontCount; i++) {
if (!strcmp(fFontName[i], basename)) {
if (mode == kCheck) return 0;
fCurFontIdx = i;
return 0;
}
}
// enough space in cache to load font?
if (fFontCount >= kTTMaxFonts) {
Error("SetTextFont", "too many fonts opened (increase kTTMaxFont = %d)",
kTTMaxFonts);
if (mode == kCheck) return 1;
Warning("SetTextFont", "using default font %s", fFontName[0]);
fCurFontIdx = 0; // use font 0 (default font, set in ctor)
return 0;
}
// try to load font (font must be in Root.TTFontPath resource)
#ifndef TTFFONTDIR
const char *ttpath = gEnv->GetValue("Root.TTFontPath",
"$(ROOTSYS)/ttf/fonts");
#else
const char *ttpath = gEnv->GetValue("Root.TTFontPath",
TTFFONTDIR );
#endif
char *ttfont = gSystem->Which(ttpath, fontname, kReadPermission);
if (!ttfont) {
Error("SetTextFont", "font file %s not found in path", fontname);
if (mode == kCheck) return 1;
if (fFontCount) {
Warning("SetTextFont", "using default font %s", fFontName[0]);
fCurFontIdx = 0; // use font 0 (default font, set in ctor)
return 0;
} else {
Error("SetTextFont", "switching back to X11 fonts");
fHasTTFonts = kFALSE;
return 1;
}
}
if (mode == kCheck) {
delete [] ttfont;
return 0;
}
Int_t res = 96; // dpi for SVGA display
TT_Error error;
TT_Face *tface = new TT_Face;
error = TT_Open_Face(*fEngine, ttfont, tface);
if (error) {
Error("SetTextFont", "error loading font %s", ttfont);
delete [] ttfont;
delete tface;
if (mode == kCheck) return 1;
if (fFontCount) {
Warning("SetTextFont", "using default font %s", fFontName[0]);
fCurFontIdx = 0; // use font 0 (default font, set in ctor)
return 0;
} else {
Error("SetTextFont", "switching back to X11 fonts");
fHasTTFonts = kFALSE;
return 1;
}
}
delete [] ttfont;
fFontName[fFontCount] = StrDup(basename);
fCurFontIdx = fFontCount;
fFace[fCurFontIdx] = tface;
fFontCount++;
// get face properties and allocate preload arrays
fProperties[fCurFontIdx] = new TT_Face_Properties;
error = TT_Get_Face_Properties(*tface, fProperties[fCurFontIdx]);
if (error) {
SafeDelete(fProperties[fCurFontIdx]);
Error("SetTextFont", "error getting properties for font %s", basename);
goto fail;
}
// create glyph
fGlyph[fCurFontIdx] = new TT_Glyph;
error = TT_New_Glyph(*tface, fGlyph[fCurFontIdx]);
if (error) {
SafeDelete(fGlyph[fCurFontIdx]);
Error("SetTextFont", "error creating glyph for font %s", basename);
goto fail;
}
// create instance
fInstance[fCurFontIdx] = new TT_Instance;
error = TT_New_Instance(*tface, fInstance[fCurFontIdx]);
if (error) {
SafeDelete(fInstance[fCurFontIdx]);
Error("SetTextFont", "error creating instance for font %s", basename);
goto fail;
}
// set device resolution
error = TT_Set_Instance_Resolutions(*fInstance[fCurFontIdx], res, res);
if (error) {
Error("SetTextFont", "could not set device resolutions for font %s", basename);
goto fail;
}
fCharMap[fCurFontIdx] = 0;
// set initial text size
SetTextSize(fTextSize);
return 0;
fail:
TT_Close_Face(*tface);
fFontCount--;
delete [] fFontName[fFontCount];
SafeDelete(fFace[fCurFontIdx]);
if (mode == kCheck) return 1;
if (fFontCount) {
Warning("SetTextFont", "using default font %s", fFontName[0]);
fCurFontIdx = 0; // use font 0 (default font, set in ctor)
return 0;
} else {
Error("SetTextFont", "switching back to X11 fonts");
fHasTTFonts = kFALSE;
return 1;
}
}
//______________________________________________________________________________
void TGX11TTF::SetTextFont(Font_t fontnumber)
{
// Set specified font.
// List of the currently supported fonts (screen and PostScript)
// =============================================================
// Font ID X11 TTF
// 1 : times-medium-i-normal timesi.ttf
// 2 : times-bold-r-normal timesbd.ttf
// 3 : times-bold-i-normal timesi.ttf
// 4 : helvetica-medium-r-normal arial.ttf
// 5 : helvetica-medium-o-normal ariali.ttf
// 6 : helvetica-bold-r-normal arialbd.ttf
// 7 : helvetica-bold-o-normal arialbi.ttf
// 8 : courier-medium-r-normal cour.ttf
// 9 : courier-medium-o-normal couri.ttf
// 10 : courier-bold-r-normal courbd.ttf
// 11 : courier-bold-o-normal courbi.ttf
// 12 : symbol-medium-r-normal symbol.ttf
// 13 : times-medium-r-normal times.ttf
// 14 : wingding.ttf
#ifndef R__TTFROT
if (!fHasTTFonts || fTextAngle != 0.) {
#else
if (!fHasTTFonts) {
#endif
TGX11::SetTextFont(fontnumber);
return;
}
fTextFont = fontnumber;
const char *fontname;
switch (fontnumber/10) {
case 1:
fontname = "timesi.ttf";
break;
case 2:
fontname = "timesbd.ttf";
break;
case 3:
fontname = "timesbi.ttf";
break;
case 4:
fontname = "arial.ttf";
break;
case 5:
fontname = "ariali.ttf";
break;
case 6:
fontname = "arialbd.ttf";
break;
case 7:
fontname = "arialbi.ttf";
break;
case 8:
fontname = "cour.ttf";
break;
case 9:
fontname = "couri.ttf";
break;
case 10:
fontname = "courbd.ttf";
break;
case 11:
fontname = "courbi.ttf";
break;
case 12:
fontname = "symbol.ttf";
break;
case 13:
fontname = "times.ttf";
break;
case 14:
fontname = "wingding.ttf";
break;
default:
fontname = "arialbd.ttf";
break;
}
SetTextFont((char *)fontname, kLoad);
}
//______________________________________________________________________________
void TGX11TTF::SetTextSize(Float_t textsize)
{
// Set current text size.
#ifndef R__TTFROT
if (!fHasTTFonts || fTextAngle != 0.) {
#else
if (!fHasTTFonts) {
#endif
TGX11::SetTextSize(textsize);
#ifndef R__TTFROT
if (!fHasTTFonts)
#endif
return;
}
if (gDebug > 0)
printf("SetTextSize: %f\n", textsize);
fTextSize = textsize;
if (fTextSize < 0) return;
if (fCurFontIdx < 0 || fFontCount <= fCurFontIdx) {
Error("SetTextSize", "current font index out of bounds");
return;
}
Int_t tsize = TMath::Nint(fTextSize * kScale) << 6;
TT_Error error = TT_Set_Instance_CharSize(*fInstance[fCurFontIdx], tsize);
if (error)
Error("SetTextSize", "could not set new size in instance");
}
//______________________________________________________________________________
TTChar *TGX11TTF::GetChar(UInt_t code, UInt_t size, Float_t angle, Bool_t force)
{
// Get a TTChar corresponding to the char code, size and current font.
// If force is true (the default) and the cache is full the lru char
// will be removed from the cache. If false it returns 0.
// look for char in cache
TTChar *c = LookupChar(code, size, angle, fFontName[fCurFontIdx]);
if (!c) {
while (fCacheCount >= kCacheSize) {
if (!force) return 0;
// get least recent used char
TTChar *lru = (TTChar *)fLRU->LastLink()->GetObject();
// remove from lru list and hashtable
fLRU->Remove(lru->fLink);
fCharCache->Remove(lru);
delete lru;
fCacheCount--;
}
// create new char
if (angle == 0.)
c = AllocChar(code, size, fFontName[fCurFontIdx]);
else
c = AllocRotatedChar(code, size, angle, fFontName[fCurFontIdx]);
}
return c;
}
//______________________________________________________________________________
TTChar *TGX11TTF::LookupChar(UInt_t code, UInt_t size, Float_t angle, const char *fontname)
{
// Find TTChar corresponding to the char code, size and font in cache.
// Returns 0 if not in cache.
TTChar tmp;
tmp.fCode = code;
tmp.fSize = size;
tmp.fAngle = angle;
tmp.fFontName = fontname;
TTChar *c = (TTChar *) fCharCache->FindObject(&tmp);
if (c) {
// when found in cache bring to front of lru list
fLRU->Remove(c->fLink);
fLRU->AddFirst(c);
c->fLink = fLRU->FirstLink();
fCacheHits++;
} else
fCacheMisses++;
return c;
}
//______________________________________________________________________________
TTChar *TGX11TTF::AllocChar(UInt_t code, UInt_t size, const char *fontname)
{
// Allocate a TTChar object corresponding to the char code, size and font.
// TTChar is added to the cache for later reuse. In case of failure
// return 0.
Short_t unicode = CharToUnicode(code);
if (!unicode)
return 0;
TT_Error error;
if ((error = LoadTrueTypeChar(unicode))) {
Error("AllocChar", "LoadTrueTypeChar %c (0x%04x) failed for font %s (err=%d)",
isprint(unicode) ? unicode : '?', unicode, fontname, error);
//fprintf(stderr, "Reason: %sn", TT_ErrToString18(error));
return 0;
}
TT_Glyph_Metrics metrics;
TT_Get_Glyph_Metrics(*fGlyph[fCurFontIdx], &metrics);
// TT_Get_Glyph_Pixmap generates pixmap starting from FreeType
// origin (leftmost side, baseline). Because of this 3rd and 4th
// arguments are necessary.
// For X axis (3rd argument), we have to take metrics.bearingX as
// offset. Y axis must be shifted if there's descent box (image
// below the baseline). 4th argument is specified for that.
TT_Raster_Map bitmap;
bitmap.rows = int((metrics.bbox.yMax - metrics.bbox.yMin) >> 6);
bitmap.rows += 2; // insurance to cope with number-round error
bitmap.width = int((metrics.bbox.xMax - metrics.bbox.xMin) >> 6);
bitmap.width += 2; // insurance to cope with number-round error
if (fSmoothing)
bitmap.cols = (bitmap.width+3) & -4;
else
bitmap.cols = (bitmap.width+7) >> 3;
bitmap.flow = TT_Flow_Down;
bitmap.size = (long)bitmap.cols * bitmap.rows;
bitmap.bitmap = (void *)new char[bitmap.size];
memset(bitmap.bitmap, 0, (size_t)bitmap.size);
// be very careful about TTCeil/TTFloor, must be multiples of 64 otherwise
// hinting will be ruined if this is not the case
if (fSmoothing)
TT_Get_Glyph_Pixmap(*fGlyph[fCurFontIdx], &bitmap, TTCeil(-metrics.bearingX),
TTCeil(metrics.bbox.yMax - metrics.bbox.yMin - metrics.bearingY));
else
TT_Get_Glyph_Bitmap(*fGlyph[fCurFontIdx], &bitmap, TTCeil(-metrics.bearingX),
TTCeil(metrics.bbox.yMax - metrics.bbox.yMin - metrics.bearingY));
TTChar *c = new TTChar;
c->fCode = code;
c->fSize = size;
c->fAngle = 0.;
c->fWidth = bitmap.width;
c->fBwidth = bitmap.cols;
c->fHeight = bitmap.rows;
// ascent must be derived from descent, to avoid number-rounding errors
c->fDescent = int(TTCeil(metrics.bbox.yMax - metrics.bbox.yMin - metrics.bearingY) >> 6);
c->fAscent = bitmap.rows - c->fDescent;
c->fXoff = int(metrics.bearingX >> 6);
if (c->fXoff < 0) c->fXoff = 0;
c->fFontName = fontname;
c->fCharlen = int(metrics.advance >> 6);
c->fBitmap = (UChar_t *)bitmap.bitmap;
fCharCache->Add(c);
fLRU->AddFirst(c);
c->fLink = fLRU->FirstLink();
fCacheCount++;
return c;
}
//______________________________________________________________________________
TTChar *TGX11TTF::AllocRotatedChar(UInt_t code, UInt_t size, Float_t angle,
const char *fontname)
{
// Allocate a TTChar object corresponding to the char code, size, angle
// and font. TTChar is added to the cache for later reuse. In case of failure
// return 0.
Short_t unicode = CharToUnicode(code);
if (!unicode)
return 0;
TT_Error error;
if ((error = LoadTrueTypeChar(unicode))) {
Error("AllocChar", "LoadTrueTypeChar %c (0x%04x) failed for font %s (err=%d)",
isprint(unicode) ? unicode : '?', unicode, fontname, error);
//fprintf(stderr, "Reason: %sn", TT_ErrToString18(error));
return 0;
}
TT_Glyph_Metrics metrics;
TT_Get_Glyph_Metrics(*fGlyph[fCurFontIdx], &metrics);
// access its outline
TT_Outline outline;
TT_Get_Glyph_Outline(*fGlyph[fCurFontIdx], &outline);
// copy outline and rotate it
TT_Outline toutline;
TT_New_Outline(outline.n_points, outline.n_contours, &toutline);
TT_Copy_Outline(&outline, &toutline);
TT_Transform_Outline(&toutline, fRotMatrix);
// get bounding box and grid-fit it
TT_BBox bbox;
TT_Get_Outline_BBox(&toutline, &bbox);
bbox.xMin = TTFloor(bbox.xMin);
bbox.yMin = TTFloor(bbox.yMin);
bbox.xMax = TTCeil(bbox.xMax);
bbox.yMax = TTCeil(bbox.yMax);
TT_Translate_Outline(&toutline, -bbox.xMin, -bbox.yMin);
// TT_Get_Outline_Pixmap generates pixmap starting from FreeType
// origin (leftmost side, baseline). Because of this 3rd and 4th
// arguments are necessary.
// For X axis (3rd argument), we have to take metrics.bearingX as
// offset. Y axis must be shifted if there's descent box (image
// below the baseline). 4th argument is specified for that.
TT_Raster_Map bitmap;
bitmap.rows = int((bbox.yMax - bbox.yMin) >> 6);
bitmap.rows += 2; // insurance to cope with number-round error
bitmap.width = int((bbox.xMax - bbox.xMin) >> 6);
bitmap.width += 2; // insurance to cope with number-round error
if (fSmoothing)
bitmap.cols = (bitmap.width+3) & -4;
else
bitmap.cols = (bitmap.width+7) >> 3;
bitmap.flow = TT_Flow_Down;
bitmap.size = (long)bitmap.cols * bitmap.rows;
bitmap.bitmap = (void *)new char[bitmap.size];
memset(bitmap.bitmap, 0, (size_t)bitmap.size);
// be very careful about TTCeil/TTFloor, must be multiples of 64 otherwise
// hinting will be ruined if this is not the case
if (fSmoothing)
TT_Get_Outline_Pixmap(*fEngine, &toutline, &bitmap);
else
TT_Get_Outline_Bitmap(*fEngine, &toutline, &bitmap);
TTChar *c = new TTChar;
c->fCode = code;
c->fSize = size;
c->fAngle = angle;
c->fWidth = bitmap.width;
c->fBwidth = bitmap.cols;
c->fHeight = bitmap.rows;
// ascent must be derived from descent, to avoid number-rounding errors
c->fDescent = int(bbox.yMin >> 6);
c->fAscent = bitmap.rows - c->fDescent;
c->fXoff = int(bbox.xMin >> 6);
c->fFontName = fontname;
c->fCharlen = int(metrics.advance >> 6);
c->fBitmap = (UChar_t *)bitmap.bitmap;
fCharCache->Add(c);
fLRU->AddFirst(c);
c->fLink = fLRU->FirstLink();
fCacheCount++;
TT_Done_Outline(&toutline);
return c;
}
//______________________________________________________________________________
Short_t TGX11TTF::CharToUnicode(UInt_t code)
{
// Map char to unicode. Returns 0 in case no mapping exists.
if (!fCharMap[fCurFontIdx]) {
UShort_t i, platform, encoding;
fCharMap[fCurFontIdx] = new TT_CharMap;
// first look for a unicode charmap
Int_t n = fProperties[fCurFontIdx]->num_CharMaps;
for (i = 0; i < n; i++) {
TT_Get_CharMap_ID(*fFace[fCurFontIdx], i, &platform, &encoding);
if ((platform == 3 && encoding == 1) ||
(platform == 0 && encoding == 0) ||
(platform == 1 && encoding == 0 &&
!strcmp(fFontName[fCurFontIdx],"symbol.ttf"))) {
TT_Get_CharMap(*fFace[fCurFontIdx], i, fCharMap[fCurFontIdx]);
return TT_Char_Index(*fCharMap[fCurFontIdx], (Short_t) code);
}
}
if (gDebug > 0)
Warning("CharToUnicode", "the fontfile %s doesn't contain any unicode "
"mapping tablen", fFontName[fCurFontIdx]);
}
return TT_Char_Index(*fCharMap[fCurFontIdx], (Short_t) code);
}
//______________________________________________________________________________
Int_t TGX11TTF::LoadTrueTypeChar(Int_t idx)
{
// Load the True Type character.
int flags;
flags = TTLOAD_SCALE_GLYPH;
if (fHinting)
flags |= TTLOAD_HINT_GLYPH;
return TT_Load_Glyph(*fInstance[fCurFontIdx], *fGlyph[fCurFontIdx], idx, flags);
}
//______________________________________________________________________________
XImage *TGX11TTF::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
// Get the background of the current window in an XImage.
XWindow_t *cws = GetCurrentWindow();
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
if (x+w > cws->width) w = cws->width - x;
if (y+h > cws->height) h = cws->height - y;
return XGetImage(fDisplay, cws->drawing, x, y, w, h, AllPlanes, ZPixmap);
}
//______________________________________________________________________________
Bool_t TGX11TTF::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
// If string falls outside window, there is probably no need to draw it.
XWindow_t *cws = GetCurrentWindow();
if (x + (int)w <= 0 || x >= (int)cws->width) return kFALSE;
if (y + (int)h <= 0 || y >= (int)cws->height) return kFALSE;
return kTRUE;
}
//______________________________________________________________________________
void TGX11TTF::DrawImage(TTChar *c, ULong_t fore, ULong_t back, XImage *xim,
Int_t bx, Int_t by)
{
// Draw TTChar bitmap to xim image at position bx,by using specified
// foreground color.
UChar_t d = 0, *s = c->fBitmap;
if (fSmoothing) {
static XColor col[5];
XColor *bcol = 0, *bc;
Int_t x, y;
//UInt_t charlen = c->fCharlen;
UInt_t charlen = c->fWidth;
// background kClear, i.e. transparent, we take as background color
// the average of the rgb values of all pixels covered by this character
if (back == (ULong_t) -1 && charlen) {
ULong_t r, g, b;
Int_t dots, dotcnt;
const Int_t maxdots = 50000;
dots = Int_t(charlen * c->fHeight);
dots = dots > maxdots ? maxdots : dots;
bcol = new XColor[dots];
if (!bcol) return;
bc = bcol;
dotcnt = 0;
for (y = 0; y < (int) c->fHeight; y++) {
for (x = 0; x < (int) charlen; x++, bc++) {
bc->pixel = XGetPixel(xim, bx + c->fXoff + x, by - c->fAscent + y);
bc->flags = DoRed|DoGreen|DoBlue;
if (++dotcnt >= maxdots) break;
}
}
XQueryColors(fDisplay, fColormap, bcol, dots);
r = g = b = 0;
bc = bcol;
dotcnt = 0;
for (y = 0; y < (int) c->fHeight; y++) {
for (x = 0; x < (int) charlen; x++, bc++) {
r += bc->red;
g += bc->green;
b += bc->blue;
if (++dotcnt >= maxdots) break;
}
}
r /= dots; g /= dots; b /= dots;
bc = &col[0];
if (bc->red == r && bc->green == g && bc->blue == b)
bc->pixel = back;
else {
bc->pixel = ~back;
bc->red = (UShort_t) r;
bc->green = (UShort_t) g;
bc->blue = (UShort_t) b;
}
}
delete [] bcol;
// if fore or background have changed from previous character
// recalculate the 3 smooting colors (interpolation between fore-
// and background colors)
if (fore != col[4].pixel || back != col[0].pixel) {
col[4].pixel = fore;
col[4].flags = DoRed|DoGreen|DoBlue;
if (back != (ULong_t) -1) {
col[3].pixel = back;
col[3].flags = DoRed|DoGreen|DoBlue;
XQueryColors(fDisplay, fColormap, &col[3], 2);
col[0] = col[3];
} else
XQueryColor(fDisplay, fColormap, &col[4]);
// interpolate between fore and backgound colors
for (x = 3; x > 0; x--) {
col[x].red = (col[4].red *x + col[0].red *(4-x)) /4;
col[x].green = (col[4].green*x + col[0].green*(4-x)) /4;
col[x].blue = (col[4].blue *x + col[0].blue *(4-x)) /4;
if (!XAllocColor(fDisplay, fColormap, &col[x])) {
Warning("DrawImage", "cannot allocate smoothing color");
col[x].pixel = col[x+1].pixel;
}
}
}
// put smoothed character, character pixmap values are an index
// into the 5 colors used for aliasing (4 = foreground, 0 = background)
for (y = 0; y < (int) c->fHeight; y++) {
for (x = 0; x < (int) c->fBwidth; x++) {
d = *s++;
if (d && x < (int) c->fWidth) {
ULong_t p = col[d].pixel;
XPutPixel(xim, bx + c->fXoff + x, by - c->fAscent + y, p);
}
}
}
} else {
// no smoothing, just put charachter using foreground color
for (int y = 0; y < (int) c->fHeight; y++) {
int n = 0;
for (int x = 0; x < (int) c->fWidth; x++) {
if (n == 0) d = *s++;
if (TESTBIT(d,7-n)) {
XPutPixel(xim, bx + c->fXoff + x, by - c->fAscent + y, fore);
}
if (++n == (int) kBitsPerByte) n = 0;
}
}
}
}
//______________________________________________________________________________
void TGX11TTF::SetRotationMatrix(Float_t angle)
{
// Set the rotation matrix used to rotate the font outlines.
//TT_Set_Instance_Transform_Flags( instance, 1, 0 );
if (fRotMatrix) {
SafeDelete(fRotMatrix);
}
fRotMatrix = new TT_Matrix;
angle = Float_t(angle * TMath::Pi() / 180.);
fRotMatrix->xx = (TT_Fixed) (TMath::Cos(angle) * (1<<16));
fRotMatrix->xy = (TT_Fixed) (TMath::Sin(angle) * (1<<16));
fRotMatrix->yx = -fRotMatrix->xy;
fRotMatrix->yy = fRotMatrix->xx;
}
//______________________________________________________________________________
void TGX11TTF::SetHinting(Bool_t state)
{
// Set hinting flag. If status changes clear cache.
if (fHinting != state) {
ClearCache();
fHinting = state;
}
}
//______________________________________________________________________________
void TGX11TTF::SetSmoothing(Bool_t state)
{
// Set smoothing (anit-aliasing) flag. If status changes clear cache.
if (state && DefaultDepth(fDisplay,fScreenNumber) <= 8)
Warning("SetSmoothing", "the colormap might not have enough free color "
"cells to fully support smoothing");
if (fSmoothing != state) {
ClearCache();
fSmoothing = state;
}
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.