diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/provider/FontsContract.java | 8 | ||||
| -rw-r--r-- | core/jni/android/graphics/FontFamily.cpp | 32 | ||||
| -rw-r--r-- | core/jni/android/graphics/Typeface.cpp | 15 | ||||
| -rw-r--r-- | graphics/java/android/graphics/FontFamily.java | 31 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Typeface.java | 177 | ||||
| -rw-r--r-- | libs/hwui/hwui/Typeface.cpp | 12 | ||||
| -rw-r--r-- | libs/hwui/hwui/Typeface.h | 2 |
10 files changed, 239 insertions, 41 deletions
diff --git a/api/current.txt b/api/current.txt index 8be087c15c88..a79e82142a0c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13789,6 +13789,7 @@ package android.graphics { ctor public Typeface.Builder(java.lang.String); ctor public Typeface.Builder(android.content.res.AssetManager, java.lang.String); method public android.graphics.Typeface build(); + method public android.graphics.Typeface.Builder setFallback(java.lang.String); method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); method public android.graphics.Typeface.Builder setItalic(boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 9ec51c7f8183..9ca22796f1c9 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -14556,6 +14556,7 @@ package android.graphics { ctor public Typeface.Builder(java.lang.String); ctor public Typeface.Builder(android.content.res.AssetManager, java.lang.String); method public android.graphics.Typeface build(); + method public android.graphics.Typeface.Builder setFallback(java.lang.String); method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); method public android.graphics.Typeface.Builder setItalic(boolean); diff --git a/api/test-current.txt b/api/test-current.txt index ca3ef74dc4bf..7c163755a15a 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -13831,6 +13831,7 @@ package android.graphics { ctor public Typeface.Builder(java.lang.String); ctor public Typeface.Builder(android.content.res.AssetManager, java.lang.String); method public android.graphics.Typeface build(); + method public android.graphics.Typeface.Builder setFallback(java.lang.String); method public android.graphics.Typeface.Builder setFontVariationSettings(java.lang.String) throws android.graphics.fonts.FontVariationAxis.InvalidFormatException; method public android.graphics.Typeface.Builder setFontVariationSettings(android.graphics.fonts.FontVariationAxis[]); method public android.graphics.Typeface.Builder setItalic(boolean); diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java index 7e56ff988158..e9ef770212c8 100644 --- a/core/java/android/provider/FontsContract.java +++ b/core/java/android/provider/FontsContract.java @@ -592,15 +592,11 @@ public class FontsContract { int weight, boolean italic, @Nullable String fallbackFontName) { final Map<Uri, ByteBuffer> uriBuffer = prepareFontData(context, fonts, cancellationSignal); - Typeface typeface = new Typeface.Builder(fonts, uriBuffer) + return new Typeface.Builder(fonts, uriBuffer) + .setFallback(fallbackFontName) .setWeight(weight) .setItalic(italic) .build(); - // TODO: Use Typeface fallback instead. - if (typeface == null) { - typeface = Typeface.create(fallbackFontName, Typeface.NORMAL); - } - return typeface; } /** diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 3010dc1699e1..fc90fb37ff7e 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -45,21 +45,24 @@ namespace android { constexpr jint RESOLVE_BY_FONT_TABLE = -1; struct NativeFamilyBuilder { + NativeFamilyBuilder(uint32_t langId, int variant) + : langId(langId), variant(variant), allowUnsupportedFont(false) {} uint32_t langId; int variant; + bool allowUnsupportedFont; std::vector<minikin::Font> fonts; std::vector<minikin::FontVariation> axes; }; static jlong FontFamily_initBuilder(JNIEnv* env, jobject clazz, jstring lang, jint variant) { - NativeFamilyBuilder* builder = new NativeFamilyBuilder(); + NativeFamilyBuilder* builder; if (lang != nullptr) { ScopedUtfChars str(env, lang); - builder->langId = minikin::FontStyle::registerLanguageList(str.c_str()); + builder = new NativeFamilyBuilder( + minikin::FontStyle::registerLanguageList(str.c_str()), variant); } else { - builder->langId = minikin::FontStyle::registerLanguageList(""); + builder = new NativeFamilyBuilder(minikin::FontStyle::registerLanguageList(""), variant); } - builder->variant = variant; return reinterpret_cast<jlong>(builder); } @@ -67,12 +70,22 @@ static jlong FontFamily_create(jlong builderPtr) { if (builderPtr == 0) { return 0; } + std::unique_ptr<NativeFamilyBuilder> builder( + reinterpret_cast<NativeFamilyBuilder*>(builderPtr)); + std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>( + builder->langId, builder->variant, std::move(builder->fonts)); + if (family->getCoverage().length() == 0 && !builder->allowUnsupportedFont) { + return 0; + } + return reinterpret_cast<jlong>(new FontFamilyWrapper(std::move(family))); +} + +static void FontFamily_allowUnsupportedFont(jlong builderPtr) { + if (builderPtr == 0) { + return; + } NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr); - FontFamilyWrapper* family = new FontFamilyWrapper( - std::make_shared<minikin::FontFamily>( - builder->langId, builder->variant, std::move(builder->fonts))); - delete builder; - return reinterpret_cast<jlong>(family); + builder->allowUnsupportedFont = true; } static void FontFamily_abort(jlong builderPtr) { @@ -258,6 +271,7 @@ static void FontFamily_addAxisValue(jlong builderPtr, jint tag, jfloat value) { static const JNINativeMethod gFontFamilyMethods[] = { { "nInitBuilder", "(Ljava/lang/String;I)J", (void*)FontFamily_initBuilder }, { "nCreateFamily", "(J)J", (void*)FontFamily_create }, + { "nAllowUnsupportedFont", "(J)V", (void*)FontFamily_allowUnsupportedFont }, { "nAbort", "(J)V", (void*)FontFamily_abort }, { "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, { "nAddFont", "(JLjava/nio/ByteBuffer;III)Z", (void*)FontFamily_addFont }, diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index d0b07d0168df..95d43c6c8203 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -42,6 +42,13 @@ static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandl return reinterpret_cast<jlong>(face); } +static jlong Typeface_createFromTypefaceWithExactStyle(JNIEnv* env, jobject, jlong nativeInstance, + jint weight, jboolean italic) { + Typeface* baseTypeface = reinterpret_cast<Typeface*>(nativeInstance); + return reinterpret_cast<jlong>( + Typeface::createFromTypefaceWithStyle(baseTypeface, weight, italic)); +} + static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle, jobject listOfAxis) { std::vector<minikin::FontVariation> variations; @@ -75,6 +82,11 @@ static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) { return face->fSkiaStyle; } +static jint Typeface_getBaseWeight(JNIEnv* env, jobject obj, jlong faceHandle) { + Typeface* face = reinterpret_cast<Typeface*>(faceHandle); + return face->fBaseWeight; +} + static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray) { ScopedLongArrayRO families(env, familyArray); std::vector<std::shared_ptr<minikin::FontFamily>> familyVec; @@ -113,11 +125,14 @@ static jobject Typeface_getSupportedAxes(JNIEnv *env, jobject, jlong faceHandle) static const JNINativeMethod gTypefaceMethods[] = { { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface }, + { "nativeCreateFromTypefaceWithExactStyle", "(JIZ)J", + (void*)Typeface_createFromTypefaceWithExactStyle }, { "nativeCreateFromTypefaceWithVariation", "(JLjava/util/List;)J", (void*)Typeface_createFromTypefaceWithVariation }, { "nativeCreateWeightAlias", "(JI)J", (void*)Typeface_createWeightAlias }, { "nativeUnref", "(J)V", (void*)Typeface_unref }, { "nativeGetStyle", "(J)I", (void*)Typeface_getStyle }, + { "nativeGetBaseWeight", "(J)I", (void*)Typeface_getBaseWeight }, { "nativeCreateFromArray", "([J)J", (void*)Typeface_createFromArray }, { "nativeSetDefault", "(J)V", (void*)Typeface_setDefault }, diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 4b1b0c641807..d9a77e752823 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -52,12 +52,19 @@ public class FontFamily { mBuilderPtr = nInitBuilder(lang, variant); } - public void freeze() { + /** + * Finalize the FontFamily creation. + * + * @return boolean returns false if some error happens in native code, e.g. broken font file is + * passed, etc. + */ + public boolean freeze() { if (mBuilderPtr == 0) { throw new IllegalStateException("This FontFamily is already frozen"); } mNativePtr = nCreateFamily(mBuilderPtr); mBuilderPtr = 0; + return mNativePtr != 0; } public void abortCreation() { @@ -143,6 +150,25 @@ public class FontFamily { isItalic); } + /** + * Allow creating unsupported FontFamily. + * + * For compatibility reasons, we still need to create a FontFamily object even if Minikin failed + * to find any usable 'cmap' table for some reasons, e.g. broken 'cmap' table, no 'cmap' table + * encoded with Unicode code points, etc. Without calling this method, the freeze() method will + * return null if Minikin fails to find any usable 'cmap' table. By calling this method, the + * freeze() won't fail and will create an empty FontFamily. This empty FontFamily is placed at + * the top of the fallback chain but is never used. if we don't create this empty FontFamily + * and put it at top, bad things (performance regressions, unexpected glyph selection) will + * happen. + */ + public void allowUnsupportedFont() { + if (mBuilderPtr == 0) { + throw new IllegalStateException("Unable to allow unsupported font."); + } + nAllowUnsupportedFont(mBuilderPtr); + } + // TODO: Remove once internal user stop using private API. private static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex) { return nAddFont(builderPtr, font, ttcIndex, -1, -1); @@ -154,6 +180,9 @@ public class FontFamily { private static native long nCreateFamily(long mBuilderPtr); @CriticalNative + private static native void nAllowUnsupportedFont(long builderPtr); + + @CriticalNative private static native void nAbort(long mBuilderPtr); @CriticalNative diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index c3588dc3c10d..2aca7824539e 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -108,6 +108,7 @@ public class Typeface { /** * Cache for Typeface objects dynamically loaded from assets. Currently max size is 16. */ + @GuardedBy("sLock") private static final LruCache<String, Typeface> sDynamicTypefaceCache = new LruCache<>(16); static Typeface sDefaultTypeface; @@ -129,6 +130,7 @@ public class Typeface { public static final int BOLD_ITALIC = 3; private int mStyle = 0; + private int mBaseWeight = 0; // Value for weight and italic. Indicates the value is resolved by font metadata. // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp @@ -180,7 +182,9 @@ public class Typeface { if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { - fontFamily.freeze(); + if (!fontFamily.freeze()) { + return null; + } FontFamily[] families = {fontFamily}; typeface = createFromFamiliesWithDefault(families); sDynamicTypefaceCache.put(key, typeface); @@ -241,6 +245,10 @@ public class Typeface { return null; } } + // Due to backward compatibility, even if the font is not supported by our font stack, + // we need to place the empty font at the first place. The typeface with empty font + // behaves different from default typeface especially in fallback font selection. + fontFamily.allowUnsupportedFont(); fontFamily.freeze(); FontFamily[] familyChain = { fontFamily }; typeface = createFromFamiliesWithDefault(familyChain); @@ -393,7 +401,11 @@ public class Typeface { IoUtils.closeQuietly(fd); } } - fontFamily.freeze(); + if (!fontFamily.freeze()) { + callback.onTypefaceRequestFailed( + FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR); + return; + } Typeface typeface = Typeface.createFromFamiliesWithDefault(new FontFamily[] { fontFamily }); synchronized (sDynamicTypefaceCache) { String key = createProviderUid(request.getProviderAuthority(), request.getQuery()); @@ -526,6 +538,7 @@ public class Typeface { private FontsContract.FontInfo[] mFonts; private Map<Uri, ByteBuffer> mFontBuffers; + private String mFallbackFamilyName; private int mWeight = RESOLVE_BY_FONT_TABLE; @@ -666,6 +679,33 @@ public class Typeface { } /** + * Sets a fallback family name. + * + * By specifying a fallback family name, a fallback Typeface will be returned if the + * {@link #build} method fails to create a Typeface from the provided font. The fallback + * family will be resolved with the provided weight and italic information specified by + * {@link #setWeight} and {@link #setItalic}. + * + * If {@link #setWeight} is not called, the fallback family keeps the default weight. + * Similary, if {@link #setItalic} is not called, the fallback family keeps the default + * italic information. For example, calling {@code builder.setFallback("sans-serif-light")} + * is equivalent to calling {@code builder.setFallback("sans-serif").setWeight(300)} in + * terms of fallback. The default weight and italic information are overridden by calling + * {@link #setWeight} and {@link #setItalic}. For example, if a Typeface is constructed + * using {@code builder.setFallback("sans-serif-light").setWeight(700)}, the fallback text + * will render as sans serif bold. + * + * @param familyName A family name to be used for fallback if the provided font can not be + * used. By passing {@code null}, build() returns {@code null}. + * If {@link #setFallback} is not called on the builder, {@code null} + * is assumed. + */ + public Builder setFallback(@Nullable String familyName) { + mFallbackFamilyName = familyName; + return this; + } + + /** * Creates a unique id for a given AssetManager and asset path. * * @param mgr AssetManager instance @@ -697,6 +737,54 @@ public class Typeface { return builder.toString(); } + private static final Object sLock = new Object(); + // TODO: Unify with Typeface.sTypefaceCache. + @GuardedBy("sLock") + private static final LongSparseArray<SparseArray<Typeface>> sTypefaceCache = + new LongSparseArray<>(3); + + private Typeface resolveFallbackTypeface() { + if (mFallbackFamilyName == null) { + return null; + } + + Typeface base = sSystemFontMap.get(mFallbackFamilyName); + if (base == null) { + base = sDefaultTypeface; + } + + if (mWeight == RESOLVE_BY_FONT_TABLE && mItalic == RESOLVE_BY_FONT_TABLE) { + return base; + } + + final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mBaseWeight : mWeight; + final boolean italic = + (mItalic == RESOLVE_BY_FONT_TABLE) ? (base.mStyle & ITALIC) != 0 : mItalic == 1; + final int key = weight << 1 | (italic ? 1 : 0); + + Typeface typeface; + synchronized(sLock) { + SparseArray<Typeface> innerCache = sTypefaceCache.get(base.native_instance); + if (innerCache != null) { + typeface = innerCache.get(key); + if (typeface != null) { + return typeface; + } + } + + typeface = new Typeface( + nativeCreateFromTypefaceWithExactStyle( + base.native_instance, weight, italic)); + + if (innerCache == null) { + innerCache = new SparseArray<>(4); // [regular, bold] x [upright, italic] + sTypefaceCache.put(base.native_instance, innerCache); + } + innerCache.put(key, typeface); + } + return typeface; + } + /** * Generates new Typeface from specified configuration. * @@ -712,26 +800,30 @@ public class Typeface { final FontFamily fontFamily = new FontFamily(); if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) { fontFamily.abortCreation(); - return null; + return resolveFallbackTypeface(); + } + if (!fontFamily.freeze()) { + return resolveFallbackTypeface(); } - fontFamily.freeze(); FontFamily[] families = { fontFamily }; return createFromFamiliesWithDefault(families); } catch (IOException e) { - return null; + return resolveFallbackTypeface(); } } else if (mAssetManager != null) { // set source by setSourceFromAsset() final String key = createAssetUid(mAssetManager, mPath, mTtcIndex, mAxes); - synchronized (sDynamicTypefaceCache) { + synchronized (sLock) { Typeface typeface = sDynamicTypefaceCache.get(key); if (typeface != null) return typeface; final FontFamily fontFamily = new FontFamily(); if (!fontFamily.addFontFromAssetManager(mAssetManager, mPath, mTtcIndex, true /* isAsset */, mTtcIndex, mWeight, mItalic, mAxes)) { fontFamily.abortCreation(); - return null; + return resolveFallbackTypeface(); + } + if (!fontFamily.freeze()) { + return resolveFallbackTypeface(); } - fontFamily.freeze(); FontFamily[] families = { fontFamily }; typeface = createFromFamiliesWithDefault(families); sDynamicTypefaceCache.put(key, typeface); @@ -741,9 +833,11 @@ public class Typeface { final FontFamily fontFamily = new FontFamily(); if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) { fontFamily.abortCreation(); - return null; + return resolveFallbackTypeface(); + } + if (!fontFamily.freeze()) { + return resolveFallbackTypeface(); } - fontFamily.freeze(); FontFamily[] families = { fontFamily }; return createFromFamiliesWithDefault(families); } else if (mFonts != null) { @@ -870,12 +964,34 @@ public class Typeface { throw new NullPointerException(); // for backward compatibility } if (sFallbackFonts != null) { - Typeface typeface = new Builder(mgr, path).build(); - if (typeface != null) { - return typeface; + synchronized (sLock) { + Typeface typeface = new Builder(mgr, path).build(); + if (typeface != null) return typeface; + + final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, + null /* axes */); + typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; + + final FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */, + 0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, + null /* axes */)) { + // Due to backward compatibility, even if the font is not supported by our font + // stack, we need to place the empty font at the first place. The typeface with + // empty font behaves different from default typeface especially in fallback + // font selection. + fontFamily.allowUnsupportedFont(); + fontFamily.freeze(); + final FontFamily[] families = { fontFamily }; + typeface = createFromFamiliesWithDefault(families); + sDynamicTypefaceCache.put(key, typeface); + return typeface; + } else { + fontFamily.abortCreation(); + } } } - // For the compatibility reasons, throw runtime exception if failed to create Typeface. throw new RuntimeException("Font asset not found " + path); } @@ -910,17 +1026,20 @@ public class Typeface { * @return The new typeface. */ public static Typeface createFromFile(@Nullable String path) { - if (path == null) { - // For the compatibility reasons, need to throw NPE if the argument is null. - // See android.graphics.cts.TypefaceTest#testCreateFromFileByFileNameNull - throw new NullPointerException(); - } if (sFallbackFonts != null) { - Typeface typeface = new Builder(path).build(); - if (typeface != null) { - // For the compatibility reasons, throw runtime exception if failed to create - // Typeface. - return typeface; + final FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) { + // Due to backward compatibility, even if the font is not supported by our font + // stack, we need to place the empty font at the first place. The typeface with + // empty font behaves different from default typeface especially in fallback font + // selection. + fontFamily.allowUnsupportedFont(); + fontFamily.freeze(); + FontFamily[] families = { fontFamily }; + return createFromFamiliesWithDefault(families); + } else { + fontFamily.abortCreation(); } } throw new RuntimeException("Font not found " + path); @@ -964,6 +1083,7 @@ public class Typeface { native_instance = ni; mStyle = nativeGetStyle(ni); + mBaseWeight = nativeGetBaseWeight(ni); } private static FontFamily makeFamilyFromParsed(FontConfig.Family family, @@ -988,7 +1108,11 @@ public class Typeface { Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex()); } } - fontFamily.freeze(); + if (!fontFamily.freeze()) { + // Treat as system error since reaching here means that a system pre-installed font + // can't be used by our font stack. + Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage()); + } return fontFamily; } @@ -1129,12 +1253,15 @@ public class Typeface { } private static native long nativeCreateFromTypeface(long native_instance, int style); + private static native long nativeCreateFromTypefaceWithExactStyle( + long native_instance, int weight, boolean italic); // TODO: clean up: change List<FontVariationAxis> to FontVariationAxis[] private static native long nativeCreateFromTypefaceWithVariation( long native_instance, List<FontVariationAxis> axes); private static native long nativeCreateWeightAlias(long native_instance, int weight); 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 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 4b8575adb32b..86709ee3a1fa 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -71,6 +71,18 @@ Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) { return result; } +Typeface* Typeface::createFromTypefaceWithStyle(Typeface* base, int weight, bool italic) { + Typeface* resolvedFace = Typeface::resolveDefault(base); + Typeface* result = new Typeface(); + if (result != nullptr) { + result->fFontCollection = resolvedFace->fFontCollection; + result->fBaseWeight = weight; + result->fStyle = minikin::FontStyle(weight / 100, italic); + result->fSkiaStyle = resolvedFace->fSkiaStyle; + } + return result; +} + Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, const std::vector<minikin::FontVariation>& variations) { Typeface* resolvedFace = Typeface::resolveDefault(src); diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index 19a4f6c5acd5..27ee4a2a35aa 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -42,6 +42,8 @@ struct ANDROID_API Typeface { static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style); + static Typeface* createFromTypefaceWithStyle(Typeface* base, int weight, bool italic); + static Typeface* createFromTypefaceWithVariation(Typeface* src, const std::vector<minikin::FontVariation>& variations); |