Fix append_fallback_font_families_for_locale.

The language was being set to garbage, now set to part of the file name.
Add a test to ensure we continue to parse fallback directories correctly.

BUG=chromium:422180

Review URL: https://codereview.chromium.org/912053003
diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h
index 6ab4439..c26e442 100644
--- a/include/core/SkTemplates.h
+++ b/include/core/SkTemplates.h
@@ -107,6 +107,10 @@
 public:
     SkAutoTCallIProc(T* obj): fObj(obj) {}
     ~SkAutoTCallIProc() { if (fObj) P(fObj); }
+
+    operator T*() const { return fObj; }
+    T* operator->() const { SkASSERT(fObj); return fObj; }
+
     T* detach() { T* obj = fObj; fObj = NULL; return obj; }
 private:
     T* fObj;
diff --git a/resources/android_fonts/v17/fallback_fonts-ja.xml b/resources/android_fonts/v17/fallback_fonts-ja.xml
new file mode 100644
index 0000000..5f9b5ed
--- /dev/null
+++ b/resources/android_fonts/v17/fallback_fonts-ja.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Fallback Fonts
+
+    This file specifies the fonts, and the priority order, that will be searched for any
+    glyphs not handled by the default fonts specified in /system/etc/system_fonts.xml.
+    Each entry consists of a family tag and a list of files (file names) which support that
+    family. The fonts for each family are listed in the order of the styles that they
+    handle (the order is: regular, bold, italic, and bold-italic). The order in which the
+    families are listed in this file represents the order in which these fallback fonts
+    will be searched for glyphs that are not supported by the default system fonts (which are
+    found in /system/etc/system_fonts.xml).
+
+    Note that there is not nameset for fallback fonts, unlike the fonts specified in
+    system_fonts.xml. The ability to support specific names in fallback fonts may be supported
+    in the future. For now, the lack of files entries here is an indicator to the system that
+    these are fallback fonts, instead of default named system fonts.
+
+    There is another optional file in /vendor/etc/fallback_fonts.xml. That file can be used to
+    provide references to other font families that should be used in addition to the default
+    fallback fonts. That file can also specify the order in which the fallback fonts should be
+    searched, to ensure that a vendor-provided font will be used before another fallback font
+    which happens to handle the same glyph.
+
+    Han languages (Chinese, Japanese, and Korean) share a common range of unicode characters;
+    their ordering in the fallback or vendor files gives priority to the first in the list.
+    Locale-specific ordering can be configured by adding language and region codes to the end
+    of the filename (e.g. /system/etc/fallback_fonts-ja.xml). When no region code is used,
+    as with this example, all regions are matched. Use separate files for each supported locale.
+    The standard fallback file (fallback_fonts.xml) is used when a locale does not have its own
+    file. All fallback files must contain the same complete set of fonts; only their ordering
+    can differ.
+-->
+<familyset>
+    <family>
+        <fileset>
+            <file>DroidNaskh-Regular-SystemUI.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansEthiopic-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansHebrew-Regular.ttf</file>
+            <file>DroidSansHebrew-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansThai.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansArmenian.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansGeorgian.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansDevanagari-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansTamil-Regular.ttf</file>
+            <file>DroidSansTamil-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>AnjaliNewLipi-light.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>Lohit-Bengali.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>Lohit-Kannada.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>Lohit-Telugu.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>AndroidEmoji.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>MTLmr3m.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>DroidSansFallback.ttf</file>
+        </fileset>
+    </family>
+</familyset>
diff --git a/src/ports/SkFontConfigParser_android.cpp b/src/ports/SkFontConfigParser_android.cpp
index 20fee40..ce4ebbe 100644
--- a/src/ports/SkFontConfigParser_android.cpp
+++ b/src/ports/SkFontConfigParser_android.cpp
@@ -502,44 +502,42 @@
     return;
 #endif
 
-    DIR* fontDirectory = opendir(dir);
-    if (fontDirectory != NULL){
-        struct dirent* dirEntry = readdir(fontDirectory);
-        while (dirEntry) {
+    SkAutoTCallIProc<DIR, closedir> fontDirectory(opendir(dir));
+    if (NULL == fontDirectory) {
+        return;
+    }
 
-            // The size of both the prefix, suffix, and a minimum valid language code
-            static const size_t minSize = strlen(LOCALE_FALLBACK_FONTS_PREFIX) +
-                                          strlen(LOCALE_FALLBACK_FONTS_SUFFIX) + 2;
+    for (struct dirent* dirEntry; (dirEntry = readdir(fontDirectory));) {
+        // The size of both the prefix, suffix, and a minimum valid language code
+        static const size_t minSize = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1
+                                    + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1
+                                    + 2;
 
-            SkString fileName(dirEntry->d_name);
-            if (fileName.size() >= minSize &&
-                    fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) &&
-                    fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX)) {
-
-                static const size_t fixedLen = strlen(LOCALE_FALLBACK_FONTS_PREFIX) -
-                                               strlen(LOCALE_FALLBACK_FONTS_SUFFIX);
-
-                SkString locale(fileName.c_str() - strlen(LOCALE_FALLBACK_FONTS_PREFIX),
-                                fileName.size() - fixedLen);
-
-                SkString absoluteFilename;
-                absoluteFilename.printf("%s/%s", dir, fileName.c_str());
-
-                SkTDArray<FontFamily*> langSpecificFonts;
-                parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true);
-
-                for (int i = 0; i < langSpecificFonts.count(); ++i) {
-                    FontFamily* family = langSpecificFonts[i];
-                    family->fLanguage = SkLanguage(locale);
-                    *fallbackFonts.append() = family;
-                }
-            }
-
-            // proceed to the next entry in the directory
-            dirEntry = readdir(fontDirectory);
+        SkString fileName(dirEntry->d_name);
+        if (fileName.size() < minSize ||
+            !fileName.startsWith(LOCALE_FALLBACK_FONTS_PREFIX) ||
+            !fileName.endsWith(LOCALE_FALLBACK_FONTS_SUFFIX))
+        {
+            continue;
         }
-        // cleanup the directory reference
-        closedir(fontDirectory);
+
+        static const size_t fixedLen = sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1
+                                     + sizeof(LOCALE_FALLBACK_FONTS_SUFFIX) - 1;
+
+        SkString locale(fileName.c_str() + sizeof(LOCALE_FALLBACK_FONTS_PREFIX) - 1,
+                        fileName.size() - fixedLen);
+
+        SkString absoluteFilename;
+        absoluteFilename.printf("%s/%s", dir, fileName.c_str());
+
+        SkTDArray<FontFamily*> langSpecificFonts;
+        parse_config_file(absoluteFilename.c_str(), langSpecificFonts, basePath, true);
+
+        for (int i = 0; i < langSpecificFonts.count(); ++i) {
+            FontFamily* family = langSpecificFonts[i];
+            family->fLanguage = SkLanguage(locale);
+            *fallbackFonts.append() = family;
+        }
     }
 }
 
@@ -604,7 +602,8 @@
 void SkFontConfigParser::GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies,
                                                const SkString& basePath,
                                                const char* fontsXml,
-                                               const char* fallbackFontsXml)
+                                               const char* fallbackFontsXml,
+                                               const char* langFallbackFontsDir)
 {
     if (fontsXml) {
         parse_config_file(fontsXml, fontFamilies, basePath, false);
@@ -612,6 +611,11 @@
     if (fallbackFontsXml) {
         parse_config_file(fallbackFontsXml, fontFamilies, basePath, true);
     }
+    if (langFallbackFontsDir) {
+        append_fallback_font_families_for_locale(fontFamilies,
+                                                 langFallbackFontsDir,
+                                                 basePath);
+    }
 }
 
 SkLanguage SkLanguage::getParent() const {
diff --git a/src/ports/SkFontConfigParser_android.h b/src/ports/SkFontConfigParser_android.h
index d77ca15..2302c77 100644
--- a/src/ports/SkFontConfigParser_android.h
+++ b/src/ports/SkFontConfigParser_android.h
@@ -101,7 +101,8 @@
 void GetCustomFontFamilies(SkTDArray<FontFamily*>& fontFamilies,
                            const SkString& basePath,
                            const char* fontsXml,
-                           const char* fallbackFontsXml);
+                           const char* fallbackFontsXml,
+                           const char* langFallbackFontsDir = NULL);
 
 } // SkFontConfigParser namespace
 
diff --git a/tests/FontConfigParser.cpp b/tests/FontConfigParser.cpp
index dfc8093..dc1fac0 100644
--- a/tests/FontConfigParser.cpp
+++ b/tests/FontConfigParser.cpp
@@ -22,6 +22,16 @@
     return countOfFallbackFonts;
 }
 
+//https://tools.ietf.org/html/rfc5234#appendix-B.1
+static bool isALPHA(int c) {
+    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+}
+
+//https://tools.ietf.org/html/rfc5234#appendix-B.1
+static bool isDIGIT(int c) {
+    return ('0' <= c && c <= '9');
+}
+
 void ValidateLoadedFonts(SkTDArray<FontFamily*> fontFamilies, const char* firstExpectedFile,
                          skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, fontFamilies[0]->fNames.count() == 5);
@@ -29,6 +39,15 @@
     REPORTER_ASSERT(reporter,
                     !strcmp(fontFamilies[0]->fFonts[0].fFileName.c_str(), firstExpectedFile));
     REPORTER_ASSERT(reporter, !fontFamilies[0]->fIsFallbackFont);
+
+    // Check that the languages are all sane.
+    for (int i = 0; i < fontFamilies.count(); ++i) {
+        const SkString& lang = fontFamilies[i]->fLanguage.getTag();
+        for (size_t j = 0; j < lang.size(); ++j) {
+            int c = lang[j];
+            REPORTER_ASSERT(reporter, isALPHA(c) || isDIGIT(c) || '-' == c);
+        }
+    }
 }
 
 void DumpLoadedFonts(SkTDArray<FontFamily*> fontFamilies) {
@@ -55,6 +74,7 @@
             SkDebugf("  file (%d) %s#%d\n", ffi.fWeight, ffi.fFileName.c_str(), ffi.fIndex);
         }
     }
+    SkDebugf("\n\n");
 }
 
 DEF_TEST(FontConfigParserAndroid, reporter) {
@@ -82,11 +102,12 @@
     SkFontConfigParser::GetCustomFontFamilies(v17FontFamilies,
         SkString("/custom/font/path/"),
         GetResourcePath("android_fonts/v17/system_fonts.xml").c_str(),
-        GetResourcePath("android_fonts/v17/fallback_fonts.xml").c_str());
+        GetResourcePath("android_fonts/v17/fallback_fonts.xml").c_str(),
+        GetResourcePath("android_fonts/v17").c_str());
 
     if (v17FontFamilies.count() > 0) {
-        REPORTER_ASSERT(reporter, v17FontFamilies.count() == 41);
-        REPORTER_ASSERT(reporter, CountFallbacks(v17FontFamilies) == 31);
+        REPORTER_ASSERT(reporter, v17FontFamilies.count() == 56);
+        REPORTER_ASSERT(reporter, CountFallbacks(v17FontFamilies) == 46);
 
         DumpLoadedFonts(v17FontFamilies);
         ValidateLoadedFonts(v17FontFamilies, "Roboto-Regular.ttf", reporter);