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/>.
8 /** @file font.cpp Cache for characters from fonts. */
13 #include "blitter/blitter.h"
14 #include "core/math_func.hpp"
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};
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
) {
66 this->widest_digit_nonnull
= widest_digit
;
68 byte w
= this->glyph_widths
['0' - 32];
69 if (w
> digit_width
) {
73 this->widest_digit
= widest_digit
;
74 this->digit_width
= digit_width
;
78 * Create a new font cache.
79 * @param fs The size of the font.
81 FontCache::FontCache (FontSize fs
) :
83 font_tables(), face (NULL
),
84 #endif /* WITH_FREETYPE */
87 memset (this->spriteid_map
, 0, sizeof(this->spriteid_map
));
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()
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('?');
215 /** Get the FreeType settings struct for a given font size. */
216 static FreeTypeSubSetting
*GetFreeTypeSettings (FontSize 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
);
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.
252 /* ========================================================================================
254 * ======================================================================================== */
257 #include "core/pointer.h"
258 #include "core/alloc_func.hpp"
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
];
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
);
281 /* Technically not needed, but do it for consistency. */
282 GetShortPathName(long_path
, short_path
, lengthof(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
;
302 TCHAR vbuffer
[MAX_PATH
], dbuffer
[256];
304 const char *font_path
;
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");
319 /* Convert font name to file system encoding. */
320 TCHAR
*font_namep
= _tcsdup(OTTD2FS(font_name
));
322 for (index
= 0;; index
++) {
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:
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;
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");
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
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
);
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
);
379 registry_no_font_found
:
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)
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
);
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
])
455 HFONT font
= CreateFontIndirect(&logfont
->elfLogFont
);
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
);
467 SelectObject (dc
, oldfont
);
468 ReleaseDC (NULL
, dc
);
473 bstrcpy (fontname
, WIDE_TO_MB((const TCHAR
*)logfont
->elfFullName
));
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. */
505 memset(&fs
, 0, sizeof(fs
));
506 HFONT font
= CreateFontIndirect(&logfont
->elfLogFont
);
508 HDC dc
= GetDC(NULL
);
509 HGDIOBJ oldfont
= SelectObject(dc
, font
);
510 GetTextCharsetInfo(dc
, &fs
, 0);
511 SelectObject(dc
, oldfont
);
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
;
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
) {
535 /* Uninit FreeType if we did the init. */
536 FT_Done_FreeType(_library
);
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");
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
);
557 langInfo
.settings
= settings
;
558 langInfo
.callback
= callback
;
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);
572 #elif defined(__APPLE__) /* end ifdef Win32 */
574 /* ========================================================================================
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
);
588 if (font
== kInvalidFont
) return err
;
590 /* Get a file system reference for the font. */
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
);
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
605 os_err
= ATSFontGetFileSpecification(font
, (ATSFSSpec
*)&spec
);
606 if (os_err
== noErr
) os_err
= FSpMakeFSRef(&spec
, &ref
);
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
);
622 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
)
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. */
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");
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
);
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
);
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;
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;
688 SetFontNames (settings
, name
, callback
);
689 if (!callback
->FindMissingGlyphs()) {
690 DEBUG(freetype
, 2, "CT-Font for %s: %s", language_isocode
, name
);
695 if (descs
!= NULL
) CFRelease(descs
);
699 /* Create a font iterator and iterate over all fonts that
700 * are available to the application. */
703 ATSFontIteratorCreate(kATSFontContextLocal
, NULL
, NULL
, kATSOptionFlagsDefaultScope
, &itr
);
704 while (!result
&& ATSFontIteratorNext(itr
, &font
) == noErr
) {
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;
724 SetFontNames (settings
, name
, callback
);
725 if (!callback
->FindMissingGlyphs()) {
726 DEBUG(freetype
, 2, "ATS-Font for %s: %s", language_isocode
, name
);
731 ATSFontIteratorRelease(&itr
);
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();
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
)
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';
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();
776 FcPattern
*match
= FcFontMatch (0, pat
, &result
);
778 FT_Error err
= FT_Err_Cannot_Open_Resource
;
779 if (fs
!= NULL
&& match
!= NULL
) {
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
);
806 FcPatternDestroy(pat
);
807 FcFontSetDestroy(fs
);
813 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
)
815 if (!FcInit()) return 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
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
);
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
) {
851 /* Get a font with the right spacing .*/
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");
871 best_font
= (const char *)file
;
875 if (best_font
!= NULL
) {
877 SetFontNames (settings
, best_font
, callback
);
878 InitFreeType(callback
->Monospace());
881 /* Clean up the list of filenames. */
882 FcFontSetDestroy(fs
);
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
)
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");
927 DEBUG(freetype
, 2, "Initialized");
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];
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) {
957 err
= FT_Set_Charmap (face
, found
);
958 if (err
== FT_Err_Ok
) goto found_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
);
970 assert(face
!= NULL
);
973 int pixels
= settings
->size
;
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
);
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.
997 if (abs (pixels
- bs
->height
) >= abs (pixels
- n
)) continue;
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
;
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
);
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();
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)];
1082 p
->duplicate
= duplicate
;
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___
,
1120 static const Blitter::RawSprite builtin_questionmark
= {
1121 builtin_questionmark_data
,
1128 Sprite
*spr
= Blitter::get()->Encode (&builtin_questionmark
, true, AllocateFont
);
1129 assert (spr
!= NULL
);
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)];
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
);
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);
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 */
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
;
1266 FT_Byte
*result
= NULL
;
1268 FT_Load_Sfnt_Table (this->face
, tag
, 0, NULL
, &len
);
1271 result
= xmalloct
<FT_Byte
>(len
);
1272 FT_Load_Sfnt_Table (this->face
, tag
, 0, result
, &len
);
1276 this->font_tables
.Insert (tag
, SmallPair
<size_t, const void *>(length
, result
));
1279 #endif /* WITH_FREETYPE */
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 */
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
;
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
);
1344 #endif /* WITH_FREETYPE */