Merge "Use provided style for fallback font selection" into oc-dev am: 43112fd26e
am: 83c52e0a40

Change-Id: Ia42f6a377c2617c8da9a84cb8bd7781326e464a1
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 95d43c6..86c97a1 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -87,7 +87,8 @@
     return face->fBaseWeight;
 }
 
-static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) {
+static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
+        int weight, int italic) {
     ScopedLongArrayRO families(env, familyArray);
     std::vector<std::shared_ptr<minikin::FontFamily>> familyVec;
     familyVec.reserve(families.size());
@@ -95,7 +96,8 @@
         FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(families[i]);
         familyVec.emplace_back(family->family);
     }
-    return reinterpret_cast<jlong>(Typeface::createFromFamilies(std::move(familyVec)));
+    return reinterpret_cast<jlong>(
+            Typeface::createFromFamilies(std::move(familyVec), weight, italic));
 }
 
 static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) {
@@ -133,7 +135,7 @@
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(J)I",  (void*)Typeface_getStyle },
     { "nativeGetBaseWeight",      "(J)I",  (void*)Typeface_getBaseWeight },
-    { "nativeCreateFromArray",    "([J)J",
+    { "nativeCreateFromArray",    "([JII)J",
                                            (void*)Typeface_createFromArray },
     { "nativeSetDefault",         "(J)V",   (void*)Typeface_setDefault },
     { "nativeGetSupportedAxes",   "(J)[I",  (void*)Typeface_getSupportedAxes },
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 2aca782..56f9cc7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -173,7 +173,8 @@
         if (sFallbackFonts != null) {
             synchronized (sDynamicTypefaceCache) {
                 final String key = Builder.createAssetUid(
-                        mgr, path, 0 /* ttcIndex */, null /* axes */);
+                        mgr, path, 0 /* ttcIndex */, null /* axes */,
+                        RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */);
                 Typeface typeface = sDynamicTypefaceCache.get(key);
                 if (typeface != null) return typeface;
 
@@ -186,7 +187,8 @@
                         return null;
                     }
                     FontFamily[] families = {fontFamily};
-                    typeface = createFromFamiliesWithDefault(families);
+                    typeface = createFromFamiliesWithDefault(families,
+                            RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
                     sDynamicTypefaceCache.put(key, typeface);
                     return typeface;
                 }
@@ -251,10 +253,12 @@
             fontFamily.allowUnsupportedFont();
             fontFamily.freeze();
             FontFamily[] familyChain = { fontFamily };
-            typeface = createFromFamiliesWithDefault(familyChain);
+            typeface = createFromFamiliesWithDefault(familyChain,
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
             synchronized (sDynamicTypefaceCache) {
                 final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
-                        null /* axes */);
+                        null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */,
+                        RESOLVE_BY_FONT_TABLE /* italic */);
                 sDynamicTypefaceCache.put(key, typeface);
             }
             return typeface;
@@ -268,7 +272,8 @@
      */
     public static Typeface findFromCache(AssetManager mgr, String path) {
         synchronized (sDynamicTypefaceCache) {
-            final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */);
+            final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */,
+                    RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */);
             Typeface typeface = sDynamicTypefaceCache.get(key);
             if (typeface != null) {
                 return typeface;
@@ -406,7 +411,9 @@
                     FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
             return;
         }
-        Typeface typeface = Typeface.createFromFamiliesWithDefault(new FontFamily[] { fontFamily });
+        Typeface typeface = Typeface.createFromFamiliesWithDefault(
+                new FontFamily[] { fontFamily },
+                RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
         synchronized (sDynamicTypefaceCache) {
             String key = createProviderUid(request.getProviderAuthority(), request.getQuery());
             sDynamicTypefaceCache.put(key, typeface);
@@ -715,7 +722,7 @@
          * @return Unique id for a given AssetManager and asset path.
          */
         private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex,
-                @Nullable FontVariationAxis[] axes) {
+                @Nullable FontVariationAxis[] axes, int weight, int italic) {
             final SparseArray<String> pkgs = mgr.getAssignedPackageIdentifiers();
             final StringBuilder builder = new StringBuilder();
             final int size = pkgs.size();
@@ -727,6 +734,10 @@
             builder.append("-");
             builder.append(Integer.toString(ttcIndex));
             builder.append("-");
+            builder.append(Integer.toString(weight));
+            builder.append("-");
+            builder.append(Integer.toString(italic));
+            builder.append("-");
             if (axes != null) {
                 for (FontVariationAxis axis : axes) {
                     builder.append(axis.getTag());
@@ -791,7 +802,7 @@
          * @return Newly created Typeface. May return null if some parameters are invalid.
          */
         public Typeface build() {
-            if (mFd != null) {  // set source by setSourceFromFile(FileDescriptor)
+            if (mFd != null) {  // Builder is created with file descriptor.
                 try (FileInputStream fis = new FileInputStream(mFd)) {
                     FileChannel channel = fis.getChannel();
                     long size = channel.size();
@@ -806,12 +817,13 @@
                         return resolveFallbackTypeface();
                     }
                     FontFamily[] families = { fontFamily };
-                    return createFromFamiliesWithDefault(families);
+                    return createFromFamiliesWithDefault(families, mWeight, mItalic);
                 } catch (IOException e) {
                     return resolveFallbackTypeface();
                 }
-            } else if (mAssetManager != null) {  // set source by setSourceFromAsset()
-                final String key = createAssetUid(mAssetManager, mPath, mTtcIndex, mAxes);
+            } else if (mAssetManager != null) {  // Builder is created with asset manager.
+                final String key = createAssetUid(
+                        mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic);
                 synchronized (sLock) {
                     Typeface typeface = sDynamicTypefaceCache.get(key);
                     if (typeface != null) return typeface;
@@ -825,11 +837,11 @@
                         return resolveFallbackTypeface();
                     }
                     FontFamily[] families = { fontFamily };
-                    typeface = createFromFamiliesWithDefault(families);
+                    typeface = createFromFamiliesWithDefault(families, mWeight, mItalic);
                     sDynamicTypefaceCache.put(key, typeface);
                     return typeface;
                 }
-            } else if (mPath != null) {  // set source by setSourceFromFile(File)
+            } else if (mPath != null) {  // Builder is created with file path.
                 final FontFamily fontFamily = new FontFamily();
                 if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) {
                     fontFamily.abortCreation();
@@ -839,7 +851,7 @@
                     return resolveFallbackTypeface();
                 }
                 FontFamily[] families = { fontFamily };
-                return createFromFamiliesWithDefault(families);
+                return createFromFamiliesWithDefault(families, mWeight, mItalic);
             } else if (mFonts != null) {
                 final FontFamily fontFamily = new FontFamily();
                 boolean atLeastOneFont = false;
@@ -865,7 +877,7 @@
                 }
                 fontFamily.freeze();
                 FontFamily[] families = { fontFamily };
-                return createFromFamiliesWithDefault(families);
+                return createFromFamiliesWithDefault(families, mWeight, mItalic);
             }
 
             // Must not reach here.
@@ -969,7 +981,7 @@
                 if (typeface != null) return typeface;
 
                 final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */,
-                        null /* axes */);
+                        null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
                 typeface = sDynamicTypefaceCache.get(key);
                 if (typeface != null) return typeface;
 
@@ -984,7 +996,8 @@
                     fontFamily.allowUnsupportedFont();
                     fontFamily.freeze();
                     final FontFamily[] families = { fontFamily };
-                    typeface = createFromFamiliesWithDefault(families);
+                    typeface = createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE,
+                            RESOLVE_BY_FONT_TABLE);
                     sDynamicTypefaceCache.put(key, typeface);
                     return typeface;
                 } else {
@@ -1037,7 +1050,8 @@
                 fontFamily.allowUnsupportedFont();
                 fontFamily.freeze();
                 FontFamily[] families = { fontFamily };
-                return createFromFamiliesWithDefault(families);
+                return createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE,
+                        RESOLVE_BY_FONT_TABLE);
             } else {
                 fontFamily.abortCreation();
             }
@@ -1055,16 +1069,25 @@
         for (int i = 0; i < families.length; i++) {
             ptrArray[i] = families[i].mNativePtr;
         }
-        return new Typeface(nativeCreateFromArray(ptrArray));
+        return new Typeface(nativeCreateFromArray(
+                ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
     }
 
     /**
      * Create a new typeface from an array of font families, including
      * also the font families in the fallback list.
-     *
+     * @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that
+     *               case, the table information in the first family's font is used. If the first
+     *               family has multiple fonts, the closest to the regular weight and upright font
+     *               is used.
+     * @param italic the italic information for this family. {@link RESOLVE_BY_FONT_TABLE} can be
+     *               used. In that case, the table information in the first family's font is used.
+     *               If the first family has multiple fonts, the closest to the regular weight and
+     *               upright font is used.
      * @param families array of font families
      */
-    private static Typeface createFromFamiliesWithDefault(FontFamily[] families) {
+    private static Typeface createFromFamiliesWithDefault(FontFamily[] families,
+                int weight, int italic) {
         long[] ptrArray = new long[families.length + sFallbackFonts.length];
         for (int i = 0; i < families.length; i++) {
             ptrArray[i] = families[i].mNativePtr;
@@ -1072,7 +1095,7 @@
         for (int i = 0; i < sFallbackFonts.length; i++) {
             ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr;
         }
-        return new Typeface(nativeCreateFromArray(ptrArray));
+        return new Typeface(nativeCreateFromArray(ptrArray, weight, italic));
     }
 
     // don't allow clients to call this directly
@@ -1155,7 +1178,8 @@
                     } else {
                         FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
                         FontFamily[] families = { fontFamily };
-                        typeface = Typeface.createFromFamiliesWithDefault(families);
+                        typeface = Typeface.createFromFamiliesWithDefault(families,
+                                RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
                     }
                     systemFonts.put(f.getName(), typeface);
                 }
@@ -1262,7 +1286,7 @@
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
     private static native int  nativeGetBaseWeight(long native_instance);
-    private static native long nativeCreateFromArray(long[] familyArray);
+    private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic);
     private static native void nativeSetDefault(long native_instance);
     private static native int[] nativeGetSupportedAxes(long native_instance);
 }
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 86709ee..4fb4b53 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -39,14 +39,22 @@
 
 namespace android {
 
-// Resolve the 1..9 weight based on base weight and bold flag
+// This indicates that the passed information should be resolved by OS/2 table.
+// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
+constexpr int RESOLVE_BY_FONT_TABLE = -1;
+
+// Resolve the 1..10 weight based on base weight and bold flag
 static void resolveStyle(Typeface* typeface) {
-    int weight = typeface->fBaseWeight / 100;
+    // TODO: Better to use raw base weight value for font selection instead of dividing by 100.
+    int weight = (typeface->fBaseWeight + 50) / 100;
     if (typeface->fSkiaStyle & SkTypeface::kBold) {
         weight += 3;
     }
-    if (weight > 9) {
-        weight = 9;
+    if (weight > 10) {
+        weight = 10;
+    }
+    if (weight < 1) {
+        weight = 1;
     }
     bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
     typeface->fStyle = minikin::FontStyle(weight, italic);
@@ -115,26 +123,50 @@
 }
 
 Typeface* Typeface::createFromFamilies(
-        std::vector<std::shared_ptr<minikin::FontFamily>>&& families) {
+        std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
+        int weight, int italic) {
     Typeface* result = new Typeface;
     result->fFontCollection.reset(new minikin::FontCollection(families));
-    if (families.empty()) {
-        ALOGW("createFromFamilies creating empty collection");
-        result->fSkiaStyle = SkTypeface::kNormal;
-    } else {
+
+    if (weight == RESOLVE_BY_FONT_TABLE || italic == RESOLVE_BY_FONT_TABLE) {
+        int weightFromFont;
+        bool italicFromFont;
+
         const minikin::FontStyle defaultStyle;
-        const std::shared_ptr<minikin::FontFamily>& firstFamily = families[0];
-        const minikin::MinikinFont* mf = firstFamily->getClosestMatch(defaultStyle).font;
+        const minikin::MinikinFont* mf =
+                families.empty() ?  nullptr : families[0]->getClosestMatch(defaultStyle).font;
         if (mf != nullptr) {
             SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
-            // TODO: probably better to query more precise style from family, will be important
-            // when we open up API to access 100..900 weights
-            result->fSkiaStyle = skTypeface->style();
+            const SkFontStyle& style = skTypeface->fontStyle();
+            weightFromFont = style.weight();
+            italicFromFont = style.slant() != SkFontStyle::kUpright_Slant;
         } else {
-            result->fSkiaStyle = SkTypeface::kNormal;
+            // We can't obtain any information from fonts. Just use default values.
+            weightFromFont = SkFontStyle::kNormal_Weight;
+            italicFromFont = false;
+        }
+
+        if (weight == RESOLVE_BY_FONT_TABLE) {
+            weight = weightFromFont;
+        }
+        if (italic == RESOLVE_BY_FONT_TABLE) {
+            italic = italicFromFont? 1 : 0;
         }
     }
-    result->fBaseWeight = 400;
+
+    // Sanitize the invalid value passed from public API.
+    if (weight < 0) {
+        weight = SkFontStyle::kNormal_Weight;
+    }
+
+    result->fBaseWeight = weight;
+    // This bold detection comes from SkTypefae.h
+    const bool isBold = weight >= SkFontStyle::kSemiBold_Weight;
+    const bool isItalic = italic == 1;
+    // TODO: remove fSkiaStyle
+    result->fSkiaStyle = isBold ?
+            (isItalic ? SkTypeface::kBoldItalic : SkTypeface::kBold) :
+            (isItalic ? SkTypeface::kItalic : SkTypeface::kNormal);
     resolveStyle(result);
     return result;
 }
@@ -165,7 +197,7 @@
     Typeface* hwTypeface = new Typeface();
     hwTypeface->fFontCollection = collection;
     hwTypeface->fSkiaStyle = SkTypeface::kNormal;
-    hwTypeface->fBaseWeight = 400;
+    hwTypeface->fBaseWeight = SkFontStyle::kSemiBold_Weight;
     hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
 
     Typeface::setDefault(hwTypeface);
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index 27ee4a2..e35a7b4 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -50,7 +50,8 @@
     static Typeface* createWeightAlias(Typeface* src, int baseweight);
 
     static Typeface* createFromFamilies(
-            std::vector<std::shared_ptr<minikin::FontFamily>>&& families);
+            std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
+            int weight, int italic);
 
     static void setDefault(Typeface* face);