10 #include "../../stdafx.h"
11 #include "../../debug.h"
12 #include "../../blitter/factory.hpp"
13 #include "../../core/math_func.hpp"
14 #include "../../core/mem_func.hpp"
15 #include "../../error_func.h"
16 #include "../../fileio_func.h"
17 #include "../../fontcache.h"
18 #include "../../fontcache/truetypefontcache.h"
19 #include "../../fontdetection.h"
20 #include "../../library_loader.h"
21 #include "../../string_func.h"
22 #include "../../strings_func.h"
23 #include "../../zoom_func.h"
26 #include "../../table/control_codes.h"
37 LOCALESIGNATURE locale;
39 std::vector<std::wstring> fonts;
41 bool Add(
const std::wstring_view &font)
43 for (
const auto &entry : this->fonts) {
44 if (font.compare(entry) == 0)
return false;
47 this->fonts.emplace_back(font);
53 static int CALLBACK EnumFontCallback(
const ENUMLOGFONTEX *logfont,
const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
58 if (!info->Add(logfont->elfFullName))
return 1;
60 if (!(type & TRUETYPE_FONTTYPE))
return 1;
62 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET)
return 1;
64 if (info->callback->
Monospace() && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH))
return 1;
67 if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0)
return 1;
69 char font_name[MAX_PATH];
72 info->callback->
SetFontNames(info->settings, font_name, &logfont->elfLogFont);
74 Debug(fontcache, 1,
"Fallback font: {}", font_name);
80 Debug(fontcache, 1,
"Trying fallback fonts");
82 if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale,
sizeof(langInfo.locale) /
sizeof(
wchar_t)) == 0) {
84 Debug(fontcache, 1,
"Can't get locale info for fallback font (langid=0x{:x})", winlangid);
88 langInfo.callback = callback;
92 font.lfCharSet = DEFAULT_CHARSET;
93 font.lfFaceName[0] =
'\0';
94 font.lfPitchAndFamily = 0;
96 HDC dc = GetDC(
nullptr);
97 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
98 ReleaseDC(
nullptr, dc);
111 this->
dc = CreateCompatibleDC(
nullptr);
112 this->SetFontSize(pixels);
115 Win32FontCache::~Win32FontCache()
119 DeleteObject(this->
font);
122 void Win32FontCache::SetFontSize(
int pixels)
126 int scaled_height =
ScaleGUITrad(FontCache::GetDefaultFontHeight(this->
fs));
127 pixels = scaled_height;
129 HFONT temp = CreateFontIndirect(&this->logfont);
130 if (temp !=
nullptr) {
131 HGDIOBJ old = SelectObject(this->
dc, temp);
133 UINT size = GetOutlineTextMetrics(this->
dc, 0,
nullptr);
134 LPOUTLINETEXTMETRIC otm = (LPOUTLINETEXTMETRIC)
new BYTE[size];
135 GetOutlineTextMetrics(this->
dc, size, otm);
144 SelectObject(
dc, old);
153 this->logfont.lfHeight = -pixels;
154 this->logfont.lfWidth = 0;
155 this->logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
156 this->logfont.lfQuality = ANTIALIASED_QUALITY;
158 if (this->
font !=
nullptr) {
160 DeleteObject(this->
font);
162 this->
font = CreateFontIndirect(&this->logfont);
166 UINT otmSize = GetOutlineTextMetrics(this->
dc, 0,
nullptr);
167 POUTLINETEXTMETRIC otm = (POUTLINETEXTMETRIC)
new BYTE[otmSize];
168 GetOutlineTextMetrics(this->
dc, otmSize, otm);
170 this->
ascender = otm->otmTextMetrics.tmAscent;
171 this->
descender = otm->otmTextMetrics.tmDescent;
173 this->
glyph_size.cx = otm->otmTextMetrics.tmMaxCharWidth;
174 this->
glyph_size.cy = otm->otmTextMetrics.tmHeight;
176 this->
fontname =
FS2OTTD((LPWSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFaceName));
178 Debug(fontcache, 2,
"Loaded font '{}' with size {}", this->
fontname, pixels);
188 if (this->
font !=
nullptr) this->SetFontSize(this->
req_size);
193 const Sprite *Win32FontCache::InternalGetGlyph(
GlyphID key,
bool aa)
196 MAT2 mat = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
199 DWORD size = GetGlyphOutline(this->
dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, 0,
nullptr, &mat);
200 if (size == GDI_ERROR) UserError(
"Unable to render font glyph");
204 uint width = std::max(1U, (uint)gm.gmBlackBoxX + shadow);
205 uint
height = std::max(1U, (uint)gm.gmBlackBoxY + shadow);
212 GetGlyphOutline(this->
dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat);
220 sprite.
width = width;
222 sprite.
x_offs = gm.gmptGlyphOrigin.x;
231 uint pitch =
Align(aa ? gm.gmBlackBoxX : std::max((gm.gmBlackBoxX + 7u) / 8u, 1u), 4);
235 for (uint y = 0; y < gm.gmBlackBoxY; y++) {
236 for (uint x = 0; x < gm.gmBlackBoxX; x++) {
237 if (aa ? (bmp[x + y * pitch] > 0) :
HasBit(bmp[(x / 8) + y * pitch], 7 - (x % 8))) {
238 sprite.
data[shadow + x + (shadow + y) * sprite.
width].
m = SHADOW_COLOUR;
239 sprite.
data[shadow + x + (shadow + y) * sprite.
width].
a = aa ? (bmp[x + y * pitch] << 2) - 1 : 0xFF;
245 for (uint y = 0; y < gm.gmBlackBoxY; y++) {
246 for (uint x = 0; x < gm.gmBlackBoxX; x++) {
247 if (aa ? (bmp[x + y * pitch] > 0) :
HasBit(bmp[(x / 8) + y * pitch], 7 - (x % 8))) {
248 sprite.
data[x + y * sprite.
width].
m = FACE_COLOUR;
249 sprite.
data[x + y * sprite.
width].
a = aa ? (bmp[x + y * pitch] << 2) - 1 : 0xFF;
258 GlyphEntry new_glyph;
259 new_glyph.
data = std::move(allocator.data);
260 new_glyph.width = gm.gmCellIncX;
262 return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
267 assert(IsPrintable(key));
271 if (key >= 0x010000U) {
272 chars[0] = (wchar_t)(((key - 0x010000U) >> 10) + 0xD800);
273 chars[1] = (wchar_t)(((key - 0x010000U) & 0x3FF) + 0xDC00);
275 chars[0] = (wchar_t)(key & 0xFFFF);
278 WORD glyphs[2] = { 0, 0 };
279 GetGlyphIndicesW(this->
dc, chars, key >= 0x010000U ? 2 : 1, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
281 if (glyphs[0] != 0xFFFF)
return glyphs[0];
282 return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->
parent->
MapCharToGlyph(key) : 0;
286 static bool TryLoadFontFromFile(
const std::string &font_name, LOGFONT &logfont)
288 wchar_t fontPath[MAX_PATH] = {};
296 if (!full_font.empty()) {
301 if (fontPath[0] != 0) {
302 if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
306 typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
307 static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction(
"GetFontResourceInfoW");
309 if (GetFontResourceInfo !=
nullptr) {
312 if (GetFontResourceInfo(fontPath, &len,
nullptr, 2) && len >=
sizeof(LOGFONT)) {
313 LOGFONT *buf = (LOGFONT *)
new uint8_t[len];
314 if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
317 delete[](uint8_t *)buf;
322 if (logfont.lfFaceName[0] == 0) {
323 wchar_t fname[_MAX_FNAME];
324 _wsplitpath(fontPath,
nullptr,
nullptr, fname,
nullptr);
326 wcsncpy_s(logfont.lfFaceName,
lengthof(logfont.lfFaceName), fname, _TRUNCATE);
327 logfont.lfWeight = strcasestr(font_name.c_str(),
" bold") !=
nullptr || strcasestr(font_name.c_str(),
"-bold") !=
nullptr ? FW_BOLD : FW_NORMAL;
332 return logfont.lfFaceName[0] != 0;
337 HFONT font = CreateFontIndirect(&logfont);
338 if (font ==
nullptr) {
339 ShowInfo(
"Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
357 if (font.empty())
return;
359 const char *font_name = font.c_str();
362 logfont.lfPitchAndFamily = fs ==
FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
363 logfont.lfCharSet = DEFAULT_CHARSET;
364 logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
365 logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
367 if (
settings->os_handle !=
nullptr) {
368 logfont = *(
const LOGFONT *)
settings->os_handle;
369 }
else if (strchr(font_name,
'.') !=
nullptr) {
371 if (!TryLoadFontFromFile(font, logfont)) {
372 ShowInfo(
"Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
376 if (logfont.lfFaceName[0] == 0) {
377 logfont.lfWeight = strcasestr(font_name,
" bold") !=
nullptr ? FW_BOLD : FW_NORMAL;
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).
int height
The height of the font.
FontCache * parent
The parent of this font cache.
virtual GlyphID MapCharToGlyph(char32_t key, bool fallback=true)=0
Map a character into a glyph.
const FontSize fs
The size of the font.
int descender
The descender value of the font.
int ascender
The ascender value of the font.
A searcher for missing glyphs.
virtual void SetFontNames(struct FontCacheSettings *settings, const char *font_name, const void *os_data=nullptr)=0
Set the right font names.
bool FindMissingGlyphs()
Check whether there are glyphs missing in the current language.
virtual bool Monospace()=0
Whether to search for a monospace font or not.
T * Allocate(size_t count)
Get buffer of at least count times T.
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.
Font cache for fonts that are based on a Win32 font.
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.
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.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
std::string FioFindFullPath(Subdirectory subdir, const std::string &filename)
Find a path to the filename in one of the search directories.
bool FileExists(const std::string &filename)
Test whether the given filename exists.
@ BASE_DIR
Base directory for all subdirectories.
fluid_settings_t * settings
FluidSynth settings handle.
bool SetFallbackFont(FontCacheSettings *settings, const std::string &, int winlangid, MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn't contain all characters we need.
void LoadWin32Font(FontSize fs)
Loads the GDI font.
Functions related to font handling on Win32.
uint GetFontCacheFontSize(FontSize fs)
Get the scalable font size to use for a FontSize.
std::string GetFontCacheFontName(FontSize fs)
Get font to use for a given font size.
FontCacheSubSetting * GetFontCacheSubSetting(FontSize fs)
Get the settings of a given font size.
uint32_t GlyphID
Glyphs are characters from a font.
@ Font
A sprite used for fonts.
FontSize
Available font sizes.
@ FS_MONO
Index of the monospaced font in the font tables.
@ FS_SMALL
Index of the small font in the font tables.
@ FS_NORMAL
Index of the normal font in the font tables.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
void MemSetT(T *ptr, uint8_t value, size_t num=1)
Type-safe version of memset().
A number of safeguards to prevent using unsafe methods.
@ SCC_ALPHA
Sprite has alpha.
@ SCC_PAL
Sprite has palette data.
#define lengthof(array)
Return the length of an fixed size array.
Settings for the four different fonts.
Settings for a single font.
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.
uint8_t data[]
Sprite data.
static const int MAX_FONT_SIZE
Maximum font size.
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.
wchar_t * convert_to_fs(const std::string_view src, std::span< wchar_t > dst_buf)
Convert from OpenTTD's encoding to that of the environment in UNICODE.
char * 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.
declarations of functions for MS windows systems
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
@ ZOOM_LVL_MIN
Minimum zoom level.