summaryrefslogtreecommitdiff
path: root/src/fontcache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/fontcache.cpp')
-rw-r--r--src/fontcache.cpp186
1 files changed, 180 insertions, 6 deletions
diff --git a/src/fontcache.cpp b/src/fontcache.cpp
index 28924885d..b35458046 100644
--- a/src/fontcache.cpp
+++ b/src/fontcache.cpp
@@ -154,8 +154,68 @@ registry_no_font_found:
RegCloseKey(hKey);
return err;
}
-#else
-# ifdef WITH_FONTCONFIG
+
+
+struct EFCParam {
+ FreeTypeSettings *settings;
+ LOCALESIGNATURE locale;
+};
+
+static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
+{
+ EFCParam *info = (EFCParam *)lParam;
+
+ /* Only use TrueType fonts */
+ if (!(type & TRUETYPE_FONTTYPE)) return 1;
+ /* Don't use SYMBOL fonts */
+ if (logfont->elfLogFont.lfCharSet == SYMBOL_CHARSET) return 1;
+
+ /* The font has to have at least one of the supported locales to be usable. */
+ if ((metric->ntmFontSig.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (metric->ntmFontSig.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) {
+ /* On win9x metric->ntmFontSig seems to contain garbage. */
+ FONTSIGNATURE fs;
+ memset(&fs, 0, sizeof(fs));
+ HFONT font = CreateFontIndirect(&logfont->elfLogFont);
+ if (font != NULL) {
+ HDC dc = GetDC(NULL);
+ HGDIOBJ oldfont = SelectObject(dc, font);
+ GetTextCharsetInfo(dc, &fs, 0);
+ SelectObject(dc, oldfont);
+ ReleaseDC(NULL, dc);
+ DeleteObject(font);
+ }
+ if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1;
+ }
+
+ strecpy(info->settings->small_font, font_name, lastof(info->settings->small_font));
+ strecpy(info->settings->medium_font, font_name, lastof(info->settings->medium_font));
+ strecpy(info->settings->large_font, font_name, lastof(info->settings->large_font));
+ return 0; // stop enumerating
+}
+
+bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid)
+{
+ EFCParam langInfo;
+ if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPWSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
+ /* Invalid langid or some other mysterious error, can't determine fallback font. */
+ DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
+ return false;
+ }
+ langInfo.settings = settings;
+
+ LOGFONT font;
+ /* Enumerate all fonts. */
+ font.lfCharSet = DEFAULT_CHARSET;
+ font.lfFaceName[0] = '\0';
+ font.lfPitchAndFamily = 0;
+
+ HDC dc = GetDC(NULL);
+ int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
+ ReleaseDC(NULL, dc);
+ return ret == 0;
+}
+
+#elif defined(WITH_FONTCONFIG)
static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
{
FT_Error err = FT_Err_Cannot_Open_Resource;
@@ -221,11 +281,75 @@ static FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
return err;
}
-# else
-FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
-# endif /* WITH_FONTCONFIG */
-#endif
+bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid)
+{
+ if (!FcInit()) return false;
+
+ bool ret = false;
+
+ /* Fontconfig doesn't handle full language isocodes, only the part
+ * before the _ of e.g. en_GB is used, so "remove" everything after
+ * the _. */
+ char lang[16];
+ strecpy(lang, language_isocode, lastof(lang));
+ char *split = strchr(lang, '_');
+ if (split != NULL) *split = '\0';
+
+ FcPattern *pat;
+ FcPattern *match;
+ FcResult result;
+ FcChar8 *file;
+ FcFontSet *fs;
+ FcValue val;
+ val.type = FcTypeString;
+ val.u.s = (FcChar8*)lang;
+
+ /* First create a pattern to match the wanted language */
+ pat = FcPatternCreate();
+ /* And fill it with the language and other defaults */
+ if (pat == NULL ||
+ !FcPatternAdd(pat, "lang", val, false) ||
+ !FcConfigSubstitute(0, pat, FcMatchPattern)) {
+ goto error_pattern;
+ }
+
+ FcDefaultSubstitute(pat);
+
+ /* The create a font set and match that */
+ match = FcFontMatch(0, pat, &result);
+
+ if (match == NULL) {
+ goto error_pattern;
+ }
+
+ /* Find all fonts that do match */
+ fs = FcFontSetCreate();
+ FcFontSetAdd(fs, match);
+
+ /* And take the first, if it exists */
+ if (fs->nfont <= 0 || FcPatternGetString(fs->fonts[0], FC_FILE, 0, &file)) {
+ goto error_fontset;
+ }
+
+ strecpy(settings->small_font, (const char*)file, lastof(settings->small_font));
+ strecpy(settings->medium_font, (const char*)file, lastof(settings->medium_font));
+ strecpy(settings->large_font, (const char*)file, lastof(settings->large_font));
+
+ ret = true;
+
+error_fontset:
+ FcFontSetDestroy(fs);
+error_pattern:
+ if (pat != NULL) FcPatternDestroy(pat);
+ FcFini();
+ return ret;
+}
+
+#else /* without WITH_FONTCONFIG */
+FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) {return FT_Err_Cannot_Open_Resource;}
+bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode) { return false; }
+#endif /* WITH_FONTCONFIG */
/**
* Loads the freetype font.
@@ -303,6 +427,35 @@ void InitFreeType()
if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size);
}
+static void ResetGlyphCache();
+
+/**
+ * Unload a face and set it to NULL.
+ * @param face the face to unload
+ */
+static void UnloadFace(FT_Face *face)
+{
+ if (*face == NULL) return;
+
+ FT_Done_Face(*face);
+ *face = NULL;
+}
+
+/**
+ * Free everything allocated w.r.t. fonts.
+ */
+void UninitFreeType()
+{
+ ResetGlyphCache();
+
+ UnloadFace(&_face_small);
+ UnloadFace(&_face_medium);
+ UnloadFace(&_face_large);
+
+ FT_Done_FreeType(_library);
+ _library = NULL;
+}
+
static FT_Face GetFontFace(FontSize size)
{
@@ -335,6 +488,27 @@ struct GlyphEntry {
*/
static GlyphEntry **_glyph_ptr[FS_END];
+/** Clear the complete cache */
+static void ResetGlyphCache()
+{
+ for (int i = 0; i < FS_END; i++) {
+ if (_glyph_ptr[i] == NULL) continue;
+
+ for (int j = 0; j < 256; j++) {
+ if (_glyph_ptr[i][j] == NULL) continue;
+
+ for (int k = 0; k < 256; k++) {
+ if (_glyph_ptr[i][j][k].sprite == NULL) continue;
+ free(_glyph_ptr[i][j][k].sprite);
+ }
+
+ free(_glyph_ptr[i][j]);
+ }
+
+ free(_glyph_ptr[i]);
+ _glyph_ptr[i] = NULL;
+ }
+}
static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
{