diff --git a/CMakeLists.txt b/CMakeLists.txt index 614fd4c230..f62917b50e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,7 +144,9 @@ if(NOT OPTION_DEDICATED) find_package(SDL) endif() find_package(Fluidsynth) - find_package(Fontconfig) + if(Freetype_FOUND) + find_package(Fontconfig) + endif() find_package(Harfbuzz) find_package(ICU OPTIONAL_COMPONENTS i18n) endif() diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp index df66b73c2b..65b1185435 100644 --- a/src/fontcache/freetypefontcache.cpp +++ b/src/fontcache/freetypefontcache.cpp @@ -143,19 +143,11 @@ void LoadFreeTypeFont(FontSize fs) /* If font is an absolute path to a ttf, try loading that first. */ FT_Error error = FT_New_Face(_library, font_name, 0, &face); -#if defined(WITH_COCOA) - extern void MacOSRegisterExternalFont(const char *file_path); - if (error == FT_Err_Ok) MacOSRegisterExternalFont(font_name); -#endif - if (error != FT_Err_Ok) { /* Check if font is a relative filename in one of our search-paths. */ std::string full_font = FioFindFullPath(BASE_DIR, font_name); if (!full_font.empty()) { error = FT_New_Face(_library, full_font.c_str(), 0, &face); -#if defined(WITH_COCOA) - if (error == FT_Err_Ok) MacOSRegisterExternalFont(full_font.c_str()); -#endif } } @@ -317,10 +309,10 @@ void UninitFreeType() _library = nullptr; } -#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) +#if !defined(WITH_FONTCONFIG) FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; } -#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */ +#endif /* !defined(WITH_FONTCONFIG) */ #endif /* WITH_FREETYPE */ diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index bdbbcada64..6179169a86 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -24,50 +24,6 @@ #include "safeguards.h" - -#ifdef WITH_FREETYPE - -#include -#include FT_FREETYPE_H - -extern FT_Library _library; - - -FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) -{ - FT_Error err = FT_Err_Cannot_Open_Resource; - - /* Get font reference from name. */ - UInt8 file_path[PATH_MAX]; - OSStatus os_err = -1; - CFAutoRelease name(CFStringCreateWithCString(kCFAllocatorDefault, font_name, kCFStringEncodingUTF8)); - - /* Simply creating the font using CTFontCreateWithNameAndSize will *always* return - * something, no matter the name. As such, we can't use it to check for existence. - * We instead query the list of all font descriptors that match the given name which - * does not do this stupid name fallback. */ - CFAutoRelease name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0)); - CFAutoRelease mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast(reinterpret_cast(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks)); - CFAutoRelease descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get())); - - /* Loop over all matches until we can get a path for one of them. */ - for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()) && os_err != noErr; i++) { - CFAutoRelease font(CTFontCreateWithFontDescriptor((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i), 0.0, nullptr)); - CFAutoRelease fontURL((CFURLRef)CTFontCopyAttribute(font.get(), kCTFontURLAttribute)); - if (CFURLGetFileSystemRepresentation(fontURL.get(), true, file_path, lengthof(file_path))) os_err = noErr; - } - - if (os_err == noErr) { - Debug(fontcache, 3, "Font path for {}: {}", font_name, file_path); - err = FT_New_Face(_library, (const char *)file_path, 0, face); - } - - return err; -} - -#endif /* WITH_FREETYPE */ - - bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { /* Determine fallback font using CoreText. This uses the language isocode diff --git a/src/os/unix/font_unix.cpp b/src/os/unix/font_unix.cpp index bfc759c0dd..b4e8c6a0f6 100644 --- a/src/os/unix/font_unix.cpp +++ b/src/os/unix/font_unix.cpp @@ -17,8 +17,6 @@ #include "safeguards.h" -#ifdef WITH_FREETYPE - #include #include FT_FREETYPE_H @@ -97,9 +95,6 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) return err; } -#endif /* WITH_FREETYPE */ - - bool SetFallbackFont(FontCacheSettings *settings, const char *language_isocode, int winlangid, MissingGlyphSearcher *callback) { bool ret = false; diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index def4f57552..e6f9147751 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -32,208 +32,6 @@ #include "safeguards.h" -#ifdef WITH_FREETYPE - -#include -#include FT_FREETYPE_H - -extern FT_Library _library; - -/** - * Get the short DOS 8.3 format for paths. - * FreeType doesn't support Unicode filenames and Windows' fopen (as used - * by FreeType) doesn't support UTF-8 filenames. So we have to convert the - * filename into something that isn't UTF-8 but represents the Unicode file - * name. This is the short DOS 8.3 format. This does not contain any - * characters that fopen doesn't support. - * @param long_path the path in system encoding. - * @return the short path in ANSI (ASCII). - */ -static const char *GetShortPath(const wchar_t *long_path) -{ - static char short_path[MAX_PATH]; - wchar_t short_path_w[MAX_PATH]; - GetShortPathName(long_path, short_path_w, lengthof(short_path_w)); - WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), nullptr, nullptr); - return short_path; -} - -/* Get the font file to be loaded into Freetype by looping the registry - * location where windows lists all installed fonts. Not very nice, will - * surely break if the registry path changes, but it works. Much better - * solution would be to use CreateFont, and extract the font data from it - * by GetFontData. The problem with this is that the font file needs to be - * kept in memory then until the font is no longer needed. This could mean - * an additional memory usage of 30MB (just for fonts!) when using an eastern - * font for all font sizes */ -static const wchar_t *FONT_DIR_NT = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; -FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) -{ - FT_Error err = FT_Err_Cannot_Open_Resource; - HKEY hKey; - LONG ret; - wchar_t vbuffer[MAX_PATH], dbuffer[256]; - const char *font_path; - uint index; - size_t path_len; - - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FONT_DIR_NT, 0, KEY_READ, &hKey); - - if (ret != ERROR_SUCCESS) { - Debug(fontcache, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"); - return err; - } - - /* Convert font name to file system encoding. */ - wchar_t *font_namep = wcsdup(OTTD2FS(font_name).c_str()); - - for (index = 0;; index++) { - wchar_t *s; - DWORD vbuflen = lengthof(vbuffer); - DWORD dbuflen = lengthof(dbuffer); - - ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, nullptr, nullptr, (byte *)dbuffer, &dbuflen); - if (ret != ERROR_SUCCESS) goto registry_no_font_found; - - /* The font names in the registry are of the following 3 forms: - * - ADMUI3.fon - * - Book Antiqua Bold (TrueType) - * - Batang & BatangChe & Gungsuh & GungsuhChe (TrueType) - * We will strip the font-type '()' if any and work with the font name - * itself, which must match exactly; if... - * TTC files, font files which contain more than one font are separated - * by '&'. Our best bet will be to do substr match for the fontname - * and then let FreeType figure out which index to load */ - s = wcschr(vbuffer, L'('); - if (s != nullptr) s[-1] = '\0'; - - if (wcschr(vbuffer, L'&') == nullptr) { - if (wcsicmp(vbuffer, font_namep) == 0) break; - } else { - if (wcsstr(vbuffer, font_namep) != nullptr) break; - } - } - - if (!SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, vbuffer))) { - Debug(fontcache, 0, "SHGetFolderPath cannot return fonts directory"); - goto folder_error; - } - - /* Some fonts are contained in .ttc files, TrueType Collection fonts. These - * contain multiple fonts inside this single file. GetFontData however - * returns the whole file, so we need to check each font inside to get the - * proper font. */ - std::wstring pathbuf(vbuffer); - pathbuf += L"\\"; - pathbuf += dbuffer; - - /* Convert the path into something that FreeType understands. */ - font_path = GetShortPath(pathbuf.c_str()); - - index = 0; - do { - err = FT_New_Face(_library, font_path, index, face); - if (err != FT_Err_Ok) break; - - if (StrStartsWithIgnoreCase(font_name, (*face)->family_name)) break; - /* Try english name if font name failed */ - if (StrStartsWithIgnoreCase(font_name + strlen(font_name) + 1, (*face)->family_name)) break; - err = FT_Err_Cannot_Open_Resource; - - } while ((FT_Long)++index != (*face)->num_faces); - - -folder_error: -registry_no_font_found: - free(font_namep); - RegCloseKey(hKey); - return err; -} - -/** - * Fonts can have localised names and when the system locale is the same as - * one of those localised names Windows will always return that localised name - * instead of allowing to get the non-localised (English US) name of the font. - * This will later on give problems as freetype uses the non-localised name of - * the font and we need to compare based on that name. - * Windows furthermore DOES NOT have an API to get the non-localised name nor - * can we override the system locale. This means that we have to actually read - * the font itself to gather the font name we want. - * Based on: http://blogs.msdn.com/michkap/archive/2006/02/13/530814.aspx - * @param logfont the font information to get the english name of. - * @return the English name (if it could be found). - */ -static std::string GetEnglishFontName(const ENUMLOGFONTEX *logfont) -{ - static char font_name[MAX_PATH]; - const char *ret_font_name = nullptr; - uint pos = 0; - HDC dc; - HGDIOBJ oldfont; - byte *buf; - DWORD dw; - uint16 format, count, stringOffset, platformId, encodingId, languageId, nameId, length, offset; - - HFONT font = CreateFontIndirect(&logfont->elfLogFont); - if (font == nullptr) goto err1; - - dc = GetDC(nullptr); - oldfont = SelectObject(dc, font); - dw = GetFontData(dc, 'eman', 0, nullptr, 0); - if (dw == GDI_ERROR) goto err2; - - buf = MallocT(dw); - dw = GetFontData(dc, 'eman', 0, buf, dw); - if (dw == GDI_ERROR) goto err3; - - format = buf[pos++] << 8; - format += buf[pos++]; - assert(format == 0); - count = buf[pos++] << 8; - count += buf[pos++]; - stringOffset = buf[pos++] << 8; - stringOffset += buf[pos++]; - for (uint i = 0; i < count; i++) { - platformId = buf[pos++] << 8; - platformId += buf[pos++]; - encodingId = buf[pos++] << 8; - encodingId += buf[pos++]; - languageId = buf[pos++] << 8; - languageId += buf[pos++]; - nameId = buf[pos++] << 8; - nameId += buf[pos++]; - if (nameId != 1) { - pos += 4; // skip length and offset - continue; - } - length = buf[pos++] << 8; - length += buf[pos++]; - offset = buf[pos++] << 8; - offset += buf[pos++]; - - /* Don't buffer overflow */ - length = std::min(length, MAX_PATH - 1); - for (uint j = 0; j < length; j++) font_name[j] = buf[stringOffset + offset + j]; - font_name[length] = '\0'; - - if ((platformId == 1 && languageId == 0) || // Macintosh English - (platformId == 3 && languageId == 0x0409)) { // Microsoft English (US) - ret_font_name = font_name; - break; - } - } - -err3: - free(buf); -err2: - SelectObject(dc, oldfont); - ReleaseDC(nullptr, dc); - DeleteObject(font); -err1: - return ret_font_name == nullptr ? FS2OTTD((const wchar_t *)logfont->elfFullName) : std::string(ret_font_name); -} -#endif /* WITH_FREETYPE */ - struct EFCParam { FontCacheSettings *settings; LOCALESIGNATURE locale; @@ -284,34 +82,9 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT char font_name[MAX_PATH]; convert_from_fs((const wchar_t *)logfont->elfFullName, font_name, lengthof(font_name)); -#ifdef WITH_FREETYPE - /* Add english name after font name */ - std::string english_name = GetEnglishFontName(logfont); - strecpy(font_name + strlen(font_name) + 1, english_name.c_str(), lastof(font_name)); - - /* Check whether we can actually load the font. */ - bool ft_init = _library != nullptr; - bool found = false; - FT_Face face; - /* Init FreeType if needed. */ - if ((ft_init || FT_Init_FreeType(&_library) == FT_Err_Ok) && GetFontByFaceName(font_name, &face) == FT_Err_Ok) { - FT_Done_Face(face); - found = true; - } - if (!ft_init) { - /* Uninit FreeType if we did the init. */ - FT_Done_FreeType(_library); - _library = nullptr; - } - - if (!found) return 1; -#else - const char *english_name = font_name; -#endif /* WITH_FREETYPE */ - info->callback->SetFontNames(info->settings, font_name, &logfont->elfLogFont); if (info->callback->FindMissingGlyphs()) return 1; - Debug(fontcache, 1, "Fallback font: {} ({})", font_name, english_name); + Debug(fontcache, 1, "Fallback font: {}", font_name); return 0; // stop enumerating }