TTF.cxx

Go to the documentation of this file.
00001 // @(#)root/graf:$Id: TTF.cxx 32449 2010-03-04 10:30:03Z couet $
00002 // Author: Olivier Couet     01/10/02
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TTF                                                                  //
00015 //                                                                      //
00016 // Interface to the freetype 2 library.                                 //
00017 //                                                                      //
00018 //////////////////////////////////////////////////////////////////////////
00019 
00020 // RConfigure.h is needed for TTFFONTDIR
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 // to scale fonts to the same size as the old TT version
00031 const Float_t kScale = 0.93376068;
00032 
00033 TTF gCleanupTTF; // Allows to call "Cleanup" at the end of the session
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    // Cleanup TTF environment.
00061 
00062    Cleanup();
00063 }
00064 
00065 //______________________________________________________________________________
00066 void TTF::Init()
00067 {
00068    // Initialise the TrueType fonts interface.
00069 
00070    fgInit = kTRUE;
00071 
00072    // initialize FTF library
00073    if (FT_Init_FreeType(&fgLibrary)) {
00074       Error("TTF::Init", "error initializing FreeType");
00075       return;
00076    }
00077 
00078    // load default font (arialbd)
00079    SetTextFont(62);
00080 }
00081 
00082 //______________________________________________________________________________
00083 void TTF::Cleanup()
00084 {
00085    // Cleanup. Is called by the gCleanupTTF destructor.
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    // Map char to unicode. Returns 0 in case no mapping exists.
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    // Get width (w) and height (h) when text is horizontal.
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    // Get advance (a) when text is horizontal.
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    // Compute the glyps positions, fgAscent and fgWidth (needed for alignment).
00165    // Perform the Glyphs transformation.
00166    // Compute the string control box.
00167    // If required take the "kerning" into account.
00168    // SetRotation and PrepareString should have been called before.
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       // compute glyph origin
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       // clear existing image if there is one
00202       if (glyph->fImage) FT_Done_Glyph(glyph->fImage);
00203 
00204       // load the glyph image (in its native format)
00205       if (FT_Load_Glyph(fgFace[fgCurFontIdx], glyph->fIndex, load_flags))
00206          continue;
00207 
00208       // extract the glyph image
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       // transform the glyphs
00217       FT_Vector_Transform(&glyph->fPos, fgRotMatrix);
00218       if (FT_Glyph_Transform(glyph->fImage, fgRotMatrix, &glyph->fPos))
00219          continue;
00220 
00221       // compute the string control box
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    // Put the characters in "string" in the "glyphs" array.
00235 
00236    const unsigned char *p = (const unsigned char*) string;
00237    TTGlyph *glyph = fgGlyphs;
00238    UInt_t index;       // Unicode value
00239    Int_t NbTBlank = 0; // number of trailing blanks
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    // compute the trailing blanks width. It is use to compute the text
00260    // width in GetTextExtent
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    // Set hinting flag.
00273 
00274    fgHinting = state;
00275 }
00276 
00277 //______________________________________________________________________________
00278 void TTF::SetKerning(Bool_t state)
00279 {
00280    // Set kerning flag.
00281 
00282    fgKerning = state;
00283 }
00284 
00285 //______________________________________________________________________________
00286 void TTF::SetRotationMatrix(Float_t angle)
00287 {
00288    // Set the rotation matrix used to rotate the font outlines.
00289 
00290    Float_t rangle = Float_t(angle * TMath::Pi() / 180.); // Angle in radian
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    // Set smoothing (anti-aliasing) flag.
00312 
00313    fgSmoothing = state;
00314 }
00315 
00316 //______________________________________________________________________________
00317 Int_t TTF::SetTextFont(const char *fontname, Int_t italic)
00318 {
00319    // Set text font to specified name.
00320    // font       : font name
00321    // italic     : the fonts should be slanted. Used for symbol font.
00322    //
00323    // Set text font to specified name. This function returns 0 if
00324    // the specified font is found, 1 if not.
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    // check if font is in cache
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    // enough space in cache to load font?
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;    // use font 0 (default font, set in ctor)
00360       return 0;
00361    }
00362 
00363    // try to load font (font must be in Root.TTFontPath resource)
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;    // use font 0 (default font, set in ctor)
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    // Set specified font.
00425    // List of the currently supported fonts (screen and PostScript)
00426    // =============================================================
00427    //   Font ID       X11                        TTF
00428    //        1 : times-medium-i-normal       timesi.ttf
00429    //        2 : times-bold-r-normal         timesbd.ttf
00430    //        3 : times-bold-i-normal         timesi.ttf
00431    //        4 : helvetica-medium-r-normal   arial.ttf
00432    //        5 : helvetica-medium-o-normal   ariali.ttf
00433    //        6 : helvetica-bold-r-normal     arialbd.ttf
00434    //        7 : helvetica-bold-o-normal     arialbi.ttf
00435    //        8 : courier-medium-r-normal     cour.ttf
00436    //        9 : courier-medium-o-normal     couri.ttf
00437    //       10 : courier-bold-r-normal       courbd.ttf
00438    //       11 : courier-bold-o-normal       courbi.ttf
00439    //       12 : symbol-medium-r-normal      symbol.ttf
00440    //       13 : times-medium-r-normal       times.ttf
00441    //       14 :                             wingding.ttf
00442    //       15 : symbol oblique is emulated from symbol.ttf
00443 
00444    // Added by cholm for use of DFSG - fonts - based on Kevins fix.
00445    // Table of Microsoft and (for non-MSFT operating systems) backup
00446    // FreeFont TTF fonts.
00447    static const char *fonttable[][2] = {
00448       // fontnumber/10  MSFT font   Free font
00449       /* 0 */ { "arialbd.ttf",   "FreeSansBold.ttf"        },
00450       /* 1 */ { "timesi.ttf",    "FreeSerifItalic.ttf"     },
00451       /* 2 */ { "timesbd.ttf",   "FreeSerifBold.ttf"       },
00452       /* 3 */ { "timesbi.ttf",   "FreeSerifBoldItalic.ttf" },
00453       /* 4 */ { "arial.ttf",     "FreeSans.ttf"            },
00454       /* 5 */ { "ariali.ttf",    "FreeSansOblique.ttf"     },
00455       /* 6 */ { "arialbd.ttf",   "FreeSansBold.ttf"        },
00456       /* 7 */ { "arialbi.ttf",   "FreeSansBoldOblique.ttf" },
00457       /* 8 */ { "cour.ttf",      "FreeMono.ttf"            },
00458       /* 9 */ { "couri.ttf",     "FreeMonoOblique.ttf"     },
00459       /*10 */ { "courbd.ttf",    "FreeMonoBold.ttf"        },
00460       /*11 */ { "courbi.ttf",    "FreeMonoBoldOblique.ttf" },
00461       /*12 */ { "symbol.ttf",    "symbol.ttf"              },
00462       /*13 */ { "times.ttf",     "FreeSerif.ttf"           },
00463       /*14 */ { "wingding.ttf",  "opens___.ttf"            },
00464       /*15 */ { "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       // try to load font (font must be in Root.TTFontPath resource)
00475       // to see which fontset we have available
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          // try backup free font
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    // Do not define font set is we're loading the symbol.ttf - it's
00496    // the same in both cases.
00497    if (ret == 0 && fontid != 12) fontset = thisset;
00498 }
00499 
00500 //______________________________________________________________________________
00501 void TTF::SetTextSize(Float_t textsize)
00502 {
00503    // Set current text size.
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 }

Generated on Tue Jul 5 14:14:28 2011 for ROOT_528-00b_version by  doxygen 1.5.1