#ifdef R__HAVE_CONFIG
#include "RConfigure.h"
#endif
#include "TTF.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TMath.h"
#include "TError.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;
char       *TTF::fgFontName[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;
   }
   
   SetTextFont(62);
}
void TTF::Cleanup()
{
   
   if (!fgInit) return;
   for (int i = 0; i < fgFontCount; i++) {
      delete [] fgFontName[i];
      FT_Done_Face(fgFace[i]);
   }
   if (fgRotMatrix) delete fgRotMatrix;
   FT_Done_FreeType(fgLibrary);
}
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) ||
             (platform == 0 && encoding == 0) ||
             (platform == 1 && encoding == 0 &&
              !strcmp(fgFontName[fgCurFontIdx], "wingding.ttf")) ||
             (platform == 1 && encoding == 0 &&
              !strcmp(fgFontName[fgCurFontIdx], "symbol.ttf")))
         {
            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::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 (index == 3) {
         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)
{
   
   
   
   
   
   if (!fgInit) Init();
   if (!fontname || !fontname[0]) {
      Warning("TTF::SetTextFont",
              "no font name specified, using default font %s", fgFontName[0]);
      fgCurFontIdx = 0;
      return 0;
   }
   const char *basename = gSystem->BaseName(fontname);
   
   int i;
   for (i = 0; i < fgFontCount; i++) {
      if (!strcmp(fgFontName[i], basename)) {
         fgCurFontIdx = i;
         return 0;
      }
   }
   
   if (fgFontCount >= kTTMaxFonts) {
      Error("TTF::SetTextFont", "too many fonts opened (increase kTTMaxFont = %d)",
            kTTMaxFonts);
      Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]);
      fgCurFontIdx = 0;    
      return 0;
   }
   
   const char *ttpath = gEnv->GetValue("Root.TTFontPath",
# ifdef TTFFONTDIR
                                       TTFFONTDIR
# else
                                       "$(ROOTSYS)/fonts"
# endif
                                      );
   char *ttfont = gSystem->Which(ttpath, fontname, kReadPermission);
   if (!ttfont) {
      Error("TTF::SetTextFont", "font file %s not found in path", fontname);
      if (fgFontCount) {
         Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]);
         fgCurFontIdx = 0;    
         return 0;
      } else {
         return 1;
      }
   }
   FT_Face  tface = 0;
   if (FT_New_Face(fgLibrary, ttfont, 0, &tface)) {
      Error("TTF::SetTextFont", "error loading font %s", ttfont);
      delete [] ttfont;
      if (tface) FT_Done_Face(tface);
      if (fgFontCount) {
         Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]);
         fgCurFontIdx = 0;
         return 0;
      } else {
         return 1;
      }
   }
   delete [] ttfont;
   fgFontName[fgFontCount] = StrDup(basename);
   fgCurFontIdx            = fgFontCount;
   fgFace[fgCurFontIdx]    = tface;
   fgCharMap[fgCurFontIdx] = 0;
   fgFontCount++;
   return 0;
}
void TTF::SetTextFont(Font_t fontnumber)
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   static const char *fonttable[][2] = {
      
       { "arialbd.ttf",   "FreeSansBold.ttf"        },
       { "timesi.ttf",    "FreeSerifItalic.ttf"     },
       { "timesbd.ttf",   "FreeSerifBold.ttf"       },
       { "timesbi.ttf",   "FreeSerifBoldItalic.ttf" },
       { "arial.ttf",     "FreeSans.ttf"            },
       { "ariali.ttf",    "FreeSansOblique.ttf"     },
       { "arialbd.ttf",   "FreeSansBold.ttf"        },
       { "arialbi.ttf",   "FreeSansBoldOblique.ttf" },
       { "cour.ttf",      "FreeMono.ttf"            },
       { "couri.ttf",     "FreeMonoOblique.ttf"     },
       { "courbd.ttf",    "FreeMonoBold.ttf"        },
       { "courbi.ttf",    "FreeMonoBoldOblique.ttf" },
       { "symbol.ttf",    "symbol.ttf"              },
       { "times.ttf",     "FreeSerif.ttf"           },
       { "wingding.ttf",  "opens___.ttf"            }
   };
   static int fontset = -1;
   int        thisset = fontset;
   int fontid = fontnumber / 10;
   if (fontid < 0 || fontid > 14) fontid = 0;
   if (thisset == -1) {
      
      
      const char *ttpath = gEnv->GetValue("Root.TTFontPath",
#ifdef TTFFONTDIR
                                          TTFFONTDIR
#else
                                          "$(ROOTSYS)/fonts"
#endif
                                         );
      char *ttfont = gSystem->Which(ttpath, fonttable[fontid][0], kReadPermission);
      if (ttfont) {
         delete [] ttfont;
         thisset = 0;
      } else {
         
         thisset = 1;
      }
   }
   int ret = SetTextFont(fonttable[fontid][thisset]);
   
   
   if (ret == 0 && fontid != 12) fontset = thisset;
}
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;
}
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.