Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion graf2d/graf/inc/LinkDef.h
Original file line number Diff line number Diff line change
@@ -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. *
Expand Down Expand Up @@ -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;
Expand Down
152 changes: 106 additions & 46 deletions graf2d/graf/inc/TTF.h
Original file line number Diff line number Diff line change
@@ -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. *
Expand All @@ -15,6 +16,7 @@


#include "Rtypes.h"
#include <memory>

/// @cond DOXYGEN_IGNORE
// Forward declare for the headers:
Expand Down Expand Up @@ -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<TTFhandle> 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();
Expand All @@ -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<TTF::TTGlyph> fGlyphs; ///< glyphs
Bool_t fHinting = kFALSE; ///< use hinting (true by default)
Bool_t fKerning = kTRUE; ///< use kerning (true by default)
std::unique_ptr<FT_Matrix> fRotMatrix; ///< rotation matrix
Copy link
Copy Markdown
Contributor

@silverweed silverweed Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be a separate allocation? Can't we just store it inline?

Edit: sorry, just noticed this is still a draft.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to emulate old API.
And these were many static members before.
Some of them used outside of TTF parsing.

Copy link
Copy Markdown
Contributor

@silverweed silverweed Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I mean why the matrix specifically needs to be wrapped in a unique_ptr? That should not be required for backward compatibility

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean why the matrix specifically needs to be wrapped in a unique_ptr

unique_ptr will automatically delete matrix in the destructor of TTFhandle.
Just simple sign of ownership.

PR is not yet ready - I just want to check that functionality is still there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant why is the matrix is not there by value, why the dynamic allocation at all

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea. Maybe you are right and dynamic allocation not needed at all.

I checking this and many other things right now.

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
26 changes: 13 additions & 13 deletions graf2d/graf/src/TMathText.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -227,24 +227,24 @@ class TMathTextRenderer : public TText, public TAttFill,
bounding_box(const wchar_t character, float &current_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) {
TTF::SetTextFont((Font_t) root_cjk_face_number());
} 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;
Expand All @@ -263,19 +263,19 @@ 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;
}
inline mathtext::bounding_box_t
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;
Expand Down
Loading
Loading