mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: Store text layout runs directly as values in a std::vector instead of heap allocated.
This reduces memory allocations and heap fragmentation.
This commit is contained in:
parent
9325d63d8e
commit
329bb52613
16
src/gfx.cpp
16
src/gfx.cpp
|
@ -376,7 +376,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left,
|
||||||
* another size would be chosen it won't have truncated too little for
|
* another size would be chosen it won't have truncated too little for
|
||||||
* the truncation dots.
|
* the truncation dots.
|
||||||
*/
|
*/
|
||||||
FontCache *fc = ((const Font*)line->GetVisualRun(0)->GetFont())->fc;
|
FontCache *fc = ((const Font*)line->GetVisualRun(0).GetFont())->fc;
|
||||||
GlyphID dot_glyph = fc->MapCharToGlyph('.');
|
GlyphID dot_glyph = fc->MapCharToGlyph('.');
|
||||||
dot_width = fc->GetGlyphWidth(dot_glyph);
|
dot_width = fc->GetGlyphWidth(dot_glyph);
|
||||||
dot_sprite = fc->GetGlyph(dot_glyph);
|
dot_sprite = fc->GetGlyph(dot_glyph);
|
||||||
|
@ -422,8 +422,8 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left,
|
||||||
TextColour colour = TC_BLACK;
|
TextColour colour = TC_BLACK;
|
||||||
bool draw_shadow = false;
|
bool draw_shadow = false;
|
||||||
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||||
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index);
|
||||||
const Font *f = (const Font*)run->GetFont();
|
const Font *f = (const Font*)run.GetFont();
|
||||||
|
|
||||||
FontCache *fc = f->fc;
|
FontCache *fc = f->fc;
|
||||||
colour = f->colour;
|
colour = f->colour;
|
||||||
|
@ -435,15 +435,15 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left,
|
||||||
|
|
||||||
draw_shadow = fc->GetDrawGlyphShadow() && (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
|
draw_shadow = fc->GetDrawGlyphShadow() && (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
|
||||||
|
|
||||||
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
for (int i = 0; i < run.GetGlyphCount(); i++) {
|
||||||
GlyphID glyph = run->GetGlyphs()[i];
|
GlyphID glyph = run.GetGlyphs()[i];
|
||||||
|
|
||||||
/* Not a valid glyph (empty) */
|
/* Not a valid glyph (empty) */
|
||||||
if (glyph == 0xFFFF) continue;
|
if (glyph == 0xFFFF) continue;
|
||||||
|
|
||||||
int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x;
|
int begin_x = (int)run.GetPositions()[i * 2] + left - offset_x;
|
||||||
int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1;
|
int end_x = (int)run.GetPositions()[i * 2 + 2] + left - offset_x - 1;
|
||||||
int top = (int)run->GetPositions()[i * 2 + 1] + y;
|
int top = (int)run.GetPositions()[i * 2 + 1] + y;
|
||||||
|
|
||||||
/* Truncated away. */
|
/* Truncated away. */
|
||||||
if (truncation && (begin_x < min_x || end_x > max_x)) continue;
|
if (truncation && (begin_x < min_x || end_x > max_x)) continue;
|
||||||
|
|
|
@ -143,14 +143,14 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A single line worth of VisualRuns. */
|
/** A single line worth of VisualRuns. */
|
||||||
class ICULine : public AutoDeleteSmallVector<ICUVisualRun *>, public ParagraphLayouter::Line {
|
class ICULine : public std::vector<ICUVisualRun>, public ParagraphLayouter::Line {
|
||||||
icu::ParagraphLayout::Line *l; ///< The actual ICU line.
|
icu::ParagraphLayout::Line *l; ///< The actual ICU line.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ICULine(icu::ParagraphLayout::Line *l) : l(l)
|
ICULine(icu::ParagraphLayout::Line *l) : l(l)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < l->countRuns(); i++) {
|
for (int i = 0; i < l->countRuns(); i++) {
|
||||||
this->push_back(new ICUVisualRun(l->getVisualRun(i)));
|
this->emplace_back(l->getVisualRun(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~ICULine() override { delete l; }
|
~ICULine() override { delete l; }
|
||||||
|
@ -158,7 +158,7 @@ public:
|
||||||
int GetLeading() const override { return l->getLeading(); }
|
int GetLeading() const override { return l->getLeading(); }
|
||||||
int GetWidth() const override { return l->getWidth(); }
|
int GetWidth() const override { return l->getWidth(); }
|
||||||
int CountRuns() const override { return l->countRuns(); }
|
int CountRuns() const override { return l->countRuns(); }
|
||||||
const ParagraphLayouter::VisualRun *GetVisualRun(int run) const override { return this->at(run); }
|
const ParagraphLayouter::VisualRun &GetVisualRun(int run) const override { return this->at(run); }
|
||||||
|
|
||||||
int GetInternalCharLength(WChar c) const override
|
int GetInternalCharLength(WChar c) const override
|
||||||
{
|
{
|
||||||
|
@ -259,6 +259,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FallbackVisualRun(Font *font, const WChar *chars, int glyph_count, int x);
|
FallbackVisualRun(Font *font, const WChar *chars, int glyph_count, int x);
|
||||||
|
FallbackVisualRun(FallbackVisualRun &&other) noexcept;
|
||||||
~FallbackVisualRun() override;
|
~FallbackVisualRun() override;
|
||||||
const Font *GetFont() const override;
|
const Font *GetFont() const override;
|
||||||
int GetGlyphCount() const override;
|
int GetGlyphCount() const override;
|
||||||
|
@ -269,12 +270,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A single line worth of VisualRuns. */
|
/** A single line worth of VisualRuns. */
|
||||||
class FallbackLine : public AutoDeleteSmallVector<FallbackVisualRun *>, public ParagraphLayouter::Line {
|
class FallbackLine : public std::vector<FallbackVisualRun>, public ParagraphLayouter::Line {
|
||||||
public:
|
public:
|
||||||
int GetLeading() const override;
|
int GetLeading() const override;
|
||||||
int GetWidth() const override;
|
int GetWidth() const override;
|
||||||
int CountRuns() const override;
|
int CountRuns() const override;
|
||||||
const ParagraphLayouter::VisualRun *GetVisualRun(int run) const override;
|
const ParagraphLayouter::VisualRun &GetVisualRun(int run) const override;
|
||||||
|
|
||||||
int GetInternalCharLength(WChar c) const override { return 1; }
|
int GetInternalCharLength(WChar c) const override { return 1; }
|
||||||
};
|
};
|
||||||
|
@ -350,6 +351,18 @@ FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Move constructor for visual runs.*/
|
||||||
|
FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(FallbackVisualRun &&other) noexcept : font(other.font), glyph_count(other.glyph_count)
|
||||||
|
{
|
||||||
|
this->positions = other.positions;
|
||||||
|
this->glyph_to_char = other.glyph_to_char;
|
||||||
|
this->glyphs = other.glyphs;
|
||||||
|
|
||||||
|
other.positions = NULL;
|
||||||
|
other.glyph_to_char = NULL;
|
||||||
|
other.glyphs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/** Free all data. */
|
/** Free all data. */
|
||||||
FallbackParagraphLayout::FallbackVisualRun::~FallbackVisualRun()
|
FallbackParagraphLayout::FallbackVisualRun::~FallbackVisualRun()
|
||||||
{
|
{
|
||||||
|
@ -419,8 +432,8 @@ int FallbackParagraphLayout::FallbackVisualRun::GetLeading() const
|
||||||
int FallbackParagraphLayout::FallbackLine::GetLeading() const
|
int FallbackParagraphLayout::FallbackLine::GetLeading() const
|
||||||
{
|
{
|
||||||
int leading = 0;
|
int leading = 0;
|
||||||
for (const FallbackVisualRun * const &run : *this) {
|
for (const auto &run : *this) {
|
||||||
leading = max(leading, run->GetLeading());
|
leading = max(leading, run.GetLeading());
|
||||||
}
|
}
|
||||||
|
|
||||||
return leading;
|
return leading;
|
||||||
|
@ -439,8 +452,8 @@ int FallbackParagraphLayout::FallbackLine::GetWidth() const
|
||||||
* Since there is no left-to-right support, taking this value of
|
* Since there is no left-to-right support, taking this value of
|
||||||
* the last run gives us the end of the line and thus the width.
|
* the last run gives us the end of the line and thus the width.
|
||||||
*/
|
*/
|
||||||
const ParagraphLayouter::VisualRun *run = this->GetVisualRun(this->CountRuns() - 1);
|
const auto &run = this->GetVisualRun(this->CountRuns() - 1);
|
||||||
return (int)run->GetPositions()[run->GetGlyphCount() * 2];
|
return (int)run.GetPositions()[run.GetGlyphCount() * 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -456,7 +469,7 @@ int FallbackParagraphLayout::FallbackLine::CountRuns() const
|
||||||
* Get a specific visual run.
|
* Get a specific visual run.
|
||||||
* @return The visual run.
|
* @return The visual run.
|
||||||
*/
|
*/
|
||||||
const ParagraphLayouter::VisualRun *FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const
|
const ParagraphLayouter::VisualRun &FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const
|
||||||
{
|
{
|
||||||
return this->at(run);
|
return this->at(run);
|
||||||
}
|
}
|
||||||
|
@ -498,7 +511,7 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width)
|
||||||
if (*this->buffer == '\0') {
|
if (*this->buffer == '\0') {
|
||||||
/* Only a newline. */
|
/* Only a newline. */
|
||||||
this->buffer = NULL;
|
this->buffer = NULL;
|
||||||
l->push_back(new FallbackVisualRun(this->runs.front().second, this->buffer, 0, 0));
|
l->emplace_back(this->runs.front().second, this->buffer, 0, 0);
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +540,7 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width)
|
||||||
|
|
||||||
if (this->buffer == next_run) {
|
if (this->buffer == next_run) {
|
||||||
int w = l->GetWidth();
|
int w = l->GetWidth();
|
||||||
l->push_back(new FallbackVisualRun(iter->second, begin, this->buffer - begin, w));
|
l->emplace_back(iter->second, begin, this->buffer - begin, w);
|
||||||
iter++;
|
iter++;
|
||||||
assert(iter != this->runs.End());
|
assert(iter != this->runs.End());
|
||||||
|
|
||||||
|
@ -574,7 +587,7 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width)
|
||||||
|
|
||||||
if (l->size() == 0 || last_char - begin != 0) {
|
if (l->size() == 0 || last_char - begin != 0) {
|
||||||
int w = l->GetWidth();
|
int w = l->GetWidth();
|
||||||
l->push_back(new FallbackVisualRun(iter->second, begin, last_char - begin, w));
|
l->emplace_back(iter->second, begin, last_char - begin, w);
|
||||||
}
|
}
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
@ -772,12 +785,12 @@ Point Layouter::GetCharPosition(const char *ch) const
|
||||||
|
|
||||||
/* Scan all runs until we've found our code point index. */
|
/* Scan all runs until we've found our code point index. */
|
||||||
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||||
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index);
|
||||||
|
|
||||||
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
for (int i = 0; i < run.GetGlyphCount(); i++) {
|
||||||
/* Matching glyph? Return position. */
|
/* Matching glyph? Return position. */
|
||||||
if ((size_t)run->GetGlyphToCharMap()[i] == index) {
|
if ((size_t)run.GetGlyphToCharMap()[i] == index) {
|
||||||
Point p = { (int)run->GetPositions()[i * 2], (int)run->GetPositions()[i * 2 + 1] };
|
Point p = { (int)run.GetPositions()[i * 2], (int)run.GetPositions()[i * 2 + 1] };
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -798,18 +811,18 @@ const char *Layouter::GetCharAtPosition(int x) const
|
||||||
const ParagraphLayouter::Line *line = this->front();
|
const ParagraphLayouter::Line *line = this->front();
|
||||||
|
|
||||||
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
for (int run_index = 0; run_index < line->CountRuns(); run_index++) {
|
||||||
const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index);
|
const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index);
|
||||||
|
|
||||||
for (int i = 0; i < run->GetGlyphCount(); i++) {
|
for (int i = 0; i < run.GetGlyphCount(); i++) {
|
||||||
/* Not a valid glyph (empty). */
|
/* Not a valid glyph (empty). */
|
||||||
if (run->GetGlyphs()[i] == 0xFFFF) continue;
|
if (run.GetGlyphs()[i] == 0xFFFF) continue;
|
||||||
|
|
||||||
int begin_x = (int)run->GetPositions()[i * 2];
|
int begin_x = (int)run.GetPositions()[i * 2];
|
||||||
int end_x = (int)run->GetPositions()[i * 2 + 2];
|
int end_x = (int)run.GetPositions()[i * 2 + 2];
|
||||||
|
|
||||||
if (IsInsideMM(x, begin_x, end_x)) {
|
if (IsInsideMM(x, begin_x, end_x)) {
|
||||||
/* Found our glyph, now convert to UTF-8 string index. */
|
/* Found our glyph, now convert to UTF-8 string index. */
|
||||||
size_t index = run->GetGlyphToCharMap()[i];
|
size_t index = run.GetGlyphToCharMap()[i];
|
||||||
|
|
||||||
size_t cur_idx = 0;
|
size_t cur_idx = 0;
|
||||||
for (const char *str = this->string; *str != '\0'; ) {
|
for (const char *str = this->string; *str != '\0'; ) {
|
||||||
|
|
|
@ -137,7 +137,7 @@ public:
|
||||||
virtual int GetLeading() const = 0;
|
virtual int GetLeading() const = 0;
|
||||||
virtual int GetWidth() const = 0;
|
virtual int GetWidth() const = 0;
|
||||||
virtual int CountRuns() const = 0;
|
virtual int CountRuns() const = 0;
|
||||||
virtual const VisualRun *GetVisualRun(int run) const = 0;
|
virtual const VisualRun &GetVisualRun(int run) const = 0;
|
||||||
virtual int GetInternalCharLength(WChar c) const = 0;
|
virtual int GetInternalCharLength(WChar c) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CoreTextVisualRun(CTRunRef run, Font *font, const CoreTextParagraphLayoutFactory::CharType *buff);
|
CoreTextVisualRun(CTRunRef run, Font *font, const CoreTextParagraphLayoutFactory::CharType *buff);
|
||||||
|
CoreTextVisualRun(CoreTextVisualRun &&other) = default;
|
||||||
|
|
||||||
const GlyphID *GetGlyphs() const override { return &this->glyphs[0]; }
|
const GlyphID *GetGlyphs() const override { return &this->glyphs[0]; }
|
||||||
const float *GetPositions() const override { return &this->positions[0]; }
|
const float *GetPositions() const override { return &this->positions[0]; }
|
||||||
|
@ -65,7 +66,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A single line worth of VisualRuns. */
|
/** A single line worth of VisualRuns. */
|
||||||
class CoreTextLine : public AutoDeleteSmallVector<CoreTextVisualRun *>, public ParagraphLayouter::Line {
|
class CoreTextLine : public std::vector<CoreTextVisualRun>, public ParagraphLayouter::Line {
|
||||||
public:
|
public:
|
||||||
CoreTextLine(CTLineRef line, const FontMap &fontMapping, const CoreTextParagraphLayoutFactory::CharType *buff)
|
CoreTextLine(CTLineRef line, const FontMap &fontMapping, const CoreTextParagraphLayoutFactory::CharType *buff)
|
||||||
{
|
{
|
||||||
|
@ -78,7 +79,7 @@ public:
|
||||||
auto map = fontMapping.begin();
|
auto map = fontMapping.begin();
|
||||||
while (map < fontMapping.end() - 1 && map->first <= chars.location) map++;
|
while (map < fontMapping.end() - 1 && map->first <= chars.location) map++;
|
||||||
|
|
||||||
this->push_back(new CoreTextVisualRun(run, map->second, buff));
|
this->emplace_back(run, map->second, buff);
|
||||||
}
|
}
|
||||||
CFRelease(line);
|
CFRelease(line);
|
||||||
}
|
}
|
||||||
|
@ -86,7 +87,7 @@ public:
|
||||||
int GetLeading() const override;
|
int GetLeading() const override;
|
||||||
int GetWidth() const override;
|
int GetWidth() const override;
|
||||||
int CountRuns() const override { return this->size(); }
|
int CountRuns() const override { return this->size(); }
|
||||||
const VisualRun *GetVisualRun(int run) const override { return this->at(run); }
|
const VisualRun &GetVisualRun(int run) const override { return this->at(run); }
|
||||||
|
|
||||||
int GetInternalCharLength(WChar c) const override
|
int GetInternalCharLength(WChar c) const override
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,6 +90,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UniscribeVisualRun(const UniscribeRun &range, int x);
|
UniscribeVisualRun(const UniscribeRun &range, int x);
|
||||||
|
UniscribeVisualRun(UniscribeVisualRun &&other) noexcept;
|
||||||
~UniscribeVisualRun() override
|
~UniscribeVisualRun() override
|
||||||
{
|
{
|
||||||
free(this->glyph_to_char);
|
free(this->glyph_to_char);
|
||||||
|
@ -106,12 +107,12 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A single line worth of VisualRuns. */
|
/** A single line worth of VisualRuns. */
|
||||||
class UniscribeLine : public AutoDeleteSmallVector<UniscribeVisualRun *>, public ParagraphLayouter::Line {
|
class UniscribeLine : public std::vector<UniscribeVisualRun>, public ParagraphLayouter::Line {
|
||||||
public:
|
public:
|
||||||
int GetLeading() const override;
|
int GetLeading() const override;
|
||||||
int GetWidth() const override;
|
int GetWidth() const override;
|
||||||
int CountRuns() const override { return (uint)this->size(); }
|
int CountRuns() const override { return (uint)this->size(); }
|
||||||
const VisualRun *GetVisualRun(int run) const override { return this->at(run); }
|
const VisualRun &GetVisualRun(int run) const override { return this->at(run); }
|
||||||
|
|
||||||
int GetInternalCharLength(WChar c) const override
|
int GetInternalCharLength(WChar c) const override
|
||||||
{
|
{
|
||||||
|
@ -424,7 +425,7 @@ static std::vector<SCRIPT_ITEM> UniscribeItemizeString(UniscribeParagraphLayoutF
|
||||||
if (!UniscribeShapeRun(this->text_buffer, run)) return NULL;
|
if (!UniscribeShapeRun(this->text_buffer, run)) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
line->push_back(new UniscribeVisualRun(run, cur_pos));
|
line->emplace_back(run, cur_pos);
|
||||||
cur_pos += run.total_advance;
|
cur_pos += run.total_advance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,8 +449,8 @@ static std::vector<SCRIPT_ITEM> UniscribeItemizeString(UniscribeParagraphLayoutF
|
||||||
int UniscribeParagraphLayout::UniscribeLine::GetLeading() const
|
int UniscribeParagraphLayout::UniscribeLine::GetLeading() const
|
||||||
{
|
{
|
||||||
int leading = 0;
|
int leading = 0;
|
||||||
for (const UniscribeVisualRun *run : *this) {
|
for (const auto &run : *this) {
|
||||||
leading = max(leading, run->GetLeading());
|
leading = max(leading, run.GetLeading());
|
||||||
}
|
}
|
||||||
|
|
||||||
return leading;
|
return leading;
|
||||||
|
@ -462,8 +463,8 @@ int UniscribeParagraphLayout::UniscribeLine::GetLeading() const
|
||||||
int UniscribeParagraphLayout::UniscribeLine::GetWidth() const
|
int UniscribeParagraphLayout::UniscribeLine::GetWidth() const
|
||||||
{
|
{
|
||||||
int length = 0;
|
int length = 0;
|
||||||
for (const UniscribeVisualRun *run : *this) {
|
for (const auto &run : *this) {
|
||||||
length += run->GetAdvance();
|
length += run.GetAdvance();
|
||||||
}
|
}
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
|
@ -484,6 +485,14 @@ UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(const Uniscribe
|
||||||
this->positions[this->num_glyphs * 2] = advance + x;
|
this->positions[this->num_glyphs * 2] = advance + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(UniscribeVisualRun&& other) noexcept
|
||||||
|
: glyphs(std::move(other.glyphs)), positions(std::move(other.positions)), char_to_glyph(std::move(other.char_to_glyph)),
|
||||||
|
start_pos(other.start_pos), total_advance(other.total_advance), num_glyphs(other.num_glyphs), font(other.font)
|
||||||
|
{
|
||||||
|
this->glyph_to_char = other.glyph_to_char;
|
||||||
|
other.glyph_to_char = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const int *UniscribeParagraphLayout::UniscribeVisualRun::GetGlyphToCharMap() const
|
const int *UniscribeParagraphLayout::UniscribeVisualRun::GetGlyphToCharMap() const
|
||||||
{
|
{
|
||||||
if (this->glyph_to_char == NULL) {
|
if (this->glyph_to_char == NULL) {
|
||||||
|
|
Loading…
Reference in New Issue