aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bungeman <bungeman@google.com>2014-09-09 12:50:36 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2014-09-09 12:50:36 -0700
commit6bc2c94de334efb40e1a09e31112262dec77532b (patch)
treebddec68e1c2a8fdbed4c00d1da7c5dafc2ff6499
parent4459a0448d84d4adb53984227fbee4c581f13a98 (diff)
Add font fallback support to SkFontMgr_fontconfig.
R=mtklein@google.com, djsollen@google.com Author: bungeman@google.com Review URL: https://codereview.chromium.org/489733005
-rw-r--r--expectations/gm/ignored-tests.txt3
-rw-r--r--src/ports/SkFontMgr_fontconfig.cpp126
2 files changed, 88 insertions, 41 deletions
diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt
index 2a451a306a..f1c74cccca 100644
--- a/expectations/gm/ignored-tests.txt
+++ b/expectations/gm/ignored-tests.txt
@@ -35,3 +35,6 @@
# jvanverth
fontcache
+
+#bungeman
+fontmgr_iter
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index 8dec85f6d5..782fb268cc 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -96,21 +96,26 @@ struct FCLocker {
} // namespace
-template<typename T, void (*P)(T*)> void FcTDestroy(T* t) {
+template<typename T, void (*D)(T*)> void FcTDestroy(T* t) {
FCLocker::AssertHeld();
- P(t);
+ D(t);
}
-template <typename T, void (*P)(T*)> class SkAutoFc
- : public SkAutoTCallVProc<T, FcTDestroy<T, P> > {
+template <typename T, T* (*C)(), void (*D)(T*)> class SkAutoFc
+ : public SkAutoTCallVProc<T, FcTDestroy<T, D> > {
public:
- SkAutoFc(T* obj) : SkAutoTCallVProc<T, FcTDestroy<T, P> >(obj) {}
+ SkAutoFc() : SkAutoTCallVProc<T, FcTDestroy<T, D> >(C()) {
+ T* obj = this->operator T*();
+ SK_ALWAYSBREAK(NULL != obj);
+ }
+ explicit SkAutoFc(T* obj) : SkAutoTCallVProc<T, FcTDestroy<T, D> >(obj) {}
};
-typedef SkAutoFc<FcConfig, FcConfigDestroy> SkAutoFcConfig;
-typedef SkAutoFc<FcFontSet, FcFontSetDestroy> SkAutoFcFontSet;
-typedef SkAutoFc<FcLangSet, FcLangSetDestroy> SkAutoFcLangSet;
-typedef SkAutoFc<FcObjectSet, FcObjectSetDestroy> SkAutoFcObjectSet;
-typedef SkAutoFc<FcPattern, FcPatternDestroy> SkAutoFcPattern;
+typedef SkAutoFc<FcCharSet, FcCharSetCreate, FcCharSetDestroy> SkAutoFcCharSet;
+typedef SkAutoFc<FcConfig, FcConfigCreate, FcConfigDestroy> SkAutoFcConfig;
+typedef SkAutoFc<FcFontSet, FcFontSetCreate, FcFontSetDestroy> SkAutoFcFontSet;
+typedef SkAutoFc<FcLangSet, FcLangSetCreate, FcLangSetDestroy> SkAutoFcLangSet;
+typedef SkAutoFc<FcObjectSet, FcObjectSetCreate, FcObjectSetDestroy> SkAutoFcObjectSet;
+typedef SkAutoFc<FcPattern, FcPatternCreate, FcPatternDestroy> SkAutoFcPattern;
static int get_int(FcPattern* pattern, const char object[], int missing) {
int value;
@@ -170,16 +175,16 @@ static SkWeakReturn is_weak(FcPattern* pattern, const char object[], int id) {
// Create a font set with two patterns.
// 1. the same 'object' as minimal and a lang object with only 'nomatchlang'.
// 2. a different 'object' from minimal and a lang object with only 'matchlang'.
- SkAutoFcFontSet fontSet(FcFontSetCreate());
+ SkAutoFcFontSet fontSet;
- SkAutoFcLangSet strongLangSet(FcLangSetCreate());
+ SkAutoFcLangSet strongLangSet;
FcLangSetAdd(strongLangSet, (const FcChar8*)"nomatchlang");
SkAutoFcPattern strong(FcPatternDuplicate(minimal));
FcPatternAddLangSet(strong, FC_LANG, strongLangSet);
- SkAutoFcLangSet weakLangSet(FcLangSetCreate());
+ SkAutoFcLangSet weakLangSet;
FcLangSetAdd(weakLangSet, (const FcChar8*)"matchlang");
- SkAutoFcPattern weak(FcPatternCreate());
+ SkAutoFcPattern weak;
FcPatternAddString(weak, object, (const FcChar8*)"nomatchstring");
FcPatternAddLangSet(weak, FC_LANG, weakLangSet);
@@ -195,7 +200,7 @@ static SkWeakReturn is_weak(FcPattern* pattern, const char object[], int id) {
// Note that this config is only used for FcFontRenderPrepare, which we don't even want.
// However, there appears to be no way to match/sort without it.
- SkAutoFcConfig config(FcConfigCreate());
+ SkAutoFcConfig config;
FcFontSet* fontSets[1] = { fontSet };
SkAutoFcPattern match(FcFontSetMatch(config, fontSets, SK_ARRAY_COUNT(fontSets),
minimal, &result));
@@ -488,11 +493,7 @@ class SkFontMgr_fontconfig : public SkFontMgr {
virtual SkTypeface* matchStyle(const SkFontStyle& style) SK_OVERRIDE {
FCLocker lock;
- SkAutoFcPattern pattern(FcPatternCreate());
- if (NULL == pattern) {
- return NULL;
- }
-
+ SkAutoFcPattern pattern;
fcpattern_from_skfontstyle(style, pattern);
FcConfigSubstitute(fFontMgr->fFC, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
@@ -650,27 +651,41 @@ protected:
return false;
}
- static bool ValidPattern(FcPattern* pattern) {
+ static bool FontAccessible(FcPattern* font) {
// FontConfig can return fonts which are unreadable.
- const char* filename = get_string(pattern, FC_FILE, NULL);
+ const char* filename = get_string(font, FC_FILE, NULL);
if (NULL == filename) {
return false;
}
return sk_exists(filename, kRead_SkFILE_Flag);
}
- static bool FontMatches(FcPattern* font, FcPattern* pattern) {
- return ValidPattern(font) && AnyMatching(font, pattern, FC_FAMILY);
+ static bool FontFamilyNameMatches(FcPattern* font, FcPattern* pattern) {
+ return AnyMatching(font, pattern, FC_FAMILY);
+ }
+
+ static bool FontContainsCharacter(FcPattern* font, uint32_t character) {
+ FcResult result;
+ FcCharSet* matchCharSet;
+ for (int charSetId = 0; ; ++charSetId) {
+ result = FcPatternGetCharSet(font, FC_CHARSET, charSetId, &matchCharSet);
+ if (FcResultNoId == result) {
+ break;
+ }
+ if (FcResultMatch != result) {
+ continue;
+ }
+ if (FcCharSetHasChar(matchCharSet, character)) {
+ return true;
+ }
+ }
+ return false;
}
virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
FCLocker lock;
- SkAutoFcPattern pattern(FcPatternCreate());
- if (NULL == pattern) {
- return NULL;
- }
-
+ SkAutoFcPattern pattern;
FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
FcConfigSubstitute(fFC, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
@@ -685,7 +700,7 @@ protected:
matchPattern = pattern;
}
- SkAutoFcFontSet matches(FcFontSetCreate());
+ SkAutoFcFontSet matches;
// TODO: Some families have 'duplicates' due to symbolic links.
// The patterns are exactly the same except for the FC_FILE.
// It should be possible to collapse these patterns by normalizing.
@@ -698,9 +713,9 @@ protected:
}
for (int fontIndex = 0; fontIndex < allFonts->nfont; ++fontIndex) {
- if (FontMatches(allFonts->fonts[fontIndex], matchPattern)) {
- FcFontSetAdd(matches,
- FcFontRenderPrepare(fFC, pattern, allFonts->fonts[fontIndex]));
+ FcPattern* font = allFonts->fonts[fontIndex];
+ if (FontAccessible(font) && FontFamilyNameMatches(font, matchPattern)) {
+ FcFontSetAdd(matches, FcFontRenderPrepare(fFC, pattern, font));
}
}
}
@@ -713,11 +728,7 @@ protected:
{
FCLocker lock;
- SkAutoFcPattern pattern(FcPatternCreate());
- if (NULL == pattern) {
- return NULL;
- }
-
+ SkAutoFcPattern pattern;
FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
fcpattern_from_skfontstyle(style, pattern);
FcConfigSubstitute(fFC, pattern, FcMatchPattern);
@@ -742,12 +753,45 @@ protected:
}
FcResult result;
- SkAutoFcPattern match(FcFontMatch(fFC, pattern, &result));
- if (NULL == match || !FontMatches(match, matchPattern)) {
+ SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
+ if (NULL == font || !FontAccessible(font) || !FontFamilyNameMatches(font, matchPattern)) {
+ return NULL;
+ }
+
+ return createTypefaceFromFcPattern(font);
+ }
+
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle& style,
+ const char bpc47[],
+ uint32_t character) const SK_OVERRIDE
+ {
+ FCLocker lock;
+
+ SkAutoFcPattern pattern;
+ FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName);
+ fcpattern_from_skfontstyle(style, pattern);
+
+ SkAutoFcCharSet charSet;
+ FcCharSetAddChar(charSet, character);
+ FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
+
+ if (bpc47) {
+ SkAutoFcLangSet langSet;
+ FcLangSetAdd(langSet, (const FcChar8*)bpc47);
+ FcPatternAddLangSet(pattern, FC_LANG, langSet);
+ }
+
+ FcConfigSubstitute(fFC, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+
+ FcResult result;
+ SkAutoFcPattern font(FcFontMatch(fFC, pattern, &result));
+ if (NULL == font || !FontAccessible(font) || !FontContainsCharacter(font, character)) {
return NULL;
}
- return createTypefaceFromFcPattern(match);
+ return createTypefaceFromFcPattern(font);
}
virtual SkTypeface* onMatchFaceStyle(const SkTypeface* typeface,