00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "RConfigure.h"
00022
00023 #include "TTF.h"
00024 #include "TSystem.h"
00025 #include "TEnv.h"
00026 #include "TMath.h"
00027 #include "TError.h"
00028
00029
00030
00031 const Float_t kScale = 0.93376068;
00032
00033 TTF gCleanupTTF;
00034
00035 Bool_t TTF::fgInit = kFALSE;
00036 Bool_t TTF::fgSmoothing = kTRUE;
00037 Bool_t TTF::fgKerning = kTRUE;
00038 Bool_t TTF::fgHinting = kFALSE;
00039 Int_t TTF::fgTBlankW = 0;
00040 Int_t TTF::fgWidth = 0;
00041 Int_t TTF::fgAscent = 0;
00042 Int_t TTF::fgCurFontIdx = -1;
00043 Int_t TTF::fgSymbItaFontIdx = -1;
00044 Int_t TTF::fgFontCount = 0;
00045 Int_t TTF::fgNumGlyphs = 0;
00046 char *TTF::fgFontName[kTTMaxFonts];
00047 FT_Matrix *TTF::fgRotMatrix;
00048 FT_Library TTF::fgLibrary;
00049 FT_BBox TTF::fgCBox;
00050 FT_Face TTF::fgFace[kTTMaxFonts];
00051 FT_CharMap TTF::fgCharMap[kTTMaxFonts];
00052 TTGlyph TTF::fgGlyphs[kMaxGlyphs];
00053
00054
00055 ClassImp(TTF)
00056
00057
00058 TTF::~TTF()
00059 {
00060
00061
00062 Cleanup();
00063 }
00064
00065
00066 void TTF::Init()
00067 {
00068
00069
00070 fgInit = kTRUE;
00071
00072
00073 if (FT_Init_FreeType(&fgLibrary)) {
00074 Error("TTF::Init", "error initializing FreeType");
00075 return;
00076 }
00077
00078
00079 SetTextFont(62);
00080 }
00081
00082
00083 void TTF::Cleanup()
00084 {
00085
00086
00087 if (!fgInit) return;
00088
00089 for (int i = 0; i < fgFontCount; i++) {
00090 delete [] fgFontName[i];
00091 FT_Done_Face(fgFace[i]);
00092 }
00093 if (fgRotMatrix) delete fgRotMatrix;
00094 FT_Done_FreeType(fgLibrary);
00095
00096 fgInit = kFALSE;
00097 }
00098
00099
00100 Short_t TTF::CharToUnicode(UInt_t code)
00101 {
00102
00103
00104 if (!fgCharMap[fgCurFontIdx]) {
00105 UShort_t i, platform, encoding;
00106 FT_CharMap charmap;
00107
00108 if (!fgFace[fgCurFontIdx]) return 0;
00109 Int_t n = fgFace[fgCurFontIdx]->num_charmaps;
00110 for (i = 0; i < n; i++) {
00111 if (!fgFace[fgCurFontIdx]) continue;
00112 charmap = fgFace[fgCurFontIdx]->charmaps[i];
00113 platform = charmap->platform_id;
00114 encoding = charmap->encoding_id;
00115 if ((platform == 3 && encoding == 1) ||
00116 (platform == 0 && encoding == 0) ||
00117 (platform == 1 && encoding == 0 &&
00118 !strcmp(fgFontName[fgCurFontIdx], "wingding.ttf")) ||
00119 (platform == 1 && encoding == 0 &&
00120 !strcmp(fgFontName[fgCurFontIdx], "symbol.ttf")))
00121 {
00122 fgCharMap[fgCurFontIdx] = charmap;
00123 if (FT_Set_Charmap(fgFace[fgCurFontIdx], fgCharMap[fgCurFontIdx]))
00124 Error("TTF::CharToUnicode", "error in FT_Set_CharMap");
00125 return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code);
00126 }
00127 }
00128 }
00129 return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code);
00130 }
00131
00132
00133 void TTF::GetTextExtent(UInt_t &w, UInt_t &h, char *text)
00134 {
00135
00136
00137 if (!fgInit) Init();
00138
00139 SetRotationMatrix(0);
00140 PrepareString(text);
00141 LayoutGlyphs();
00142 Int_t Xoff = 0; if (fgCBox.xMin < 0) Xoff = -fgCBox.xMin;
00143 Int_t Yoff = 0; if (fgCBox.yMin < 0) Yoff = -fgCBox.yMin;
00144 w = fgCBox.xMax + Xoff + fgTBlankW;
00145 h = fgCBox.yMax + Yoff;
00146 }
00147
00148
00149 void TTF::GetTextAdvance(UInt_t &a, char *text)
00150 {
00151
00152
00153 if (!fgInit) Init();
00154
00155 SetRotationMatrix(0);
00156 PrepareString(text);
00157 LayoutGlyphs();
00158 a = GetWidth()>>6;
00159 }
00160
00161
00162 void TTF::LayoutGlyphs()
00163 {
00164
00165
00166
00167
00168
00169
00170 TTGlyph* glyph = fgGlyphs;
00171 FT_Vector origin;
00172 FT_UInt load_flags;
00173 FT_UInt prev_index = 0;
00174
00175 fgAscent = 0;
00176 fgWidth = 0;
00177
00178 load_flags = FT_LOAD_DEFAULT;
00179 if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
00180
00181 fgCBox.xMin = fgCBox.yMin = 32000;
00182 fgCBox.xMax = fgCBox.yMax = -32000;
00183
00184 for (int n = 0; n < fgNumGlyphs; n++, glyph++) {
00185
00186
00187 if (fgKerning) {
00188 if (prev_index) {
00189 FT_Vector kern;
00190 FT_Get_Kerning(fgFace[fgCurFontIdx], prev_index, glyph->fIndex,
00191 fgHinting ? ft_kerning_default : ft_kerning_unfitted,
00192 &kern);
00193 fgWidth += kern.x;
00194 }
00195 prev_index = glyph->fIndex;
00196 }
00197
00198 origin.x = fgWidth;
00199 origin.y = 0;
00200
00201
00202 if (glyph->fImage) FT_Done_Glyph(glyph->fImage);
00203
00204
00205 if (FT_Load_Glyph(fgFace[fgCurFontIdx], glyph->fIndex, load_flags))
00206 continue;
00207
00208
00209 if (FT_Get_Glyph (fgFace[fgCurFontIdx]->glyph, &glyph->fImage))
00210 continue;
00211
00212 glyph->fPos = origin;
00213 fgWidth += fgFace[fgCurFontIdx]->glyph->advance.x;
00214 fgAscent = TMath::Max((Int_t)(fgFace[fgCurFontIdx]->glyph->metrics.horiBearingY), fgAscent);
00215
00216
00217 FT_Vector_Transform(&glyph->fPos, fgRotMatrix);
00218 if (FT_Glyph_Transform(glyph->fImage, fgRotMatrix, &glyph->fPos))
00219 continue;
00220
00221
00222 FT_BBox bbox;
00223 FT_Glyph_Get_CBox(glyph->fImage, ft_glyph_bbox_pixels, &bbox);
00224 if (bbox.xMin < fgCBox.xMin) fgCBox.xMin = bbox.xMin;
00225 if (bbox.yMin < fgCBox.yMin) fgCBox.yMin = bbox.yMin;
00226 if (bbox.xMax > fgCBox.xMax) fgCBox.xMax = bbox.xMax;
00227 if (bbox.yMax > fgCBox.yMax) fgCBox.yMax = bbox.yMax;
00228 }
00229 }
00230
00231
00232 void TTF::PrepareString(const char *string)
00233 {
00234
00235
00236 const unsigned char *p = (const unsigned char*) string;
00237 TTGlyph *glyph = fgGlyphs;
00238 UInt_t index;
00239 Int_t NbTBlank = 0;
00240
00241 fgTBlankW = 0;
00242 fgNumGlyphs = 0;
00243 while (*p) {
00244 index = CharToUnicode((FT_ULong)*p);
00245 if (index != 0) {
00246 glyph->fIndex = index;
00247 glyph++;
00248 fgNumGlyphs++;
00249 }
00250 if (index == 3) {
00251 NbTBlank++;
00252 } else {
00253 NbTBlank = 0;
00254 }
00255 if (fgNumGlyphs >= kMaxGlyphs) break;
00256 p++;
00257 }
00258
00259
00260
00261 if (NbTBlank) {
00262 FT_UInt load_flags = FT_LOAD_DEFAULT;
00263 if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING;
00264 if (FT_Load_Glyph(fgFace[fgCurFontIdx], 3, load_flags)) return;
00265 fgTBlankW = (Int_t)((fgFace[fgCurFontIdx]->glyph->advance.x)>>6)*NbTBlank;
00266 }
00267 }
00268
00269
00270 void TTF::SetHinting(Bool_t state)
00271 {
00272
00273
00274 fgHinting = state;
00275 }
00276
00277
00278 void TTF::SetKerning(Bool_t state)
00279 {
00280
00281
00282 fgKerning = state;
00283 }
00284
00285
00286 void TTF::SetRotationMatrix(Float_t angle)
00287 {
00288
00289
00290 Float_t rangle = Float_t(angle * TMath::Pi() / 180.);
00291 #if defined(FREETYPE_PATCH) && \
00292 (FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH == 2)
00293 Float_t sin = TMath::Sin(rangle);
00294 Float_t cos = TMath::Cos(rangle);
00295 #else
00296 Float_t sin = TMath::Sin(-rangle);
00297 Float_t cos = TMath::Cos(-rangle);
00298 #endif
00299
00300 if (!fgRotMatrix) fgRotMatrix = new FT_Matrix;
00301
00302 fgRotMatrix->xx = (FT_Fixed) (cos * (1<<16));
00303 fgRotMatrix->xy = (FT_Fixed) (sin * (1<<16));
00304 fgRotMatrix->yx = -fgRotMatrix->xy;
00305 fgRotMatrix->yy = fgRotMatrix->xx;
00306 }
00307
00308
00309 void TTF::SetSmoothing(Bool_t state)
00310 {
00311
00312
00313 fgSmoothing = state;
00314 }
00315
00316
00317 Int_t TTF::SetTextFont(const char *fontname, Int_t italic)
00318 {
00319
00320
00321
00322
00323
00324
00325
00326 if (!fgInit) Init();
00327
00328 if (!fontname || !fontname[0]) {
00329 Warning("TTF::SetTextFont",
00330 "no font name specified, using default font %s", fgFontName[0]);
00331 fgCurFontIdx = 0;
00332 return 0;
00333 }
00334 const char *basename = gSystem->BaseName(fontname);
00335
00336
00337 int i;
00338 for (i = 0; i < fgFontCount; i++) {
00339 if (!strcmp(fgFontName[i], basename)) {
00340 if (italic) {
00341 if (i==fgSymbItaFontIdx) {
00342 fgCurFontIdx = i;
00343 return 0;
00344 }
00345 } else {
00346 if (i!=fgSymbItaFontIdx) {
00347 fgCurFontIdx = i;
00348 return 0;
00349 }
00350 }
00351 }
00352 }
00353
00354
00355 if (fgFontCount >= kTTMaxFonts) {
00356 Error("TTF::SetTextFont", "too many fonts opened (increase kTTMaxFont = %d)",
00357 kTTMaxFonts);
00358 Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]);
00359 fgCurFontIdx = 0;
00360 return 0;
00361 }
00362
00363
00364 const char *ttpath = gEnv->GetValue("Root.TTFontPath",
00365 # ifdef TTFFONTDIR
00366 TTFFONTDIR
00367 # else
00368 "$(ROOTSYS)/fonts"
00369 # endif
00370 );
00371
00372 char *ttfont = gSystem->Which(ttpath, fontname, kReadPermission);
00373
00374 if (!ttfont) {
00375 Error("TTF::SetTextFont", "font file %s not found in path", fontname);
00376 if (fgFontCount) {
00377 Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]);
00378 fgCurFontIdx = 0;
00379 return 0;
00380 } else {
00381 return 1;
00382 }
00383 }
00384
00385 FT_Face tface = 0;
00386
00387 if (FT_New_Face(fgLibrary, ttfont, 0, &tface)) {
00388 Error("TTF::SetTextFont", "error loading font %s", ttfont);
00389 delete [] ttfont;
00390 if (tface) FT_Done_Face(tface);
00391 if (fgFontCount) {
00392 Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]);
00393 fgCurFontIdx = 0;
00394 return 0;
00395 } else {
00396 return 1;
00397 }
00398 }
00399
00400 delete [] ttfont;
00401
00402 fgFontName[fgFontCount] = StrDup(basename);
00403 fgCurFontIdx = fgFontCount;
00404 fgFace[fgCurFontIdx] = tface;
00405 fgCharMap[fgCurFontIdx] = 0;
00406 fgFontCount++;
00407
00408 if (italic) {
00409 fgSymbItaFontIdx = fgCurFontIdx;
00410 FT_Matrix slantMat;
00411 slantMat.xx = (1 << 16);
00412 slantMat.xy = ((1 << 16) >> 2);
00413 slantMat.yx = 0;
00414 slantMat.yy = (1 << 16);
00415 FT_Set_Transform( fgFace[fgSymbItaFontIdx], &slantMat, NULL );
00416 }
00417
00418 return 0;
00419 }
00420
00421
00422 void TTF::SetTextFont(Font_t fontnumber)
00423 {
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 static const char *fonttable[][2] = {
00448
00449 { "arialbd.ttf", "FreeSansBold.ttf" },
00450 { "timesi.ttf", "FreeSerifItalic.ttf" },
00451 { "timesbd.ttf", "FreeSerifBold.ttf" },
00452 { "timesbi.ttf", "FreeSerifBoldItalic.ttf" },
00453 { "arial.ttf", "FreeSans.ttf" },
00454 { "ariali.ttf", "FreeSansOblique.ttf" },
00455 { "arialbd.ttf", "FreeSansBold.ttf" },
00456 { "arialbi.ttf", "FreeSansBoldOblique.ttf" },
00457 { "cour.ttf", "FreeMono.ttf" },
00458 { "couri.ttf", "FreeMonoOblique.ttf" },
00459 { "courbd.ttf", "FreeMonoBold.ttf" },
00460 { "courbi.ttf", "FreeMonoBoldOblique.ttf" },
00461 { "symbol.ttf", "symbol.ttf" },
00462 { "times.ttf", "FreeSerif.ttf" },
00463 { "wingding.ttf", "opens___.ttf" },
00464 { "symbol.ttf", "symbol.ttf" }
00465 };
00466
00467 static int fontset = -1;
00468 int thisset = fontset;
00469
00470 int fontid = fontnumber / 10;
00471 if (fontid < 0 || fontid > 15) fontid = 0;
00472
00473 if (thisset == -1) {
00474
00475
00476 const char *ttpath = gEnv->GetValue("Root.TTFontPath",
00477 #ifdef TTFFONTDIR
00478 TTFFONTDIR
00479 #else
00480 "$(ROOTSYS)/fonts"
00481 #endif
00482 );
00483 char *ttfont = gSystem->Which(ttpath, fonttable[fontid][0], kReadPermission);
00484 if (ttfont) {
00485 delete [] ttfont;
00486 thisset = 0;
00487 } else {
00488
00489 thisset = 1;
00490 }
00491 }
00492 Int_t italic = 0;
00493 if (fontid==15) italic = 1;
00494 int ret = SetTextFont(fonttable[fontid][thisset], italic);
00495
00496
00497 if (ret == 0 && fontid != 12) fontset = thisset;
00498 }
00499
00500
00501 void TTF::SetTextSize(Float_t textsize)
00502 {
00503
00504
00505 if (!fgInit) Init();
00506 if (textsize < 0) return;
00507
00508 if (fgCurFontIdx < 0 || fgFontCount <= fgCurFontIdx) {
00509 Error("TTF::SetTextSize", "current font index out of bounds");
00510 fgCurFontIdx = 0;
00511 return;
00512 }
00513
00514 Int_t tsize = (Int_t)(textsize*kScale+0.5) << 6;
00515 if (FT_Set_Char_Size(fgFace[fgCurFontIdx], tsize, tsize, 72, 72))
00516 Error("TTF::SetTextSize", "error in FT_Set_Char_Size");
00517 }
00518
00519
00520 void TTF::Version(Int_t &major, Int_t &minor, Int_t &patch)
00521 {
00522 FT_Library_Version(fgLibrary, &major, &minor, &patch);
00523 }
00524
00525
00526 Bool_t TTF::GetHinting()
00527 {
00528 return fgHinting;
00529 }
00530
00531
00532 Bool_t TTF::GetKerning()
00533 {
00534 return fgKerning;
00535 }
00536
00537
00538 Bool_t TTF::GetSmoothing()
00539 {
00540 return fgSmoothing;
00541 }
00542
00543
00544 Bool_t TTF::IsInitialized()
00545 {
00546 return fgInit;
00547 }
00548
00549
00550 Int_t TTF::GetWidth()
00551 {
00552 return fgWidth;
00553 }
00554
00555
00556 Int_t TTF::GetAscent()
00557 {
00558 return fgAscent;
00559 }
00560
00561
00562 Int_t TTF::GetNumGlyphs()
00563 {
00564 return fgNumGlyphs;
00565 }
00566
00567
00568 FT_Matrix *TTF::GetRotMatrix()
00569 {
00570 return fgRotMatrix;
00571 }
00572
00573
00574 const FT_BBox &TTF::GetBox()
00575 {
00576 return fgCBox;
00577 }
00578
00579
00580 TTGlyph *TTF::GetGlyphs()
00581 {
00582 return fgGlyphs;
00583 }