Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d154829c authored by Seigo Nonaka's avatar Seigo Nonaka
Browse files

Use provided style for fallback font selection

If the developer gives some weight/italic to the Typeface.Builder
the fallback used the metadata in the font file. We should use
provided data instead.

This CL also adjusts upper and lower limits on weight, from 100..900 to
1..1000

Bug: 37257745
Bug: 37251569
Test: android.graphics.cts.TypefaceTest passes
Change-Id: I7cf390d96b49afcce359928373698b0c9a9babd8
parent 92fc8bdd
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -87,7 +87,8 @@ static jint Typeface_getBaseWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
    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 @@ static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArr
        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 @@ static const JNINativeMethod gTypefaceMethods[] = {
    { "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 },
+48 −24
Original line number Diff line number Diff line
@@ -173,7 +173,8 @@ public class Typeface {
        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 @@ public class Typeface {
                        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 @@ public class Typeface {
            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 class Typeface {
     */
    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 @@ public class Typeface {
                    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 @@ public class Typeface {
         * @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 @@ public class Typeface {
            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 @@ public class Typeface {
         * @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 @@ public class Typeface {
                        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 @@ public class Typeface {
                        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 @@ public class Typeface {
                    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 @@ public class Typeface {
                }
                fontFamily.freeze();
                FontFamily[] families = { fontFamily };
                return createFromFamiliesWithDefault(families);
                return createFromFamiliesWithDefault(families, mWeight, mItalic);
            }

            // Must not reach here.
@@ -969,7 +981,7 @@ public class Typeface {
                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 @@ public class Typeface {
                    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 @@ public class Typeface {
                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 @@ public class Typeface {
        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 @@ public class Typeface {
        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 @@ public class Typeface {
                    } 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 @@ public class Typeface {
    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);
}
+49 −17
Original line number Diff line number Diff line
@@ -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::createWeightAlias(Typeface* src, int weight) {
}

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

    // Sanitize the invalid value passed from public API.
    if (weight < 0) {
        weight = SkFontStyle::kNormal_Weight;
    }
    result->fBaseWeight = 400;

    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 @@ void Typeface::setRobotoTypefaceForTest() {
    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);
+2 −1
Original line number Diff line number Diff line
@@ -50,7 +50,8 @@ struct ANDROID_API Typeface {
    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);