#include "RConfigure.h"
#include "TTF.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TMath.h"
#include "TError.h"
#include <fontconfig/fontconfig.h>
const Float_t kScale = 0.93376068;
TTF gCleanupTTF;
Bool_t TTF::fgInit = kFALSE;
Bool_t TTF::fgSmoothing = kTRUE;
Bool_t TTF::fgKerning = kTRUE;
Bool_t TTF::fgHinting = kFALSE;
Int_t TTF::fgTBlankW = 0;
Int_t TTF::fgWidth = 0;
Int_t TTF::fgAscent = 0;
Int_t TTF::fgCurFontIdx = -1;
Int_t TTF::fgFontCount = 0;
Int_t TTF::fgNumGlyphs = 0;
Int_t TTF::fgFontID[kTTMaxFonts];
FT_Matrix *TTF::fgRotMatrix;
FT_Library TTF::fgLibrary;
FT_BBox TTF::fgCBox;
FT_Face TTF::fgFace[kTTMaxFonts];
FT_CharMap TTF::fgCharMap[kTTMaxFonts];
TTGlyph TTF::fgGlyphs[kMaxGlyphs];
ClassImp(TTF)
TTF::~TTF()
{
Cleanup();
}
void TTF::Init()
{
fgInit = kTRUE;
if (FT_Init_FreeType(&fgLibrary)) {
Error("TTF::Init", "error initializing FreeType");
return;
}
const char *ttpath = gEnv->GetValue("Root.TTFontPath",
# ifdef TTFFONTDIR
TTFFONTDIR
# else
"$(ROOTSYS)/fonts"
# endif
);
FcConfigAppFontAddDir (NULL, (const FcChar8*)ttpath);
SetTextFont(62);
}
void TTF::Cleanup()
{
if (!fgInit) return;
for (int i = 0; i < fgFontCount; i++) {
FT_Done_Face(fgFace[i]);
}
if (fgRotMatrix) delete fgRotMatrix;
FT_Done_FreeType(fgLibrary);
fgInit = kFALSE;
}
Short_t TTF::CharToUnicode(UInt_t code)
{
if (!fgCharMap[fgCurFontIdx]) {
UShort_t i, platform, encoding;
FT_CharMap charmap;
if (!fgFace[fgCurFontIdx]) return 0;
Int_t n = fgFace[fgCurFontIdx]->num_charmaps;
for (i = 0; i < n; i++) {
if (!fgFace[fgCurFontIdx]) continue;
charmap = fgFace[fgCurFontIdx]->charmaps[i];
platform = charmap->platform_id;
encoding = charmap->encoding_id;
if ((platform == 3 && encoding == 1 &&
(fgFontID[fgCurFontIdx] != 12 &&
fgFontID[fgCurFontIdx] != 14 &&
fgFontID[fgCurFontIdx] != 15)) ||
(platform == 0 && encoding == 0) ||
(platform == 7 && encoding == 2 &&
(fgFontID[fgCurFontIdx] == 12 ||
fgFontID[fgCurFontIdx] == 14 ||
fgFontID[fgCurFontIdx] == 15)) ||
(platform == 1 && encoding == 0 &&
(fgFontID[fgCurFontIdx] == 12 ||
fgFontID[fgCurFontIdx] == 14 ||
fgFontID[fgCurFontIdx] == 15)))
{
fgCharMap[fgCurFontIdx] = charmap;
if (FT_Set_Charmap(fgFace[fgCurFontIdx], fgCharMap[fgCurFontIdx]))
Error("TTF::CharToUnicode", "error in FT_Set_CharMap");
return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code);
}
}
}
return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code);
}
void TTF::GetTextExtent(UInt_t &w, UInt_t &h, char *text)
{
if (!fgInit) Init();
SetRotationMatrix(0);
PrepareString(text);
LayoutGlyphs();
Int_t Xoff = 0; if (fgCBox.xMin < 0) Xoff = -fgCBox.xMin;
Int_t Yoff = 0; if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin;
w = fgCBox.xMax + Xoff + fgTBlankW;
h = fgCBox.yMax + Yoff;
}
void TTF::GetTextAdvance(UInt_t &a, char *text)
{
if (!fgInit) Init();
SetRotationMatrix(0);
PrepareString(text);
LayoutGlyphs();
a = GetWidth()>>6;
}
void TTF::GetTextExtent(UInt_t &w, UInt_t &h, wchar_t *text)
{
if (!fgInit) Init();
SetRotationMatrix(0);
PrepareString(text);
LayoutGlyphs();
Int_t Xoff = 0; if (fgCBox.xMin < 0) Xoff = -fgCBox.xMin;
Int_t Yoff = 0; if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin;
w = fgCBox.xMax + Xoff + fgTBlankW;
h = fgCBox.yMax + Yoff;
}
void TTF::LayoutGlyphs()
{
TTGlyph* glyph = fgGlyphs;
FT_Vector origin;
FT_UInt load_flags;
FT_UInt prev_index = 0;
fgAscent = 0;
fgWidth = 0;
load_flags = FT_LOAD_DEFAULT;
if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
fgCBox.xMin = fgCBox.yMin = 32000;
fgCBox.xMax = fgCBox.yMax = -32000;
for (int n = 0; n < fgNumGlyphs; n++, glyph++) {
if (fgKerning) {
if (prev_index) {
FT_Vector kern;
FT_Get_Kerning(fgFace[fgCurFontIdx], prev_index, glyph->fIndex,
fgHinting ? ft_kerning_default : ft_kerning_unfitted,
&kern);
fgWidth += kern.x;
}
prev_index = glyph->fIndex;
}
origin.x = fgWidth;
origin.y = 0;
if (glyph->fImage) FT_Done_Glyph(glyph->fImage);
if (FT_Load_Glyph(fgFace[fgCurFontIdx], glyph->fIndex, load_flags))
continue;
if (FT_Get_Glyph (fgFace[fgCurFontIdx]->glyph, &glyph->fImage))
continue;
glyph->fPos = origin;
fgWidth += fgFace[fgCurFontIdx]->glyph->advance.x;
fgAscent = TMath::Max((Int_t)(fgFace[fgCurFontIdx]->glyph->metrics.horiBearingY), fgAscent);
FT_Vector_Transform(&glyph->fPos, fgRotMatrix);
if (FT_Glyph_Transform(glyph->fImage, fgRotMatrix, &glyph->fPos))
continue;
FT_BBox bbox;
FT_Glyph_Get_CBox(glyph->fImage, ft_glyph_bbox_pixels, &bbox);
if (bbox.xMin < fgCBox.xMin) fgCBox.xMin = bbox.xMin;
if (bbox.yMin < fgCBox.yMin) fgCBox.yMin = bbox.yMin;
if (bbox.xMax > fgCBox.xMax) fgCBox.xMax = bbox.xMax;
if (bbox.yMax > fgCBox.yMax) fgCBox.yMax = bbox.yMax;
}
}
void TTF::PrepareString(const char *string)
{
const unsigned char *p = (const unsigned char*) string;
TTGlyph *glyph = fgGlyphs;
UInt_t index;
Int_t NbTBlank = 0;
fgTBlankW = 0;
fgNumGlyphs = 0;
while (*p) {
index = CharToUnicode((FT_ULong)*p);
if (index != 0) {
glyph->fIndex = index;
glyph++;
fgNumGlyphs++;
}
if (*p == ' ') {
NbTBlank++;
} else {
NbTBlank = 0;
}
if (fgNumGlyphs >= kMaxGlyphs) break;
p++;
}
if (NbTBlank) {
FT_UInt load_flags = FT_LOAD_DEFAULT;
if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
if (FT_Load_Glyph(fgFace[fgCurFontIdx], 3, load_flags)) return;
fgTBlankW = (Int_t)((fgFace[fgCurFontIdx]->glyph->advance.x)>>6)*NbTBlank;
}
}
void TTF::PrepareString(const wchar_t *string)
{
const wchar_t *p = string;
TTGlyph *glyph = fgGlyphs;
UInt_t index;
Int_t NbTBlank = 0;
fgTBlankW = 0;
fgNumGlyphs = 0;
while (*p) {
index = FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)*p);
if (index != 0) {
glyph->fIndex = index;
glyph++;
fgNumGlyphs++;
}
if (*p == ' ') {
NbTBlank++;
} else {
NbTBlank = 0;
}
if (fgNumGlyphs >= kMaxGlyphs) break;
p++;
}
if (NbTBlank) {
FT_UInt load_flags = FT_LOAD_DEFAULT;
if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
if (FT_Load_Glyph(fgFace[fgCurFontIdx], 3, load_flags)) return;
fgTBlankW = (Int_t)((fgFace[fgCurFontIdx]->glyph->advance.x)>>6)*NbTBlank;
}
}
void TTF::SetHinting(Bool_t state)
{
fgHinting = state;
}
void TTF::SetKerning(Bool_t state)
{
fgKerning = state;
}
void TTF::SetRotationMatrix(Float_t angle)
{
Float_t rangle = Float_t(angle * TMath::Pi() / 180.);
#if defined(FREETYPE_PATCH) && \
(FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH == 2)
Float_t sin = TMath::Sin(rangle);
Float_t cos = TMath::Cos(rangle);
#else
Float_t sin = TMath::Sin(-rangle);
Float_t cos = TMath::Cos(-rangle);
#endif
if (!fgRotMatrix) fgRotMatrix = new FT_Matrix;
fgRotMatrix->xx = (FT_Fixed) (cos * (1<<16));
fgRotMatrix->xy = (FT_Fixed) (sin * (1<<16));
fgRotMatrix->yx = -fgRotMatrix->xy;
fgRotMatrix->yy = fgRotMatrix->xx;
}
void TTF::SetSmoothing(Bool_t state)
{
fgSmoothing = state;
}
Int_t TTF::SetTextFont(const char *fontname, Int_t italic)
{
if (!fgInit) Init();
if (!fontname || !fontname[0]) {
Warning("TTF::SetTextFont",
"no font name specified, using default font");
fgCurFontIdx = 0;
return 0;
}
const char *basename = gSystem->BaseName(fontname);
if (strcmp(basename, "timesi.ttf") == 0 ||
strcmp(basename, "FreeSerifItalic.otf") == 0) {
SetTextFont(12);
}
else if (strcmp(basename, "timesbd.ttf") == 0 ||
strcmp(basename, "FreeSerifBold.otf") == 0) {
SetTextFont(22);
}
else if (strcmp(basename, "timesbi.ttf") == 0 ||
strcmp(basename, "FreeSerifBoldItalic.otf") == 0) {
SetTextFont(32);
}
else if (strcmp(basename, "arial.ttf") == 0 ||
strcmp(basename, "FreeSans.otf") == 0) {
SetTextFont(42);
}
else if (strcmp(basename, "ariali.ttf") == 0 ||
strcmp(basename, "FreeSansOblique.otf") == 0) {
SetTextFont(52);
}
else if (strcmp(basename, "arialbd.ttf") == 0 ||
strcmp(basename, "FreeSansBold.otf") == 0) {
SetTextFont(62);
}
else if (strcmp(basename, "arialbi.ttf") == 0 ||
strcmp(basename, "FreeSansBoldOblique.otf") == 0) {
SetTextFont(72);
}
else if (strcmp(basename, "cour.ttf") == 0 ||
strcmp(basename, "FreeMono.otf") == 0) {
SetTextFont(82);
}
else if (strcmp(basename, "couri.ttf") == 0 ||
strcmp(basename, "FreeMonoOblique.otf") == 0) {
SetTextFont(92);
}
else if (strcmp(basename, "courbd.ttf") == 0 ||
strcmp(basename, "FreeMonoBold.otf") == 0) {
SetTextFont(102);
}
else if (strcmp(basename, "courbi.ttf") == 0 ||
strcmp(basename, "FreeMonoBoldOblique.otf") == 0) {
SetTextFont(112);
}
else if (strcmp(basename, "symbol.ttf") == 0) {
if (italic)
SetTextFont(152);
else
SetTextFont(122);
}
else if (strcmp(basename, "times.ttf") == 0 ||
strcmp(basename, "FreeSerif.otf") == 0) {
SetTextFont(132);
}
else if (strcmp(basename, "wingding.ttf") == 0) {
SetTextFont(142);
}
else if (strcmp(basename, "STIXGeneral.otf") == 0) {
SetTextFont(162);
}
else if (strcmp(basename, "STIXGeneralItalic.otf") == 0) {
SetTextFont(172);
}
else if (strcmp(basename, "STIXGeneralBol.otf") == 0) {
SetTextFont(182);
}
else if (strcmp(basename, "STIXGeneralBolIta.otf") == 0) {
SetTextFont(192);
}
else if (strcmp(basename, "STIXSiz1Sym.otf") == 0) {
SetTextFont(202);
}
else if (strcmp(basename, "STIXSiz1SymBol.otf") == 0) {
SetTextFont(212);
}
else if (strcmp(basename, "STIXSiz2Sym.otf") == 0) {
SetTextFont(222);
}
else if (strcmp(basename, "STIXSiz2SymBol.otf") == 0) {
SetTextFont(232);
}
else if (strcmp(basename, "STIXSiz3Sym.otf") == 0) {
SetTextFont(242);
}
else if (strcmp(basename, "STIXSiz3SymBol.otf") == 0) {
SetTextFont(252);
}
else if (strcmp(basename, "STIXSiz4Sym.otf") == 0) {
SetTextFont(262);
}
else if (strcmp(basename, "STIXSiz4SymBol.otf") == 0) {
SetTextFont(272);
}
else if (strcmp(basename, "STIXSiz5Sym.otf") == 0) {
SetTextFont(282);
}
else if (strcmp(basename, "DroidSansFallback.ttf") == 0) {
SetTextFont(292);
}
else {
Error("TTF::SetTextFont", "font %s not known to ROOT", basename);
if (fgFontCount) {
Warning("TTF::SetTextFont", "using default font");
fgCurFontIdx = 0;
return 0;
} else {
return 1;
}
}
return 0;
}
void TTF::SetTextFont(Font_t fontnumber)
{
int fontid = fontnumber / 10;
if (fontid < 0 || fontid > 31) fontid = 0;
Int_t italic = 0;
if (fontid==15) italic = 1;
if (!fgInit) Init();
if (fontid == 0) {
fgCurFontIdx = 0;
return;
}
int i;
for (i = 0; i < fgFontCount; i++) {
if (fgFontID[i] == fontid) {
fgCurFontIdx = i;
return;
}
}
if (fgFontCount >= kTTMaxFonts) {
Error("TTF::SetTextFont", "too many fonts opened (increase kTTMaxFont = %d)",
kTTMaxFonts);
Warning("TTF::SetTextFont", "using default font");
fgCurFontIdx = 0;
return;
}
char *ttfont = NULL;
int ttindex = 0;
FcPattern *pat, *match;
FcCharSet *set = NULL;
FcResult result;
pat = FcPatternCreate ();
switch (fontid) {
case 1:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freeserif");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 2:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freeserif");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 3:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freeserif");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 4:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freesans");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 5:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freesans");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 6:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freesans");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 7:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freesans");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 8:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freemono");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 9:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freemono");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 10:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freemono");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 11:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freemono");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 12:
case 15:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"symbol");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 13:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"freeserif");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 14:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"dingbats");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 16:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixgeneral");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 17:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixgeneral");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 18:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixgeneral");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 19:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixgeneral");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ITALIC);
break;
case 20:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize1");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 21:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize1");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 22:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize2");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 23:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize2");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 24:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize3");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 25:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize3");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 26:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize4");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 27:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize4");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_BOLD);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 28:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"stixsize5");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
break;
case 29:
case 30:
case 31:
FcPatternAddString (pat, FC_FAMILY, (const FcChar8*)"droidsansfallback");
FcPatternAddInteger (pat, FC_WEIGHT, FC_WEIGHT_REGULAR);
FcPatternAddInteger (pat, FC_SLANT, FC_SLANT_ROMAN);
set = FcCharSetCreate ();
FcCharSetAddChar (set, 0x0410);
FcCharSetAddChar (set, 0x4e00);
FcPatternAddCharSet (pat, FC_CHARSET, set);
break;
default:
Error("TTF::SetTextFont", "font %i not known to ROOT", fontid);
FcPatternDestroy (pat);
Warning("TTF::SetTextFont", "using default font");
fgCurFontIdx = 0;
return;
break;
}
FcConfigSubstitute (NULL, pat, FcMatchPattern);
FcDefaultSubstitute (pat);
match = FcFontMatch (NULL, pat, &result);
char *ttfnt;
FcPatternGetString (match, FC_FILE, 0, (FcChar8**)&ttfnt);
ttfont = StrDup (ttfnt);
FcPatternGetInteger (match, FC_INDEX, 0, &ttindex);
FcPatternDestroy (match);
FcPatternDestroy (pat);
if (set) FcCharSetDestroy (set);
FT_Face tface = 0;
if (FT_New_Face(fgLibrary, ttfont, ttindex, &tface)) {
Error("TTF::SetTextFont", "error loading font %s", ttfont);
delete [] ttfont;
if (tface) FT_Done_Face(tface);
Warning("TTF::SetTextFont", "using default font");
fgCurFontIdx = 0;
return;
}
delete [] ttfont;
fgFontID[fgFontCount] = fontid;
fgCurFontIdx = fgFontCount;
fgFace[fgCurFontIdx] = tface;
fgCharMap[fgCurFontIdx] = 0;
fgFontCount++;
if (italic) {
FT_Matrix slantMat;
slantMat.xx = (1 << 16);
slantMat.xy = ((1 << 16) >> 2);
slantMat.yx = 0;
slantMat.yy = (1 << 16);
FT_Set_Transform( fgFace[fgCurFontIdx], &slantMat, NULL );
}
}
void TTF::SetTextSize(Float_t textsize)
{
if (!fgInit) Init();
if (textsize < 0) return;
if (fgCurFontIdx < 0 || fgFontCount <= fgCurFontIdx) {
Error("TTF::SetTextSize", "current font index out of bounds");
fgCurFontIdx = 0;
return;
}
Int_t tsize = (Int_t)(textsize*kScale+0.5) << 6;
if (FT_Set_Char_Size(fgFace[fgCurFontIdx], tsize, tsize, 72, 72))
Error("TTF::SetTextSize", "error in FT_Set_Char_Size");
}
void TTF::Version(Int_t &major, Int_t &minor, Int_t &patch)
{
FT_Library_Version(fgLibrary, &major, &minor, &patch);
}
Bool_t TTF::GetHinting()
{
return fgHinting;
}
Bool_t TTF::GetKerning()
{
return fgKerning;
}
Bool_t TTF::GetSmoothing()
{
return fgSmoothing;
}
Bool_t TTF::IsInitialized()
{
return fgInit;
}
Int_t TTF::GetWidth()
{
return fgWidth;
}
Int_t TTF::GetAscent()
{
return fgAscent;
}
Int_t TTF::GetNumGlyphs()
{
return fgNumGlyphs;
}
FT_Matrix *TTF::GetRotMatrix()
{
return fgRotMatrix;
}
const FT_BBox &TTF::GetBox()
{
return fgCBox;
}
TTGlyph *TTF::GetGlyphs()
{
return fgGlyphs;
}