Remove second template parameter from class GUIList
[openttd/fttd.git] / src / font.cpp
blob8473d096f417810505fce5d56720a180cef85f20
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 */
8 /** @file font.cpp Cache for characters from fonts. */
10 #include "stdafx.h"
11 #include "debug.h"
12 #include "font.h"
13 #include "blitter/blitter.h"
14 #include "core/math_func.hpp"
15 #include "string.h"
16 #include "strings_func.h"
17 #include "zoom_type.h"
18 #include "gfx_layout.h"
19 #include "zoom_func.h"
21 #include "table/sprites.h"
22 #include "table/control_codes.h"
24 static const int MAX_FONT_SIZE = 72; ///< Maximum font size.
26 /** Default heights for the different sizes of fonts. */
27 static const int _default_font_height[FS_END] = {10, 6, 18, 10};
28 static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8};
30 #ifdef WITH_FREETYPE
32 static FT_Library _library = NULL;
34 FreeTypeSettings _freetype;
36 static const byte FACE_COLOUR = 1;
37 static const byte SHADOW_COLOUR = 2;
39 #endif /* WITH_FREETYPE */
42 /** Reset font metrics of the font. */
43 void FontCache::ResetFontMetrics (void)
45 FontSize fs = this->fs;
46 int height = _default_font_height[fs];
47 int ascender = _default_font_ascender[fs];
48 this->height = ScaleGUITrad (height);
49 this->ascender = ScaleGUITrad (ascender);
50 this->descender = ScaleGUITrad (ascender - height);
51 this->units_per_em = 1;
53 for (uint i = 0; i != 224; i++) {
54 this->glyph_widths[i] = this->GetGlyphWidth (this->MapCharToGlyph (i + 32));
57 byte widest_digit = 9;
58 byte digit_width = this->glyph_widths['9' - 32];
59 for (byte i = 8; i > 0; i--) {
60 byte w = this->glyph_widths[i + '0' - 32];
61 if (w > digit_width) {
62 widest_digit = i;
63 digit_width = w;
66 this->widest_digit_nonnull = widest_digit;
68 byte w = this->glyph_widths['0' - 32];
69 if (w > digit_width) {
70 widest_digit = 0;
71 digit_width = w;
73 this->widest_digit = widest_digit;
74 this->digit_width = digit_width;
77 /**
78 * Create a new font cache.
79 * @param fs The size of the font.
81 FontCache::FontCache (FontSize fs) :
82 #ifdef WITH_FREETYPE
83 font_tables(), face (NULL),
84 #endif /* WITH_FREETYPE */
85 fs (fs)
87 memset (this->spriteid_map, 0, sizeof(this->spriteid_map));
88 #ifdef WITH_FREETYPE
89 memset (this->sprite_map, 0, sizeof(this->sprite_map));
90 #endif /* WITH_FREETYPE */
92 this->ResetFontMetrics();
93 this->InitializeUnicodeGlyphMap();
96 /** Clean everything up. */
97 FontCache::~FontCache()
99 #ifdef WITH_FREETYPE
100 this->UnloadFreeTypeFont();
101 #endif /* WITH_FREETYPE */
102 this->ClearGlyphToSpriteMap();
107 * Get height of a character for a given font size.
108 * @param size Font size to get height of
109 * @return Height of characters in the given font (pixels)
111 int GetCharacterHeight(FontSize size)
113 return FontCache::Get(size)->GetHeight();
117 SpriteID FontCache::GetUnicodeGlyph (GlyphID key) const
119 SpriteID *p = this->spriteid_map[GB(key, 8, 8)];
120 return (p == NULL) ? 0 : p[GB(key, 0, 8)];
123 void FontCache::SetUnicodeGlyph (GlyphID key, SpriteID sprite)
125 SpriteID **p = &this->spriteid_map[GB(key, 8, 8)];
126 if (*p == NULL) *p = xcalloct<SpriteID>(256);
127 (*p)[GB(key, 0, 8)] = sprite;
130 void FontCache::InitializeUnicodeGlyphMap (void)
132 static const uint ASCII_LETTERSTART = 32; ///< First printable ASCII letter.
134 /* Font sprites are contiguous and arranged by font size. */
135 static const uint delta = 256 - ASCII_LETTERSTART;
136 assert_compile (SPR_ASCII_SPACE_SMALL == SPR_ASCII_SPACE + delta);
137 assert_compile (SPR_ASCII_SPACE_BIG == SPR_ASCII_SPACE + 2 * delta);
139 /* Clear out existing glyph map if it exists */
140 this->ClearGlyphToSpriteMap();
142 assert_compile (FS_NORMAL == 0);
143 assert_compile (FS_SMALL == 1);
144 assert_compile (FS_LARGE == 2);
145 assert_compile (FS_MONO == 3);
147 /* (this->fs % 3) maps FS_MONO to FS_NORMAL. */
148 SpriteID base = SPR_ASCII_SPACE + (this->fs % 3) * delta - ASCII_LETTERSTART;
150 for (uint i = ASCII_LETTERSTART; i < 256; i++) {
151 SpriteID sprite = base + i;
152 if (!SpriteExists(sprite)) continue;
153 this->SetUnicodeGlyph(i, sprite);
154 this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite);
157 /* Glyphs to be accessed through an SCC_* enum entry only. */
158 static const byte clear_list[] = {
159 0xAA, // Feminine ordinal indicator / Down arrow
160 0xAC, // Not sign / Tick mark
161 0xAF, // Macron / Right arrow
162 0xB4, // Acute accent / Train symbol
163 0xB5, // Micro sign / Truck symbol
164 0xB6, // Pilcrow sign / Bus symbol
165 0xB7, // Middle dot / Aircraft symbol
166 0xB8, // Cedilla / Ship symbol
167 0xB9, // Superscript 1 / Superscript -1
168 0xBC, // One quarter / Small up arrow
169 0xBD, // One half / Small down arrow
172 for (uint i = 0; i < lengthof(clear_list); i++) {
173 this->SetUnicodeGlyph (clear_list[i], 0);
176 /* Default unicode mapping table for sprite based glyphs.
177 * This table allows us use unicode characters even though the glyphs
178 * don't exist, or are in the wrong place, in the standard sprite
179 * fonts. This is not used for FreeType rendering */
180 static const uint16 translation_map[][2] = {
181 { 0x00A0, 0x20 }, // Non-breaking space / Up arrow
182 { 0x00AD, 0x20 }, // Soft hyphen / X mark
183 { 0x0178, 0x9F }, // Capital letter Y with diaeresis
184 { 0x010D, 0x63 }, // Small letter c with caron
187 for (uint i = 0; i < lengthof(translation_map); i++) {
188 WChar code = translation_map[i][0];
189 byte key = translation_map[i][1];
190 this->SetUnicodeGlyph (code, base + key);
195 * Clear the glyph to sprite mapping.
197 void FontCache::ClearGlyphToSpriteMap (void)
199 for (uint i = 0; i < 256; i++) {
200 free (this->spriteid_map[i]);
201 this->spriteid_map[i] = NULL;
205 SpriteID FontCache::GetGlyphSprite (GlyphID key) const
207 SpriteID sprite = this->GetUnicodeGlyph(key);
208 if (sprite == 0) sprite = this->GetUnicodeGlyph('?');
209 return sprite;
213 #ifdef WITH_FREETYPE
215 /** Get the FreeType settings struct for a given font size. */
216 static FreeTypeSubSetting *GetFreeTypeSettings (FontSize fs)
218 switch (fs) {
219 default: NOT_REACHED();
220 case FS_NORMAL: return &_freetype.medium;
221 case FS_SMALL: return &_freetype.small;
222 case FS_LARGE: return &_freetype.large;
223 case FS_MONO: return &_freetype.mono;
228 * Set the right font names.
229 * @param settings The settings to modify.
230 * @param font_name The new font name.
231 * @param searcher The searcher that says whether we are dealing with a monospaced font.
233 static void SetFontNames (FreeTypeSettings *settings, const char *font_name,
234 const MissingGlyphSearcher *searcher)
236 if (searcher->Monospace()) {
237 bstrcpy (settings->mono.font, font_name);
238 } else {
239 bstrcpy (settings->small.font, font_name);
240 bstrcpy (settings->medium.font, font_name);
241 bstrcpy (settings->large.font, font_name);
246 * Get the font loaded into a Freetype face by using a font-name.
247 * If no appropriate font is found, the function returns an error.
250 #ifdef WIN32
252 /* ========================================================================================
253 * Windows support
254 * ======================================================================================== */
256 #include <vector>
257 #include "core/pointer.h"
258 #include "core/alloc_func.hpp"
259 #include <windows.h>
260 #include <shlobj.h> /* SHGetFolderPath */
261 #include "os/windows/win32.h"
264 * Get the short DOS 8.3 format for paths.
265 * FreeType doesn't support Unicode filenames and Windows' fopen (as used
266 * by FreeType) doesn't support UTF-8 filenames. So we have to convert the
267 * filename into something that isn't UTF-8 but represents the Unicode file
268 * name. This is the short DOS 8.3 format. This does not contain any
269 * characters that fopen doesn't support.
270 * @param long_path the path in system encoding.
271 * @return the short path in ANSI (ASCII).
273 static const char *GetShortPath (const TCHAR *long_path)
275 static char short_path[MAX_PATH];
276 #ifdef UNICODE
277 WCHAR short_path_w[MAX_PATH];
278 GetShortPathName(long_path, short_path_w, lengthof(short_path_w));
279 WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), NULL, NULL);
280 #else
281 /* Technically not needed, but do it for consistency. */
282 GetShortPathName(long_path, short_path, lengthof(short_path));
283 #endif
284 return short_path;
287 /* Get the font file to be loaded into Freetype by looping the registry
288 * location where windows lists all installed fonts. Not very nice, will
289 * surely break if the registry path changes, but it works. Much better
290 * solution would be to use CreateFont, and extract the font data from it
291 * by GetFontData. The problem with this is that the font file needs to be
292 * kept in memory then until the font is no longer needed. This could mean
293 * an additional memory usage of 30MB (just for fonts!) when using an eastern
294 * font for all font sizes */
295 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
296 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
297 static FT_Error GetFontByFaceName (const char *font_name, const char *alt_name, FT_Face *face)
299 FT_Error err = FT_Err_Cannot_Open_Resource;
300 HKEY hKey;
301 LONG ret;
302 TCHAR vbuffer[MAX_PATH], dbuffer[256];
303 TCHAR *pathbuf;
304 const char *font_path;
305 uint index;
306 size_t path_len;
308 /* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
309 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
310 * to retrieve the windows version, we'll just query both */
311 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
312 if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
314 if (ret != ERROR_SUCCESS) {
315 DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
316 return err;
319 /* Convert font name to file system encoding. */
320 TCHAR *font_namep = _tcsdup(OTTD2FS(font_name));
322 for (index = 0;; index++) {
323 TCHAR *s;
324 DWORD vbuflen = lengthof(vbuffer);
325 DWORD dbuflen = lengthof(dbuffer);
327 ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
328 if (ret != ERROR_SUCCESS) goto registry_no_font_found;
330 /* The font names in the registry are of the following 3 forms:
331 * - ADMUI3.fon
332 * - Book Antiqua Bold (TrueType)
333 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
334 * We will strip the font-type '()' if any and work with the font name
335 * itself, which must match exactly; if...
336 * TTC files, font files which contain more than one font are separated
337 * by '&'. Our best bet will be to do substr match for the fontname
338 * and then let FreeType figure out which index to load */
339 s = _tcschr(vbuffer, _T('('));
340 if (s != NULL) s[-1] = '\0';
342 if (_tcschr(vbuffer, _T('&')) == NULL) {
343 if (_tcsicmp(vbuffer, font_namep) == 0) break;
344 } else {
345 if (_tcsstr(vbuffer, font_namep) != NULL) break;
349 if (!SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
350 DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
351 goto folder_error;
354 /* Some fonts are contained in .ttc files, TrueType Collection fonts. These
355 * contain multiple fonts inside this single file. GetFontData however
356 * returns the whole file, so we need to check each font inside to get the
357 * proper font. */
358 path_len = _tcslen(vbuffer) + _tcslen(dbuffer) + 2; // '\' and terminating nul.
359 pathbuf = AllocaM(TCHAR, path_len);
360 _sntprintf(pathbuf, path_len, _T("%s\\%s"), vbuffer, dbuffer);
362 /* Convert the path into something that FreeType understands. */
363 font_path = GetShortPath(pathbuf);
365 index = 0;
366 do {
367 err = FT_New_Face(_library, font_path, index, face);
368 if (err != FT_Err_Ok) break;
370 if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
371 /* Try english name if font name failed */
372 if (alt_name != NULL && strncasecmp(alt_name, (*face)->family_name, strlen((*face)->family_name)) == 0) break;
373 err = FT_Err_Cannot_Open_Resource;
375 } while ((FT_Long)++index != (*face)->num_faces);
378 folder_error:
379 registry_no_font_found:
380 free(font_namep);
381 RegCloseKey(hKey);
382 return err;
385 static FT_Error GetFontByFaceName (const char *font_name, FT_Face *face)
387 return GetFontByFaceName (font_name, NULL, face);
391 * Get the English font name for a buffer of font data (see below).
392 * @param buf the buffer with the font data
393 * @param len the length of the buffer
394 * @param fontname the buffer where to store the English name
395 * @return whether the name was found
397 static bool GetEnglishFontName (const byte *buf, size_t len,
398 char (&fontname) [MAX_PATH])
400 if (len < 6) return NULL;
402 if ((buf[0] != 0) || (buf[1] != 0)) return NULL;
404 uint count = (buf[2] << 8) + buf[3];
405 if (count > (len - 6) / 12) return NULL;
407 size_t data_offset = (buf[4] << 8) + buf[5];
408 if (data_offset > len) return NULL;
409 const byte *data = buf + data_offset;
410 size_t data_len = len - data_offset;
412 for (buf += 6; count > 0; count--, buf += 12) {
413 uint platform = (buf[0] << 8) + buf[1];
414 /* ignore encoding (bytes 2 and 3) */
415 uint language = (buf[4] << 8) + buf[5];
416 if ((platform != 1 || language != 0) && // Macintosh English
417 (platform != 3 || language != 0x0409)) { // Microsoft English (US)
418 continue;
421 uint name = (buf[6] << 8) + buf[7];
422 if (name != 1) continue;
424 uint offset = (buf[10] << 8) + buf[11];
425 if (offset > data_len) continue;
427 uint length = (buf[8] << 8) + buf[9];
428 if (length > (data_len - offset)) continue;
430 bstrfmt (fontname, "%.*s", length, data + offset);
431 return true;
434 return false;
438 * Fonts can have localised names and when the system locale is the same as
439 * one of those localised names Windows will always return that localised name
440 * instead of allowing to get the non-localised (English US) name of the font.
441 * This will later on give problems as freetype uses the non-localised name of
442 * the font and we need to compare based on that name.
443 * Windows furthermore DOES NOT have an API to get the non-localised name nor
444 * can we override the system locale. This means that we have to actually read
445 * the font itself to gather the font name we want.
446 * Based on: http://blogs.msdn.com/michkap/archive/2006/02/13/530814.aspx
447 * @param logfont the font information to get the english name of.
448 * @param fontname the buffer where to store the English name
450 static void GetEnglishFontName (const ENUMLOGFONTEX *logfont,
451 char (&fontname) [MAX_PATH])
453 bool found = false;
455 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
456 if (font != NULL) {
457 HDC dc = GetDC (NULL);
458 HGDIOBJ oldfont = SelectObject (dc, font);
459 DWORD dw = GetFontData (dc, 'eman', 0, NULL, 0);
460 if (dw != GDI_ERROR) {
461 byte *buf = xmalloct<byte>(dw);
462 if (GetFontData (dc, 'eman', 0, buf, dw) != GDI_ERROR) {
463 found = GetEnglishFontName (buf, dw, fontname);
465 free(buf);
467 SelectObject (dc, oldfont);
468 ReleaseDC (NULL, dc);
469 DeleteObject (font);
472 if (!found) {
473 bstrcpy (fontname, WIDE_TO_MB((const TCHAR*)logfont->elfFullName));
477 struct EFCParam {
478 FreeTypeSettings *settings;
479 LOCALESIGNATURE locale;
480 MissingGlyphSearcher *callback;
481 std::vector <ttd_unique_free_ptr <TCHAR> > fonts;
484 static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
486 EFCParam *info = (EFCParam *)lParam;
488 /* Skip duplicates */
489 const TCHAR *fname = (const TCHAR*)logfont->elfFullName;
490 for (uint i = 0; i < info->fonts.size(); i++) {
491 if (_tcscmp (info->fonts[i].get(), fname) == 0) return 1;
493 info->fonts.push_back (ttd_unique_free_ptr<TCHAR> (_tcsdup (fname)));
494 /* Only use TrueType fonts */
495 if (!(type & TRUETYPE_FONTTYPE)) return 1;
496 /* Don't use SYMBOL fonts */
497 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
498 /* Use monospaced fonts when asked for it. */
499 if (info->callback->Monospace() && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH)) return 1;
501 /* The font has to have at least one of the supported locales to be usable. */
502 if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
503 /* On win9x metric->ntmFontSig seems to contain garbage. */
504 FONTSIGNATURE fs;
505 memset(&fs, 0, sizeof(fs));
506 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
507 if (font != NULL) {
508 HDC dc = GetDC(NULL);
509 HGDIOBJ oldfont = SelectObject(dc, font);
510 GetTextCharsetInfo(dc, &fs, 0);
511 SelectObject(dc, oldfont);
512 ReleaseDC(NULL, dc);
513 DeleteObject(font);
515 if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1;
518 char font_name[MAX_PATH];
519 convert_from_fs (fname, font_name, lengthof(font_name));
521 /* Add english name after font name */
522 char english_name [MAX_PATH];
523 GetEnglishFontName (logfont, english_name);
525 /* Check whether we can actually load the font. */
526 bool ft_init = _library != NULL;
527 bool found = false;
528 FT_Face face;
529 /* Init FreeType if needed. */
530 if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName (font_name, english_name, &face) == FT_Err_Ok) {
531 FT_Done_Face(face);
532 found = true;
534 if (!ft_init) {
535 /* Uninit FreeType if we did the init. */
536 FT_Done_FreeType(_library);
537 _library = NULL;
540 if (!found) return 1;
542 SetFontNames (info->settings, font_name, info->callback);
543 if (info->callback->FindMissingGlyphs()) return 1;
544 DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name);
545 return 0; // stop enumerating
548 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
550 DEBUG(freetype, 1, "Trying fallback fonts");
551 EFCParam langInfo;
552 if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
553 /* Invalid langid or some other mysterious error, can't determine fallback font. */
554 DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
555 return false;
557 langInfo.settings = settings;
558 langInfo.callback = callback;
560 LOGFONT font;
561 /* Enumerate all fonts. */
562 font.lfCharSet = DEFAULT_CHARSET;
563 font.lfFaceName[0] = '\0';
564 font.lfPitchAndFamily = 0;
566 HDC dc = GetDC(NULL);
567 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
568 ReleaseDC(NULL, dc);
569 return ret == 0;
572 #elif defined(__APPLE__) /* end ifdef Win32 */
574 /* ========================================================================================
575 * OSX support
576 * ======================================================================================== */
578 #include "os/macosx/macos.h"
580 static FT_Error GetFontByFaceName (const char *font_name, FT_Face *face)
582 FT_Error err = FT_Err_Cannot_Open_Resource;
584 /* Get font reference from name. */
585 CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name, kCFStringEncodingUTF8);
586 ATSFontRef font = ATSFontFindFromName(name, kATSOptionFlagsDefault);
587 CFRelease(name);
588 if (font == kInvalidFont) return err;
590 /* Get a file system reference for the font. */
591 FSRef ref;
592 OSStatus os_err = -1;
593 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
594 if (MacOSVersionIsAtLeast(10, 5, 0)) {
595 os_err = ATSFontGetFileReference(font, &ref);
596 } else
597 #endif
599 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(__LP64__)
600 /* This type was introduced with the 10.5 SDK. */
601 #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
602 #define ATSFSSpec FSSpec
603 #endif
604 FSSpec spec;
605 os_err = ATSFontGetFileSpecification(font, (ATSFSSpec *)&spec);
606 if (os_err == noErr) os_err = FSpMakeFSRef(&spec, &ref);
607 #endif
610 if (os_err == noErr) {
611 /* Get unix path for file. */
612 UInt8 file_path[PATH_MAX];
613 if (FSRefMakePath(&ref, file_path, sizeof(file_path)) == noErr) {
614 DEBUG(freetype, 3, "Font path for %s: %s", font_name, file_path);
615 err = FT_New_Face(_library, (const char *)file_path, 0, face);
619 return err;
622 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
624 bool result = false;
626 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
627 if (MacOSVersionIsAtLeast(10, 5, 0)) {
628 /* Determine fallback font using CoreText. This uses the language isocode
629 * to find a suitable font. CoreText is available from 10.5 onwards. */
630 char lang[16];
631 if (strcmp(language_isocode, "zh_TW") == 0) {
632 /* Traditional Chinese */
633 bstrcpy (lang, "zh-Hant");
634 } else if (strcmp(language_isocode, "zh_CN") == 0) {
635 /* Simplified Chinese */
636 bstrcpy (lang, "zh-Hans");
637 } else {
638 /* Just copy the first part of the isocode. */
639 bstrcpy (lang, language_isocode);
640 char *sep = strchr(lang, '_');
641 if (sep != NULL) *sep = '\0';
644 /* Create a font descriptor matching the wanted language and latin (english) glyphs. */
645 CFStringRef lang_codes[2];
646 lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
647 lang_codes[1] = CFSTR("en");
648 CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
649 CFDictionaryRef lang_attribs = CFDictionaryCreate(kCFAllocatorDefault, (const void**)&kCTFontLanguagesAttribute, (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
650 CTFontDescriptorRef lang_desc = CTFontDescriptorCreateWithAttributes(lang_attribs);
651 CFRelease(lang_arr);
652 CFRelease(lang_attribs);
653 CFRelease(lang_codes[0]);
655 /* Get array of all font descriptors for the wanted language. */
656 CFSetRef mandatory_attribs = CFSetCreate(kCFAllocatorDefault, (const void **)&kCTFontLanguagesAttribute, 1, &kCFTypeSetCallBacks);
657 CFArrayRef descs = CTFontDescriptorCreateMatchingFontDescriptors(lang_desc, mandatory_attribs);
658 CFRelease(mandatory_attribs);
659 CFRelease(lang_desc);
661 for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs); i++) {
662 CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i);
664 /* Get font traits. */
665 CFDictionaryRef traits = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
666 CTFontSymbolicTraits symbolic_traits;
667 CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
668 CFRelease(traits);
670 /* Skip symbol fonts and vertical fonts. */
671 if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
672 /* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
673 if (symbolic_traits & kCTFontBoldTrait) continue;
674 /* Select monospaced fonts if asked for. */
675 if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
677 /* Get font name. */
678 char name[128];
679 CFStringRef font_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
680 CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
681 CFRelease(font_name);
683 /* There are some special fonts starting with an '.' and the last
684 * resort font that aren't usable. Skip them. */
685 if (name[0] == '.' || strncmp(name, "LastResort", 10) == 0) continue;
687 /* Save result. */
688 SetFontNames (settings, name, callback);
689 if (!callback->FindMissingGlyphs()) {
690 DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name);
691 result = true;
692 break;
695 if (descs != NULL) CFRelease(descs);
696 } else
697 #endif
699 /* Create a font iterator and iterate over all fonts that
700 * are available to the application. */
701 ATSFontIterator itr;
702 ATSFontRef font;
703 ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsDefaultScope, &itr);
704 while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
705 /* Get font name. */
706 char name[128];
707 CFStringRef font_name;
708 ATSFontGetName(font, kATSOptionFlagsDefault, &font_name);
709 CFStringGetCString(font_name, name, lengthof(name), kCFStringEncodingUTF8);
711 bool monospace = IsMonospaceFont(font_name);
712 CFRelease(font_name);
714 /* Select monospaced fonts if asked for. */
715 if (monospace != callback->Monospace()) continue;
717 /* We only want the base font and not bold or italic variants. */
718 if (strstr(name, "Italic") != NULL || strstr(name, "Bold")) continue;
720 /* Skip some inappropriate or ugly looking fonts that have better alternatives. */
721 if (name[0] == '.' || strncmp(name, "Apple Symbols", 13) == 0 || strncmp(name, "LastResort", 10) == 0) continue;
723 /* Save result. */
724 SetFontNames (settings, name, callback);
725 if (!callback->FindMissingGlyphs()) {
726 DEBUG(freetype, 2, "ATS-Font for %s: %s", language_isocode, name);
727 result = true;
728 break;
731 ATSFontIteratorRelease(&itr);
734 if (!result) {
735 /* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
736 * supports. If we didn't find any other font, just try it, maybe we get lucky. */
737 SetFontNames (settings, "Arial Unicode MS", callback);
738 result = !callback->FindMissingGlyphs();
741 callback->FindMissingGlyphs();
742 return result;
745 #elif defined(WITH_FONTCONFIG) /* end ifdef __APPLE__ */
747 #include <fontconfig/fontconfig.h>
749 /* ========================================================================================
750 * FontConfig (unix) support
751 * ======================================================================================== */
753 static FT_Error GetFontByFaceName (const char *font_name, FT_Face *face)
755 if (!FcInit()) {
756 ShowInfoF("Unable to load font configuration");
757 return FT_Err_Cannot_Open_Resource;
760 /* Split & strip the font's style */
761 char *font_family = xstrdup (font_name);
762 char *font_style = strchr (font_family, ',');
763 if (font_style != NULL) {
764 font_style[0] = '\0';
765 font_style++;
766 while (*font_style == ' ' || *font_style == '\t') font_style++;
769 /* Resolve the name and populate the information structure */
770 FcPattern *pat = FcNameParse ((FcChar8*)font_family);
771 if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
772 FcConfigSubstitute(0, pat, FcMatchPattern);
773 FcDefaultSubstitute(pat);
774 FcFontSet *fs = FcFontSetCreate();
775 FcResult result;
776 FcPattern *match = FcFontMatch (0, pat, &result);
778 FT_Error err = FT_Err_Cannot_Open_Resource;
779 if (fs != NULL && match != NULL) {
780 int i;
781 FcChar8 *family;
782 FcChar8 *style;
783 FcChar8 *file;
784 FcFontSetAdd(fs, match);
786 for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
787 /* Try the new filename */
788 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
789 FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
790 FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
792 /* The correct style? */
793 if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue;
795 /* Font config takes the best shot, which, if the family name is spelled
796 * wrongly a 'random' font, so check whether the family name is the
797 * same as the supplied name */
798 if (strcasecmp(font_family, (char*)family) == 0) {
799 err = FT_New_Face(_library, (char *)file, 0, face);
805 free(font_family);
806 FcPatternDestroy(pat);
807 FcFontSetDestroy(fs);
808 FcFini();
810 return err;
813 bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
815 if (!FcInit()) return false;
817 bool ret = false;
819 /* Fontconfig doesn't handle full language isocodes, only the part
820 * before the _ of e.g. en_GB is used, so "remove" everything after
821 * the _. */
822 char lang[16];
823 bstrfmt (lang, ":lang=%s", language_isocode);
824 char *split = strchr(lang, '_');
825 if (split != NULL) *split = '\0';
827 /* First create a pattern to match the wanted language. */
828 FcPattern *pat = FcNameParse((FcChar8*)lang);
829 /* We only want to know the filename. */
830 FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SPACING, FC_SLANT, FC_WEIGHT, NULL);
831 /* Get the list of filenames matching the wanted language. */
832 FcFontSet *fs = FcFontList(NULL, pat, os);
834 /* We don't need these anymore. */
835 FcObjectSetDestroy(os);
836 FcPatternDestroy(pat);
838 if (fs != NULL) {
839 int best_weight = -1;
840 const char *best_font = NULL;
842 for (int i = 0; i < fs->nfont; i++) {
843 FcPattern *font = fs->fonts[i];
845 FcChar8 *file = NULL;
846 FcResult res = FcPatternGetString(font, FC_FILE, 0, &file);
847 if (res != FcResultMatch || file == NULL) {
848 continue;
851 /* Get a font with the right spacing .*/
852 int value = 0;
853 FcPatternGetInteger(font, FC_SPACING, 0, &value);
854 if (callback->Monospace() != (value == FC_MONO) && value != FC_DUAL) continue;
856 /* Do not use those that explicitly say they're slanted. */
857 FcPatternGetInteger(font, FC_SLANT, 0, &value);
858 if (value != 0) continue;
860 /* We want the fatter font as they look better at small sizes. */
861 FcPatternGetInteger(font, FC_WEIGHT, 0, &value);
862 if (value <= best_weight) continue;
864 SetFontNames (settings, (const char*)file, callback);
866 bool missing = callback->FindMissingGlyphs();
867 DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no");
869 if (!missing) {
870 best_weight = value;
871 best_font = (const char *)file;
875 if (best_font != NULL) {
876 ret = true;
877 SetFontNames (settings, best_font, callback);
878 InitFreeType(callback->Monospace());
881 /* Clean up the list of filenames. */
882 FcFontSetDestroy(fs);
885 FcFini();
886 return ret;
889 #else /* without WITH_FONTCONFIG */
891 static inline FT_Error GetFontByFaceName (const char *font_name, FT_Face *face)
893 return FT_Err_Cannot_Open_Resource;
896 bool SetFallbackFont (FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
898 return false;
901 #endif /* WITH_FONTCONFIG */
904 * Loads the freetype font.
905 * First type to load the fontname as if it were a path. If that fails,
906 * try to resolve the filename of the font using fontconfig, where the
907 * format is 'font family name' or 'font family name, font style'.
909 void FontCache::LoadFreeTypeFont (void)
911 this->UnloadFreeTypeFont();
913 assert (this->face == NULL);
914 assert (this->font_tables.Length() == 0);
916 FontSize fs = this->fs;
917 FreeTypeSubSetting *settings = GetFreeTypeSettings (fs);
919 if (StrEmpty(settings->font)) return;
921 if (_library == NULL) {
922 if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
923 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
924 return;
927 DEBUG(freetype, 2, "Initialized");
930 FT_Face face = NULL;
931 FT_Error err = FT_New_Face (_library, settings->font, 0, &face);
933 if (err != FT_Err_Ok) err = GetFontByFaceName (settings->font, &face);
935 if (err == FT_Err_Ok) {
936 DEBUG(freetype, 2, "Requested '%s', using '%s %s'", settings->font, face->family_name, face->style_name);
938 /* Attempt to select the unicode character map */
939 err = FT_Select_Charmap (face, ft_encoding_unicode);
940 if (err == FT_Err_Ok) goto found_face; // Success
942 if (err == FT_Err_Invalid_CharMap_Handle) {
943 /* Try to pick a different character map instead. We default to
944 * the first map, but platform_id 0 encoding_id 0 should also
945 * be unicode (strange system...) */
946 FT_CharMap found = face->charmaps[0];
947 int i;
949 for (i = 0; i < face->num_charmaps; i++) {
950 FT_CharMap charmap = face->charmaps[i];
951 if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
952 found = charmap;
956 if (found != NULL) {
957 err = FT_Set_Charmap (face, found);
958 if (err == FT_Err_Ok) goto found_face;
963 FT_Done_Face(face);
965 static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" };
966 ShowInfoF ("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->font, SIZE_TO_NAME[fs], err);
967 return;
969 found_face:
970 assert(face != NULL);
971 this->face = face;
973 int pixels = settings->size;
974 if (pixels == 0) {
975 /* Try to determine a good height based on the minimal height recommended by the font. */
976 pixels = _default_font_height[fs];
978 TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table (face, ft_sfnt_head);
979 if (head != NULL) {
980 /* Font height is minimum height plus the difference between the default
981 * height for this font size and the small size. */
982 int diff = _default_font_height[fs] - _default_font_height[FS_SMALL];
983 pixels = Clamp (min (head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[fs], MAX_FONT_SIZE);
987 err = FT_Set_Pixel_Sizes (face, 0, pixels);
988 if (err != FT_Err_Ok) {
990 /* Find nearest size to that requested */
991 FT_Bitmap_Size *bs = face->available_sizes;
992 int i = face->num_fixed_sizes;
993 if (i > 0) { // In pathetic cases one might get no fixed sizes at all.
994 int n = bs->height;
995 FT_Int chosen = 0;
996 for (; --i; bs++) {
997 if (abs (pixels - bs->height) >= abs (pixels - n)) continue;
998 n = bs->height;
999 chosen = face->num_fixed_sizes - i;
1002 /* Don't use FT_Set_Pixel_Sizes here - it might give us another
1003 * error, even though the size is available (FS#5885). */
1004 err = FT_Select_Size (face, chosen);
1008 if (err == FT_Err_Ok) {
1009 this->units_per_em = this->face->units_per_EM;
1010 this->ascender = this->face->size->metrics.ascender >> 6;
1011 this->descender = this->face->size->metrics.descender >> 6;
1012 this->height = this->ascender - this->descender;
1013 } else {
1014 /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
1015 DEBUG(freetype, 0, "Font size selection failed. Using FontCache defaults.");
1019 /** Unload the freetype font. */
1020 void FontCache::UnloadFreeTypeFont (void)
1022 if (this->face == NULL) return;
1024 this->ClearFontCache();
1026 for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) {
1027 free(iter->second.second);
1030 this->font_tables.Clear();
1032 FT_Done_Face(this->face);
1033 this->face = NULL;
1035 this->ResetFontMetrics();
1038 #endif /* WITH_FREETYPE */
1041 /** Reset cached glyphs. */
1042 void FontCache::ClearFontCache (void)
1044 #ifdef WITH_FREETYPE
1045 if (this->face == NULL) {
1046 this->ResetFontMetrics();
1047 } else {
1048 for (int i = 0; i < 256; i++) {
1049 if (this->sprite_map[i] == NULL) continue;
1051 for (int j = 0; j < 256; j++) {
1052 if (this->sprite_map[i][j].duplicate) continue;
1053 free (this->sprite_map[i][j].sprite);
1056 free (this->sprite_map[i]);
1057 this->sprite_map[i] = NULL;
1060 #else /* WITH_FREETYPE */
1061 this->ResetFontMetrics();
1062 #endif /* WITH_FREETYPE */
1064 Layouter::ResetFontCache(this->fs);
1068 #ifdef WITH_FREETYPE
1070 FontCache::GlyphEntry *FontCache::SetGlyphPtr (GlyphID key,
1071 Sprite *sprite, byte width, bool duplicate)
1073 if (this->sprite_map[GB(key, 8, 8)] == NULL) {
1074 DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs);
1075 this->sprite_map[GB(key, 8, 8)] = xcalloct<GlyphEntry>(256);
1078 DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs);
1079 GlyphEntry *p = &this->sprite_map[GB(key, 8, 8)][GB(key, 0, 8)];
1080 p->sprite = sprite;
1081 p->width = width;
1082 p->duplicate = duplicate;
1083 return p;
1086 static void *AllocateFont(size_t size)
1088 return xmalloc (size);
1091 /* Check if a glyph should be rendered with antialiasing */
1092 static bool GetFontAAState(FontSize size)
1094 /* AA is only supported for 32 bpp */
1095 if (Blitter::get()->GetScreenDepth() != 32) return false;
1096 return GetFreeTypeSettings(size)->aa;
1099 static Sprite *MakeBuiltinQuestionMark (void)
1101 /* The font misses the '?' character. Use built-in sprite.
1102 * Note: We cannot use the baseset as this also has to work
1103 * in the bootstrap GUI. */
1104 #define CPSET { 0, 0, 0, 0, 1 }
1105 #define CP___ { 0, 0, 0, 0, 0 }
1106 static Blitter::RawSprite::Pixel builtin_questionmark_data[10 * 8] = {
1107 CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___,
1108 CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___,
1109 CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___,
1110 CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___,
1111 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
1112 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
1113 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
1114 CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___,
1115 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
1116 CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___,
1118 #undef CPSET
1119 #undef CP___
1120 static const Blitter::RawSprite builtin_questionmark = {
1121 builtin_questionmark_data,
1122 10, // height
1123 8, // width
1124 0, // x_offs
1125 0, // y_offs
1128 Sprite *spr = Blitter::get()->Encode (&builtin_questionmark, true, AllocateFont);
1129 assert (spr != NULL);
1130 return spr;
1133 FontCache::GlyphEntry *FontCache::GetGlyphPtr (GlyphID key)
1135 /* Check for the glyph in our cache */
1136 GlyphEntry *p = this->sprite_map[GB(key, 8, 8)];
1137 if (p != NULL) {
1138 GlyphEntry *glyph = &p[GB(key, 0, 8)];
1139 if (glyph->sprite != NULL) return glyph;
1142 FT_GlyphSlot slot = this->face->glyph;
1144 bool aa = GetFontAAState(this->fs);
1146 if (key == 0) {
1147 GlyphID question_glyph = this->MapCharToGlyph('?');
1148 if (question_glyph == 0) {
1149 /* The font misses the '?' character. Use built-in sprite. */
1150 Sprite *spr = MakeBuiltinQuestionMark();
1151 return this->SetGlyphPtr (key, spr, spr->width + (this->fs != FS_NORMAL), false);
1152 } else {
1153 /* Use '?' for missing characters. */
1154 GlyphEntry *glyph = this->GetGlyphPtr (question_glyph);
1155 return this->SetGlyphPtr (key, glyph->sprite, glyph->width, true);
1158 FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT);
1159 FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
1161 /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
1162 aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1164 /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
1165 unsigned int width = max(1U, (unsigned int)slot->bitmap.width + (this->fs == FS_NORMAL));
1166 unsigned int height = max(1U, (unsigned int)slot->bitmap.rows + (this->fs == FS_NORMAL));
1168 /* Limit glyph size to prevent overflows later on. */
1169 if (width > 256 || height > 256) usererror("Font glyph is too large");
1171 /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it.
1172 * Use a static buffer to prevent repeated allocation/deallocation. */
1173 static ReusableBuffer <Blitter::RawSprite::Pixel> buffer;
1174 Blitter::RawSprite sprite;
1175 sprite.data = buffer.ZeroAllocate (width * height);
1176 sprite.width = width;
1177 sprite.height = height;
1178 sprite.x_offs = slot->bitmap_left;
1179 sprite.y_offs = this->ascender - slot->bitmap_top;
1181 /* Draw shadow for medium size */
1182 if (this->fs == FS_NORMAL && !aa) {
1183 for (unsigned int y = 0; y < (unsigned int)slot->bitmap.rows; y++) {
1184 for (unsigned int x = 0; x < (unsigned int)slot->bitmap.width; x++) {
1185 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
1186 sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
1187 sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
1193 for (unsigned int y = 0; y < (unsigned int)slot->bitmap.rows; y++) {
1194 for (unsigned int x = 0; x < (unsigned int)slot->bitmap.width; x++) {
1195 if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
1196 sprite.data[x + y * sprite.width].m = FACE_COLOUR;
1197 sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
1202 Sprite *spr = Blitter::get()->Encode (&sprite, true, AllocateFont);
1204 return this->SetGlyphPtr (key, spr, slot->advance.x >> 6);
1207 #endif /* WITH_FREETYPE */
1209 const Sprite *FontCache::GetGlyph (GlyphID key)
1211 #ifdef WITH_FREETYPE
1212 if ((this->face != NULL) && ((key & SPRITE_GLYPH) == 0)) {
1213 return this->GetGlyphPtr(key)->sprite;
1215 #endif /* WITH_FREETYPE */
1217 return GetSprite (this->GetGlyphSprite (key), ST_FONT);
1220 bool FontCache::GetDrawGlyphShadow (void) const
1222 #ifdef WITH_FREETYPE
1223 return this->fs == FS_NORMAL && GetFontAAState (FS_NORMAL);
1224 #else /* WITH_FREETYPE */
1225 return false;
1226 #endif /* WITH_FREETYPE */
1229 uint FontCache::GetGlyphWidth (GlyphID key)
1231 #ifdef WITH_FREETYPE
1232 if ((this->face != NULL) && ((key & SPRITE_GLYPH) == 0)) {
1233 return this->GetGlyphPtr(key)->width;
1235 #endif /* WITH_FREETYPE */
1237 SpriteID sprite = this->GetGlyphSprite (key);
1238 return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + ScaleGUITrad(this->fs != FS_NORMAL ? 1 : 0) : 0;
1241 GlyphID FontCache::MapCharToGlyph (WChar key) const
1243 assert(IsPrintable(key));
1245 #ifdef WITH_FREETYPE
1246 if ((this->face != NULL)
1247 && (key < SCC_SPRITE_START || key > SCC_SPRITE_END)) {
1248 return FT_Get_Char_Index (this->face, key);
1250 #endif /* WITH_FREETYPE */
1252 return SPRITE_GLYPH | key;
1255 const void *FontCache::GetFontTable (uint32 tag, size_t &length)
1257 #ifdef WITH_FREETYPE
1258 if (this->face != NULL) {
1259 const FontTable::iterator iter = this->font_tables.Find(tag);
1260 if (iter != this->font_tables.End()) {
1261 length = iter->second.first;
1262 return iter->second.second;
1265 FT_ULong len = 0;
1266 FT_Byte *result = NULL;
1268 FT_Load_Sfnt_Table (this->face, tag, 0, NULL, &len);
1270 if (len > 0) {
1271 result = xmalloct<FT_Byte>(len);
1272 FT_Load_Sfnt_Table (this->face, tag, 0, result, &len);
1274 length = len;
1276 this->font_tables.Insert (tag, SmallPair<size_t, const void *>(length, result));
1277 return result;
1279 #endif /* WITH_FREETYPE */
1281 length = 0;
1282 return NULL;
1285 const char *FontCache::GetFontName (void) const
1287 #ifdef WITH_FREETYPE
1288 if (this->face != NULL) return this->face->family_name;
1289 #endif /* WITH_FREETYPE */
1291 return "sprite";
1294 /** Compute the broadest n-digit value in this font. */
1295 uint64 FontCache::GetBroadestValue (uint n) const
1297 uint d = this->widest_digit;
1299 if (n <= 1) return d;
1301 uint64 val = this->widest_digit_nonnull;
1302 do {
1303 val = 10 * val + d;
1304 } while (--n > 1);
1305 return val;
1309 FontCache FontCache::cache [FS_END] = {
1310 FontCache (FS_NORMAL),
1311 FontCache (FS_SMALL),
1312 FontCache (FS_LARGE),
1313 FontCache (FS_MONO),
1317 #ifdef WITH_FREETYPE
1320 * (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
1321 * @param monospace Whether to initialise the monospace or regular fonts.
1323 void InitFreeType(bool monospace)
1325 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
1326 if (monospace != (fs == FS_MONO)) continue;
1327 FontCache::Get(fs)->LoadFreeTypeFont();
1332 * Free everything allocated w.r.t. fonts.
1334 void UninitFreeType()
1336 for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
1337 FontCache::Get(fs)->UnloadFreeTypeFont();
1340 FT_Done_FreeType(_library);
1341 _library = NULL;
1344 #endif /* WITH_FREETYPE */