20 extern FT_Library _library;
50 const char *GetShortPath(
const TCHAR *long_path)
52 static char short_path[MAX_PATH];
54 WCHAR short_path_w[MAX_PATH];
55 GetShortPathName(long_path, short_path_w,
lengthof(short_path_w));
56 WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path,
lengthof(short_path), NULL, NULL);
59 GetShortPathName(long_path, short_path,
lengthof(short_path));
72 #define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" 73 #define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts" 76 FT_Error err = FT_Err_Cannot_Open_Resource;
79 TCHAR vbuffer[MAX_PATH], dbuffer[256];
81 const char *font_path;
88 ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
89 if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
91 if (ret != ERROR_SUCCESS) {
92 DEBUG(freetype, 0,
"Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
97 TCHAR *font_namep = _tcsdup(
OTTD2FS(font_name));
99 for (index = 0;; index++) {
104 ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen);
105 if (ret != ERROR_SUCCESS)
goto registry_no_font_found;
116 s = _tcschr(vbuffer, _T(
'('));
117 if (s != NULL) s[-1] =
'\0';
119 if (_tcschr(vbuffer, _T(
'&')) == NULL) {
120 if (_tcsicmp(vbuffer, font_namep) == 0)
break;
122 if (_tcsstr(vbuffer, font_namep) != NULL)
break;
126 if (!SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) {
127 DEBUG(freetype, 0,
"SHGetFolderPath cannot return fonts directory");
135 path_len = _tcslen(vbuffer) + _tcslen(dbuffer) + 2;
136 pathbuf =
AllocaM(TCHAR, path_len);
137 _sntprintf(pathbuf, path_len, _T(
"%s\\%s"), vbuffer, dbuffer);
140 font_path = GetShortPath(pathbuf);
144 err = FT_New_Face(_library, font_path, index, face);
145 if (err != FT_Err_Ok)
break;
147 if (strncasecmp(font_name, (*face)->family_name, strlen((*face)->family_name)) == 0)
break;
149 if (strncasecmp(font_name + strlen(font_name) + 1, (*face)->family_name, strlen((*face)->family_name)) == 0)
break;
150 err = FT_Err_Cannot_Open_Resource;
152 }
while ((FT_Long)++index != (*face)->num_faces);
156 registry_no_font_found:
175 static const char *GetEnglishFontName(
const ENUMLOGFONTEX *logfont)
177 static char font_name[MAX_PATH];
178 const char *ret_font_name = NULL;
184 uint16 format, count, stringOffset, platformId, encodingId, languageId, nameId, length, offset;
186 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
187 if (font == NULL)
goto err1;
190 oldfont = SelectObject(dc, font);
191 dw = GetFontData(dc,
'eman', 0, NULL, 0);
192 if (dw == GDI_ERROR)
goto err2;
194 buf = MallocT<byte>(dw);
195 dw = GetFontData(dc,
'eman', 0, buf, dw);
196 if (dw == GDI_ERROR)
goto err3;
198 format = buf[pos++] << 8;
199 format += buf[pos++];
201 count = buf[pos++] << 8;
203 stringOffset = buf[pos++] << 8;
204 stringOffset += buf[pos++];
205 for (uint i = 0; i < count; i++) {
206 platformId = buf[pos++] << 8;
207 platformId += buf[pos++];
208 encodingId = buf[pos++] << 8;
209 encodingId += buf[pos++];
210 languageId = buf[pos++] << 8;
211 languageId += buf[pos++];
212 nameId = buf[pos++] << 8;
213 nameId += buf[pos++];
218 length = buf[pos++] << 8;
219 length += buf[pos++];
220 offset = buf[pos++] << 8;
221 offset += buf[pos++];
224 length =
min(length, MAX_PATH - 1);
225 for (uint j = 0; j < length; j++) font_name[j] = buf[stringOffset + offset + j];
226 font_name[length] =
'\0';
228 if ((platformId == 1 && languageId == 0) ||
229 (platformId == 3 && languageId == 0x0409)) {
230 ret_font_name = font_name;
238 SelectObject(dc, oldfont);
242 return ret_font_name == NULL ? WIDE_TO_MB((
const TCHAR*)logfont->elfFullName) : ret_font_name;
252 FontList() : fonts(NULL), items(0), capacity(0) { };
255 if (this->fonts == NULL)
return;
257 for (uint i = 0; i < this->items; i++) {
258 free(this->fonts[i]);
264 bool Add(
const TCHAR *font) {
265 for (uint i = 0; i < this->items; i++) {
266 if (_tcscmp(this->fonts[i], font) == 0)
return false;
269 if (this->items == this->capacity) {
270 this->capacity += 10;
271 this->fonts =
ReallocT(this->fonts, this->capacity);
274 this->fonts[this->items++] = _tcsdup(font);
282 LOCALESIGNATURE locale;
287 static int CALLBACK EnumFontCallback(
const ENUMLOGFONTEX *logfont,
const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
289 EFCParam *info = (EFCParam *)lParam;
292 if (!info->fonts.Add((
const TCHAR*)logfont->elfFullName))
return 1;
294 if (!(type & TRUETYPE_FONTTYPE))
return 1;
296 if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET)
return 1;
298 if (info->callback->Monospace() && (logfont->elfLogFont.lfPitchAndFamily & (FF_MODERN | FIXED_PITCH)) != (FF_MODERN | FIXED_PITCH))
return 1;
301 if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
304 memset(&fs, 0,
sizeof(fs));
305 HFONT font = CreateFontIndirect(&logfont->elfLogFont);
307 HDC dc = GetDC(NULL);
308 HGDIOBJ oldfont = SelectObject(dc, font);
309 GetTextCharsetInfo(dc, &fs, 0);
310 SelectObject(dc, oldfont);
314 if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0)
return 1;
317 char font_name[MAX_PATH];
321 const char *english_name = GetEnglishFontName(logfont);
322 strecpy(font_name + strlen(font_name) + 1, english_name,
lastof(font_name));
325 bool ft_init = _library != NULL;
329 if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) &&
GetFontByFaceName(font_name, &face) == FT_Err_Ok) {
335 FT_Done_FreeType(_library);
339 if (!found)
return 1;
341 info->callback->SetFontNames(info->settings, font_name);
342 if (info->callback->FindMissingGlyphs(NULL))
return 1;
343 DEBUG(freetype, 1,
"Fallback font: %s (%s)", font_name, english_name);
349 DEBUG(freetype, 1,
"Trying fallback fonts");
351 if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale,
sizeof(langInfo.locale) /
sizeof(TCHAR)) == 0) {
353 DEBUG(freetype, 1,
"Can't get locale info for fallback font (langid=0x%x)", winlangid);
357 langInfo.callback = callback;
361 font.lfCharSet = DEFAULT_CHARSET;
362 font.lfFaceName[0] =
'\0';
363 font.lfPitchAndFamily = 0;
365 HDC dc = GetDC(NULL);
366 int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
371 #elif defined(__APPLE__) 382 FT_Error err = FT_Err_Cannot_Open_Resource;
386 OSStatus os_err = -1;
387 CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, font_name, kCFStringEncodingUTF8);
389 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) 395 CTFontDescriptorRef name_desc = CTFontDescriptorCreateWithNameAndSize(name, 0.0);
396 CFSetRef mandatory_attribs = CFSetCreate(kCFAllocatorDefault, (
const void **)&kCTFontNameAttribute, 1, &kCFTypeSetCallBacks);
397 CFArrayRef descs = CTFontDescriptorCreateMatchingFontDescriptors(name_desc, mandatory_attribs);
398 CFRelease(mandatory_attribs);
399 CFRelease(name_desc);
403 for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs) && os_err != noErr; i++) {
404 CTFontRef font = CTFontCreateWithFontDescriptor((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i), 0.0, NULL);
405 CFURLRef fontURL = (CFURLRef)CTFontCopyAttribute(font, kCTFontURLAttribute);
406 if (CFURLGetFileSystemRepresentation(fontURL,
true, file_path,
lengthof(file_path))) os_err = noErr;
410 if (descs != NULL) CFRelease(descs);
414 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6) 415 ATSFontRef font = ATSFontFindFromName(name, kATSOptionFlagsDefault);
417 if (font == kInvalidFont)
return err;
421 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 423 os_err = ATSFontGetFileReference(font, &ref);
427 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(__LP64__) 429 #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) 430 #define ATSFSSpec FSSpec 433 os_err = ATSFontGetFileSpecification(font, (ATSFSSpec *)&spec);
434 if (os_err == noErr) os_err = FSpMakeFSRef(&spec, &ref);
439 if (os_err == noErr) os_err = FSRefMakePath(&ref, file_path,
sizeof(file_path));
443 if (os_err == noErr) {
444 DEBUG(freetype, 3,
"Font path for %s: %s", font_name, file_path);
445 err = FT_New_Face(_library, (
const char *)file_path, 0, face);
455 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 460 if (strcmp(language_isocode,
"zh_TW") == 0) {
463 }
else if (strcmp(language_isocode,
"zh_CN") == 0) {
469 char *sep = strchr(lang,
'_');
470 if (sep != NULL) *sep =
'\0';
474 CFStringRef lang_codes[2];
475 lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
476 lang_codes[1] = CFSTR(
"en");
477 CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (
const void **)lang_codes,
lengthof(lang_codes), &kCFTypeArrayCallBacks);
478 CFDictionaryRef lang_attribs = CFDictionaryCreate(kCFAllocatorDefault, (
const void**)&kCTFontLanguagesAttribute, (
const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
479 CTFontDescriptorRef lang_desc = CTFontDescriptorCreateWithAttributes(lang_attribs);
481 CFRelease(lang_attribs);
482 CFRelease(lang_codes[0]);
485 CFSetRef mandatory_attribs = CFSetCreate(kCFAllocatorDefault, (
const void **)&kCTFontLanguagesAttribute, 1, &kCFTypeSetCallBacks);
486 CFArrayRef descs = CTFontDescriptorCreateMatchingFontDescriptors(lang_desc, mandatory_attribs);
487 CFRelease(mandatory_attribs);
488 CFRelease(lang_desc);
490 for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs); i++) {
491 CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i);
494 CFDictionaryRef traits = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute);
495 CTFontSymbolicTraits symbolic_traits;
496 CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
500 if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait))
continue;
502 if (symbolic_traits & kCTFontBoldTrait)
continue;
504 if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->
Monospace())
continue;
508 CFStringRef font_name = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute);
509 CFStringGetCString(font_name, name,
lengthof(name), kCFStringEncodingUTF8);
510 CFRelease(font_name);
514 if (name[0] ==
'.' || strncmp(name,
"LastResort", 10) == 0)
continue;
519 DEBUG(freetype, 2,
"CT-Font for %s: %s", language_isocode, name);
524 if (descs != NULL) CFRelease(descs);
528 #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6) 533 ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsDefaultScope, &itr);
534 while (!result && ATSFontIteratorNext(itr, &font) == noErr) {
537 CFStringRef font_name;
538 ATSFontGetName(font, kATSOptionFlagsDefault, &font_name);
539 CFStringGetCString(font_name, name,
lengthof(name), kCFStringEncodingUTF8);
541 bool monospace = IsMonospaceFont(font_name);
542 CFRelease(font_name);
545 if (monospace != callback->
Monospace())
continue;
548 if (strstr(name,
"Italic") != NULL || strstr(name,
"Bold"))
continue;
551 if (name[0] ==
'.' || strncmp(name,
"Apple Symbols", 13) == 0 || strncmp(name,
"LastResort", 10) == 0)
continue;
556 DEBUG(freetype, 2,
"ATS-Font for %s: %s", language_isocode, name);
561 ATSFontIteratorRelease(&itr);
576 #elif defined(WITH_FONTCONFIG) 578 #include <fontconfig/fontconfig.h> 587 FT_Error err = FT_Err_Cannot_Open_Resource;
590 ShowInfoF(
"Unable to load font configuration");
600 font_family =
stredup(font_name);
601 font_style = strchr(font_family,
',');
602 if (font_style != NULL) {
603 font_style[0] =
'\0';
605 while (*font_style ==
' ' || *font_style ==
'\t') font_style++;
609 pat = FcNameParse((FcChar8*)font_family);
610 if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style);
611 FcConfigSubstitute(0, pat, FcMatchPattern);
612 FcDefaultSubstitute(pat);
613 fs = FcFontSetCreate();
614 match = FcFontMatch(0, pat, &result);
616 if (fs != NULL && match != NULL) {
621 FcFontSetAdd(fs, match);
623 for (i = 0; err != FT_Err_Ok && i < fs->nfont; i++) {
625 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch &&
626 FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch &&
627 FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) {
630 if (font_style != NULL && strcasecmp(font_style, (
char*)style) != 0)
continue;
635 if (strcasecmp(font_family, (
char*)family) == 0) {
636 err = FT_New_Face(_library, (
char *)file, 0, face);
643 FcPatternDestroy(pat);
644 FcFontSetDestroy(fs);
653 if (!FcInit())
return false;
662 char *split = strchr(lang,
'_');
663 if (split != NULL) *split =
'\0';
666 FcPattern *pat = FcNameParse((FcChar8*)lang);
668 FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SPACING, FC_SLANT, FC_WEIGHT, NULL);
670 FcFontSet *fs = FcFontList(NULL, pat, os);
673 FcObjectSetDestroy(os);
674 FcPatternDestroy(pat);
677 int best_weight = -1;
678 const char *best_font = NULL;
680 for (
int i = 0; i < fs->nfont; i++) {
681 FcPattern *font = fs->fonts[i];
683 FcChar8 *file = NULL;
684 FcResult res = FcPatternGetString(font, FC_FILE, 0, &file);
685 if (res != FcResultMatch || file == NULL) {
691 FcPatternGetInteger(font, FC_SPACING, 0, &value);
692 if (callback->
Monospace() != (value == FC_MONO) && value != FC_DUAL)
continue;
695 FcPatternGetInteger(font, FC_SLANT, 0, &value);
696 if (value != 0)
continue;
699 FcPatternGetInteger(font, FC_WEIGHT, 0, &value);
700 if (value <= best_weight)
continue;
705 DEBUG(freetype, 1,
"Font \"%s\" misses%s glyphs", file, missing ?
"" :
" no");
709 best_font = (
const char *)file;
713 if (best_font != NULL) {
720 FcFontSetDestroy(fs);
728 FT_Error
GetFontByFaceName(
const char *font_name, FT_Face *face) {
return FT_Err_Cannot_Open_Resource;}
Functions related to OTTD's strings.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Functions related to debugging.
HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
Our very own SHGetFolderPath function for support of windows operating systems that don't have this f...
fluid_settings_t * settings
FluidSynth settings handle.
static bool MacOSVersionIsAtLeast(long major, long minor, long bugfix)
Check if we are at least running on the specified version of Mac OS.
Functions related to detecting/finding the right font.
virtual bool Monospace()=0
Whether to search for a monospace font or not.
#define lastof(x)
Get the last element of an fixed size array.
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
char * convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
Settings for the freetype fonts.
void InitFreeType(bool monospace)
(Re)initialize the freetype related things, i.e.
void CDECL ShowInfoF(const char *str,...)
Shows some information on the console/a popup box depending on the OS.
Functions related to low-level strings.
Functions related to the allocation of memory.
A searcher for missing glyphs.
Definition of base types and functions in a cross-platform compatible way.
A number of safeguards to prevent using unsafe methods.
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
Get the font loaded into a Freetype face by using a font-name.
char * stredup(const char *s, const char *last)
Create a duplicate of the given string.
static T * ReallocT(T *t_ptr, size_t num_elements)
Simplified reallocation function that allocates the specified number of elements of the given type...
bool FindMissingGlyphs(const char **str)
Check whether there are glyphs missing in the current language.
#define lengthof(x)
Return the length of an fixed size array.
static T min(const T a, const T b)
Returns the minimum of two values.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD's encoding to that of the local environment.
bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback)
We would like to have a fallback font as the current one doesn't contain all characters we need...
#define DEBUG(name, level,...)
Output a line of debugging information.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
#define PATH_MAX
The maximum length of paths, if we don't know it.
virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name)=0
Set the right font names.
Functions related to MacOS support.
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
declarations of functions for MS windows systems