OpenTTD Source 20251213-master-g1091fa6071
fontcache.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "stdafx.h"
11
13#include "fontcache.h"
14#include "blitter/factory.hpp"
15#include "gfx_layout.h"
16#include "openttd.h"
17#include "settings_func.h"
18#include "strings_func.h"
19#include "viewport_func.h"
20#include "window_func.h"
21#include "fileio_func.h"
22#include "zoom_func.h"
23
24#include "safeguards.h"
25
27/* static */ const int FontCache::DEFAULT_FONT_HEIGHT[FS_END] = {10, 6, 18, 10};
29/* static */ const int FontCache::DEFAULT_FONT_ASCENDER[FS_END] = {8, 6, 15, 8};
30
31FontCacheSettings _fcsettings;
32
39/* static */ std::unique_ptr<FontCache> FontProviderManager::LoadFont(FontSize fs, FontType fonttype, bool search, const std::string &font_name, std::span<const std::byte> os_handle)
40{
41 for (auto &provider : FontProviderManager::GetProviders()) {
42 auto fc = provider->LoadFont(fs, fonttype, search, font_name, os_handle);
43 if (fc != nullptr) return fc;
44 }
45
46 return nullptr;
47}
48
58/* static */ bool FontProviderManager::FindFallbackFont(const std::string &language_isocode, FontSizes fontsizes, MissingGlyphSearcher *callback)
59{
60 return std::ranges::any_of(FontProviderManager::GetProviders(),
61 [&](auto *provider) { return provider->FindFallbackFont(language_isocode, fontsizes, callback); });
62}
63
64int FontCache::GetDefaultFontHeight(FontSize fs)
65{
67}
68
69/* static */ void FontCache::UpdateCharacterHeight(FontSize fs)
70{
71 FontMetrics &metrics = FontCache::metrics[fs];
72
73 int ascender = 0;
74 int descender = 0;
75
76 for (const auto &fc : FontCache::caches) {
77 if (fc == nullptr || fc->fs != fs) continue;
78 if (fc->load_reason == FontLoadReason::MissingFallback) continue; // Avoid dynamically loaded fonts affecting widget sizes.
79 ascender = std::max(ascender, fc->ascender);
80 descender = std::min(descender, fc->descender);
81 }
82
83 if (ascender == 0 && descender == 0) {
84 /* It's possible that no font is loaded yet, in which case use default values. */
87 }
88
89 metrics.height = ascender - descender;
90 metrics.baseline = ascender;
91}
92
93int FontCache::GetGlyphYOffset()
94{
95 return FontCache::GetFontBaseline(this->fs) - this->ascender;
96}
97
104{
105 uint height = FontCache::GetCharacterHeight(size);
106 if (height == 0) height = ScaleGUITrad(FontCache::GetDefaultFontHeight(FS_MONO));
107 return height;
108}
109
110/* static */ FontCache::FontCaches FontCache::caches;
111/* static */ std::array<FontCache::FontMetrics, FS_END> FontCache::metrics{};
112/* static */ std::array<FontIndex, FS_END> FontCache::default_font_index{};
113
118{
119 for (FontSize fs : FONTSIZES_ALL) {
120 UpdateCharacterHeight(fs);
121 }
122}
123
124/* Check if a glyph should be rendered with anti-aliasing. */
125bool GetFontAAState()
126{
127 /* AA is only supported for 32 bpp */
128 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false;
129
130 return _fcsettings.global_aa;
131}
132
133void SetFont(FontSize fontsize, const std::string &font, uint size)
134{
135 FontCacheSubSetting *setting = GetFontCacheSubSetting(fontsize);
136 bool changed = false;
137
138 if (setting->font != font) {
139 setting->font = font;
140 changed = true;
141 }
142
143 if (setting->size != size) {
144 setting->size = size;
145 changed = true;
146 }
147
148 if (!changed) return;
149
150 if (fontsize != FS_MONO) {
151 /* Check if fallback fonts are needed. */
153 } else {
155 }
156
157 FontCache::UpdateCharacterHeight(fontsize);
158 LoadStringWidthTable(fontsize);
160 ReInitAllWindows(true);
161
162 if (_save_config) SaveToConfig();
163}
164
169static bool IsDefaultFont(const FontCacheSubSetting &setting)
170{
171 return setting.font.empty();
172}
173
180{
181 const FontCacheSubSetting &setting = *GetFontCacheSubSetting(fs);
182 return IsDefaultFont(setting) ? FontCache::GetDefaultFontHeight(fs) : setting.size;
183}
184
185#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
191static std::string GetDefaultTruetypeFont(FontSize fs)
192{
193 switch (fs) {
194 case FS_NORMAL: return "OpenTTD-Sans.ttf";
195 case FS_SMALL: return "OpenTTD-Small.ttf";
196 case FS_LARGE: return "OpenTTD-Serif.ttf";
197 case FS_MONO: return "OpenTTD-Mono.ttf";
198 default: NOT_REACHED();
199 }
200}
201#endif /* defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) */
202
208std::string GetDefaultTruetypeFontFile([[maybe_unused]] FontSize fs)
209{
210#if defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA)
211 /* Find font file. */
213#else
214 return {};
215#endif /* defined(WITH_FREETYPE) || defined(_WIN32) || defined(WITH_COCOA) */
216}
217
224{
226 if (!settings->font.empty()) return settings->font;
227 if (_fcsettings.prefer_sprite) return {};
229}
230
231/* static */ void FontCache::Register(std::unique_ptr<FontCache> &&fc, FontLoadReason load_reason)
232{
233 if (fc == nullptr) return;
234
235 FontSize fs = fc->fs;
236
237 /* Find an empty font cache slot. */
238 auto it = std::find(std::begin(FontCache::caches), std::end(FontCache::caches), nullptr);
239 if (it == std::end(FontCache::caches)) it = FontCache::caches.insert(it, nullptr);
240
241 /* Set up our font index and make us the default font cache for this font size. */
242 fc->font_index = static_cast<FontIndex>(std::distance(std::begin(FontCache::caches), it));
243 fc->load_reason = load_reason;
244 FontCache::default_font_index[fs] = fc->font_index;
245
246 /* Register this font cache in the slot. */
247 *it = std::move(fc);
248}
249
256/* static */ void FontCache::AddFallback(FontSizes fontsizes, FontLoadReason load_reason, std::string_view name, std::span<const std::byte> os_data)
257{
258 for (FontSize fs : fontsizes) {
259 GetFontCacheSubSetting(fs)->fallback_fonts.emplace_back(load_reason, std::string{name}, std::vector<std::byte>{os_data.begin(), os_data.end()});
260 }
261}
262
263/* static */ void FontCache::LoadDefaultFonts(FontSize fs)
264{
265 /* Load the sprite font, even if it's not preferred. */
266 FontCache::Register(FontProviderManager::LoadFont(fs, FontType::Sprite, false, {}, {}), FontLoadReason::Default);
267 if (!_fcsettings.prefer_sprite) {
268 /* Load the default truetype font if sprite font is not preferred. */
269 FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType, false, GetDefaultTruetypeFontFile(fs), {}), FontLoadReason::Default);
270 }
271}
272
273/* static */ void FontCache::LoadFallbackFonts(FontSize fs, FontLoadReason load_reason)
274{
276 for (auto it = setting->fallback_fonts.rbegin(); it != setting->fallback_fonts.rend(); ++it) {
277 if (it->load_reason != load_reason) continue;
278 FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType, false, it->name, it->os_handle), it->load_reason);
279 }
280}
281
286/* static */ void FontCache::LoadFontCaches(FontSizes fontsizes)
287{
288 static constexpr std::string_view FALLBACK_FONT = "fallback";
289 static constexpr std::string_view DEFAULT_FONT = "default";
290 static constexpr std::initializer_list<std::string_view> extra_prefer_default = {DEFAULT_FONT, FALLBACK_FONT};
291 static constexpr std::initializer_list<std::string_view> extra_prefer_fallback = {FALLBACK_FONT, DEFAULT_FONT};
292
293 for (FontSize fs : fontsizes) {
295 FontCache::default_font_index[fs] = INVALID_FONT_INDEX;
296 }
297
298 /* Remove all existing FontCaches. */
299 if (fontsizes == FONTSIZES_ALL) {
300 FontCache::caches.clear();
301 } else {
302 for (auto it = std::begin(FontCache::caches); it != std::end(FontCache::caches); ++it) {
303 if (*it == nullptr) continue;
304 if (!fontsizes.Test((*it)->fs)) continue;
305 it->reset();
306 }
307 }
308
309 for (FontSize fs : fontsizes) {
310 /* Parse configured fonts, separated by ';' into a list. */
311 std::vector<std::string_view> fontnames;
313 do {
314 auto fontname = StrTrimView(consumer.ReadUntilChar(';', StringConsumer::SKIP_ONE_SEPARATOR), " \t");
315 if (!fontname.empty()) fontnames.push_back(fontname);
316 } while (consumer.AnyBytesLeft());
317
318 /* Add the default and fallback fonts as lowest priority if not manually specified. */
319 for (const auto &extra_font : _fcsettings.prefer_default ? extra_prefer_default : extra_prefer_fallback) {
320 if (std::ranges::find(fontnames, extra_font) == std::end(fontnames)) fontnames.push_back(extra_font);
321 }
322
323 /* First load fonts for missing glyphs discovered during string formatting. */
324 FontCache::LoadFallbackFonts(fs, FontLoadReason::MissingFallback);
325
326 /* Load configured fonts in reverse order so that the first entry has priority. */
327 for (auto it = fontnames.rbegin(); it != fontnames.rend(); ++it) {
328 if (*it == DEFAULT_FONT) {
329 FontCache::LoadDefaultFonts(fs);
330 } else if (*it == FALLBACK_FONT) {
331 FontCache::LoadFallbackFonts(fs, FontLoadReason::LanguageFallback);
332 } else {
333 FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType, true, std::string{*it}, {}), FontLoadReason::Configured);
334 }
335 }
336
337 FontCache::UpdateCharacterHeight(fs);
338 }
339}
340
345/* static */ void FontCache::ClearFontCaches(FontSizes fontsizes)
346{
347 for (const auto &fc : FontCache::caches) {
348 if (fc == nullptr) continue;
349 if (!fontsizes.Test(fc->GetSize())) continue;
350 fc->ClearFontCache();
351 }
352
353 for (FontSize fs : fontsizes) {
354 FontCache::UpdateCharacterHeight(fs);
355 }
356}
357
362{
363 FontCache::caches.clear();
364}
void UpdateAllVirtCoords()
Update the viewport coordinates of all signs.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:136
Font cache for basic fonts.
Definition fontcache.h:32
static void UninitializeFontCaches()
Free everything allocated w.r.t.
static void ClearFontCaches(FontSizes fontsizes)
Clear cached information for the specified font caches.
const FontSize fs
The size of the font.
Definition fontcache.h:45
FontLoadReason load_reason
Reason why the font is loaded.
Definition fontcache.h:47
static const int DEFAULT_FONT_ASCENDER[FS_END]
Default unscaled font ascenders.
Definition fontcache.h:29
static const int DEFAULT_FONT_HEIGHT[FS_END]
Default unscaled font heights.
Definition fontcache.h:27
static void LoadFontCaches(FontSizes fontsizes)
(Re)initialize the font cache related things, i.e.
int descender
The descender value of the font.
Definition fontcache.h:50
static void InitializeFontCaches()
Initialise font caches with the base sprite font cache for all sizes.
int ascender
The ascender value of the font.
Definition fontcache.h:49
static void AddFallback(FontSizes fontsizes, FontLoadReason load_reason, std::string_view name, std::span< const std::byte > os_data={})
Add a fallback font, with optional OS-specific handle.
static std::unique_ptr< FontCache > LoadFont(FontSize fs, FontType fonttype, bool search, const std::string &font_name, std::span< const std::byte > os_handle)
Try loading a font with any fontcache factory.
Definition fontcache.cpp:39
static bool FindFallbackFont(const std::string &language_isocode, FontSizes fontsizes, class MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn't contain all characters we need.
Definition fontcache.cpp:58
static void ResetFontCache(FontSize fs)
Reset cached font information.
A searcher for missing glyphs.
static std::vector< const FontCacheFactory * > & GetProviders()
Get the currently known providers.
Parse data from a string / buffer.
std::string_view ReadUntilChar(char c, SeparatorUsage sep)
Read data until the first occurrence of 8-bit char 'c', and advance reader.
@ SKIP_ONE_SEPARATOR
Read and discard one separator, do not include it in the result.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
Factory to 'query' all available blitters.
std::string FioFindFullPath(Subdirectory subdir, std::string_view filename)
Find a path to the filename in one of the search directories.
Definition fileio.cpp:144
Functions for Standard In/Out file operations.
@ BASESET_DIR
Subdirectory for all base data (base sets, intro game)
Definition fileio_type.h:96
fluid_settings_t * settings
FluidSynth settings handle.
std::string GetDefaultTruetypeFontFile(FontSize fs)
Get path of default font file for a given font size.
uint GetFontCacheFontSize(FontSize fs)
Get the scalable font size to use for a FontSize.
static bool IsDefaultFont(const FontCacheSubSetting &setting)
Test if a font setting uses the default font.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
std::string GetFontCacheFontName(FontSize fs)
Get font to use for a given font size.
static std::string GetDefaultTruetypeFont(FontSize fs)
Get name of default font file for a given font size.
Functions to read fonts from files and cache them.
FontType
Different types of font that can be loaded.
Definition fontcache.h:298
@ TrueType
Scalable TrueType fonts.
@ Sprite
Bitmap sprites from GRF files.
FontCacheSubSetting * GetFontCacheSubSetting(FontSize fs)
Get the settings of a given font size.
Definition fontcache.h:280
void LoadStringWidthTable(FontSizes fontsizes)
Initialize _stringwidth_table cache for the specified font sizes.
Definition gfx.cpp:1250
Functions related to laying out the texts.
FontSize
Available font sizes.
Definition gfx_type.h:248
@ FS_MONO
Index of the monospaced font in the font tables.
Definition gfx_type.h:252
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ FS_LARGE
Index of the large font in the font tables.
Definition gfx_type.h:251
constexpr FontSizes FONTSIZES_ALL
Mask of all possible font sizes.
Definition gfx_type.h:262
Some generic types.
A number of safeguards to prevent using unsafe methods.
void SaveToConfig()
Save the values to the configuration file.
Functions related to setting/changing the settings.
Definition of base types and functions in a cross-platform compatible way.
Parse strings.
void CheckForMissingGlyphs(MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition strings.cpp:2370
Functions related to OTTD's strings.
Settings for the four different fonts.
Definition fontcache.h:263
bool prefer_default
Prefer OpenTTD's default font over autodetected fallback fonts.
Definition fontcache.h:270
bool prefer_sprite
Whether to prefer the built-in sprite font over resizable fonts.
Definition fontcache.h:268
bool global_aa
Whether to anti alias all font sizes.
Definition fontcache.h:269
Settings for a single font.
Definition fontcache.h:249
std::string font
The name of the font, or path to the font.
Definition fontcache.h:250
uint size
The (requested) size of the font.
Definition fontcache.h:251
Functions related to (drawing on) viewports.
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
void ReInitAllWindows(bool zoom_changed)
Re-initialize all windows.
Definition window.cpp:3410
Window functions not directly related to making/drawing windows.
Functions related to zooming.