OpenTTD Source  20241108-master-g80f628063a
freetypefontcache.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 <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "../stdafx.h"
11 #include "../debug.h"
12 #include "../fontcache.h"
13 #include "../fontdetection.h"
14 #include "../blitter/factory.hpp"
15 #include "../core/math_func.hpp"
16 #include "../zoom_func.h"
17 #include "../fileio_func.h"
18 #include "../error_func.h"
19 #include "truetypefontcache.h"
20 
21 #include "../table/control_codes.h"
22 
23 #include "../safeguards.h"
24 
25 #ifdef WITH_FREETYPE
26 #include <ft2build.h>
27 #include FT_FREETYPE_H
28 #include FT_GLYPH_H
29 #include FT_TRUETYPE_TABLES_H
30 
33 private:
34  FT_Face face;
35 
36  void SetFontSize(int pixels);
37  const Sprite *InternalGetGlyph(GlyphID key, bool aa) override;
38 
39 public:
40  FreeTypeFontCache(FontSize fs, FT_Face face, int pixels);
42  void ClearFontCache() override;
43  GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override;
44  std::string GetFontName() override { return fmt::format("{}, {}", face->family_name, face->style_name); }
45  bool IsBuiltInFont() override { return false; }
46  const void *GetOSHandle() override { return &face; }
47 };
48 
49 FT_Library _library = nullptr;
50 
51 
58 FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : TrueTypeFontCache(fs, pixels), face(face)
59 {
60  assert(face != nullptr);
61 
62  this->SetFontSize(pixels);
63 }
64 
65 void FreeTypeFontCache::SetFontSize(int pixels)
66 {
67  if (pixels == 0) {
68  /* Try to determine a good height based on the minimal height recommended by the font. */
69  int scaled_height = ScaleGUITrad(FontCache::GetDefaultFontHeight(this->fs));
70  pixels = scaled_height;
71 
72  TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head);
73  if (head != nullptr) {
74  /* Font height is minimum height plus the difference between the default
75  * height for this font size and the small size. */
76  int diff = scaled_height - ScaleGUITrad(FontCache::GetDefaultFontHeight(FS_SMALL));
77  /* Clamp() is not used as scaled_height could be greater than MAX_FONT_SIZE, which is not permitted in Clamp(). */
78  pixels = std::min(std::max(std::min<int>(head->Lowest_Rec_PPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height), MAX_FONT_SIZE);
79  }
80  } else {
81  pixels = ScaleGUITrad(pixels);
82  }
83  this->used_size = pixels;
84 
85  FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels);
86  if (err != FT_Err_Ok) {
87 
88  /* Find nearest size to that requested */
89  FT_Bitmap_Size *bs = this->face->available_sizes;
90  int i = this->face->num_fixed_sizes;
91  if (i > 0) { // In pathetic cases one might get no fixed sizes at all.
92  int n = bs->height;
93  FT_Int chosen = 0;
94  for (; --i; bs++) {
95  if (abs(pixels - bs->height) >= abs(pixels - n)) continue;
96  n = bs->height;
97  chosen = this->face->num_fixed_sizes - i;
98  }
99 
100  /* Don't use FT_Set_Pixel_Sizes here - it might give us another
101  * error, even though the size is available (FS#5885). */
102  err = FT_Select_Size(this->face, chosen);
103  }
104  }
105 
106  if (err == FT_Err_Ok) {
107  this->ascender = this->face->size->metrics.ascender >> 6;
108  this->descender = this->face->size->metrics.descender >> 6;
109  this->height = this->ascender - this->descender;
110  } else {
111  /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
112  Debug(fontcache, 0, "Font size selection failed. Using FontCache defaults.");
113  }
114 }
115 
116 static FT_Error LoadFont(FontSize fs, FT_Face face, const char *font_name, uint size)
117 {
118  Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
119 
120  /* Attempt to select the unicode character map */
121  FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
122  if (error == FT_Err_Ok) goto found_face; // Success
123 
124  if (error == FT_Err_Invalid_CharMap_Handle) {
125  /* Try to pick a different character map instead. We default to
126  * the first map, but platform_id 0 encoding_id 0 should also
127  * be unicode (strange system...) */
128  FT_CharMap found = face->charmaps[0];
129  int i;
130 
131  for (i = 0; i < face->num_charmaps; i++) {
132  FT_CharMap charmap = face->charmaps[i];
133  if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
134  found = charmap;
135  }
136  }
137 
138  if (found != nullptr) {
139  error = FT_Set_Charmap(face, found);
140  if (error == FT_Err_Ok) goto found_face;
141  }
142  }
143 
144  FT_Done_Face(face);
145  return error;
146 
147 found_face:
148  new FreeTypeFontCache(fs, face, size);
149  return FT_Err_Ok;
150 }
151 
160 {
162 
163  std::string font = GetFontCacheFontName(fs);
164  if (font.empty()) return;
165 
166  if (_library == nullptr) {
167  if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
168  ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
169  return;
170  }
171 
172  Debug(fontcache, 2, "Initialized");
173  }
174 
175  const char *font_name = font.c_str();
176  FT_Face face = nullptr;
177 
178  /* If font is an absolute path to a ttf, try loading that first. */
179  int32_t index = 0;
180  if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
181  FT_Error error = FT_New_Face(_library, font_name, index, &face);
182 
183  if (error != FT_Err_Ok) {
184  /* Check if font is a relative filename in one of our search-paths. */
185  std::string full_font = FioFindFullPath(BASE_DIR, font_name);
186  if (!full_font.empty()) {
187  error = FT_New_Face(_library, full_font.c_str(), 0, &face);
188  }
189  }
190 
191  /* Try loading based on font face name (OS-wide fonts). */
192  if (error != FT_Err_Ok) error = GetFontByFaceName(font_name, &face);
193 
194  if (error == FT_Err_Ok) {
195  error = LoadFont(fs, face, font_name, GetFontCacheFontSize(fs));
196  if (error != FT_Err_Ok) {
197  ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
198  }
199  } else {
200  FT_Done_Face(face);
201  }
202 }
203 
208 {
209  FT_Done_Face(this->face);
210  this->face = nullptr;
211  this->ClearFontCache();
212 }
213 
218 {
219  /* Font scaling might have changed, determine font size anew if it was automatically selected. */
220  if (this->face != nullptr) this->SetFontSize(this->req_size);
221 
223 }
224 
225 
226 const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa)
227 {
228  FT_GlyphSlot slot = this->face->glyph;
229 
230  FT_Load_Glyph(this->face, key, aa ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
231  FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
232 
233  /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
234  aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
235 
236  /* Add 1 scaled pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
237  uint shadow = (this->fs == FS_NORMAL) ? ScaleGUITrad(1) : 0;
238  uint width = std::max(1U, (uint)slot->bitmap.width + shadow);
239  uint height = std::max(1U, (uint)slot->bitmap.rows + shadow);
240 
241  /* Limit glyph size to prevent overflows later on. */
242  if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) UserError("Font glyph is too large");
243 
244  /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
245  SpriteLoader::SpriteCollection spritecollection;
246  SpriteLoader::Sprite &sprite = spritecollection[ZOOM_LVL_MIN];
247  sprite.AllocateData(ZOOM_LVL_MIN, static_cast<size_t>(width) * height);
248  sprite.type = SpriteType::Font;
249  sprite.colours = (aa ? SCC_PAL | SCC_ALPHA : SCC_PAL);
250  sprite.width = width;
251  sprite.height = height;
252  sprite.x_offs = slot->bitmap_left;
253  sprite.y_offs = this->ascender - slot->bitmap_top;
254 
255  /* Draw shadow for medium size */
256  if (this->fs == FS_NORMAL && !aa) {
257  for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
258  for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
259  if (HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
260  sprite.data[shadow + x + (shadow + y) * sprite.width].m = SHADOW_COLOUR;
261  sprite.data[shadow + x + (shadow + y) * sprite.width].a = 0xFF;
262  }
263  }
264  }
265  }
266 
267  for (uint y = 0; y < (uint)slot->bitmap.rows; y++) {
268  for (uint x = 0; x < (uint)slot->bitmap.width; x++) {
269  if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
270  sprite.data[x + y * sprite.width].m = FACE_COLOUR;
271  sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
272  }
273  }
274  }
275 
276  UniquePtrSpriteAllocator allocator;
277  BlitterFactory::GetCurrentBlitter()->Encode(spritecollection, allocator);
278 
279  GlyphEntry new_glyph;
280  new_glyph.data = std::move(allocator.data);
281  new_glyph.width = slot->advance.x >> 6;
282 
283  return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
284 }
285 
286 
287 GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
288 {
289  assert(IsPrintable(key));
290 
291  FT_UInt glyph = FT_Get_Char_Index(this->face, key);
292 
293  if (glyph == 0 && allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
294  return this->parent->MapCharToGlyph(key);
295  }
296 
297  return glyph;
298 }
299 
304 {
305  FT_Done_FreeType(_library);
306  _library = nullptr;
307 }
308 
309 #if !defined(WITH_FONTCONFIG)
310 
311 FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
312 
313 #endif /* !defined(WITH_FONTCONFIG) */
314 
315 #endif /* WITH_FREETYPE */
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition: factory.hpp:138
int height
The height of the font.
Definition: fontcache.h:26
FontCache * parent
The parent of this font cache.
Definition: fontcache.h:24
virtual GlyphID MapCharToGlyph(char32_t key, bool fallback=true)=0
Map a character into a glyph.
const FontSize fs
The size of the font.
Definition: fontcache.h:25
int descender
The descender value of the font.
Definition: fontcache.h:28
int ascender
The ascender value of the font.
Definition: fontcache.h:27
Font cache for fonts that are based on a freetype font.
FreeTypeFontCache(FontSize fs, FT_Face face, int pixels)
Create a new FreeTypeFontCache.
~FreeTypeFontCache()
Free everything that was allocated for this font cache.
void ClearFontCache() override
Reset cached glyphs.
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback=true) override
Map a character into a glyph.
FT_Face face
The font face associated with this font.
std::string GetFontName() override
Get the name of this font.
const void * GetOSHandle() override
Get the native OS font handle, if there is one.
bool IsBuiltInFont() override
Is this a built-in sprite font?
virtual Sprite * Encode(const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)=0
Convert a sprite from the loader to our own format.
std::array< Sprite, ZOOM_LVL_END > SpriteCollection
Type defining a collection of sprites, one for each zoom level.
Font cache for fonts that are based on a TrueType font.
static constexpr int MAX_GLYPH_DIM
Maximum glyph dimensions.
int used_size
Used font size.
int req_size
Requested font size.
void ClearFontCache() override
Reset cached glyphs.
static constexpr uint MAX_FONT_MIN_REC_SIZE
Upper limit for the recommended font size in case a font file contains nonsensical values.
SpriteAllocator that allocates memory via a unique_ptr array.
Definition: spritecache.h:41
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
std::string FioFindFullPath(Subdirectory subdir, const std::string &filename)
Find a path to the filename in one of the search directories.
Definition: fileio.cpp:144
@ BASE_DIR
Base directory for all subdirectories.
Definition: fileio_type.h:116
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:21
uint GetFontCacheFontSize(FontSize fs)
Get the scalable font size to use for a FontSize.
Definition: fontcache.cpp:162
std::string GetFontCacheFontName(FontSize fs)
Get font to use for a given font size.
Definition: fontcache.cpp:206
FontCacheSubSetting * GetFontCacheSubSetting(FontSize fs)
Get the settings of a given font size.
Definition: fontcache.h:216
uint32_t GlyphID
Glyphs are characters from a font.
Definition: fontcache.h:17
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
Load a freetype font face with the given font name.
Definition: font_unix.cpp:42
void UninitFreeType()
Free everything allocated w.r.t.
void LoadFreeTypeFont(FontSize fs)
Loads the freetype font.
@ Font
A sprite used for fonts.
FontSize
Available font sizes.
Definition: gfx_type.h:208
@ FS_SMALL
Index of the small font in the font tables.
Definition: gfx_type.h:210
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:23
@ SCC_ALPHA
Sprite has alpha.
@ SCC_PAL
Sprite has palette data.
Settings for a single font.
Definition: fontcache.h:192
uint8_t m
Remap-channel.
uint8_t a
Alpha-channel.
Structure for passing information from the sprite loader to the blitter.
void AllocateData(ZoomLevel zoom, size_t size)
Allocate the sprite data of this sprite.
SpriteColourComponent colours
The colour components of the sprite with useful information.
uint16_t width
Width of the sprite.
int16_t x_offs
The x-offset of where the sprite will be drawn.
SpriteLoader::CommonPixel * data
The sprite itself.
uint16_t height
Height of the sprite.
SpriteType type
The sprite type.
int16_t y_offs
The y-offset of where the sprite will be drawn.
Data structure describing a sprite.
Definition: spritecache.h:17
uint8_t data[]
Sprite data.
Definition: spritecache.h:22
Common base definition for font file based font caches.
static const int MAX_FONT_SIZE
Maximum font size.
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:117
@ ZOOM_LVL_MIN
Minimum zoom level.
Definition: zoom_type.h:41