Merge "Introduce setFallbackTypeface" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 8be087c..a79e821 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13789,6 +13789,7 @@
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 9ec51c7..9ca2279 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -14556,6 +14556,7 @@
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 ca3ef74d..7c16375 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -13831,6 +13831,7 @@
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 7e56ff9..e9ef770 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -592,15 +592,11 @@
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 3010dc1..fc90fb3 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -45,21 +45,24 @@
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 @@
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 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 d0b07d0..95d43c6 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -42,6 +42,13 @@
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 @@
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 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 4b1b0c6..d9a77e7 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -52,12 +52,19 @@
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 @@
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 @@
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 c3588dc..2aca782 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -108,6 +108,7 @@
/**
* 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 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 @@
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 @@
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 @@
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 @@
private FontsContract.FontInfo[] mFonts;
private Map<Uri, ByteBuffer> mFontBuffers;
+
private String mFallbackFamilyName;
private int mWeight = RESOLVE_BY_FONT_TABLE;
@@ -666,6 +679,33 @@
}
/**
+ * 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 @@
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 @@
final FontFamily fontFamily = new FontFamily();
if (!fontFamily.addFontFromBuffer(buffer, mTtcIndex, mAxes, mWeight, mItalic)) {
fontFamily.abortCreation();
- return null;
+ return resolveFallbackTypeface();
}
- fontFamily.freeze();
+ if (!fontFamily.freeze()) {
+ return resolveFallbackTypeface();
+ }
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();
}
- fontFamily.freeze();
+ if (!fontFamily.freeze()) {
+ return resolveFallbackTypeface();
+ }
FontFamily[] families = { fontFamily };
typeface = createFromFamiliesWithDefault(families);
sDynamicTypefaceCache.put(key, typeface);
@@ -741,9 +833,11 @@
final FontFamily fontFamily = new FontFamily();
if (!fontFamily.addFont(mPath, mTtcIndex, mAxes, mWeight, mItalic)) {
fontFamily.abortCreation();
- return null;
+ return resolveFallbackTypeface();
}
- fontFamily.freeze();
+ if (!fontFamily.freeze()) {
+ return resolveFallbackTypeface();
+ }
FontFamily[] families = { fontFamily };
return createFromFamiliesWithDefault(families);
} else if (mFonts != null) {
@@ -870,12 +964,34 @@
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 @@
* @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 @@
native_instance = ni;
mStyle = nativeGetStyle(ni);
+ mBaseWeight = nativeGetBaseWeight(ni);
}
private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
@@ -988,7 +1108,11 @@
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 @@
}
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 4b8575a..86709ee 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -71,6 +71,18 @@
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 19a4f6c5..27ee4a2 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -42,6 +42,8 @@
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);