18 # include <ft2build.h>
19 # include FT_FREETYPE_H
29 const Float_t kScale = 0.93376068;
33 Bool_t TTF::fgInit = kFALSE;
34 Bool_t TTF::fgSmoothing = kTRUE;
35 Bool_t TTF::fgKerning = kTRUE;
36 Bool_t TTF::fgHinting = kFALSE;
37 Int_t TTF::fgTBlankW = 0;
38 Int_t TTF::fgWidth = 0;
39 Int_t TTF::fgAscent = 0;
40 Int_t TTF::fgCurFontIdx = -1;
41 Int_t TTF::fgSymbItaFontIdx = -1;
42 Int_t TTF::fgFontCount = 0;
43 Int_t TTF::fgNumGlyphs = 0;
44 char *TTF::fgFontName[kTTMaxFonts];
45 FT_Matrix *TTF::fgRotMatrix;
46 FT_Library TTF::fgLibrary;
48 FT_Face TTF::fgFace[kTTMaxFonts];
49 FT_CharMap TTF::fgCharMap[kTTMaxFonts];
50 TTF::TTGlyph TTF::fgGlyphs[kMaxGlyphs];
70 if (FT_Init_FreeType(&fgLibrary)) {
71 Error(
"TTF::Init",
"error initializing FreeType");
86 for (
int i = 0; i < fgFontCount; i++) {
87 delete [] fgFontName[i];
88 FT_Done_Face(fgFace[i]);
90 if (fgRotMatrix)
delete fgRotMatrix;
91 FT_Done_FreeType(fgLibrary);
99 Short_t TTF::CharToUnicode(UInt_t code)
101 if (!fgCharMap[fgCurFontIdx]) {
102 UShort_t i, platform, encoding;
105 if (!fgFace[fgCurFontIdx])
return 0;
106 Int_t n = fgFace[fgCurFontIdx]->num_charmaps;
107 for (i = 0; i < n; i++) {
108 if (!fgFace[fgCurFontIdx])
continue;
109 charmap = fgFace[fgCurFontIdx]->charmaps[i];
110 platform = charmap->platform_id;
111 encoding = charmap->encoding_id;
112 if ((platform == 3 && encoding == 1) ||
113 (platform == 0 && encoding == 0) ||
114 (platform == 1 && encoding == 0 &&
115 !strcmp(fgFontName[fgCurFontIdx],
"wingding.ttf")) ||
116 (platform == 1 && encoding == 0 &&
117 !strcmp(fgFontName[fgCurFontIdx],
"symbol.ttf")))
119 fgCharMap[fgCurFontIdx] = charmap;
120 if (FT_Set_Charmap(fgFace[fgCurFontIdx], fgCharMap[fgCurFontIdx]))
121 Error(
"TTF::CharToUnicode",
"error in FT_Set_CharMap");
122 return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code);
126 return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code);
132 void TTF::GetTextExtent(UInt_t &w, UInt_t &h,
char *text)
136 SetRotationMatrix(0);
139 Int_t Xoff = 0;
if (fgCBox.xMin < 0) Xoff = -fgCBox.xMin;
140 Int_t Yoff = 0;
if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin;
141 w = fgCBox.xMax + Xoff + fgTBlankW;
142 h = fgCBox.yMax + Yoff;
148 void TTF::GetTextAdvance(UInt_t &a,
char *text)
152 SetRotationMatrix(0);
161 void TTF::GetTextExtent(UInt_t &w, UInt_t &h,
wchar_t *text)
165 SetRotationMatrix(0);
168 Int_t Xoff = 0;
if (fgCBox.xMin < 0) Xoff = -fgCBox.xMin;
169 Int_t Yoff = 0;
if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin;
170 w = fgCBox.xMax + Xoff + fgTBlankW;
171 h = fgCBox.yMax + Yoff;
181 void TTF::LayoutGlyphs()
183 TTGlyph* glyph = fgGlyphs;
186 FT_UInt prev_index = 0;
191 load_flags = FT_LOAD_DEFAULT;
192 if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
194 fgCBox.xMin = fgCBox.yMin = 32000;
195 fgCBox.xMax = fgCBox.yMax = -32000;
197 for (
int n = 0; n < fgNumGlyphs; n++, glyph++) {
203 FT_Get_Kerning(fgFace[fgCurFontIdx], prev_index, glyph->fIndex,
204 fgHinting ? ft_kerning_default : ft_kerning_unfitted,
208 prev_index = glyph->fIndex;
215 if (glyph->fImage) FT_Done_Glyph(glyph->fImage);
218 if (FT_Load_Glyph(fgFace[fgCurFontIdx], glyph->fIndex, load_flags))
222 if (FT_Get_Glyph (fgFace[fgCurFontIdx]->glyph, &glyph->fImage))
225 glyph->fPos = origin;
226 fgWidth += fgFace[fgCurFontIdx]->glyph->advance.x;
227 fgAscent = TMath::Max((Int_t)(fgFace[fgCurFontIdx]->glyph->metrics.horiBearingY), fgAscent);
230 FT_Vector_Transform(&glyph->fPos, fgRotMatrix);
231 if (FT_Glyph_Transform(glyph->fImage, fgRotMatrix, &glyph->fPos))
236 FT_Glyph_Get_CBox(glyph->fImage, ft_glyph_bbox_pixels, &bbox);
237 if (bbox.xMin < fgCBox.xMin) fgCBox.xMin = bbox.xMin;
238 if (bbox.yMin < fgCBox.yMin) fgCBox.yMin = bbox.yMin;
239 if (bbox.xMax > fgCBox.xMax) fgCBox.xMax = bbox.xMax;
240 if (bbox.yMax > fgCBox.yMax) fgCBox.yMax = bbox.yMax;
247 void TTF::PrepareString(
const char *
string)
249 const unsigned char *p = (
const unsigned char*)
string;
250 TTGlyph *glyph = fgGlyphs;
257 index = CharToUnicode((FT_ULong)*p);
259 glyph->fIndex = index;
268 if (fgNumGlyphs >= kMaxGlyphs)
break;
275 FT_UInt load_flags = FT_LOAD_DEFAULT;
276 if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
277 if (FT_Load_Glyph(fgFace[fgCurFontIdx], 3, load_flags))
return;
278 fgTBlankW = (Int_t)((fgFace[fgCurFontIdx]->glyph->advance.x)>>6)*NbTBlank;
285 void TTF::PrepareString(
const wchar_t *
string)
287 const wchar_t *p = string;
288 TTGlyph *glyph = fgGlyphs;
295 index = FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)*p);
297 glyph->fIndex = index;
306 if (fgNumGlyphs >= kMaxGlyphs)
break;
313 FT_UInt load_flags = FT_LOAD_DEFAULT;
314 if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
315 if (FT_Load_Glyph(fgFace[fgCurFontIdx], 3, load_flags))
return;
316 fgTBlankW = (Int_t)((fgFace[fgCurFontIdx]->glyph->advance.x)>>6)*NbTBlank;
323 void TTF::SetHinting(Bool_t state)
331 void TTF::SetKerning(Bool_t state)
339 void TTF::SetRotationMatrix(Float_t angle)
341 Float_t rangle = Float_t(angle * TMath::Pi() / 180.);
342 #if defined(FREETYPE_PATCH) && \
343 (FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH == 2)
344 Float_t sin = TMath::Sin(rangle);
345 Float_t cos = TMath::Cos(rangle);
347 Float_t sin = TMath::Sin(-rangle);
348 Float_t cos = TMath::Cos(-rangle);
351 if (!fgRotMatrix) fgRotMatrix =
new FT_Matrix;
353 fgRotMatrix->xx = (FT_Fixed) (cos * (1<<16));
354 fgRotMatrix->xy = (FT_Fixed) (sin * (1<<16));
355 fgRotMatrix->yx = -fgRotMatrix->xy;
356 fgRotMatrix->yy = fgRotMatrix->xx;
362 void TTF::SetSmoothing(Bool_t state)
375 Int_t TTF::SetTextFont(
const char *fontname, Int_t italic)
379 if (!fontname || !fontname[0]) {
380 Warning(
"TTF::SetTextFont",
381 "no font name specified, using default font %s", fgFontName[0]);
385 const char *basename = gSystem->BaseName(fontname);
389 for (i = 0; i < fgFontCount; i++) {
390 if (!strcmp(fgFontName[i], basename)) {
392 if (i==fgSymbItaFontIdx) {
397 if (i!=fgSymbItaFontIdx) {
406 if (fgFontCount >= kTTMaxFonts) {
407 Error(
"TTF::SetTextFont",
"too many fonts opened (increase kTTMaxFont = %d)",
409 Warning(
"TTF::SetTextFont",
"using default font %s", fgFontName[0]);
415 const char *ttpath = gEnv->GetValue(
"Root.TTFontPath",
416 TROOT::GetTTFFontDir());
417 char *ttfont = gSystem->Which(ttpath, fontname, kReadPermission);
420 Error(
"TTF::SetTextFont",
"font file %s not found in path", fontname);
422 Warning(
"TTF::SetTextFont",
"using default font %s", fgFontName[0]);
432 if (FT_New_Face(fgLibrary, ttfont, 0, &tface)) {
433 Error(
"TTF::SetTextFont",
"error loading font %s", ttfont);
435 if (tface) FT_Done_Face(tface);
437 Warning(
"TTF::SetTextFont",
"using default font %s", fgFontName[0]);
447 fgFontName[fgFontCount] = StrDup(basename);
448 fgCurFontIdx = fgFontCount;
449 fgFace[fgCurFontIdx] = tface;
450 fgCharMap[fgCurFontIdx] = 0;
454 fgSymbItaFontIdx = fgCurFontIdx;
456 slantMat.xx = (1 << 16);
457 slantMat.xy = ((1 << 16) >> 2);
459 slantMat.yy = (1 << 16);
460 FT_Set_Transform( fgFace[fgSymbItaFontIdx], &slantMat, NULL );
488 void TTF::SetTextFont(Font_t fontnumber)
493 static const char *fonttable[][2] = {
494 {
"Root.TTFont.0",
"FreeSansBold.otf" },
495 {
"Root.TTFont.1",
"FreeSerifItalic.otf" },
496 {
"Root.TTFont.2",
"FreeSerifBold.otf" },
497 {
"Root.TTFont.3",
"FreeSerifBoldItalic.otf" },
498 {
"Root.TTFont.4",
"FreeSans.otf" },
499 {
"Root.TTFont.5",
"FreeSansOblique.otf" },
500 {
"Root.TTFont.6",
"FreeSansBold.otf" },
501 {
"Root.TTFont.7",
"FreeSansBoldOblique.otf" },
502 {
"Root.TTFont.8",
"FreeMono.otf" },
503 {
"Root.TTFont.9",
"FreeMonoOblique.otf" },
504 {
"Root.TTFont.10",
"FreeMonoBold.otf" },
505 {
"Root.TTFont.11",
"FreeMonoBoldOblique.otf" },
506 {
"Root.TTFont.12",
"symbol.ttf" },
507 {
"Root.TTFont.13",
"FreeSerif.otf" },
508 {
"Root.TTFont.14",
"wingding.ttf" },
509 {
"Root.TTFont.15",
"symbol.ttf" },
510 {
"Root.TTFont.STIXGen",
"STIXGeneral.otf" },
511 {
"Root.TTFont.STIXGenIt",
"STIXGeneralItalic.otf" },
512 {
"Root.TTFont.STIXGenBd",
"STIXGeneralBol.otf" },
513 {
"Root.TTFont.STIXGenBdIt",
"STIXGeneralBolIta.otf" },
514 {
"Root.TTFont.STIXSiz1Sym",
"STIXSiz1Sym.otf" },
515 {
"Root.TTFont.STIXSiz1SymBd",
"STIXSiz1SymBol.otf" },
516 {
"Root.TTFont.STIXSiz2Sym",
"STIXSiz2Sym.otf" },
517 {
"Root.TTFont.STIXSiz2SymBd",
"STIXSiz2SymBol.otf" },
518 {
"Root.TTFont.STIXSiz3Sym",
"STIXSiz3Sym.otf" },
519 {
"Root.TTFont.STIXSiz3SymBd",
"STIXSiz3SymBol.otf" },
520 {
"Root.TTFont.STIXSiz4Sym",
"STIXSiz4Sym.otf" },
521 {
"Root.TTFont.STIXSiz4SymBd",
"STIXSiz4SymBol.otf" },
522 {
"Root.TTFont.STIXSiz5Sym",
"STIXSiz5Sym.otf" },
523 {
"Root.TTFont.ME",
"DroidSansFallback.ttf" },
524 {
"Root.TTFont.CJKMing",
"DroidSansFallback.ttf" },
525 {
"Root.TTFont.CJKGothic",
"DroidSansFallback.ttf" }
528 static int fontset = -1;
529 int thisset = fontset;
531 int fontid = fontnumber / 10;
532 if (fontid < 0 || fontid > 31) fontid = 0;
537 const char *ttpath = gEnv->GetValue(
"Root.TTFontPath",
538 TROOT::GetTTFFontDir());
539 char *ttfont = gSystem->Which(ttpath, gEnv->GetValue(fonttable[fontid][0], fonttable[fontid][1]), kReadPermission);
549 if (fontid==15) italic = 1;
550 int ret = SetTextFont(gEnv->GetValue(fonttable[fontid][thisset], fonttable[fontid][1]), italic);
553 if (ret == 0 && fontid != 12) fontset = thisset;
559 void TTF::SetTextSize(Float_t textsize)
562 if (textsize < 0)
return;
564 if (fgCurFontIdx < 0 || fgFontCount <= fgCurFontIdx) {
565 Error(
"TTF::SetTextSize",
"current font index out of bounds");
570 Int_t tsize = (Int_t)(textsize*kScale+0.5) << 6;
571 if (FT_Set_Char_Size(fgFace[fgCurFontIdx], tsize, tsize, 72, 72))
572 Error(
"TTF::SetTextSize",
"error in FT_Set_Char_Size");
577 void TTF::Version(Int_t &major, Int_t &minor, Int_t &patch)
579 FT_Library_Version(fgLibrary, &major, &minor, &patch);
584 Bool_t TTF::GetHinting()
591 Bool_t TTF::GetKerning()
598 Bool_t TTF::GetSmoothing()
605 Bool_t TTF::IsInitialized()
612 Int_t TTF::GetWidth()
619 Int_t TTF::GetAscent()
626 Int_t TTF::GetNumGlyphs()
633 FT_Matrix *TTF::GetRotMatrix()
640 const FT_BBox &TTF::GetBox()
647 TTF::TTGlyph *TTF::GetGlyphs()