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);