34 LOCALESIGNATURE locale;
36 std::vector<std::wstring> fonts;
38 bool Add(
const std::wstring_view &font)
40 auto it = std::ranges::find(this->fonts, font);
41 if (it != std::end(this->fonts))
return false;
43 this->fonts.emplace_back(font);
49static int CALLBACK EnumFontCallback(
const ENUMLOGFONTEX *logfont,
const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
54 if (!info->Add(logfont->elfFullName))
return 1;
56 if (!(type & TRUETYPE_FONTTYPE))
return 1;
58 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET)
return 1;
63 auto check_bitfields = [&]() {
65 for (uint8_t i = 0; i < 4; i++) {
66 if ((metric->ntmFontSig.fsUsb[i] & info->locale.lsUsb[i]) != 0)
return true;
69 for (uint8_t i = 0; i < 2; i++) {
70 if ((metric->ntmFontSig.fsCsb[i] & info->locale.lsCsbSupported[i]) != 0)
return true;
74 if (!check_bitfields())
return 1;
76 char font_name[MAX_PATH];
82 Debug(fontcache, 1,
"Fallback font: {}", font_name);
94 this->
dc = CreateCompatibleDC(
nullptr);
95 this->SetFontSize(pixels);
103 DeleteObject(this->
font);
106void Win32FontCache::SetFontSize(
int pixels)
110 int scaled_height =
ScaleGUITrad(FontCache::GetDefaultFontHeight(this->
fs));
111 pixels = scaled_height;
113 HFONT temp = CreateFontIndirect(&this->logfont);
114 if (temp !=
nullptr) {
115 HGDIOBJ old = SelectObject(this->
dc, temp);
117 UINT size = GetOutlineTextMetrics(this->
dc, 0,
nullptr);
118 LPOUTLINETEXTMETRIC otm = (LPOUTLINETEXTMETRIC)
new BYTE[size];
119 GetOutlineTextMetrics(this->
dc, size, otm);
128 SelectObject(
dc, old);
137 this->
logfont.lfHeight = -pixels;
139 this->
logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
140 this->
logfont.lfQuality = ANTIALIASED_QUALITY;
142 if (this->
font !=
nullptr) {
144 DeleteObject(this->
font);
150 UINT otmSize = GetOutlineTextMetrics(this->
dc, 0,
nullptr);
151 POUTLINETEXTMETRIC otm = (POUTLINETEXTMETRIC)
new BYTE[otmSize];
152 GetOutlineTextMetrics(this->
dc, otmSize, otm);
154 this->
ascender = otm->otmTextMetrics.tmAscent;
155 this->
descender = otm->otmTextMetrics.tmDescent;
157 this->
glyph_size.cx = otm->otmTextMetrics.tmMaxCharWidth;
158 this->
glyph_size.cy = otm->otmTextMetrics.tmHeight;
160 this->
fontname =
FS2OTTD((LPWSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFaceName));
162 Debug(fontcache, 2,
"Loaded font '{}' with size {}", this->
fontname, pixels);
172 if (this->
font !=
nullptr) this->SetFontSize(this->
req_size);
180 MAT2 mat = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
183 DWORD size = GetGlyphOutline(this->
dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, 0,
nullptr, &mat);
184 if (size == GDI_ERROR) UserError(
"Unable to render font glyph");
188 uint width = std::max(1U, (uint)gm.gmBlackBoxX + shadow);
189 uint
height = std::max(1U, (uint)gm.gmBlackBoxY + shadow);
196 GetGlyphOutline(this->
dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat);
204 sprite.
width = width;
206 sprite.
x_offs = gm.gmptGlyphOrigin.x;
215 uint pitch =
Align(aa ? gm.gmBlackBoxX : std::max((gm.gmBlackBoxX + 7u) / 8u, 1u), 4);
219 for (uint y = 0; y < gm.gmBlackBoxY; y++) {
220 for (uint x = 0; x < gm.gmBlackBoxX; x++) {
221 if (aa ? (bmp[x + y * pitch] > 0) :
HasBit(bmp[(x / 8) + y * pitch], 7 - (x % 8))) {
222 sprite.
data[shadow + x + (shadow + y) * sprite.
width].
m = SHADOW_COLOUR;
223 sprite.
data[shadow + x + (shadow + y) * sprite.
width].
a = aa ? (bmp[x + y * pitch] << 2) - 1 : 0xFF;
229 for (uint y = 0; y < gm.gmBlackBoxY; y++) {
230 for (uint x = 0; x < gm.gmBlackBoxX; x++) {
231 if (aa ? (bmp[x + y * pitch] > 0) :
HasBit(bmp[(x / 8) + y * pitch], 7 - (x % 8))) {
232 sprite.
data[x + y * sprite.
width].
m = FACE_COLOUR;
233 sprite.
data[x + y * sprite.
width].
a = aa ? (bmp[x + y * pitch] << 2) - 1 : 0xFF;
243 new_glyph.
data = std::move(allocator.data);
244 new_glyph.
width = gm.gmCellIncX;
246 return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
251 assert(IsPrintable(key));
255 if (key >= 0x010000U) {
256 chars[0] = (wchar_t)(((key - 0x010000U) >> 10) + 0xD800);
257 chars[1] = (wchar_t)(((key - 0x010000U) & 0x3FF) + 0xDC00);
259 chars[0] = (wchar_t)(key & 0xFFFF);
262 WORD glyphs[2] = { 0, 0 };
263 GetGlyphIndicesW(this->
dc, chars, key >= 0x010000U ? 2 : 1, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
265 if (glyphs[0] != 0xFFFF)
return glyphs[0];
266 return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->
parent->MapCharToGlyph(key) : 0;
269class Win32FontCacheFactory : FontCacheFactory {
271 Win32FontCacheFactory() : FontCacheFactory(
"win32",
"Win32 font loader") {}
273 std::unique_ptr<FontCache>
LoadFont(
FontSize fs,
FontType fonttype,
bool search,
const std::string &font_name,
const std::any &os_handle)
const override
279 logfont.lfCharSet = DEFAULT_CHARSET;
280 logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
281 logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
285 if (
auto ptr = std::any_cast<LOGFONT>(&os_handle)) {
287 }
else if (font_name.find(
'.') != std::string::npos) {
290 ShowInfo(
"Unable to load file '{}' for {} font, using default windows font selection instead", font_name, FontSizeToName(fs));
291 if (!search)
return nullptr;
295 if (logfont.lfFaceName[0] == 0) {
305 Debug(fontcache, 1,
"Trying fallback fonts");
307 std::wstring lang =
OTTD2FS(language_isocode.substr(0, language_isocode.find(
'_')));
308 if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE,
reinterpret_cast<LPWSTR
>(&langInfo.locale),
sizeof(langInfo.locale) /
sizeof(
wchar_t)) == 0) {
310 Debug(fontcache, 1,
"Can't get locale info for fallback font (isocode={})", language_isocode);
313 langInfo.callback = callback;
317 font.lfCharSet = DEFAULT_CHARSET;
318 font.lfFaceName[0] =
'\0';
319 font.lfPitchAndFamily = 0;
321 HDC dc = GetDC(
nullptr);
322 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
323 ReleaseDC(
nullptr, dc);
328 static std::unique_ptr<FontCache> LoadWin32Font(
FontSize fs,
const LOGFONT &logfont, uint size, std::string_view font_name)
330 HFONT font = CreateFontIndirect(&logfont);
331 if (font ==
nullptr) {
332 ShowInfo(
"Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
337 return std::make_unique<Win32FontCache>(fs, logfont, size);
348 wchar_t fontPath[MAX_PATH] = {};
356 if (!full_font.empty()) {
361 if (fontPath[0] != 0) {
362 if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
366 typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
367 static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.
GetFunction(
"GetFontResourceInfoW");
369 if (GetFontResourceInfo !=
nullptr) {
372 if (GetFontResourceInfo(fontPath, &len,
nullptr, 2) && len >=
sizeof(LOGFONT)) {
373 LOGFONT *buf = (LOGFONT *)
new uint8_t[len];
374 if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
377 delete[](uint8_t *)buf;
382 if (logfont.lfFaceName[0] == 0) {
383 wchar_t fname[_MAX_FNAME];
384 _wsplitpath(fontPath,
nullptr,
nullptr, fname,
nullptr);
386 wcsncpy_s(logfont.lfFaceName,
lengthof(logfont.lfFaceName), fname, _TRUNCATE);
392 return logfont.lfFaceName[0] != 0;
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
int height
The height of the font.
std::unique_ptr< FontCache > parent
The parent of this font cache.
static void AddFallback(FontSizes fontsizes, std::string_view name, const std::any &os_handle={})
Add a fallback font, with optional OS-specific handle.
const FontSize fs
The size of the font.
int descender
The descender value of the font.
static bool TryFallback(FontSizes fontsizes, const std::set< char32_t > &glyphs, const std::string &name, const std::any &os_handle={})
Test a fallback font, with optional OS-specific handle, for specific glyphs.
int ascender
The ascender value of the font.
Function GetFunction(const std::string &symbol_name)
Get a function from a loaded library.
A searcher for missing glyphs.
std::set< char32_t > missing_glyphs
Glyphs to search for.
FontSizes missing_fontsizes
Font sizes to actually search for.
virtual Sprite * Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)=0
Convert a sprite from the loader to our own format.
SpriteCollMap< Sprite > SpriteCollection
Type defining a collection of sprites, one for each zoom level.
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.
TrueTypeFontCache(FontSize fs, int pixels)
Create a new TrueTypeFontCache.
SpriteAllocator that allocates memory via a unique_ptr array.
bool FindFallbackFont(const std::string &language_isocode, MissingGlyphSearcher *callback) const override
We would like to have a fallback font as the current one doesn't contain all characters we need.
std::unique_ptr< FontCache > LoadFont(FontSize fs, FontType fonttype, bool search, const std::string &font_name, const std::any &os_handle) const override
Try loading a font with this factory.
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
Try to load a font by filename.
HGDIOBJ old_font
Old font selected into the GDI context.
std::string fontname
Cached copy of loaded font facename.
HFONT font
The font face associated with this font.
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback=true) override
Map a character into a glyph.
HDC dc
Cached GDI device context.
void ClearFontCache() override
Reset cached glyphs.
const Sprite * InternalGetGlyph(GlyphID key, bool aa) override
Load the glyph as a sprite.
~Win32FontCache() override
Release all the operating system objects.
LOGFONT logfont
Logical font information for selecting the font face.
SIZE glyph_size
Maximum size of regular glyphs.
Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels)
Create a new Win32FontCache.
ReusableBuffer< uint8_t > render_buffer
Temporary buffer for rendering glyphs.
Control codes that are embedded in the translation strings.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Error reporting related functions.
Factory to 'query' all available blitters.
bool FileExists(std::string_view filename)
Test whether the given filename exists.
std::string FioFindFullPath(Subdirectory subdir, std::string_view filename)
Find a path to the filename in one of the search directories.
Functions for standard in/out file operations.
@ Base
Base directory for all subdirectories.
Functions related to font handling on Win32.
uint GetFontCacheFontSize(FontSize fs)
Get the scalable font size to use for a FontSize.
Functions to read fonts from files and cache them.
FontType
Different types of font that can be loaded.
@ TrueType
Scalable TrueType fonts.
@ Font
A sprite used for fonts.
FontSize
Available font sizes.
@ Small
Index of the small font in the font tables.
@ Normal
Index of the normal font in the font tables.
@ Monospace
Index of the monospaced font in the font tables.
Functions/types related to loading libraries dynamically.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
A number of safeguards to prevent using unsafe methods.
@ Palette
Sprite has palette data.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
bool StrContainsIgnoreCase(std::string_view str, std::string_view value)
Checks if a string is contained in another string, while ignoring the case of the characters.
Functions related to low-level strings.
Functions related to OTTD's strings.
Structure for passing information from the sprite loader to the blitter.
SpriteComponents colours
The colour components of the sprite with useful information.
void AllocateData(ZoomLevel zoom, size_t size)
Allocate the sprite data of this sprite.
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.
int16_t y_offs
The y-offset of where the sprite will be drawn.
Data structure describing a sprite.
Container for information about a glyph.
std::unique_ptr< std::byte[]> data
The loaded sprite.
uint8_t width
The width of the glyph.
Common base definition for font file based font caches.
static const int MAX_FONT_SIZE
Maximum font size.
std::string_view convert_from_fs(const std::wstring_view src, std::span< char > dst_buf)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
std::wstring OTTD2FS(std::string_view name)
Convert from OpenTTD's encoding to a wide string.
std::string FS2OTTD(std::wstring_view name)
Convert to OpenTTD's encoding from a wide string.
wchar_t * convert_to_fs(std::string_view src, std::span< wchar_t > dst_buf)
Convert from OpenTTD's encoding to that of the environment in UNICODE.
Declarations of functions for MS windows systems.
Functions related to zooming.