1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-19 04:29:09 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
f220ed179d Codechange: Use std::unordered_map for SpriteFontCache's glyph map. (#12724)
Replaces a C-style malloc'd array and malloc'd contents, and no manual memory clean up is necessary.
2024-05-28 19:34:03 +01:00
3d4b98845a Codechange: Remove initial colour from layouter cache. (#12728)
Initial colour is now always TC_INVALID, which is substituted with the desired colour when drawing the layout line.

This allows strings which differ only by initial colour to use the same layout cache entry, increasing the efficacy of the cache.
2024-05-28 19:33:44 +01:00
6 changed files with 32 additions and 51 deletions

View File

@@ -35,7 +35,7 @@ static int ScaleFontTrad(int value)
* Create a new sprite font cache.
* @param fs The font size to create the cache for.
*/
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(nullptr)
SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs)
{
this->InitializeUnicodeGlyphMap();
this->height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
@@ -43,30 +43,26 @@ SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid
}
/**
* Free everything we allocated.
* Get SpriteID associated with a GlyphID.
* @param key Glyph to find.
* @return SpriteID of glyph, or 0 if not present.
*/
SpriteFontCache::~SpriteFontCache()
SpriteID SpriteFontCache::GetUnicodeGlyph(GlyphID key)
{
this->ClearGlyphToSpriteMap();
}
SpriteID SpriteFontCache::GetUnicodeGlyph(char32_t key)
{
if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) return 0;
return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)];
const auto found = this->glyph_to_spriteid_map.find(key & ~SPRITE_GLYPH);
if (found == std::end(this->glyph_to_spriteid_map)) return 0;
return found->second;
}
void SpriteFontCache::SetUnicodeGlyph(char32_t key, SpriteID sprite)
{
if (this->glyph_to_spriteid_map == nullptr) this->glyph_to_spriteid_map = CallocT<SpriteID*>(256);
if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT<SpriteID>(256);
this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
this->glyph_to_spriteid_map[key] = sprite;
}
void SpriteFontCache::InitializeUnicodeGlyphMap()
{
/* Clear out existing glyph map if it exists */
this->ClearGlyphToSpriteMap();
this->glyph_to_spriteid_map.clear();
SpriteID base;
switch (this->fs) {
@@ -98,20 +94,6 @@ void SpriteFontCache::InitializeUnicodeGlyphMap()
}
}
/**
* Clear the glyph to sprite mapping.
*/
void SpriteFontCache::ClearGlyphToSpriteMap()
{
if (this->glyph_to_spriteid_map == nullptr) return;
for (uint i = 0; i < 256; i++) {
free(this->glyph_to_spriteid_map[i]);
}
free(this->glyph_to_spriteid_map);
this->glyph_to_spriteid_map = nullptr;
}
void SpriteFontCache::ClearFontCache()
{
Layouter::ResetFontCache(this->fs);
@@ -121,14 +103,14 @@ void SpriteFontCache::ClearFontCache()
const Sprite *SpriteFontCache::GetGlyph(GlyphID key)
{
SpriteID sprite = this->GetUnicodeGlyph(key);
SpriteID sprite = this->GetUnicodeGlyph(static_cast<char32_t>(key & ~SPRITE_GLYPH));
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
return GetSprite(sprite, SpriteType::Font);
}
uint SpriteFontCache::GetGlyphWidth(GlyphID key)
{
SpriteID sprite = this->GetUnicodeGlyph(key);
SpriteID sprite = this->GetUnicodeGlyph(static_cast<char32_t>(key & ~SPRITE_GLYPH));
if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
return SpriteExists(sprite) ? GetSprite(sprite, SpriteType::Font)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
}

View File

@@ -15,14 +15,8 @@
/** Font cache for fonts that are based on a freetype font. */
class SpriteFontCache : public FontCache {
private:
SpriteID **glyph_to_spriteid_map; ///< Mapping of glyphs to sprite IDs.
SpriteID GetUnicodeGlyph(char32_t key);
void ClearGlyphToSpriteMap();
public:
SpriteFontCache(FontSize fs);
~SpriteFontCache();
void SetUnicodeGlyph(char32_t key, SpriteID sprite) override;
void InitializeUnicodeGlyphMap() override;
void ClearFontCache() override;
@@ -32,6 +26,10 @@ public:
GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; }
std::string GetFontName() override { return "sprite"; }
bool IsBuiltInFont() override { return true; }
private:
std::unordered_map<GlyphID, SpriteID> glyph_to_spriteid_map{}; ///< Mapping of glyphs to sprite IDs.
SpriteID GetUnicodeGlyph(GlyphID key);
};
#endif /* SPRITEFONTCACHE_H */

View File

@@ -491,11 +491,12 @@ static void SetColourRemap(TextColour colour)
* will be drawn in the right direction.
* @param underline Whether to underline what has been drawn or not.
* @param truncation Whether to perform string truncation or not.
* @param default_colour Colour of text if not specified within string.
*
* @return In case of left or center alignment the right most pixel we have drawn to.
* In case of right alignment the left most pixel we have drawn to.
*/
static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, int right, StringAlignment align, bool underline, bool truncation)
static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, int right, StringAlignment align, bool underline, bool truncation, TextColour default_colour)
{
if (line.CountRuns() == 0) return 0;
@@ -589,6 +590,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left,
FontCache *fc = f->fc;
TextColour colour = f->colour;
if (colour == TC_INVALID) colour = default_colour;
colour_has_shadow = (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK;
SetColourRemap(do_shadow ? TC_BLACK : colour); // the last run also sets the colour for the truncation dots
if (do_shadow && (!fc->GetDrawGlyphShadow() || !colour_has_shadow)) continue;
@@ -665,10 +667,10 @@ int DrawString(int left, int right, int top, std::string_view str, TextColour co
return 0;
}
Layouter layout(str, INT32_MAX, colour, fontsize);
Layouter layout(str, INT32_MAX, fontsize);
if (layout.empty()) return 0;
return DrawLayoutLine(*layout.front(), top, left, right, align, underline, true);
return DrawLayoutLine(*layout.front(), top, left, right, align, underline, true, colour);
}
/**
@@ -702,7 +704,7 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour, St
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
{
assert(maxw > 0);
Layouter layout(str, maxw, TC_FROMSTRING, fontsize);
Layouter layout(str, maxw, fontsize);
return layout.GetBounds().height;
}
@@ -778,7 +780,7 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_vi
* do we really want to support fonts of 0 or less pixels high? */
if (maxh <= 0) return top;
Layouter layout(str, maxw, colour, fontsize);
Layouter layout(str, maxw, fontsize);
int total_height = layout.GetBounds().height;
int y;
switch (align & SA_VERT_MASK) {
@@ -807,7 +809,7 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_vi
last_line = y + line_height;
if (first_line > y) first_line = y;
DrawLayoutLine(*line, y, left, right, align, underline, false);
DrawLayoutLine(*line, y, left, right, align, underline, false, colour);
}
y += line_height;
}
@@ -848,7 +850,7 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str,
*/
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
{
Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
Layouter layout(str, INT32_MAX, start_fontsize);
return layout.GetBounds();
}
@@ -907,7 +909,7 @@ Point GetCharPosInString(std::string_view str, const char *ch, FontSize start_fo
assert(ch >= str.data() && (ch - str.data()) <= static_cast<ptrdiff_t>(str.size()));
auto it_ch = str.begin() + (ch - str.data());
Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
Layouter layout(str, INT32_MAX, start_fontsize);
return layout.GetCharPosition(it_ch);
}
@@ -922,7 +924,7 @@ ptrdiff_t GetCharAtPosition(std::string_view str, int x, FontSize start_fontsize
{
if (x < 0) return -1;
Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize);
Layouter layout(str, INT32_MAX, start_fontsize);
return layout.GetCharAtPosition(x, 0);
}

View File

@@ -125,12 +125,11 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, std::string_view s
* Create a new layouter.
* @param str The string to create the layout for.
* @param maxw The maximum width.
* @param colour The colour of the font.
* @param fontsize The size of font to use.
*/
Layouter::Layouter(std::string_view str, int maxw, TextColour colour, FontSize fontsize) : string(str)
Layouter::Layouter(std::string_view str, int maxw, FontSize fontsize) : string(str)
{
FontState state(colour, fontsize);
FontState state(TC_INVALID, fontsize);
while (true) {
auto line_length = str.find_first_of('\n');

View File

@@ -36,7 +36,7 @@ struct FontState {
*/
inline void SetColour(TextColour c)
{
assert((c & TC_COLOUR_MASK) >= TC_BLUE && (c & TC_COLOUR_MASK) <= TC_BLACK);
assert(((c & TC_COLOUR_MASK) >= TC_BLUE && (c & TC_COLOUR_MASK) <= TC_BLACK) || (c & TC_COLOUR_MASK) == TC_INVALID);
assert((c & (TC_COLOUR_MASK | TC_FLAGS_MASK)) == c);
if ((this->cur_colour & TC_FORCED) == 0) this->cur_colour = c;
}
@@ -174,7 +174,7 @@ private:
public:
static Font *GetFont(FontSize size, TextColour colour);
Layouter(std::string_view str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL);
Layouter(std::string_view str, int maxw = INT32_MAX, FontSize fontsize = FS_NORMAL);
Dimension GetBounds();
Point GetCharPosition(std::string_view::const_iterator ch) const;
ptrdiff_t GetCharAtPosition(int x, size_t line_index) const;

View File

@@ -331,7 +331,7 @@ void TextfileWindow::CheckHyperlinkClick(Point pt)
/* Build line layout to figure out character position that was clicked. */
uint window_width = IsWidgetLowered(WID_TF_WRAPTEXT) ? this->GetWidget<NWidgetCore>(WID_TF_BACKGROUND)->current_x - WidgetDimensions::scaled.frametext.Horizontal() : INT_MAX;
Layouter layout(this->lines[line_index].text, window_width, this->lines[line_index].colour, FS_MONO);
Layouter layout(this->lines[line_index].text, window_width, FS_MONO);
assert(subline < layout.size());
ptrdiff_t char_index = layout.GetCharAtPosition(pt.x - WidgetDimensions::scaled.frametext.left, subline);
if (char_index < 0) return;