Update fontMgr to take list of bcp47 language tags.
This will enable clients to pass more than one bcp47 tag to ensure
that the most appropriate font is selected.
BUG=chromium:422180
Review URL: https://codereview.chromium.org/670243002
Cherry-pick: c20386e3937d3d398ac9b35f9c7d997e972ade98
Cherry-pick: 4aa75b798049741f214aac4a9ed959aa46d54d7e
Cherry-pick: 5f6094a1eb9bf5bb9fd17ada84a5763de2853eff
Approval: https://code.google.com/p/chromium/issues/detail?id=422180#c32
diff --git a/gm/fontmgr.cpp b/gm/fontmgr.cpp
index 7986898..e334274 100644
--- a/gm/fontmgr.cpp
+++ b/gm/fontmgr.cpp
@@ -31,7 +31,11 @@
// find typeface containing the requested character and draw it
SkString ch;
ch.appendUnichar(character);
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
+ SkTypeface* typeface = fm->matchFamilyStyleCharacter(fontName, fontStyle, &bpc47, 1, character);
+#else
SkTypeface* typeface = fm->matchFamilyStyleCharacter(fontName, fontStyle, bpc47, character);
+#endif
SkSafeUnref(paint.setTypeface(typeface));
x = drawString(canvas, ch, x, y, paint) + 20;
diff --git a/include/ports/SkFontMgr.h b/include/ports/SkFontMgr.h
index bb8c7b7..0ffcc27e 100644
--- a/include/ports/SkFontMgr.h
+++ b/include/ports/SkFontMgr.h
@@ -64,14 +64,24 @@
/**
* Use the system fallback to find a typeface for the given character.
- * Note that bpc47 is a combination of ISO 639, 15924, and 3166-1 codes,
+ * Note that bcp47 is a combination of ISO 639, 15924, and 3166-1 codes,
* so it is fine to just pass a ISO 639 here.
*
* Will return NULL if no family can be found for the character
* in the system fallback.
+ *
+ * bcp47[0] is the least significant fallback, bcp47[bcp47Count-1] is the
+ * most significant. If no specified bcp47 codes match, any font with the
+ * requested character will be matched.
*/
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
SkTypeface* matchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
- const char bpc47[], uint32_t character) const;
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const;
+#else
+ SkTypeface* matchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
+ const char bcp47[], SkUnichar character) const;
+#endif
SkTypeface* matchFaceStyle(const SkTypeface*, const SkFontStyle&) const;
@@ -117,8 +127,14 @@
virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
const SkFontStyle&) const = 0;
// TODO: pure virtual, implement on all impls.
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
- const char bpc47[], uint32_t character) const
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const
+#else
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
+ const char bcp47[], SkUnichar character) const
+#endif
{ return NULL; }
virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
const SkFontStyle&) const = 0;
diff --git a/include/ports/SkFontMgr_indirect.h b/include/ports/SkFontMgr_indirect.h
index b9ce344..95a2355 100644
--- a/include/ports/SkFontMgr_indirect.h
+++ b/include/ports/SkFontMgr_indirect.h
@@ -39,10 +39,18 @@
virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
const SkFontStyle& fontStyle) const SK_OVERRIDE;
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle&,
- const char bpc47[],
- uint32_t character) const SK_OVERRIDE;
+ const char* bcp47[],
+ int bcp47Count,
+ SkUnichar character) const SK_OVERRIDE;
+#else
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle&,
+ const char bcp47[],
+ SkUnichar character) const SK_OVERRIDE;
+#endif
virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
const SkFontStyle& fontStyle) const SK_OVERRIDE;
diff --git a/include/ports/SkRemotableFontMgr.h b/include/ports/SkRemotableFontMgr.h
index bd99497..1ff96a3 100644
--- a/include/ports/SkRemotableFontMgr.h
+++ b/include/ports/SkRemotableFontMgr.h
@@ -133,8 +133,14 @@
* Note that bpc47 is a combination of ISO 639, 15924, and 3166-1 codes,
* so it is fine to just pass a ISO 639 here.
*/
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], const SkFontStyle&,
- const char bpc47[], SkUnichar character) const=0;
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const=0;
+#else
+ virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], const SkFontStyle&,
+ const char bcp47[], SkUnichar character) const=0;
+#endif
/**
* Returns the data for the given data id.
diff --git a/src/core/SkFontHost.cpp b/src/core/SkFontHost.cpp
index c582ba5..ef5d41f 100644
--- a/src/core/SkFontHost.cpp
+++ b/src/core/SkFontHost.cpp
@@ -110,10 +110,18 @@
const SkFontStyle&) const SK_OVERRIDE {
return NULL;
}
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle& style,
- const char bpc47[],
- uint32_t character) const SK_OVERRIDE {
+ const char* bcp47[],
+ int bcp47Count,
+ SkUnichar character) const SK_OVERRIDE {
+#else
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle& style,
+ const char bcp47[],
+ SkUnichar character) const SK_OVERRIDE {
+#endif
return NULL;
}
virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
@@ -162,10 +170,18 @@
return this->onMatchFamilyStyle(familyName, fs);
}
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
SkTypeface* SkFontMgr::matchFamilyStyleCharacter(const char familyName[], const SkFontStyle& style,
- const char bpc47[], uint32_t character) const {
- return this->onMatchFamilyStyleCharacter(familyName, style, bpc47, character);
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const {
+ return this->onMatchFamilyStyleCharacter(familyName, style, bcp47, bcp47Count, character);
}
+#else
+SkTypeface* SkFontMgr::matchFamilyStyleCharacter(const char familyName[], const SkFontStyle& style,
+ const char bcp47[], SkUnichar character) const {
+ return this->onMatchFamilyStyleCharacter(familyName, style, bcp47, character);
+}
+#endif
SkTypeface* SkFontMgr::matchFaceStyle(const SkTypeface* face,
const SkFontStyle& fs) const {
diff --git a/src/fonts/SkFontMgr_indirect.cpp b/src/fonts/SkFontMgr_indirect.cpp
index 54f2de8..c9d3025 100644
--- a/src/fonts/SkFontMgr_indirect.cpp
+++ b/src/fonts/SkFontMgr_indirect.cpp
@@ -245,13 +245,25 @@
return this->createTypefaceFromFontId(id);
}
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle& style,
- const char bpc47[],
- uint32_t character) const {
- SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bpc47, character);
+ const char* bcp47[],
+ int bcp47Count,
+ SkUnichar character) const {
+ SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bcp47,
+ bcp47Count, character);
return this->createTypefaceFromFontId(id);
}
+#else
+SkTypeface* SkFontMgr_Indirect::onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle& style,
+ const char bcp47[],
+ SkUnichar character) const {
+ SkFontIdentity id = fProxy->matchNameStyleCharacter(familyName, style, bcp47, character);
+ return this->createTypefaceFromFontId(id);
+}
+#endif
SkTypeface* SkFontMgr_Indirect::onMatchFaceStyle(const SkTypeface* familyMember,
const SkFontStyle& fontStyle) const {
diff --git a/src/ports/SkFontMgr_android.cpp b/src/ports/SkFontMgr_android.cpp
index 5e93bf8..1126b75 100644
--- a/src/ports/SkFontMgr_android.cpp
+++ b/src/ports/SkFontMgr_android.cpp
@@ -344,50 +344,79 @@
return NULL;
}
+static SkTypeface_AndroidSystem* find_family_style_character(
+ const SkTDArray<NameToFamily>& fallbackNameToFamilyMap,
+ const SkFontStyle& style, bool elegant,
+ const SkString& langTag, SkUnichar character)
+{
+ for (int i = 0; i < fallbackNameToFamilyMap.count(); ++i) {
+ SkFontStyleSet_Android* family = fallbackNameToFamilyMap[i].styleSet;
+ SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
+
+ if (!langTag.isEmpty() && !face->fLang.getTag().startsWith(langTag.c_str())) {
+ continue;
+ }
+
+ if (SkToBool(face->fVariantStyle & kElegant_FontVariant) != elegant) {
+ continue;
+ }
+
+ SkPaint paint;
+ paint.setTypeface(face);
+ paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
+
+ uint16_t glyphID;
+ paint.textToGlyphs(&character, sizeof(character), &glyphID);
+ if (glyphID != 0) {
+ return face.detach();
+ }
+ }
+ return NULL;
+}
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle& style,
- const char bpc47[],
- uint32_t character) const SK_OVERRIDE
+ const char* bcp47[],
+ int bcp47Count,
+ SkUnichar character) const SK_OVERRIDE
{
+#else
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle& style,
+ const char bcp47_val[],
+ SkUnichar character) const SK_OVERRIDE
+ {
+ const char** bcp47 = &bcp47_val;
+ int bcp47Count = bcp47_val ? 1 : 0;
+#endif
// The variant 'elegant' is 'not squashed', 'compact' is 'stays in ascent/descent'.
// The variant 'default' means 'compact and elegant'.
// As a result, it is not possible to know the variant context from the font alone.
// TODO: add 'is_elegant' and 'is_compact' bits to 'style' request.
- // For compatibility, try 'elegant' fonts first in fallback.
- uint32_t variantMask = kElegant_FontVariant;
-
- // The first time match anything in the mask, second time anything not in the mask.
- for (bool maskMatches = true; maskMatches != false; maskMatches = false) {
- SkLanguage lang(bpc47);
- // Match against the language, removing a segment each time.
- // The last time through the loop, the language will be empty.
- // The empty language is special, and matches all languages.
- do {
- const SkString& langTag = lang.getTag();
- for (int i = 0; i < fFallbackNameToFamilyMap.count(); ++i) {
- SkFontStyleSet_Android* family = fFallbackNameToFamilyMap[i].styleSet;
- SkAutoTUnref<SkTypeface_AndroidSystem> face(family->matchStyle(style));
-
- if (!langTag.isEmpty() && langTag != face->fLang.getTag()) {
- continue;
+ // The first time match anything elegant, second time anything not elegant.
+ for (int elegant = 2; elegant --> 0;) {
+ for (int bcp47Index = bcp47Count; bcp47Index --> 0;) {
+ SkLanguage lang(bcp47[bcp47Index]);
+ while (!lang.getTag().isEmpty()) {
+ SkTypeface_AndroidSystem* matchingTypeface =
+ find_family_style_character(fFallbackNameToFamilyMap,
+ style, SkToBool(elegant),
+ lang.getTag(), character);
+ if (matchingTypeface) {
+ return matchingTypeface;
}
- if (SkToBool(face->fVariantStyle & variantMask) != maskMatches) {
- continue;
- }
-
- SkPaint paint;
- paint.setTypeface(face);
- paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
-
- uint16_t glyphID;
- paint.textToGlyphs(&character, sizeof(character), &glyphID);
- if (glyphID != 0) {
- return face.detach();
- }
+ lang = lang.getParent();
}
- } while (!lang.getTag().isEmpty() && (lang = lang.getParent(), true));
+ }
+ SkTypeface_AndroidSystem* matchingTypeface =
+ find_family_style_character(fFallbackNameToFamilyMap,
+ style, SkToBool(elegant),
+ SkString(), character);
+ if (matchingTypeface) {
+ return matchingTypeface;
+ }
}
return NULL;
}
diff --git a/src/ports/SkFontMgr_fontconfig.cpp b/src/ports/SkFontMgr_fontconfig.cpp
index 6fc1f28..38f0e3a 100644
--- a/src/ports/SkFontMgr_fontconfig.cpp
+++ b/src/ports/SkFontMgr_fontconfig.cpp
@@ -769,11 +769,22 @@
return createTypefaceFromFcPattern(font);
}
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
const SkFontStyle& style,
- const char bpc47[],
- uint32_t character) const SK_OVERRIDE
+ const char* bcp47[],
+ int bcp47Count,
+ SkUnichar character) const SK_OVERRIDE
{
+#else
+ virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[],
+ const SkFontStyle& style,
+ const char bcp47_val[],
+ SkUnichar character) const SK_OVERRIDE
+ {
+ const char** bcp47 = &bcp47_val;
+ int bcp47Count = bcp47_val ? 1 : 0;
+#endif
FCLocker lock;
SkAutoFcPattern pattern;
@@ -784,9 +795,12 @@
FcCharSetAddChar(charSet, character);
FcPatternAddCharSet(pattern, FC_CHARSET, charSet);
- if (bpc47) {
+ if (bcp47Count > 0) {
+ SkASSERT(bcp47);
SkAutoFcLangSet langSet;
- FcLangSetAdd(langSet, (const FcChar8*)bpc47);
+ for (int i = bcp47Count; i --> 0;) {
+ FcLangSetAdd(langSet, (const FcChar8*)bcp47[i]);
+ }
FcPatternAddLangSet(pattern, FC_LANG, langSet);
}
diff --git a/src/ports/SkRemotableFontMgr_win_dw.cpp b/src/ports/SkRemotableFontMgr_win_dw.cpp
index d979683..498f21f 100644
--- a/src/ports/SkRemotableFontMgr_win_dw.cpp
+++ b/src/ports/SkRemotableFontMgr_win_dw.cpp
@@ -408,11 +408,21 @@
SkFontIdentity fIdentity;
};
+#ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
const SkFontStyle& pattern,
- const char bpc47[],
- SkUnichar character) const SK_OVERRIDE
+ const char* bcp47[], int bcp47Count,
+ SkUnichar character) const SK_OVERRIDE
{
+#else
+ virtual SkFontIdentity matchNameStyleCharacter(const char familyName[],
+ const SkFontStyle& pattern,
+ const char bcp47_val[],
+ SkUnichar character) const SK_OVERRIDE
+ {
+ const char** bcp47 = &bcp47_val;
+ int bcp47Count = bcp47_val ? 1 : 0;
+#endif
SkFontIdentity identity = { SkFontIdentity::kInvalidDataId };
IDWriteFactory* dwFactory = sk_get_dwrite_factory();
@@ -431,13 +441,14 @@
HR_GENERAL(sk_cstring_to_wchar(familyName, &dwFamilyName), NULL, identity);
}
- const SkSMallocWCHAR* dwBpc47;
- SkSMallocWCHAR dwBpc47Local;
- if (NULL == bpc47) {
- dwBpc47 = &fLocaleName;
+ const SkSMallocWCHAR* dwBcp47;
+ SkSMallocWCHAR dwBcp47Local;
+ if (bcp47Count < 1) {
+ dwBcp47 = &fLocaleName;
} else {
- HR_GENERAL(sk_cstring_to_wchar(bpc47, &dwBpc47Local), NULL, identity);
- dwBpc47 = &dwBpc47Local;
+ //TODO: support fallback stack.
+ HR_GENERAL(sk_cstring_to_wchar(bcp47[bcp47Count-1], &dwBcp47Local), NULL, identity);
+ dwBcp47 = &dwBcp47Local;
}
SkTScopedComPtr<IDWriteTextFormat> fallbackFormat;
@@ -447,7 +458,7 @@
dwStyle.fSlant,
dwStyle.fWidth,
72.0f,
- *dwBpc47,
+ *dwBcp47,
&fallbackFormat),
"Could not create text format.",
identity);