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};
33 * Encapsulate accesses to FreeType. This allows us to declare a static
34 * handle below that will be autodestructed on program termination.
36 class TTDFreeTypeHandle
{
39 TTDFreeTypeHandle (const TTDFreeTypeHandle
&) DELETED
;
41 TTDFreeTypeHandle
& operator = (const TTDFreeTypeHandle
&) DELETED
;
44 CONSTEXPR
TTDFreeTypeHandle (void) : library (NULL
)
48 operator bool (void) const
50 return this->library
!= NULL
;
56 return FT_Init_FreeType (&this->library
) == FT_Err_Ok
;
62 FT_Done_FreeType (this->library
);
68 if (*this) this->done();
71 FT_Error
new_face (const char *path
, FT_Face
*face
, FT_Long index
= 0)
74 return FT_New_Face (this->library
, path
, index
, face
);
78 static TTDFreeTypeHandle library
;
80 FreeTypeSettings _freetype
;
82 static const byte FACE_COLOUR
= 1;
83 static const byte SHADOW_COLOUR
= 2;
85 #endif /* WITH_FREETYPE */
88 /** Rebuild the glyph width cache of the font. */
89 void FontCache::RebuildWidthCache (void)
91 for (uint i
= 0; i
!= 224; i
++) {
92 this->glyph_widths
[i
] = this->GetGlyphWidth (this->MapCharToGlyph (i
+ 32));
95 byte widest_digit
= 9;
96 byte digit_width
= this->glyph_widths
['9' - 32];
97 for (byte i
= 8; i
> 0; i
--) {
98 byte w
= this->glyph_widths
[i
+ '0' - 32];
99 if (w
> digit_width
) {
104 this->widest_digit_nonnull
= widest_digit
;
106 byte w
= this->glyph_widths
['0' - 32];
107 if (w
> digit_width
) {
111 this->widest_digit
= widest_digit
;
112 this->digit_width
= digit_width
;
115 /** Reset font metrics of the font. */
116 void FontCache::ResetFontMetrics (void)
118 FontSize fs
= this->fs
;
119 int height
= _default_font_height
[fs
];
120 int ascender
= _default_font_ascender
[fs
];
121 this->height
= ScaleGUITrad (height
);
122 this->ascender
= ScaleGUITrad (ascender
);
123 this->descender
= ScaleGUITrad (ascender
- height
);
124 this->units_per_em
= 1;
125 this->RebuildWidthCache();
129 * Create a new font cache.
130 * @param fs The size of the font.
132 FontCache::FontCache (FontSize fs
) :
134 missing_sprite (NULL
), font_tables(), face (NULL
),
135 #endif /* WITH_FREETYPE */
138 memset (this->spriteid_map
, 0, sizeof(this->spriteid_map
));
140 memset (this->sprite_map
, 0, sizeof(this->sprite_map
));
141 #endif /* WITH_FREETYPE */
143 this->ResetFontMetrics();
144 this->InitializeUnicodeGlyphMap();
147 /** Clean everything up. */
148 FontCache::~FontCache()
151 this->UnloadFreeTypeFont();
152 #endif /* WITH_FREETYPE */
153 this->ClearGlyphToSpriteMap();
158 * Get height of a character for a given font size.
159 * @param size Font size to get height of
160 * @return Height of characters in the given font (pixels)
162 int GetCharacterHeight(FontSize size
)
164 return FontCache::Get(size
)->GetHeight();
168 SpriteID
FontCache::GetUnicodeGlyph (GlyphID key
) const
170 SpriteID
*p
= this->spriteid_map
[GB(key
, 8, 8)];
171 return (p
== NULL
) ? 0 : p
[GB(key
, 0, 8)];
174 void FontCache::SetUnicodeGlyph (GlyphID key
, SpriteID sprite
)
176 SpriteID
**p
= &this->spriteid_map
[GB(key
, 8, 8)];
177 if (*p
== NULL
) *p
= xcalloct
<SpriteID
>(256);
178 (*p
)[GB(key
, 0, 8)] = sprite
;
181 void FontCache::InitializeUnicodeGlyphMap (void)
183 static const uint ASCII_LETTERSTART
= 32; ///< First printable ASCII letter.
185 /* Font sprites are contiguous and arranged by font size. */
186 static const uint delta
= 256 - ASCII_LETTERSTART
;
187 assert_compile (SPR_ASCII_SPACE_SMALL
== SPR_ASCII_SPACE
+ delta
);
188 assert_compile (SPR_ASCII_SPACE_BIG
== SPR_ASCII_SPACE
+ 2 * delta
);
190 /* Clear out existing glyph map if it exists */
191 this->ClearGlyphToSpriteMap();
193 assert_compile (FS_NORMAL
== 0);
194 assert_compile (FS_SMALL
== 1);
195 assert_compile (FS_LARGE
== 2);
196 assert_compile (FS_MONO
== 3);
198 /* (this->fs % 3) maps FS_MONO to FS_NORMAL. */
199 SpriteID base
= SPR_ASCII_SPACE
+ (this->fs
% 3) * delta
- ASCII_LETTERSTART
;
201 for (uint i
= ASCII_LETTERSTART
; i
< 256; i
++) {
202 SpriteID sprite
= base
+ i
;
203 if (!SpriteExists(sprite
)) continue;
204 this->SetUnicodeGlyph(i
, sprite
);
205 this->SetUnicodeGlyph(i
+ SCC_SPRITE_START
, sprite
);
208 /* Glyphs to be accessed through an SCC_* enum entry only. */
209 static const byte clear_list
[] = {
210 0xAA, // Feminine ordinal indicator / Down arrow
211 0xAC, // Not sign / Tick mark
212 0xAF, // Macron / Right arrow
213 0xB4, // Acute accent / Train symbol
214 0xB5, // Micro sign / Truck symbol
215 0xB6, // Pilcrow sign / Bus symbol
216 0xB7, // Middle dot / Aircraft symbol
217 0xB8, // Cedilla / Ship symbol
218 0xB9, // Superscript 1 / Superscript -1
219 0xBC, // One quarter / Small up arrow
220 0xBD, // One half / Small down arrow
223 for (uint i
= 0; i
< lengthof(clear_list
); i
++) {
224 this->SetUnicodeGlyph (clear_list
[i
], 0);
227 /* Default unicode mapping table for sprite based glyphs.
228 * This table allows us use unicode characters even though the glyphs
229 * don't exist, or are in the wrong place, in the standard sprite
230 * fonts. This is not used for FreeType rendering */
231 static const uint16 translation_map
[][2] = {
232 { 0x00A0, 0x20 }, // Non-breaking space / Up arrow
233 { 0x00AD, 0x20 }, // Soft hyphen / X mark
234 { 0x0178, 0x9F }, // Capital letter Y with diaeresis
235 { 0x010D, 0x63 }, // Small letter c with caron
238 for (uint i
= 0; i
< lengthof(translation_map
); i
++) {
239 WChar code
= translation_map
[i
][0];
240 byte key
= translation_map
[i
][1];
241 this->SetUnicodeGlyph (code
, base
+ key
);
246 * Clear the glyph to sprite mapping.
248 void FontCache::ClearGlyphToSpriteMap (void)
250 for (uint i
= 0; i
< 256; i
++) {
251 free (this->spriteid_map
[i
]);
252 this->spriteid_map
[i
] = NULL
;
256 SpriteID
FontCache::GetGlyphSprite (GlyphID key
) const
258 SpriteID sprite
= this->GetUnicodeGlyph(key
);
259 if (sprite
== 0) sprite
= this->GetUnicodeGlyph('?');
266 /** Get the FreeType settings struct for a given font size. */
267 static FreeTypeSubSetting
*GetFreeTypeSettings (FontSize fs
)
270 default: NOT_REACHED();
271 case FS_NORMAL
: return &_freetype
.medium
;
272 case FS_SMALL
: return &_freetype
.small
;
273 case FS_LARGE
: return &_freetype
.large
;
274 case FS_MONO
: return &_freetype
.mono
;
279 * Set the right font names.
280 * @param settings The settings to modify.
281 * @param font_name The new font name.
282 * @param searcher The searcher that says whether we are dealing with a monospaced font.
284 static void SetFontNames (FreeTypeSettings
*settings
, const char *font_name
,
285 const MissingGlyphSearcher
*searcher
)
287 if (searcher
->Monospace()) {
288 bstrcpy (settings
->mono
.font
, font_name
);
290 bstrcpy (settings
->small
.font
, font_name
);
291 bstrcpy (settings
->medium
.font
, font_name
);
292 bstrcpy (settings
->large
.font
, font_name
);
297 * Get the font loaded into a Freetype face by using a font-name.
298 * If no appropriate font is found, the function returns an error.
303 /* ========================================================================================
305 * ======================================================================================== */
308 #include "core/pointer.h"
309 #include "core/alloc_func.hpp"
311 #include <shlobj.h> /* SHGetFolderPath */
312 #include "os/windows/win32.h"
315 * Get the short DOS 8.3 format for paths.
316 * FreeType doesn't support Unicode filenames and Windows' fopen (as used
317 * by FreeType) doesn't support UTF-8 filenames. So we have to convert the
318 * filename into something that isn't UTF-8 but represents the Unicode file
319 * name. This is the short DOS 8.3 format. This does not contain any
320 * characters that fopen doesn't support.
321 * @param long_path the path in system encoding.
322 * @return the short path in ANSI (ASCII).
324 static const char *GetShortPath (const TCHAR
*long_path
)
326 static char short_path
[MAX_PATH
];
328 WCHAR short_path_w
[MAX_PATH
];
329 GetShortPathName(long_path
, short_path_w
, lengthof(short_path_w
));
330 WideCharToMultiByte(CP_ACP
, 0, short_path_w
, -1, short_path
, lengthof(short_path
), NULL
, NULL
);
332 /* Technically not needed, but do it for consistency. */
333 GetShortPathName(long_path
, short_path
, lengthof(short_path
));
338 /* Get the font file to be loaded into Freetype by looping the registry
339 * location where windows lists all installed fonts. Not very nice, will
340 * surely break if the registry path changes, but it works. Much better
341 * solution would be to use CreateFont, and extract the font data from it
342 * by GetFontData. The problem with this is that the font file needs to be
343 * kept in memory then until the font is no longer needed. This could mean
344 * an additional memory usage of 30MB (just for fonts!) when using an eastern
345 * font for all font sizes */
346 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
347 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
348 static FT_Error
GetFontByFaceName (const char *font_name
, const char *alt_name
, FT_Face
*face
)
350 FT_Error err
= FT_Err_Cannot_Open_Resource
;
353 TCHAR vbuffer
[MAX_PATH
], dbuffer
[256];
355 const char *font_path
;
359 /* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
360 * "Windows NT" key, on Windows 9x in the Windows key. To save us having
361 * to retrieve the windows version, we'll just query both */
362 ret
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T(FONT_DIR_NT
), 0, KEY_READ
, &hKey
);
363 if (ret
!= ERROR_SUCCESS
) ret
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, _T(FONT_DIR_9X
), 0, KEY_READ
, &hKey
);
365 if (ret
!= ERROR_SUCCESS
) {
366 DEBUG(freetype
, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
370 /* Convert font name to file system encoding. */
371 TCHAR
*font_namep
= _tcsdup(OTTD2FS(font_name
));
373 for (index
= 0;; index
++) {
375 DWORD vbuflen
= lengthof(vbuffer
);
376 DWORD dbuflen
= lengthof(dbuffer
);
378 ret
= RegEnumValue(hKey
, index
, vbuffer
, &vbuflen
, NULL
, NULL
, (byte
*)dbuffer
, &dbuflen
);
379 if (ret
!= ERROR_SUCCESS
) goto registry_no_font_found
;
381 /* The font names in the registry are of the following 3 forms:
383 * - Book Antiqua Bold (TrueType)
384 * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType)
385 * We will strip the font-type '()' if any and work with the font name
386 * itself, which must match exactly; if...
387 * TTC files, font files which contain more than one font are separated
388 * by '&'. Our best bet will be to do substr match for the fontname
389 * and then let FreeType figure out which index to load */
390 s
= _tcschr(vbuffer
, _T('('));
391 if (s
!= NULL
) s
[-1] = '\0';
393 if (_tcschr(vbuffer
, _T('&')) == NULL
) {
394 if (_tcsicmp(vbuffer
, font_namep
) == 0) break;
396 if (_tcsstr(vbuffer
, font_namep
) != NULL
) break;
400 if (!SUCCEEDED(OTTDSHGetFolderPath(NULL
, CSIDL_FONTS
, NULL
, SHGFP_TYPE_CURRENT
, vbuffer
))) {
401 DEBUG(freetype
, 0, "SHGetFolderPath cannot return fonts directory");
405 /* Some fonts are contained in .ttc files, TrueType Collection fonts. These
406 * contain multiple fonts inside this single file. GetFontData however
407 * returns the whole file, so we need to check each font inside to get the
409 path_len
= _tcslen(vbuffer
) + _tcslen(dbuffer
) + 2; // '\' and terminating nul.
410 pathbuf
= AllocaM(TCHAR
, path_len
);
411 _sntprintf(pathbuf
, path_len
, _T("%s\\%s"), vbuffer
, dbuffer
);
413 /* Convert the path into something that FreeType understands. */
414 font_path
= GetShortPath(pathbuf
);
418 err
= library
.new_face (font_path
, face
, index
);
419 if (err
!= FT_Err_Ok
) break;
421 if (strncasecmp(font_name
, (*face
)->family_name
, strlen((*face
)->family_name
)) == 0) break;
422 /* Try english name if font name failed */
423 if (alt_name
!= NULL
&& strncasecmp(alt_name
, (*face
)->family_name
, strlen((*face
)->family_name
)) == 0) break;
424 err
= FT_Err_Cannot_Open_Resource
;
426 } while ((FT_Long
)++index
!= (*face
)->num_faces
);
430 registry_no_font_found
:
436 static FT_Error
GetFontByFaceName (const char *font_name
, FT_Face
*face
)
438 return GetFontByFaceName (font_name
, NULL
, face
);
442 * Get the English font name for a buffer of font data (see below).
443 * @param buf the buffer with the font data
444 * @param len the length of the buffer
445 * @param fontname the buffer where to store the English name
446 * @return whether the name was found
448 static bool GetEnglishFontName (const byte
*buf
, size_t len
,
449 char (&fontname
) [MAX_PATH
])
451 if (len
< 6) return NULL
;
453 if ((buf
[0] != 0) || (buf
[1] != 0)) return NULL
;
455 uint count
= (buf
[2] << 8) + buf
[3];
456 if (count
> (len
- 6) / 12) return NULL
;
458 size_t data_offset
= (buf
[4] << 8) + buf
[5];
459 if (data_offset
> len
) return NULL
;
460 const byte
*data
= buf
+ data_offset
;
461 size_t data_len
= len
- data_offset
;
463 for (buf
+= 6; count
> 0; count
--, buf
+= 12) {
464 uint platform
= (buf
[0] << 8) + buf
[1];
465 /* ignore encoding (bytes 2 and 3) */
466 uint language
= (buf
[4] << 8) + buf
[5];
467 if ((platform
!= 1 || language
!= 0) && // Macintosh English
468 (platform
!= 3 || language
!= 0x0409)) { // Microsoft English (US)
472 uint name
= (buf
[6] << 8) + buf
[7];
473 if (name
!= 1) continue;
475 uint offset
= (buf
[10] << 8) + buf
[11];
476 if (offset
> data_len
) continue;
478 uint length
= (buf
[8] << 8) + buf
[9];
479 if (length
> (data_len
- offset
)) continue;
481 bstrfmt (fontname
, "%.*s", length
, data
+ offset
);
489 * Fonts can have localised names and when the system locale is the same as
490 * one of those localised names Windows will always return that localised name
491 * instead of allowing to get the non-localised (English US) name of the font.
492 * This will later on give problems as freetype uses the non-localised name of
493 * the font and we need to compare based on that name.
494 * Windows furthermore DOES NOT have an API to get the non-localised name nor
495 * can we override the system locale. This means that we have to actually read
496 * the font itself to gather the font name we want.
497 * Based on: http://blogs.msdn.com/michkap/archive/2006/02/13/530814.aspx
498 * @param logfont the font information to get the english name of.
499 * @param fontname the buffer where to store the English name
501 static void GetEnglishFontName (const ENUMLOGFONTEX
*logfont
,
502 char (&fontname
) [MAX_PATH
])
506 HFONT font
= CreateFontIndirect(&logfont
->elfLogFont
);
508 HDC dc
= GetDC (NULL
);
509 HGDIOBJ oldfont
= SelectObject (dc
, font
);
510 DWORD dw
= GetFontData (dc
, 'eman', 0, NULL
, 0);
511 if (dw
!= GDI_ERROR
) {
512 byte
*buf
= xmalloct
<byte
>(dw
);
513 if (GetFontData (dc
, 'eman', 0, buf
, dw
) != GDI_ERROR
) {
514 found
= GetEnglishFontName (buf
, dw
, fontname
);
518 SelectObject (dc
, oldfont
);
519 ReleaseDC (NULL
, dc
);
524 bstrcpy (fontname
, WIDE_TO_MB((const TCHAR
*)logfont
->elfFullName
));
529 FreeTypeSettings
*settings
;
530 LOCALESIGNATURE locale
;
531 MissingGlyphSearcher
*callback
;
532 std::vector
<ttd_unique_free_ptr
<TCHAR
> > fonts
;
535 static int CALLBACK
EnumFontCallback(const ENUMLOGFONTEX
*logfont
, const NEWTEXTMETRICEX
*metric
, DWORD type
, LPARAM lParam
)
537 EFCParam
*info
= (EFCParam
*)lParam
;
539 /* Skip duplicates */
540 const TCHAR
*fname
= (const TCHAR
*)logfont
->elfFullName
;
541 for (uint i
= 0; i
< info
->fonts
.size(); i
++) {
542 if (_tcscmp (info
->fonts
[i
].get(), fname
) == 0) return 1;
544 info
->fonts
.push_back (ttd_unique_free_ptr
<TCHAR
> (_tcsdup (fname
)));
545 /* Only use TrueType fonts */
546 if (!(type
& TRUETYPE_FONTTYPE
)) return 1;
547 /* Don't use SYMBOL fonts */
548 if (logfont
->elfLogFont
.lfCharSet
== SYMBOL_CHARSET
) return 1;
549 /* Use monospaced fonts when asked for it. */
550 if (info
->callback
->Monospace() && (logfont
->elfLogFont
.lfPitchAndFamily
& (FF_MODERN
| FIXED_PITCH
)) != (FF_MODERN
| FIXED_PITCH
)) return 1;
552 /* The font has to have at least one of the supported locales to be usable. */
553 if ((metric
->ntmFontSig
.fsCsb
[0] & info
->locale
.lsCsbSupported
[0]) == 0 && (metric
->ntmFontSig
.fsCsb
[1] & info
->locale
.lsCsbSupported
[1]) == 0) {
554 /* On win9x metric->ntmFontSig seems to contain garbage. */
556 memset(&fs
, 0, sizeof(fs
));
557 HFONT font
= CreateFontIndirect(&logfont
->elfLogFont
);
559 HDC dc
= GetDC(NULL
);
560 HGDIOBJ oldfont
= SelectObject(dc
, font
);
561 GetTextCharsetInfo(dc
, &fs
, 0);
562 SelectObject(dc
, oldfont
);
566 if ((fs
.fsCsb
[0] & info
->locale
.lsCsbSupported
[0]) == 0 && (fs
.fsCsb
[1] & info
->locale
.lsCsbSupported
[1]) == 0) return 1;
569 char font_name
[MAX_PATH
];
570 convert_from_fs (fname
, font_name
, lengthof(font_name
));
572 /* Add english name after font name */
573 char english_name
[MAX_PATH
];
574 GetEnglishFontName (logfont
, english_name
);
576 /* Check whether we can actually load the font. */
577 bool ft_init
= library
;
580 /* Init FreeType if needed. */
581 if ((ft_init
|| library
.init()) && GetFontByFaceName (font_name
, english_name
, &face
) == FT_Err_Ok
) {
586 /* Uninit FreeType if we did the init. */
590 if (!found
) return 1;
592 SetFontNames (info
->settings
, font_name
, info
->callback
);
593 if (info
->callback
->FindMissingGlyphs()) return 1;
594 DEBUG(freetype
, 1, "Fallback font: %s (%s)", font_name
, english_name
);
595 return 0; // stop enumerating
598 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
)
600 DEBUG(freetype
, 1, "Trying fallback fonts");
602 if (GetLocaleInfo(MAKELCID(winlangid
, SORT_DEFAULT
), LOCALE_FONTSIGNATURE
, (LPTSTR
)&langInfo
.locale
, sizeof(langInfo
.locale
) / sizeof(TCHAR
)) == 0) {
603 /* Invalid langid or some other mysterious error, can't determine fallback font. */
604 DEBUG(freetype
, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid
);
607 langInfo
.settings
= settings
;
608 langInfo
.callback
= callback
;
611 /* Enumerate all fonts. */
612 font
.lfCharSet
= DEFAULT_CHARSET
;
613 font
.lfFaceName
[0] = '\0';
614 font
.lfPitchAndFamily
= 0;
616 HDC dc
= GetDC(NULL
);
617 int ret
= EnumFontFamiliesEx(dc
, &font
, (FONTENUMPROC
)&EnumFontCallback
, (LPARAM
)&langInfo
, 0);
622 #elif defined(__APPLE__) /* end ifdef Win32 */
624 /* ========================================================================================
626 * ======================================================================================== */
628 #include "os/macosx/macos.h"
630 static FT_Error
GetFontByFaceName (const char *font_name
, FT_Face
*face
)
632 FT_Error err
= FT_Err_Cannot_Open_Resource
;
634 /* Get font reference from name. */
635 CFStringRef name
= CFStringCreateWithCString(kCFAllocatorDefault
, font_name
, kCFStringEncodingUTF8
);
636 ATSFontRef font
= ATSFontFindFromName(name
, kATSOptionFlagsDefault
);
638 if (font
== kInvalidFont
) return err
;
640 /* Get a file system reference for the font. */
642 OSStatus os_err
= -1;
643 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
644 if (MacOSVersionIsAtLeast(10, 5, 0)) {
645 os_err
= ATSFontGetFileReference(font
, &ref
);
649 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(__LP64__)
650 /* This type was introduced with the 10.5 SDK. */
651 #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
652 #define ATSFSSpec FSSpec
655 os_err
= ATSFontGetFileSpecification(font
, (ATSFSSpec
*)&spec
);
656 if (os_err
== noErr
) os_err
= FSpMakeFSRef(&spec
, &ref
);
660 if (os_err
== noErr
) {
661 /* Get unix path for file. */
662 UInt8 file_path
[PATH_MAX
];
663 if (FSRefMakePath(&ref
, file_path
, sizeof(file_path
)) == noErr
) {
664 DEBUG(freetype
, 3, "Font path for %s: %s", font_name
, file_path
);
665 err
= library
.new_face ((const char *)file_path
, face
);
672 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
)
676 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
677 if (MacOSVersionIsAtLeast(10, 5, 0)) {
678 /* Determine fallback font using CoreText. This uses the language isocode
679 * to find a suitable font. CoreText is available from 10.5 onwards. */
681 if (strcmp(language_isocode
, "zh_TW") == 0) {
682 /* Traditional Chinese */
683 bstrcpy (lang
, "zh-Hant");
684 } else if (strcmp(language_isocode
, "zh_CN") == 0) {
685 /* Simplified Chinese */
686 bstrcpy (lang
, "zh-Hans");
688 /* Just copy the first part of the isocode. */
689 bstrcpy (lang
, language_isocode
);
690 char *sep
= strchr(lang
, '_');
691 if (sep
!= NULL
) *sep
= '\0';
694 /* Create a font descriptor matching the wanted language and latin (english) glyphs. */
695 CFStringRef lang_codes
[2];
696 lang_codes
[0] = CFStringCreateWithCString(kCFAllocatorDefault
, lang
, kCFStringEncodingUTF8
);
697 lang_codes
[1] = CFSTR("en");
698 CFArrayRef lang_arr
= CFArrayCreate(kCFAllocatorDefault
, (const void **)lang_codes
, lengthof(lang_codes
), &kCFTypeArrayCallBacks
);
699 CFDictionaryRef lang_attribs
= CFDictionaryCreate(kCFAllocatorDefault
, (const void**)&kCTFontLanguagesAttribute
, (const void **)&lang_arr
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
700 CTFontDescriptorRef lang_desc
= CTFontDescriptorCreateWithAttributes(lang_attribs
);
702 CFRelease(lang_attribs
);
703 CFRelease(lang_codes
[0]);
705 /* Get array of all font descriptors for the wanted language. */
706 CFSetRef mandatory_attribs
= CFSetCreate(kCFAllocatorDefault
, (const void **)&kCTFontLanguagesAttribute
, 1, &kCFTypeSetCallBacks
);
707 CFArrayRef descs
= CTFontDescriptorCreateMatchingFontDescriptors(lang_desc
, mandatory_attribs
);
708 CFRelease(mandatory_attribs
);
709 CFRelease(lang_desc
);
711 for (CFIndex i
= 0; descs
!= NULL
&& i
< CFArrayGetCount(descs
); i
++) {
712 CTFontDescriptorRef font
= (CTFontDescriptorRef
)CFArrayGetValueAtIndex(descs
, i
);
714 /* Get font traits. */
715 CFDictionaryRef traits
= (CFDictionaryRef
)CTFontDescriptorCopyAttribute(font
, kCTFontTraitsAttribute
);
716 CTFontSymbolicTraits symbolic_traits
;
717 CFNumberGetValue((CFNumberRef
)CFDictionaryGetValue(traits
, kCTFontSymbolicTrait
), kCFNumberIntType
, &symbolic_traits
);
720 /* Skip symbol fonts and vertical fonts. */
721 if ((symbolic_traits
& kCTFontClassMaskTrait
) == (CTFontStylisticClass
)kCTFontSymbolicClass
|| (symbolic_traits
& kCTFontVerticalTrait
)) continue;
722 /* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
723 if (symbolic_traits
& kCTFontBoldTrait
) continue;
724 /* Select monospaced fonts if asked for. */
725 if (((symbolic_traits
& kCTFontMonoSpaceTrait
) == kCTFontMonoSpaceTrait
) != callback
->Monospace()) continue;
729 CFStringRef font_name
= (CFStringRef
)CTFontDescriptorCopyAttribute(font
, kCTFontDisplayNameAttribute
);
730 CFStringGetCString(font_name
, name
, lengthof(name
), kCFStringEncodingUTF8
);
731 CFRelease(font_name
);
733 /* There are some special fonts starting with an '.' and the last
734 * resort font that aren't usable. Skip them. */
735 if (name
[0] == '.' || strncmp(name
, "LastResort", 10) == 0) continue;
738 SetFontNames (settings
, name
, callback
);
739 if (!callback
->FindMissingGlyphs()) {
740 DEBUG(freetype
, 2, "CT-Font for %s: %s", language_isocode
, name
);
745 if (descs
!= NULL
) CFRelease(descs
);
749 /* Create a font iterator and iterate over all fonts that
750 * are available to the application. */
753 ATSFontIteratorCreate(kATSFontContextLocal
, NULL
, NULL
, kATSOptionFlagsDefaultScope
, &itr
);
754 while (!result
&& ATSFontIteratorNext(itr
, &font
) == noErr
) {
757 CFStringRef font_name
;
758 ATSFontGetName(font
, kATSOptionFlagsDefault
, &font_name
);
759 CFStringGetCString(font_name
, name
, lengthof(name
), kCFStringEncodingUTF8
);
761 bool monospace
= IsMonospaceFont(font_name
);
762 CFRelease(font_name
);
764 /* Select monospaced fonts if asked for. */
765 if (monospace
!= callback
->Monospace()) continue;
767 /* We only want the base font and not bold or italic variants. */
768 if (strstr(name
, "Italic") != NULL
|| strstr(name
, "Bold")) continue;
770 /* Skip some inappropriate or ugly looking fonts that have better alternatives. */
771 if (name
[0] == '.' || strncmp(name
, "Apple Symbols", 13) == 0 || strncmp(name
, "LastResort", 10) == 0) continue;
774 SetFontNames (settings
, name
, callback
);
775 if (!callback
->FindMissingGlyphs()) {
776 DEBUG(freetype
, 2, "ATS-Font for %s: %s", language_isocode
, name
);
781 ATSFontIteratorRelease(&itr
);
785 /* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
786 * supports. If we didn't find any other font, just try it, maybe we get lucky. */
787 SetFontNames (settings
, "Arial Unicode MS", callback
);
788 result
= !callback
->FindMissingGlyphs();
791 callback
->FindMissingGlyphs();
795 #elif defined(WITH_FONTCONFIG) /* end ifdef __APPLE__ */
797 #include <fontconfig/fontconfig.h>
799 /* ========================================================================================
800 * FontConfig (unix) support
801 * ======================================================================================== */
803 static FT_Error
GetFontByFaceName (const char *font_name
, FT_Face
*face
)
806 ShowInfoF("Unable to load font configuration");
807 return FT_Err_Cannot_Open_Resource
;
810 /* Split & strip the font's style */
811 char *font_family
= xstrdup (font_name
);
812 char *font_style
= strchr (font_family
, ',');
813 if (font_style
!= NULL
) {
814 font_style
[0] = '\0';
816 while (*font_style
== ' ' || *font_style
== '\t') font_style
++;
819 /* Resolve the name and populate the information structure */
820 FcPattern
*pat
= FcNameParse ((FcChar8
*)font_family
);
821 if (font_style
!= NULL
) FcPatternAddString(pat
, FC_STYLE
, (FcChar8
*)font_style
);
822 FcConfigSubstitute(0, pat
, FcMatchPattern
);
823 FcDefaultSubstitute(pat
);
824 FcFontSet
*fs
= FcFontSetCreate();
826 FcPattern
*match
= FcFontMatch (0, pat
, &result
);
828 FT_Error err
= FT_Err_Cannot_Open_Resource
;
829 if (fs
!= NULL
&& match
!= NULL
) {
834 FcFontSetAdd(fs
, match
);
836 for (i
= 0; err
!= FT_Err_Ok
&& i
< fs
->nfont
; i
++) {
837 /* Try the new filename */
838 if (FcPatternGetString(fs
->fonts
[i
], FC_FILE
, 0, &file
) == FcResultMatch
&&
839 FcPatternGetString(fs
->fonts
[i
], FC_FAMILY
, 0, &family
) == FcResultMatch
&&
840 FcPatternGetString(fs
->fonts
[i
], FC_STYLE
, 0, &style
) == FcResultMatch
) {
842 /* The correct style? */
843 if (font_style
!= NULL
&& strcasecmp(font_style
, (char*)style
) != 0) continue;
845 /* Font config takes the best shot, which, if the family name is spelled
846 * wrongly a 'random' font, so check whether the family name is the
847 * same as the supplied name */
848 if (strcasecmp(font_family
, (char*)family
) == 0) {
849 err
= library
.new_face ((char *)file
, face
);
856 FcPatternDestroy(pat
);
857 FcFontSetDestroy(fs
);
863 bool SetFallbackFont(FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
)
865 if (!FcInit()) return false;
869 /* Fontconfig doesn't handle full language isocodes, only the part
870 * before the _ of e.g. en_GB is used, so "remove" everything after
873 bstrfmt (lang
, ":lang=%s", language_isocode
);
874 char *split
= strchr(lang
, '_');
875 if (split
!= NULL
) *split
= '\0';
877 /* First create a pattern to match the wanted language. */
878 FcPattern
*pat
= FcNameParse((FcChar8
*)lang
);
879 /* We only want to know the filename. */
880 FcObjectSet
*os
= FcObjectSetBuild(FC_FILE
, FC_SPACING
, FC_SLANT
, FC_WEIGHT
, NULL
);
881 /* Get the list of filenames matching the wanted language. */
882 FcFontSet
*fs
= FcFontList(NULL
, pat
, os
);
884 /* We don't need these anymore. */
885 FcObjectSetDestroy(os
);
886 FcPatternDestroy(pat
);
889 int best_weight
= -1;
890 const char *best_font
= NULL
;
892 for (int i
= 0; i
< fs
->nfont
; i
++) {
893 FcPattern
*font
= fs
->fonts
[i
];
895 FcChar8
*file
= NULL
;
896 FcResult res
= FcPatternGetString(font
, FC_FILE
, 0, &file
);
897 if (res
!= FcResultMatch
|| file
== NULL
) {
901 /* Get a font with the right spacing .*/
903 FcPatternGetInteger(font
, FC_SPACING
, 0, &value
);
904 if (callback
->Monospace() != (value
== FC_MONO
) && value
!= FC_DUAL
) continue;
906 /* Do not use those that explicitly say they're slanted. */
907 FcPatternGetInteger(font
, FC_SLANT
, 0, &value
);
908 if (value
!= 0) continue;
910 /* We want the fatter font as they look better at small sizes. */
911 FcPatternGetInteger(font
, FC_WEIGHT
, 0, &value
);
912 if (value
<= best_weight
) continue;
914 SetFontNames (settings
, (const char*)file
, callback
);
916 bool missing
= callback
->FindMissingGlyphs();
917 DEBUG(freetype
, 1, "Font \"%s\" misses%s glyphs", file
, missing
? "" : " no");
921 best_font
= (const char *)file
;
925 if (best_font
!= NULL
) {
927 SetFontNames (settings
, best_font
, callback
);
928 InitFreeType(callback
->Monospace());
931 /* Clean up the list of filenames. */
932 FcFontSetDestroy(fs
);
939 #else /* without WITH_FONTCONFIG */
941 static inline FT_Error
GetFontByFaceName (const char *font_name
, FT_Face
*face
)
943 return FT_Err_Cannot_Open_Resource
;
946 bool SetFallbackFont (FreeTypeSettings
*settings
, const char *language_isocode
, int winlangid
, MissingGlyphSearcher
*callback
)
951 #endif /* WITH_FONTCONFIG */
954 * Loads the freetype font.
955 * First type to load the fontname as if it were a path. If that fails,
956 * try to resolve the filename of the font using fontconfig, where the
957 * format is 'font family name' or 'font family name, font style'.
959 void FontCache::LoadFreeTypeFont (void)
961 this->UnloadFreeTypeFont();
962 this->ResetFontMetrics();
964 assert (this->face
== NULL
);
965 assert (this->font_tables
.Length() == 0);
967 FontSize fs
= this->fs
;
968 FreeTypeSubSetting
*settings
= GetFreeTypeSettings (fs
);
970 if (StrEmpty(settings
->font
)) return;
973 if (!library
.init()) {
974 ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
978 DEBUG(freetype
, 2, "Initialized");
982 FT_Error err
= library
.new_face (settings
->font
, &face
);
984 if (err
!= FT_Err_Ok
) err
= GetFontByFaceName (settings
->font
, &face
);
986 if (err
== FT_Err_Ok
) {
987 DEBUG(freetype
, 2, "Requested '%s', using '%s %s'", settings
->font
, face
->family_name
, face
->style_name
);
989 /* Attempt to select the unicode character map */
990 err
= FT_Select_Charmap (face
, ft_encoding_unicode
);
991 if (err
== FT_Err_Ok
) goto found_face
; // Success
993 if (err
== FT_Err_Invalid_CharMap_Handle
) {
994 /* Try to pick a different character map instead. We default to
995 * the first map, but platform_id 0 encoding_id 0 should also
996 * be unicode (strange system...) */
997 FT_CharMap found
= face
->charmaps
[0];
1000 for (i
= 0; i
< face
->num_charmaps
; i
++) {
1001 FT_CharMap charmap
= face
->charmaps
[i
];
1002 if (charmap
->platform_id
== 0 && charmap
->encoding_id
== 0) {
1007 if (found
!= NULL
) {
1008 err
= FT_Set_Charmap (face
, found
);
1009 if (err
== FT_Err_Ok
) goto found_face
;
1016 static const char *SIZE_TO_NAME
[] = { "medium", "small", "large", "mono" };
1017 ShowInfoF ("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings
->font
, SIZE_TO_NAME
[fs
], err
);
1021 assert(face
!= NULL
);
1024 int pixels
= settings
->size
;
1026 /* Try to determine a good height based on the minimal height recommended by the font. */
1027 pixels
= _default_font_height
[fs
];
1029 TT_Header
*head
= (TT_Header
*)FT_Get_Sfnt_Table (face
, ft_sfnt_head
);
1031 /* Font height is minimum height plus the difference between the default
1032 * height for this font size and the small size. */
1033 int diff
= _default_font_height
[fs
] - _default_font_height
[FS_SMALL
];
1034 pixels
= Clamp (min (head
->Lowest_Rec_PPEM
, 20) + diff
, _default_font_height
[fs
], MAX_FONT_SIZE
);
1038 err
= FT_Set_Pixel_Sizes (face
, 0, pixels
);
1039 if (err
!= FT_Err_Ok
) {
1041 /* Find nearest size to that requested */
1042 FT_Bitmap_Size
*bs
= face
->available_sizes
;
1043 int i
= face
->num_fixed_sizes
;
1044 if (i
> 0) { // In pathetic cases one might get no fixed sizes at all.
1048 if (abs (pixels
- bs
->height
) >= abs (pixels
- n
)) continue;
1050 chosen
= face
->num_fixed_sizes
- i
;
1053 /* Don't use FT_Set_Pixel_Sizes here - it might give us another
1054 * error, even though the size is available (FS#5885). */
1055 err
= FT_Select_Size (face
, chosen
);
1059 if (err
== FT_Err_Ok
) {
1060 this->units_per_em
= this->face
->units_per_EM
;
1061 this->ascender
= this->face
->size
->metrics
.ascender
>> 6;
1062 this->descender
= this->face
->size
->metrics
.descender
>> 6;
1063 this->height
= this->ascender
- this->descender
;
1065 /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */
1066 DEBUG(freetype
, 0, "Font size selection failed. Using FontCache defaults.");
1070 /* *Clear the glyph cache. */
1071 void FontCache::ClearGlyphCache (void)
1073 this->missing_sprite
= NULL
;
1074 for (int i
= 0; i
< 256; i
++) {
1075 if (this->sprite_map
[i
] == NULL
) continue;
1077 for (int j
= 0; j
< 256; j
++) {
1078 free (this->sprite_map
[i
][j
].sprite
);
1081 free (this->sprite_map
[i
]);
1082 this->sprite_map
[i
] = NULL
;
1086 /** Unload the freetype font. */
1087 void FontCache::UnloadFreeTypeFont (void)
1089 if (this->face
== NULL
) return;
1091 this->ClearGlyphCache();
1093 for (FontTable::iterator iter
= this->font_tables
.Begin(); iter
!= this->font_tables
.End(); iter
++) {
1094 free(iter
->second
.second
);
1097 this->font_tables
.Clear();
1099 FT_Done_Face(this->face
);
1103 #endif /* WITH_FREETYPE */
1106 /** Reset cached glyphs. */
1107 void FontCache::ClearFontCache (void)
1109 #ifdef WITH_FREETYPE
1110 if (this->face
== NULL
) {
1111 this->ResetFontMetrics();
1113 this->ClearGlyphCache();
1114 this->RebuildWidthCache();
1116 #else /* WITH_FREETYPE */
1117 this->ResetFontMetrics();
1118 #endif /* WITH_FREETYPE */
1120 Layouter::ResetFontCache(this->fs
);
1124 #ifdef WITH_FREETYPE
1126 static void *AllocateFont(size_t size
)
1128 return xmalloc (size
);
1131 /* Check if a glyph should be rendered with antialiasing */
1132 static bool GetFontAAState(FontSize size
)
1134 /* AA is only supported for 32 bpp */
1135 if (Blitter::get()->screen_depth
!= 32) return false;
1136 return GetFreeTypeSettings(size
)->aa
;
1139 static Sprite
*MakeBuiltinQuestionMark (void)
1141 /* The font misses the '?' character. Use built-in sprite.
1142 * Note: We cannot use the baseset as this also has to work
1143 * in the bootstrap GUI. */
1144 #define CPSET { 0, 0, 0, 0, 1 }
1145 #define CP___ { 0, 0, 0, 0, 0 }
1146 static Blitter::RawSprite::Pixel builtin_questionmark_data
[10 * 8] = {
1147 CP___
, CP___
, CPSET
, CPSET
, CPSET
, CPSET
, CP___
, CP___
,
1148 CP___
, CPSET
, CPSET
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
1149 CP___
, CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
,
1150 CP___
, CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
,
1151 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
1152 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
1153 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
1154 CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
, CP___
,
1155 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
1156 CP___
, CP___
, CP___
, CPSET
, CPSET
, CP___
, CP___
, CP___
,
1160 static const Blitter::RawSprite builtin_questionmark
= {
1161 builtin_questionmark_data
,
1168 Sprite
*spr
= Blitter::get()->encode (&builtin_questionmark
, true, AllocateFont
);
1169 assert (spr
!= NULL
);
1173 /** Copy the pixels from a glyph rendered by FreeType into a RawSprite. */
1174 static inline void CopyGlyphPixels (Blitter::RawSprite::Pixel
*data
,
1175 uint width
, FT_GlyphSlot slot
, byte colour
, bool aa
= false)
1177 for (uint y
= 0; y
< (unsigned int)slot
->bitmap
.rows
; y
++) {
1178 for (uint x
= 0; x
< (unsigned int)slot
->bitmap
.width
; x
++) {
1179 byte a
= aa
? slot
->bitmap
.buffer
[x
+ y
* slot
->bitmap
.pitch
] :
1180 HasBit(slot
->bitmap
.buffer
[(x
/ 8) + y
* slot
->bitmap
.pitch
], 7 - (x
% 8)) ? 0xFF : 0;
1182 data
[x
+ y
* width
].m
= colour
;
1183 data
[x
+ y
* width
].a
= a
;
1189 const FontCache::GlyphEntry
*FontCache::GetGlyphPtr (GlyphID key
)
1192 const GlyphEntry
*glyph
= this->missing_sprite
;
1193 if (glyph
!= NULL
) return glyph
;
1195 GlyphID question_glyph
= this->MapCharToGlyph ('?');
1196 if (question_glyph
!= 0) {
1197 /* Use '?' for missing characters. */
1198 glyph
= this->GetGlyphPtr (question_glyph
);
1199 this->missing_sprite
= glyph
;
1203 /* The font misses the '?' character. We handle this below. */
1206 /* Check for the glyph in our cache */
1207 GlyphEntry
*p
= this->sprite_map
[GB(key
, 8, 8)];
1210 if (p
->sprite
!= NULL
) return p
;
1212 DEBUG(freetype
, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key
, 8, 8), this->fs
);
1213 p
= xcalloct
<GlyphEntry
>(256);
1214 this->sprite_map
[GB(key
, 8, 8)] = p
;
1218 DEBUG(freetype
, 4, "Set glyph for unicode character 0x%04X, size %u", key
, this->fs
);
1221 /* The font misses the '?' character. Use built-in sprite. */
1222 this->missing_sprite
= p
;
1223 Sprite
*spr
= MakeBuiltinQuestionMark();
1225 p
->width
= spr
->width
+ (this->fs
!= FS_NORMAL
);
1229 FT_GlyphSlot slot
= this->face
->glyph
;
1231 bool aa
= GetFontAAState(this->fs
);
1233 FT_Load_Glyph(this->face
, key
, FT_LOAD_DEFAULT
);
1234 FT_Render_Glyph(this->face
->glyph
, aa
? FT_RENDER_MODE_NORMAL
: FT_RENDER_MODE_MONO
);
1236 /* Despite requesting a normal glyph, FreeType may have returned a bitmap */
1237 aa
= (slot
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
);
1239 /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
1240 unsigned int width
= max(1U, (unsigned int)slot
->bitmap
.width
+ (this->fs
== FS_NORMAL
));
1241 unsigned int height
= max(1U, (unsigned int)slot
->bitmap
.rows
+ (this->fs
== FS_NORMAL
));
1243 /* Limit glyph size to prevent overflows later on. */
1244 if (width
> 256 || height
> 256) usererror("Font glyph is too large");
1246 /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it.
1247 * Use a static buffer to prevent repeated allocation/deallocation. */
1248 static ReusableBuffer
<Blitter::RawSprite::Pixel
> buffer
;
1249 Blitter::RawSprite sprite
;
1250 sprite
.data
= buffer
.ZeroAllocate (width
* height
);
1251 sprite
.width
= width
;
1252 sprite
.height
= height
;
1253 sprite
.x_offs
= slot
->bitmap_left
;
1254 sprite
.y_offs
= this->ascender
- slot
->bitmap_top
;
1256 /* Draw shadow for medium size */
1257 if (this->fs
== FS_NORMAL
&& !aa
) {
1258 CopyGlyphPixels (sprite
.data
+ width
+ 1, width
, slot
, SHADOW_COLOUR
);
1261 CopyGlyphPixels (sprite
.data
, width
, slot
, FACE_COLOUR
, aa
);
1263 p
->sprite
= Blitter::get()->encode (&sprite
, true, AllocateFont
);
1264 p
->width
= slot
->advance
.x
>> 6;
1268 #endif /* WITH_FREETYPE */
1270 const Sprite
*FontCache::GetGlyph (GlyphID key
)
1272 #ifdef WITH_FREETYPE
1273 if ((this->face
!= NULL
) && ((key
& SPRITE_GLYPH
) == 0)) {
1274 return this->GetGlyphPtr(key
)->sprite
;
1276 #endif /* WITH_FREETYPE */
1278 return GetSprite (this->GetGlyphSprite (key
), ST_FONT
);
1281 bool FontCache::GetDrawGlyphShadow (void) const
1283 #ifdef WITH_FREETYPE
1284 return this->fs
== FS_NORMAL
&& GetFontAAState (FS_NORMAL
);
1285 #else /* WITH_FREETYPE */
1287 #endif /* WITH_FREETYPE */
1290 uint
FontCache::GetGlyphWidth (GlyphID key
)
1292 #ifdef WITH_FREETYPE
1293 if ((this->face
!= NULL
) && ((key
& SPRITE_GLYPH
) == 0)) {
1294 return this->GetGlyphPtr(key
)->width
;
1296 #endif /* WITH_FREETYPE */
1298 SpriteID sprite
= this->GetGlyphSprite (key
);
1299 return SpriteExists(sprite
) ? GetSprite(sprite
, ST_FONT
)->width
+ ScaleGUITrad(this->fs
!= FS_NORMAL
? 1 : 0) : 0;
1302 GlyphID
FontCache::MapCharToGlyph (WChar key
) const
1304 assert(IsPrintable(key
));
1306 #ifdef WITH_FREETYPE
1307 if ((this->face
!= NULL
)
1308 && (key
< SCC_SPRITE_START
|| key
> SCC_SPRITE_END
)) {
1309 return FT_Get_Char_Index (this->face
, key
);
1311 #endif /* WITH_FREETYPE */
1313 return SPRITE_GLYPH
| key
;
1316 const void *FontCache::GetFontTable (uint32 tag
, size_t &length
)
1318 #ifdef WITH_FREETYPE
1319 if (this->face
!= NULL
) {
1320 const FontTable::iterator iter
= this->font_tables
.Find(tag
);
1321 if (iter
!= this->font_tables
.End()) {
1322 length
= iter
->second
.first
;
1323 return iter
->second
.second
;
1327 FT_Byte
*result
= NULL
;
1329 FT_Load_Sfnt_Table (this->face
, tag
, 0, NULL
, &len
);
1332 result
= xmalloct
<FT_Byte
>(len
);
1333 FT_Load_Sfnt_Table (this->face
, tag
, 0, result
, &len
);
1337 this->font_tables
.Insert (tag
, SmallPair
<size_t, const void *>(length
, result
));
1340 #endif /* WITH_FREETYPE */
1346 const char *FontCache::GetFontName (void) const
1348 #ifdef WITH_FREETYPE
1349 if (this->face
!= NULL
) return this->face
->family_name
;
1350 #endif /* WITH_FREETYPE */
1355 /** Compute the broadest n-digit value in this font. */
1356 uint64
FontCache::GetBroadestValue (uint n
) const
1358 uint d
= this->widest_digit
;
1360 if (n
<= 1) return d
;
1362 uint64 val
= this->widest_digit_nonnull
;
1370 FontCache
FontCache::cache
[FS_END
] = {
1371 FontCache (FS_NORMAL
),
1372 FontCache (FS_SMALL
),
1373 FontCache (FS_LARGE
),
1374 FontCache (FS_MONO
),
1378 #ifdef WITH_FREETYPE
1381 * (Re)initialize the freetype related things, i.e. load the non-sprite fonts.
1382 * @param monospace Whether to initialise the monospace or regular fonts.
1384 void InitFreeType(bool monospace
)
1386 for (FontSize fs
= FS_BEGIN
; fs
< FS_END
; fs
++) {
1387 if (monospace
!= (fs
== FS_MONO
)) continue;
1388 FontCache::Get(fs
)->LoadFreeTypeFont();
1392 #endif /* WITH_FREETYPE */