diff --git a/graf2d/graf/inc/LinkDef.h b/graf2d/graf/inc/LinkDef.h index 95f132df5493c..ccb0862fc2b64 100644 --- a/graf2d/graf/inc/LinkDef.h +++ b/graf2d/graf/inc/LinkDef.h @@ -1,7 +1,7 @@ /* @(#)root/graf:$Id$ */ /************************************************************************* - * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -57,6 +57,7 @@ #pragma link C++ class TPolyLine-; #pragma link C++ class TText-; #pragma link C++ class TTF; +#pragma link C++ class TTFhandle; #pragma link C++ class TWbox+; #pragma link C++ enum TImage::EImageFileTypes; diff --git a/graf2d/graf/inc/TTF.h b/graf2d/graf/inc/TTF.h index 1663f3d45f148..0cdc37913675f 100644 --- a/graf2d/graf/inc/TTF.h +++ b/graf2d/graf/inc/TTF.h @@ -1,9 +1,10 @@ // @(#)root/graf:$Id$ -// Author: Olivier Couet 01/10/02 -// Author: Fons Rademakers 21/11/98 +// Author: Olivier Couet 01/10/2002 +// Author: Fons Rademakers 21/11/1998 +// Author: Sergey Linev 29/14/2026 /************************************************************************* - * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * @@ -15,6 +16,7 @@ #include "Rtypes.h" +#include /// @cond DOXYGEN_IGNORE // Forward declare for the headers: @@ -45,66 +47,45 @@ extern "C" { /// @endcond -class TGX11TTF; -class TGWin32; -class TMathTextRenderer; - +class TTFhandle; class TTF { -friend class TGX11TTF; -friend class TGWin32; -friend class TMathTextRenderer; + friend class TTFhandle; + + static std::unique_ptr fgHandle; ///< global handle to support old static API public: -/** \class TTGlyph -TTF helper class containing glyphs description. -*/ + /** \class TTGlyph + TTF helper class containing glyphs description. + */ class TTGlyph { public: UInt_t fIndex{0}; ///< glyph index in face FT_Vector fPos; ///< position of glyph origin FT_Glyph fImage{nullptr}; ///< glyph image + TTGlyph(UInt_t indx = 0) : fIndex(indx) {} }; -protected: - enum { kTTMaxFonts = 32, kMaxGlyphs = 1024 }; - - static Int_t fgAscent; ///< string ascent, used to compute Y alignment - static FT_BBox fgCBox; ///< string control box - static FT_CharMap fgCharMap[kTTMaxFonts]; ///< font character map - static Int_t fgCurFontIdx; ///< current font index - static Int_t fgSymbItaFontIdx; ///< Symbol italic font index - static Int_t fgFontCount; ///< number of fonts loaded - static char *fgFontName[kTTMaxFonts]; ///< font name - static FT_Face fgFace[kTTMaxFonts]; ///< font face - static TTF::TTGlyph fgGlyphs[kMaxGlyphs]; ///< glyphs - static Bool_t fgHinting; ///< use hinting (true by default) - static Bool_t fgInit; ///< true if the Init has been called - static Bool_t fgKerning; ///< use kerning (true by default) - static FT_Library fgLibrary; ///< FreeType font library - static Int_t fgNumGlyphs; ///< number of glyphs in the string - static FT_Matrix *fgRotMatrix; ///< rotation matrix - static Bool_t fgSmoothing; ///< use anti-aliasing (true when >8 planes, false otherwise) - static Int_t fgTBlankW; ///< trailing blanks width - static Int_t fgWidth; ///< string width, used to compute X alignment - -public: - static Short_t CharToUnicode(UInt_t code); - static void LayoutGlyphs(); - static void PrepareString(const char *string); - static void PrepareString(const wchar_t *string); - static void SetRotationMatrix(Float_t angle); - static void CleanupGlyphs(); - -public: - TTF() { } + TTF() {} virtual ~TTF(); + // old static methods which are fully replaced by TTFhandle + // remain here only for backward compatibility until ROOT7 + + // minimal static interface to initialize library and handle fonts static void Init(); static void Cleanup(); + static Bool_t IsInitialized(); + + static Short_t CharToUnicode(UInt_t code); + static void LayoutGlyphs(); + static void PrepareString(const char *string); + static void PrepareString(const wchar_t *string); + static void SetRotationMatrix(Float_t angle); + static void ComputeTrailingBlanksWidth(Int_t n); static Int_t GetAscent(); static const FT_BBox &GetBox(); @@ -125,10 +106,89 @@ TTF helper class containing glyphs description. static void SetTextFont(Font_t fontnumber); static Int_t SetTextFont(const char *fontname, Int_t italic=0); static void SetTextSize(Float_t textsize); - static Bool_t IsInitialized(); + static void Version(Int_t &major, Int_t &minor, Int_t &patch); + // new temporary methods, can be removed at the end + static void CleanupGlyphs(); + static void SetCurFontIdx(Int_t indx); + static Int_t GetCurFontIdx(); + static FT_Face GetCurFontFace(); + ClassDef(TTF,0) //Interface to TTF font handling }; +class TTFhandle { + friend class TTF; + + private: + enum { kTTMaxFonts = 32 }; + + static FT_Library fgLibrary; ///< FreeType font library + static Bool_t fgInit; ///< true if the Init has been called + static Int_t fgSymbItaFontIdx; ///< Symbol italic font index + static Int_t fgFontCount; ///< number of fonts loaded + static char *fgFontName[kTTMaxFonts]; ///< font name + static FT_Face fgFace[kTTMaxFonts]; ///< font face + static FT_CharMap fgCharMap[kTTMaxFonts]; ///< font character map + + Int_t fAscent = 0; ///< string ascent, used to compute Y alignment + FT_BBox fCBox; ///< string control box + Int_t fCurFontIdx = -1; ///< current font index + std::vector fGlyphs; ///< glyphs + Bool_t fHinting = kFALSE; ///< use hinting (true by default) + Bool_t fKerning = kTRUE; ///< use kerning (true by default) + std::unique_ptr fRotMatrix; ///< rotation matrix + Bool_t fSmoothing = kTRUE; ///< use anti-aliasing (true when >8 planes, false otherwise) + Int_t fTBlankW = 0; ///< trailing blanks width + Int_t fWidth = 0; ///< string width, used to compute X alignment + + void ComputeTrailingBlanksWidth(Int_t n); + + public: + TTFhandle(); + virtual ~TTFhandle(); + + TTF::TTGlyph *GetGlyphs() { return fGlyphs.data(); } + UInt_t GetNumGlyphs() const { return fGlyphs.size(); } + Int_t GetCurFontIdx() const { return fCurFontIdx; } + FT_Face GetCurFontFace() const; + Int_t GetAscent() const { return fAscent; } + Bool_t GetHinting() const { return fHinting; } + Bool_t GetKerning() const { return fKerning; } + FT_Matrix *GetRotMatrix() const { return fRotMatrix.get(); } + Bool_t GetSmoothing() const { return fSmoothing; } + Int_t GetTrailingBlanksWidth() const { return fTBlankW; } + Int_t GetWidth() const { return fWidth; } + const FT_BBox &GetBox() const { return fCBox; } + + + void SetCurFontIdx(Int_t indx) { fCurFontIdx = indx; } + void SetHinting(Bool_t state) { fHinting = state; } + void SetKerning(Bool_t state) { fKerning = state; } + void SetSmoothing(Bool_t state) { fSmoothing = state; } + + void SetTextFont(Font_t fontnumber); + Int_t SetTextFont(const char *fontname, Int_t italic = 0); + Bool_t SetTextSize(Float_t textsize); + + Short_t CharToUnicode(UInt_t code); + void LayoutGlyphs(); + void PrepareString(const char *string); + void PrepareString(const wchar_t *string); + void SetRotationMatrix(Float_t angle); + void CleanupGlyphs(); + + void GetTextExtent(UInt_t &w, UInt_t &h, const char *text); + void GetTextExtent(UInt_t &w, UInt_t &h, const wchar_t *text); + void GetTextAdvance(UInt_t &a, const char *text); + + void Version(Int_t &major, Int_t &minor, Int_t &patch); + + static void CloseLibrary(); + + ClassDef(TTFhandle, 0) // Dynamic interface to TTF + +}; + #endif diff --git a/graf2d/graf/src/TMathText.cxx b/graf2d/graf/src/TMathText.cxx index db37252c02cbc..f88133c5e685f 100644 --- a/graf2d/graf/src/TMathText.cxx +++ b/graf2d/graf/src/TMathText.cxx @@ -227,7 +227,7 @@ class TMathTextRenderer : public TText, public TAttFill, bounding_box(const wchar_t character, float ¤t_x, const unsigned int family) { - const size_t old_font_index = TTF::fgCurFontIdx; + const auto old_font_index = TTF::GetCurFontIdx(); const bool cyrillic_or_cjk = is_cyrillic_or_cjk(character); if (cyrillic_or_cjk) { @@ -235,16 +235,16 @@ class TMathTextRenderer : public TText, public TAttFill, } else { TTF::SetTextFont((Font_t) root_face_number(family)); } + + auto font_face = TTF::GetCurFontFace(); + FT_Load_Glyph( - TTF::fgFace[TTF::fgCurFontIdx], - FT_Get_Char_Index( - TTF::fgFace[TTF::fgCurFontIdx], character), + font_face, + FT_Get_Char_Index(font_face, character), FT_LOAD_NO_SCALE); - const float scale = _current_font_size[family] / - TTF::fgFace[TTF::fgCurFontIdx]->units_per_EM; - const FT_Glyph_Metrics metrics = - TTF::fgFace[TTF::fgCurFontIdx]->glyph->metrics; + const float scale = _current_font_size[family] / font_face->units_per_EM; + const FT_Glyph_Metrics metrics = font_face->glyph->metrics; const float lower_left_x = metrics.horiBearingX; const float lower_left_y = metrics.horiBearingY - metrics.height; @@ -263,7 +263,8 @@ class TMathTextRenderer : public TText, public TAttFill, advance, italic_correction) * scale; current_x += ret.advance(); - TTF::fgCurFontIdx = old_font_index; + + TTF::SetCurFontIdx(old_font_index); return ret; } @@ -271,11 +272,10 @@ class TMathTextRenderer : public TText, public TAttFill, bounding_box(const std::wstring string, const unsigned int family = FAMILY_PLAIN) override { - if (TTF::fgCurFontIdx<0) return mathtext::bounding_box_t(0, 0, 0, 0, 0, 0); - if (string.empty() || TTF::fgFace[TTF::fgCurFontIdx] == NULL || - TTF::fgFace[TTF::fgCurFontIdx]->units_per_EM == 0) { + auto font_face = TTF::GetCurFontFace(); + + if (string.empty() || !font_face || font_face->units_per_EM == 0) return mathtext::bounding_box_t(0, 0, 0, 0, 0, 0); - } std::wstring::const_iterator iterator = string.begin(); float current_x = 0; diff --git a/graf2d/graf/src/TTF.cxx b/graf2d/graf/src/TTF.cxx index 38af54bcd5312..db2cc74d91b2a 100644 --- a/graf2d/graf/src/TTF.cxx +++ b/graf2d/graf/src/TTF.cxx @@ -1,23 +1,27 @@ // @(#)root/graf:$Id$ -// Author: Olivier Couet 01/10/02 +// Author: Olivier Couet 01/10/2002 +// Author: Sergey Linev 29/04/2026 /************************************************************************* - * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ -/** \class TTF + +/** \class TTFhandle \ingroup BasicGraphics -Interface to the freetype 2 library. +Dynamic handle to work with freetype 2 library. +in ROOT7 TTFhandle will be renamed into TTF class */ -# include -# include FT_FREETYPE_H -# include FT_GLYPH_H + +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H #include "TROOT.h" #include "TTF.h" #include "TSystem.h" @@ -28,160 +32,130 @@ Interface to the freetype 2 library. // to scale fonts to the same size as the old TT version const Float_t kScale = 0.93376068; -TTF gCleanupTTF; // Allows to call "Cleanup" at the end of the session -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::fgSymbItaFontIdx = -1; -Int_t TTF::fgFontCount = 0; -Int_t TTF::fgNumGlyphs = 0; -char *TTF::fgFontName[kTTMaxFonts]; -FT_Matrix *TTF::fgRotMatrix = nullptr; -FT_Library TTF::fgLibrary; -FT_BBox TTF::fgCBox; -FT_Face TTF::fgFace[kTTMaxFonts]; -FT_CharMap TTF::fgCharMap[kTTMaxFonts]; -TTF::TTGlyph TTF::fgGlyphs[kMaxGlyphs]; +Bool_t TTFhandle::fgInit = kFALSE; +FT_Library TTFhandle::fgLibrary; +Int_t TTFhandle::fgFontCount = 0; +char *TTFhandle::fgFontName[kTTMaxFonts]; +FT_Face TTFhandle::fgFace[kTTMaxFonts]; +FT_CharMap TTFhandle::fgCharMap[kTTMaxFonts]; +Int_t TTFhandle::fgSymbItaFontIdx = -1; //////////////////////////////////////////////////////////////////////////////// -/// Cleanup TTF environment. -TTF::~TTF() +TTFhandle::TTFhandle() { - Cleanup(); + if (!fgInit) { + // initialize FTF library + if (FT_Init_FreeType(&fgLibrary)) + Error("TTFhandle", "error initializing FreeType"); + else + fgInit = kTRUE; + } } + //////////////////////////////////////////////////////////////////////////////// -/// Initialise the TrueType fonts interface. -void TTF::Init() +TTFhandle::~TTFhandle() { - if (fgInit) - return; - - fgInit = kTRUE; - - // initialize FTF library - if (FT_Init_FreeType(&fgLibrary)) { - Error("TTF::Init", "error initializing FreeType"); - return; - } - - // load default font (arialbd) - SetTextFont(62); + CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// -/// Cleanup. Is called by the gCleanupTTF destructor. +/// Close library handle. Is called by the gCleanupTTF destructor. -void TTF::Cleanup() +void TTFhandle::CloseLibrary() { if (!fgInit) return; - CleanupGlyphs(); - - for (int i = 0; i < fgFontCount; i++) { + for (Int_t i = 0; i < fgFontCount; i++) { delete [] fgFontName[i]; fgFontName[i] = nullptr; FT_Done_Face(fgFace[i]); } - if (fgRotMatrix) { - delete fgRotMatrix; - fgRotMatrix = nullptr; - } FT_Done_FreeType(fgLibrary); - fgInit = kFALSE; } //////////////////////////////////////////////////////////////////////////////// /// Map char to unicode. Returns 0 in case no mapping exists. -Short_t TTF::CharToUnicode(UInt_t code) +Short_t TTFhandle::CharToUnicode(UInt_t code) { - if (!fgCharMap[fgCurFontIdx]) { + if (!fgCharMap[fCurFontIdx]) { UShort_t i, platform, encoding; FT_CharMap charmap; - if (!fgFace[fgCurFontIdx]) return 0; - Int_t n = fgFace[fgCurFontIdx]->num_charmaps; + if (!fgFace[fCurFontIdx]) return 0; + Int_t n = fgFace[fCurFontIdx]->num_charmaps; for (i = 0; i < n; i++) { - if (!fgFace[fgCurFontIdx]) continue; - charmap = fgFace[fgCurFontIdx]->charmaps[i]; + if (!fgFace[fCurFontIdx]) continue; + charmap = fgFace[fCurFontIdx]->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")) || + !strcmp(fgFontName[fCurFontIdx], "wingding.ttf")) || (platform == 1 && encoding == 0 && - !strcmp(fgFontName[fgCurFontIdx], "symbol.ttf"))) + !strcmp(fgFontName[fCurFontIdx], "symbol.ttf"))) { - fgCharMap[fgCurFontIdx] = charmap; - if (FT_Set_Charmap(fgFace[fgCurFontIdx], fgCharMap[fgCurFontIdx])) + fgCharMap[fCurFontIdx] = charmap; + if (FT_Set_Charmap(fgFace[fCurFontIdx], fgCharMap[fCurFontIdx])) Error("TTF::CharToUnicode", "error in FT_Set_CharMap"); - return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code); + return FT_Get_Char_Index(fgFace[fCurFontIdx], (FT_ULong)code); } } } - return FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)code); + return FT_Get_Char_Index(fgFace[fCurFontIdx], (FT_ULong)code); } //////////////////////////////////////////////////////////////////////////////// /// Compute the trailing blanks width. It is use to compute the text width in GetTextExtent /// `n` is the number of trailing blanks in a string. -void TTF::ComputeTrailingBlanksWidth(Int_t n) +void TTFhandle::ComputeTrailingBlanksWidth(Int_t n) { - fgTBlankW = 0; + fTBlankW = 0; if (n) { - FT_Face face = fgFace[fgCurFontIdx]; + FT_Face face = fgFace[fCurFontIdx]; char space = ' '; FT_UInt load_flags = FT_LOAD_DEFAULT; - if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING; + if (!fHinting) load_flags |= FT_LOAD_NO_HINTING; FT_Load_Char(face, space, load_flags); FT_GlyphSlot slot = face->glyph; FT_Pos advance_x = slot->advance.x; Int_t advance_x_pixels = advance_x >> 6; - fgTBlankW = advance_x_pixels * n; + fTBlankW = advance_x_pixels * n; } } //////////////////////////////////////////////////////////////////////////////// /// Get width (w) and height (h) when text is horizontal. -void TTF::GetTextExtent(UInt_t &w, UInt_t &h, const char *text) +void TTFhandle::GetTextExtent(UInt_t &w, UInt_t &h, const char *text) { - 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 + GetTrailingBlanksWidth(); - h = fgCBox.yMax + Yoff; + Int_t Xoff = 0; if (fCBox.xMin < 0) Xoff = -fCBox.xMin; + Int_t Yoff = 0; if (fCBox.yMin < 0) Yoff = -fCBox.yMin; + w = fCBox.xMax + Xoff + GetTrailingBlanksWidth(); + h = fCBox.yMax + Yoff; CleanupGlyphs(); } //////////////////////////////////////////////////////////////////////////////// /// Get advance (a) when text is horizontal. -void TTF::GetTextAdvance(UInt_t &a, const char *text) +void TTFhandle::GetTextAdvance(UInt_t &a, const char *text) { - Init(); - SetRotationMatrix(0); PrepareString(text); LayoutGlyphs(); @@ -192,17 +166,15 @@ void TTF::GetTextAdvance(UInt_t &a, const char *text) //////////////////////////////////////////////////////////////////////////////// /// Get width (w) and height (h) when text is horizontal. -void TTF::GetTextExtent(UInt_t &w, UInt_t &h, const wchar_t *text) +void TTFhandle::GetTextExtent(UInt_t &w, UInt_t &h, const wchar_t *text) { - 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 + GetTrailingBlanksWidth(); - h = fgCBox.yMax + Yoff; + Int_t Xoff = 0; if (fCBox.xMin < 0) Xoff = -fCBox.xMin; + Int_t Yoff = 0; if (fCBox.yMin < 0) Yoff = -fCBox.yMin; + w = fCBox.xMax + Xoff + GetTrailingBlanksWidth(); + h = fCBox.yMax + Yoff; CleanupGlyphs(); } @@ -213,115 +185,105 @@ void TTF::GetTextExtent(UInt_t &w, UInt_t &h, const wchar_t *text) /// If required take the "kerning" into account. /// SetRotation and PrepareString should have been called before. -void TTF::LayoutGlyphs() +void TTFhandle::LayoutGlyphs() { - TTGlyph* glyph = fgGlyphs; FT_Vector origin; FT_UInt load_flags; FT_UInt prev_index = 0; - fgAscent = 0; - fgWidth = 0; + fAscent = 0; + fWidth = 0; load_flags = FT_LOAD_DEFAULT; - if (!fgHinting) load_flags |= FT_LOAD_NO_HINTING; + if (!fHinting) load_flags |= FT_LOAD_NO_HINTING; - fgCBox.xMin = fgCBox.yMin = 32000; - fgCBox.xMax = fgCBox.yMax = -32000; + fCBox.xMin = fCBox.yMin = 32000; + fCBox.xMax = fCBox.yMax = -32000; - for (int n = 0; n < fgNumGlyphs; n++, glyph++) { + for (auto &glyph : fGlyphs) { // compute glyph origin - if (fgKerning) { + if (fKerning) { if (prev_index) { FT_Vector kern; - FT_Get_Kerning(fgFace[fgCurFontIdx], prev_index, glyph->fIndex, - fgHinting ? ft_kerning_default : ft_kerning_unfitted, + FT_Get_Kerning(fgFace[fCurFontIdx], prev_index, glyph.fIndex, + fHinting ? ft_kerning_default : ft_kerning_unfitted, &kern); - fgWidth += kern.x; + fWidth += kern.x; } - prev_index = glyph->fIndex; + prev_index = glyph.fIndex; } - origin.x = fgWidth; + origin.x = fWidth; origin.y = 0; // clear existing image if there is one - if (glyph->fImage) { - FT_Done_Glyph(glyph->fImage); - glyph->fImage = nullptr; + if (glyph.fImage) { + FT_Done_Glyph(glyph.fImage); + glyph.fImage = nullptr; } // load the glyph image (in its native format) - if (FT_Load_Glyph(fgFace[fgCurFontIdx], glyph->fIndex, load_flags)) + if (FT_Load_Glyph(fgFace[fCurFontIdx], glyph.fIndex, load_flags)) continue; // extract the glyph image - if (FT_Get_Glyph (fgFace[fgCurFontIdx]->glyph, &glyph->fImage)) + if (FT_Get_Glyph(fgFace[fCurFontIdx]->glyph, &glyph.fImage)) continue; - glyph->fPos = origin; - fgWidth += fgFace[fgCurFontIdx]->glyph->advance.x; - fgAscent = TMath::Max((Int_t)(fgFace[fgCurFontIdx]->glyph->metrics.horiBearingY), fgAscent); + glyph.fPos = origin; + fWidth += fgFace[fCurFontIdx]->glyph->advance.x; + fAscent = TMath::Max((Int_t)(fgFace[fCurFontIdx]->glyph->metrics.horiBearingY), fAscent); // transform the glyphs - FT_Vector_Transform(&glyph->fPos, fgRotMatrix); - if (FT_Glyph_Transform(glyph->fImage, fgRotMatrix, &glyph->fPos)) + FT_Vector_Transform(&glyph.fPos, fRotMatrix.get()); + if (FT_Glyph_Transform(glyph.fImage, fRotMatrix.get(), &glyph.fPos)) continue; // compute the string control box 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; + FT_Glyph_Get_CBox(glyph.fImage, ft_glyph_bbox_pixels, &bbox); + if (bbox.xMin < fCBox.xMin) fCBox.xMin = bbox.xMin; + if (bbox.yMin < fCBox.yMin) fCBox.yMin = bbox.yMin; + if (bbox.xMax > fCBox.xMax) fCBox.xMax = bbox.xMax; + if (bbox.yMax > fCBox.yMax) fCBox.yMax = bbox.yMax; } } //////////////////////////////////////////////////////////////////////////////// /// Remove temporary data created by LayoutGlyphs -void TTF::CleanupGlyphs() +void TTFhandle::CleanupGlyphs() { - TTGlyph* glyph = fgGlyphs; - - for (int n = 0; n < fgNumGlyphs; n++, glyph++) { + for(auto &glyph : fGlyphs) { // clear existing image if there is one - if (glyph->fImage) { - FT_Done_Glyph(glyph->fImage); - glyph->fImage = nullptr; + if (glyph.fImage && fgInit) { + FT_Done_Glyph(glyph.fImage); + glyph.fImage = nullptr; } } - - fgNumGlyphs = 0; + fGlyphs.clear(); } - //////////////////////////////////////////////////////////////////////////////// /// Put the characters in "string" in the "glyphs" array. -void TTF::PrepareString(const char *string) +void TTFhandle::PrepareString(const char *string) { + CleanupGlyphs(); + const unsigned char *p = (const unsigned char*) string; - TTGlyph *glyph = fgGlyphs; - UInt_t index; // Unicode value + Int_t NbTBlank = 0; // number of trailing blanks - fgNumGlyphs = 0; while (*p) { - index = CharToUnicode((FT_ULong)*p); - if (index != 0) { - glyph->fIndex = index; - glyph++; - fgNumGlyphs++; - } - if (*p == ' ') { + UInt_t index = CharToUnicode((FT_ULong)*p); + if (index != 0) + fGlyphs.emplace_back(index); + if (*p == ' ') NbTBlank++; - } else { + else NbTBlank = 0; - } - if (fgNumGlyphs >= kMaxGlyphs) break; p++; } @@ -331,27 +293,22 @@ void TTF::PrepareString(const char *string) //////////////////////////////////////////////////////////////////////////////// /// Put the characters in "string" in the "glyphs" array. -void TTF::PrepareString(const wchar_t *string) +void TTFhandle::PrepareString(const wchar_t *string) { + CleanupGlyphs(); + const wchar_t *p = string; - TTGlyph *glyph = fgGlyphs; - UInt_t index; // Unicode value + Int_t NbTBlank = 0; // number of trailing blanks - fgNumGlyphs = 0; while (*p) { - index = FT_Get_Char_Index(fgFace[fgCurFontIdx], (FT_ULong)*p); - if (index != 0) { - glyph->fIndex = index; - glyph++; - fgNumGlyphs++; - } - if (*p == ' ') { + UInt_t index = FT_Get_Char_Index(fgFace[fCurFontIdx], (FT_ULong) *p); + if (index != 0) + fGlyphs.emplace_back(index); + if (*p == ' ') NbTBlank++; - } else { + else NbTBlank = 0; - } - if (fgNumGlyphs >= kMaxGlyphs) break; p++; } @@ -359,27 +316,19 @@ void TTF::PrepareString(const wchar_t *string) } //////////////////////////////////////////////////////////////////////////////// -/// Set hinting flag. +/// Return current font index -void TTF::SetHinting(Bool_t state) +FT_Face TTFhandle::GetCurFontFace() const { - fgHinting = state; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set kerning flag. - -void TTF::SetKerning(Bool_t state) -{ - fgKerning = state; + return (fCurFontIdx < 0) || (fCurFontIdx >= kTTMaxFonts) ? nullptr : fgFace[fCurFontIdx]; } //////////////////////////////////////////////////////////////////////////////// /// Set the rotation matrix used to rotate the font outlines. -void TTF::SetRotationMatrix(Float_t angle) +void TTFhandle::SetRotationMatrix(Float_t angle) { - Float_t rangle = Float_t(angle * TMath::Pi() / 180.); // Angle in radian + Float_t rangle = angle * TMath::Pi() / 180.; // Angle in radian #if defined(FREETYPE_PATCH) && \ (FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH == 2) Float_t sin = TMath::Sin(rangle); @@ -389,20 +338,13 @@ void TTF::SetRotationMatrix(Float_t angle) Float_t cos = TMath::Cos(-rangle); #endif - if (!fgRotMatrix) fgRotMatrix = new FT_Matrix; + if (!fRotMatrix) + fRotMatrix = std::make_unique(); - fgRotMatrix->xx = (FT_Fixed) (cos * (1<<16)); - fgRotMatrix->xy = (FT_Fixed) (sin * (1<<16)); - fgRotMatrix->yx = -fgRotMatrix->xy; - fgRotMatrix->yy = fgRotMatrix->xx; -} - -//////////////////////////////////////////////////////////////////////////////// -/// Set smoothing (anti-aliasing) flag. - -void TTF::SetSmoothing(Bool_t state) -{ - fgSmoothing = state; + fRotMatrix->xx = (FT_Fixed) (cos * (1<<16)); + fRotMatrix->xy = (FT_Fixed) (sin * (1<<16)); + fRotMatrix->yx = -fRotMatrix->xy; + fRotMatrix->yy = fRotMatrix->xx; } //////////////////////////////////////////////////////////////////////////////// @@ -413,14 +355,12 @@ void TTF::SetSmoothing(Bool_t state) /// Set text font to specified name. This function returns 0 if /// the specified font is found, 1 if not. -Int_t TTF::SetTextFont(const char *fontname, Int_t italic) +Int_t TTFhandle::SetTextFont(const char *fontname, Int_t italic) { - if (!fgInit) Init(); - if (!fontname || !fontname[0]) { - Warning("TTF::SetTextFont", + Warning("TTFhandle::SetTextFont", "no font name specified, using default font %s", fgFontName[0]); - fgCurFontIdx = 0; + fCurFontIdx = 0; return 0; } const char *basename = gSystem->BaseName(fontname); @@ -430,13 +370,13 @@ Int_t TTF::SetTextFont(const char *fontname, Int_t italic) for (i = 0; i < fgFontCount; i++) { if (!strcmp(fgFontName[i], basename)) { if (italic) { - if (i==fgSymbItaFontIdx) { - fgCurFontIdx = i; + if (i == fgSymbItaFontIdx) { + fCurFontIdx = i; return 0; } } else { - if (i!=fgSymbItaFontIdx) { - fgCurFontIdx = i; + if (i != fgSymbItaFontIdx) { + fCurFontIdx = i; return 0; } } @@ -445,10 +385,10 @@ Int_t TTF::SetTextFont(const char *fontname, Int_t italic) // enough space in cache to load font? if (fgFontCount >= kTTMaxFonts) { - Error("TTF::SetTextFont", "too many fonts opened (increase kTTMaxFont = %d)", + Error("TTFhandle::SetTextFont", "too many fonts opened (increase kTTMaxFont = %d)", kTTMaxFonts); - Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]); - fgCurFontIdx = 0; // use font 0 (default font, set in ctor) + Warning("TTFhandle::SetTextFont", "using default font %s", fgFontName[0]); + fCurFontIdx = 0; // use font 0 (default font, set in ctor) return 0; } @@ -458,25 +398,25 @@ Int_t TTF::SetTextFont(const char *fontname, Int_t italic) char *ttfont = gSystem->Which(ttpath, fontname, kReadPermission); if (!ttfont) { - Error("TTF::SetTextFont", "font file %s not found in path %s", fontname, ttpath); + Error("TTFhandle::SetTextFont", "font file %s not found in path %s", fontname, ttpath); if (fgFontCount) { - Warning("TTF::SetTextFont", "using default font %s", fgFontName[0]); - fgCurFontIdx = 0; // use font 0 (default font, set in ctor) + Warning("TTFhandle::SetTextFont", "using default font %s", fgFontName[0]); + fCurFontIdx = 0; // use font 0 (default font, set in ctor) return 0; } else { return 1; } } - FT_Face tface = (FT_Face) 0; + FT_Face tface = (FT_Face) 0; if (FT_New_Face(fgLibrary, ttfont, 0, &tface)) { - Error("TTF::SetTextFont", "error loading font %s", ttfont); + Error("TTFhandle::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; + Warning("TTFhandle::SetTextFont", "using default font %s", fgFontName[0]); + fCurFontIdx = 0; return 0; } else { return 1; @@ -486,19 +426,18 @@ Int_t TTF::SetTextFont(const char *fontname, Int_t italic) delete [] ttfont; fgFontName[fgFontCount] = StrDup(basename); - fgCurFontIdx = fgFontCount; - fgFace[fgCurFontIdx] = tface; - fgCharMap[fgCurFontIdx] = (FT_CharMap) 0; - fgFontCount++; + fgFace[fgFontCount] = tface; + fgCharMap[fgFontCount] = (FT_CharMap) 0; + fCurFontIdx = fgFontCount++; if (italic) { - fgSymbItaFontIdx = fgCurFontIdx; + fgSymbItaFontIdx = fCurFontIdx; FT_Matrix slantMat; slantMat.xx = (1 << 16); slantMat.xy = ((1 << 16) >> 2); slantMat.yx = 0; slantMat.yy = (1 << 16); - FT_Set_Transform( fgFace[fgSymbItaFontIdx], &slantMat, NULL ); + FT_Set_Transform(fgFace[fgSymbItaFontIdx], &slantMat, NULL); } return 0; @@ -525,7 +464,7 @@ Int_t TTF::SetTextFont(const char *fontname, Int_t italic) /// | 13 | Free Serif | Times-Roman | /// | 14 | Wingdings | ZapfDingbats | -void TTF::SetTextFont(Font_t fontnumber) +void TTFhandle::SetTextFont(Font_t fontnumber) { // Added by cholm for use of DFSG - fonts - based on Kevins fix. // Table of Microsoft and (for non-MSFT operating systems) backup @@ -596,104 +535,318 @@ void TTF::SetTextFont(Font_t fontnumber) //////////////////////////////////////////////////////////////////////////////// /// Set current text size. -void TTF::SetTextSize(Float_t textsize) +Bool_t TTFhandle::SetTextSize(Float_t textsize) { - if (!fgInit) Init(); - if (textsize < 0) return; + if (textsize < 0) + return kFALSE; - if (fgCurFontIdx < 0 || fgFontCount <= fgCurFontIdx) { - Error("TTF::SetTextSize", "current font index out of bounds"); - fgCurFontIdx = 0; - return; + if (fCurFontIdx < 0 || fgFontCount <= fCurFontIdx) { + Error("TTFhandle::SetTextSize", "current font index out of bounds"); + fCurFontIdx = 0; + return kFALSE; } Int_t tsize = (Int_t)(textsize*kScale+0.5) << 6; - FT_Error err = FT_Set_Char_Size(fgFace[fgCurFontIdx], tsize, tsize, 72, 72); + FT_Error err = FT_Set_Char_Size(fgFace[fCurFontIdx], tsize, tsize, 72, 72); + if (err) - Error("TTF::SetTextSize", "error in FT_Set_Char_Size: 0x%x (input size %f, calc. size 0x%x)", err, textsize, - tsize); + Error("TTFhandle::SetTextSize", "error in FT_Set_Char_Size: 0x%x (input size %f, calc. size 0x%x)", err, textsize, tsize); + + return !err; } //////////////////////////////////////////////////////////////////////////////// -void TTF::Version(Int_t &major, Int_t &minor, Int_t &patch) +void TTFhandle::Version(Int_t &major, Int_t &minor, Int_t &patch) { FT_Library_Version(fgLibrary, &major, &minor, &patch); } + +/** \class TTF +\ingroup BasicGraphics + +Interface to the freetype 2 library. +Implements old static API. +Unitl ROOT7 just redirects to static TTFhandle instance +*/ + +TTF gCleanupTTF; // Allows to call "Cleanup" at the end of the session +std::unique_ptr TTF::fgHandle; // static handle, destroyed automatically + +//////////////////////////////////////////////////////////////////////////////// +/// Cleanup TTF environment. + +TTF::~TTF() +{ + TTFhandle::CloseLibrary(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Init TTF environment. + +void TTF::Init() +{ + if (!fgHandle) { + fgHandle = std::make_unique(); + fgHandle->SetTextFont(62); + } +} + //////////////////////////////////////////////////////////////////////////////// Bool_t TTF::GetHinting() { - return fgHinting; + return fgHandle ? fgHandle->GetHinting() : kFALSE; } //////////////////////////////////////////////////////////////////////////////// Bool_t TTF::GetKerning() { - return fgKerning; + return fgHandle ? fgHandle->GetKerning() : kFALSE; } //////////////////////////////////////////////////////////////////////////////// Bool_t TTF::GetSmoothing() { - return fgSmoothing; + return fgHandle ? fgHandle->GetSmoothing() : kFALSE; } //////////////////////////////////////////////////////////////////////////////// Bool_t TTF::IsInitialized() { - return fgInit; + return fgHandle.get() != nullptr; } //////////////////////////////////////////////////////////////////////////////// Int_t TTF::GetWidth() { - return fgWidth; + return fgHandle ? fgHandle->GetWidth() : 0; } //////////////////////////////////////////////////////////////////////////////// Int_t TTF::GetAscent() { - return fgAscent; + return fgHandle ? fgHandle->GetAscent() : 0; } //////////////////////////////////////////////////////////////////////////////// Int_t TTF::GetNumGlyphs() { - return fgNumGlyphs; + return fgHandle ? fgHandle->GetNumGlyphs() : 0; } //////////////////////////////////////////////////////////////////////////////// FT_Matrix *TTF::GetRotMatrix() { - return fgRotMatrix; + return fgHandle ? fgHandle->GetRotMatrix() : nullptr; } //////////////////////////////////////////////////////////////////////////////// Int_t TTF::GetTrailingBlanksWidth() { - return fgTBlankW; + return fgHandle ? fgHandle->GetTrailingBlanksWidth() : 0; } //////////////////////////////////////////////////////////////////////////////// const FT_BBox &TTF::GetBox() { - return fgCBox; + static FT_BBox dummy; + return fgHandle ? fgHandle->GetBox() : dummy; } //////////////////////////////////////////////////////////////////////////////// TTF::TTGlyph *TTF::GetGlyphs() { - return fgGlyphs; + return fgHandle ? fgHandle->GetGlyphs() : nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Return current font index + +Int_t TTF::GetCurFontIdx() +{ + return fgHandle ? fgHandle->GetCurFontIdx() : -1; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Return current font index + +FT_Face TTF::GetCurFontFace() +{ + return fgHandle ? fgHandle->GetCurFontFace() : nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Map char to unicode. Returns 0 in case no mapping exists. + +Short_t TTF::CharToUnicode(UInt_t code) +{ + Init(); + return fgHandle->CharToUnicode(code); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set the rotation matrix used to rotate the font outlines. + +void TTF::SetRotationMatrix(Float_t angle) +{ + Init(); + fgHandle->SetRotationMatrix(angle); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set current font index + +void TTF::SetCurFontIdx(Int_t indx) +{ + Init(); + fgHandle->SetCurFontIdx(indx); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set hinting flag. + +void TTF::SetHinting(Bool_t state) +{ + Init(); + fgHandle->SetHinting(state); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set kerning flag. + +void TTF::SetKerning(Bool_t state) +{ + Init(); + fgHandle->SetKerning(state); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set smoothing (anti-aliasing) flag. + +void TTF::SetSmoothing(Bool_t state) +{ + Init(); + fgHandle->SetSmoothing(state); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set text font to specified name. +/// - font : font name +/// - italic : the fonts should be slanted. Used for symbol font. + +Int_t TTF::SetTextFont(const char *fontname, Int_t italic) +{ + Init(); + return fgHandle->SetTextFont(fontname, italic); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set specified font. + +void TTF::SetTextFont(Font_t fontnumber) +{ + Init(); + fgHandle->SetTextFont(fontnumber); +} + +//////////////////////////////////////////////////////////////////////////////// + +void TTF::SetTextSize(Float_t textsize) +{ + Init(); + fgHandle->SetTextSize(textsize); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Put the characters in "string" in the "glyphs" array. + +void TTF::PrepareString(const char *string) +{ + Init(); + fgHandle->PrepareString(string); } + +//////////////////////////////////////////////////////////////////////////////// +/// Put the characters in "string" in the "glyphs" array. + +void TTF::PrepareString(const wchar_t *string) +{ + Init(); + fgHandle->PrepareString(string); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Compute the glyphs positions, fgAscent and fgWidth (needed for alignment). + +void TTF::LayoutGlyphs() +{ + if (fgHandle) + fgHandle->LayoutGlyphs(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Compute the trailing blanks width. It is use to compute the text width in GetTextExtent +/// `n` is the number of trailing blanks in a string. + +void TTF::ComputeTrailingBlanksWidth(Int_t n) +{ + if (fgHandle) + fgHandle->ComputeTrailingBlanksWidth(n); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Remove temporary data created by LayoutGlyphs + +void TTF::CleanupGlyphs() +{ + if (fgHandle) + fgHandle->CleanupGlyphs(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Get width (w) and height (h) when text is horizontal. + +void TTF::GetTextExtent(UInt_t &w, UInt_t &h, const char *text) +{ + Init(); + fgHandle->GetTextExtent(w, h, text); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Get advance (a) when text is horizontal. + +void TTF::GetTextAdvance(UInt_t &a, const char *text) +{ + Init(); + fgHandle->GetTextAdvance(a, text); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Get width (w) and height (h) when text is horizontal. + +void TTF::GetTextExtent(UInt_t &w, UInt_t &h, const wchar_t *text) +{ + Init(); + fgHandle->GetTextExtent(w, h, text); +} + +//////////////////////////////////////////////////////////////////////////////// + +void TTF::Version(Int_t &major, Int_t &minor, Int_t &patch) +{ + Init(); + fgHandle->Version(major, minor, patch); +} + diff --git a/graf2d/x11ttf/src/TGX11TTF.cxx b/graf2d/x11ttf/src/TGX11TTF.cxx index cda8cc71ae51e..a1f755ac7023d 100644 --- a/graf2d/x11ttf/src/TGX11TTF.cxx +++ b/graf2d/x11ttf/src/TGX11TTF.cxx @@ -217,23 +217,23 @@ void TGX11TTF::Align(WinContext_t wctxt) // vertical alignment if (align == kTLeft || align == kTCenter || align == kTRight) { - fAlign.y = TTF::fgAscent; + fAlign.y = TTF::GetAscent(); } else if (align == kMLeft || align == kMCenter || align == kMRight) { - fAlign.y = TTF::fgAscent/2; + fAlign.y = TTF::GetAscent() / 2; } else { fAlign.y = 0; } // horizontal alignment if (align == kTRight || align == kMRight || align == kBRight) { - fAlign.x = TTF::fgWidth; + fAlign.x = TTF::GetWidth(); } else if (align == kTCenter || align == kMCenter || align == kBCenter) { - fAlign.x = TTF::fgWidth/2; + fAlign.x = TTF::GetWidth() / 2; } else { fAlign.x = 0; } - FT_Vector_Transform(&fAlign, TTF::fgRotMatrix); + FT_Vector_Transform(&fAlign, TTF::GetRotMatrix()); fAlign.x = fAlign.x >> 6; fAlign.y = fAlign.y >> 6; } @@ -247,7 +247,7 @@ void TGX11TTF::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back, { UChar_t d = 0, *s = source->buffer; - if (TTF::fgSmoothing) { + if (TTF::GetSmoothing()) { static RXColor col[5]; RXColor *bcol = nullptr; @@ -269,7 +269,7 @@ void TGX11TTF::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back, dotcnt = 0; for (y = 0; y < (int) source->rows; y++) { for (x = 0; x < (int) source->width; x++, bc++) { -/// bc->pixel = XGetPixel(xim, bx + x, by - c->TTF::fgAscent + y); +/// bc->pixel = XGetPixel(xim, bx + x, by - c->TTF::GetAscent() + y); bc->pixel = XGetPixel(xim, bx + x, by + y); bc->flags = DoRed | DoGreen | DoBlue; if (++dotcnt >= maxdots) break; @@ -529,8 +529,8 @@ void TGX11TTF::RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode TTF::TTGlyph *glyph = TTF::GetGlyphs(); for (int n = 0; n < TTF::GetNumGlyphs(); n++, glyph++) { if (FT_Glyph_To_Bitmap(&glyph->fImage, - TTF::fgSmoothing ? ft_render_mode_normal - : ft_render_mode_mono, + TTF::GetSmoothing() ? ft_render_mode_normal + : ft_render_mode_mono, nullptr, 1 )) continue; FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph->fImage; FT_Bitmap* source = &bitmap->bitmap;