From 9ff994d98846d24bc488939af6e7dc440149a4bc Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Wed, 30 Nov 2016 14:04:21 -0800 Subject: [PATCH] Introduce set/getFontVariationSettings. This is 2nd attempt of I249d464f8cdaa56017a987588b94ed685aadeb58. The original CL was reverted due to conflicting with another CL submitted before. Nothing has changed except for following class name changes. Here is the original commit message of reverted change. This CL enables developers to specify axis values to the underlying font collection. The specification of the font variation settings is the same as the CSS font-variation-settings attribute in CSS working draft as of 2016-11-30. Code example: Here is an example to set width 100 and weight 1.5. TextView tv = (TextView) findViewById(R.id.textView); tv.setFontVariationSettings("'wdth' 100, 'wght' 1.5"); Bug: 33062398 Test: Manually done. Ran FrameworksGraphicsTests, CtsGraphicsTestCases and CtsWidgetTestCases Change-Id: I9cdfbdecc87c995d805096883ef2652768c6c21e --- api/current.txt | 4 + api/system-current.txt | 4 + api/test-current.txt | 4 + core/java/android/widget/TextView.java | 49 ++++++++ core/jni/Android.mk | 1 + core/jni/android/graphics/FontFamily.cpp | 30 ++--- core/jni/android/graphics/FontUtils.h | 54 ++++++++ core/jni/android/graphics/Typeface.cpp | 21 ++++ .../java/android/graphics/FontListParser.java | 10 +- graphics/java/android/graphics/Paint.java | 32 +++++ graphics/java/android/graphics/Typeface.java | 12 ++ .../android/graphics/VariationParserTest.java | 115 +++++++++--------- libs/hwui/hwui/MinikinSkia.cpp | 25 +++- libs/hwui/hwui/MinikinSkia.h | 2 + libs/hwui/hwui/Typeface.cpp | 24 +++- libs/hwui/hwui/Typeface.h | 3 + 16 files changed, 304 insertions(+), 86 deletions(-) create mode 100644 core/jni/android/graphics/FontUtils.h diff --git a/api/current.txt b/api/current.txt index 6d491cdac3f2b..2eafbadfe84a7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12731,6 +12731,7 @@ package android.graphics { method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt); method public android.graphics.Paint.FontMetricsInt getFontMetricsInt(); method public float getFontSpacing(); + method public java.lang.String getFontVariationSettings(); method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); @@ -12788,6 +12789,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(java.lang.String); + method public void setFontVariationSettings(java.lang.String); method public void setHinting(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); @@ -49983,6 +49985,7 @@ package android.widget { method public int getExtendedPaddingTop(); method public android.text.InputFilter[] getFilters(); method public java.lang.String getFontFeatureSettings(); + method public java.lang.String getFontVariationSettings(); method public boolean getFreezesText(); method public int getGravity(); method public int getHighlightColor(); @@ -50092,6 +50095,7 @@ package android.widget { method public void setExtractedText(android.view.inputmethod.ExtractedText); method public void setFilters(android.text.InputFilter[]); method public void setFontFeatureSettings(java.lang.String); + method public void setFontVariationSettings(java.lang.String); method protected boolean setFrame(int, int, int, int); method public void setFreezesText(boolean); method public void setGravity(int); diff --git a/api/system-current.txt b/api/system-current.txt index 7a08e8a7c977f..08b7431030b6a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -13293,6 +13293,7 @@ package android.graphics { method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt); method public android.graphics.Paint.FontMetricsInt getFontMetricsInt(); method public float getFontSpacing(); + method public java.lang.String getFontVariationSettings(); method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); @@ -13350,6 +13351,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(java.lang.String); + method public void setFontVariationSettings(java.lang.String); method public void setHinting(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); @@ -53749,6 +53751,7 @@ package android.widget { method public int getExtendedPaddingTop(); method public android.text.InputFilter[] getFilters(); method public java.lang.String getFontFeatureSettings(); + method public java.lang.String getFontVariationSettings(); method public boolean getFreezesText(); method public int getGravity(); method public int getHighlightColor(); @@ -53858,6 +53861,7 @@ package android.widget { method public void setExtractedText(android.view.inputmethod.ExtractedText); method public void setFilters(android.text.InputFilter[]); method public void setFontFeatureSettings(java.lang.String); + method public void setFontVariationSettings(java.lang.String); method protected boolean setFrame(int, int, int, int); method public void setFreezesText(boolean); method public void setGravity(int); diff --git a/api/test-current.txt b/api/test-current.txt index cd335e771a097..f4a6af96f174f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12765,6 +12765,7 @@ package android.graphics { method public int getFontMetricsInt(android.graphics.Paint.FontMetricsInt); method public android.graphics.Paint.FontMetricsInt getFontMetricsInt(); method public float getFontSpacing(); + method public java.lang.String getFontVariationSettings(); method public int getHinting(); method public float getLetterSpacing(); method public android.graphics.MaskFilter getMaskFilter(); @@ -12822,6 +12823,7 @@ package android.graphics { method public void setFilterBitmap(boolean); method public void setFlags(int); method public void setFontFeatureSettings(java.lang.String); + method public void setFontVariationSettings(java.lang.String); method public void setHinting(int); method public void setLetterSpacing(float); method public void setLinearText(boolean); @@ -50303,6 +50305,7 @@ package android.widget { method public int getExtendedPaddingTop(); method public android.text.InputFilter[] getFilters(); method public java.lang.String getFontFeatureSettings(); + method public java.lang.String getFontVariationSettings(); method public boolean getFreezesText(); method public int getGravity(); method public int getHighlightColor(); @@ -50412,6 +50415,7 @@ package android.widget { method public void setExtractedText(android.view.inputmethod.ExtractedText); method public void setFilters(android.text.InputFilter[]); method public void setFontFeatureSettings(java.lang.String); + method public void setFontVariationSettings(java.lang.String); method protected boolean setFrame(int, int, int, int); method public void setFreezesText(boolean); method public void setGravity(int); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 51b5b13c10d31..60382a0b83b55 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3432,6 +3432,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mTextPaint.getFontFeatureSettings(); } + /** + * Returns the font variation settings. + * + * @return the currently set font variation settings. Returns null if no variation is + * specified. + * + * @see #setFontVariationSettings(String) + * @see Paint#setFontVariationSettings(String) Paint.setFontVariationSettings(String) + */ + @Nullable + public String getFontVariationSettings() { + return mTextPaint.getFontVariationSettings(); + } + /** * Sets the break strategy for breaking paragraphs into lines. The default value for * TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for @@ -3538,6 +3552,41 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } + /** + * Sets TrueType or OpenType font variation settings. The settings string is constructed from + * multiple pairs of axis tag and style values. The axis tag must contain four ASCII characters + * and must be wrapped with single quotes (U+0027) or double quotes (U+0022). Axis strings that + * are longer or shorter than four characters, or contain characters outside of U+0020..U+007E + * are invalid. If a specified axis name is not defined in the font, the settings will be + * ignored. + * + *
+     *   textView.setFontVariationSettings("'wdth' 1.0");
+     *   textView.setFontVariationSettings("'AX  ' 1.8, 'FB  ' 2.0");
+     * 
+ * + * @param fontVariationSettings font variation settings. You can pass null or empty string as + * no variation settings. + * + * @see #getFontVariationSettings() + * @see Paint#getFontVariationSettings() Paint.getFontVariationSettings() + */ + public void setFontVariationSettings(@Nullable String fontVariationSettings) { + final String existingSettings = mTextPaint.getFontVariationSettings(); + if (fontVariationSettings == existingSettings + || (fontVariationSettings != null + && fontVariationSettings.equals(existingSettings))) { + return; + } + mTextPaint.setFontVariationSettings(fontVariationSettings); + + if (mLayout != null) { + nullLayouts(); + requestLayout(); + invalidate(); + } + } + /** * Sets the text color for all the states (normal, selected, * focused) to be this color. diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 327f142fc319e..cf9441b5c69c6 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -118,6 +118,7 @@ LOCAL_SRC_FILES:= \ android/graphics/ColorFilter.cpp \ android/graphics/DrawFilter.cpp \ android/graphics/FontFamily.cpp \ + android/graphics/FontUtils.cpp \ android/graphics/CreateJavaOutputStreamAdaptor.cpp \ android/graphics/GIFMovie.cpp \ android/graphics/GraphicBuffer.cpp \ diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 0c863fd6eca86..6ec658b9b916e 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -30,6 +30,7 @@ #include #include #include "Utils.h" +#include "FontUtils.h" #include #include @@ -149,16 +150,6 @@ static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong builderPtr, return true; } -static struct { - jmethodID mGet; - jmethodID mSize; -} gListClassInfo; - -static struct { - jfieldID mTag; - jfieldID mStyleValue; -} gAxisClassInfo; - static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong builderPtr, jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) { NPE_CHECK_RETURN_ZERO(env, font); @@ -167,20 +158,22 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong std::unique_ptr skiaAxes; int skiaAxesLength = 0; if (listOfAxis) { - jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize); + ListHelper list(env, listOfAxis); + jint listSize = list.size(); skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]); skiaAxesLength = listSize; for (jint i = 0; i < listSize; ++i) { - jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i); + jobject axisObject = list.get(i); if (!axisObject) { skiaAxes[i].fTag = 0; skiaAxes[i].fStyleValue = 0; continue; } + AxisHelper axis(env, axisObject); - jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag); - jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue); + jint tag = axis.getTag(); + jfloat stylevalue = axis.getStyleValue(); skiaAxes[i].fTag = tag; skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue); } @@ -291,14 +284,7 @@ int register_android_graphics_FontFamily(JNIEnv* env) int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods, NELEM(gFontFamilyMethods)); - jclass listClass = FindClassOrDie(env, "java/util/List"); - gListClassInfo.mGet = GetMethodIDOrDie(env, listClass, "get", "(I)Ljava/lang/Object;"); - gListClassInfo.mSize = GetMethodIDOrDie(env, listClass, "size", "()I"); - - jclass axisClass = FindClassOrDie(env, "android/text/FontConfig$Axis"); - gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "mTag", "I"); - gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "mStyleValue", "F"); - + init_FontUtils(env); return err; } diff --git a/core/jni/android/graphics/FontUtils.h b/core/jni/android/graphics/FontUtils.h new file mode 100644 index 0000000000000..8f44b1e82de8b --- /dev/null +++ b/core/jni/android/graphics/FontUtils.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_GRAPHICS_FONT_UTILS_H_ +#define _ANDROID_GRAPHICS_FONT_UTILS_H_ + +#include + +namespace android { + +// Utility wrapper for java.util.List +class ListHelper { +public: + ListHelper(JNIEnv* env, jobject list) : mEnv(env), mList(list) {} + + jint size() const; + jobject get(jint index) const; + +private: + JNIEnv* mEnv; + jobject mList; +}; + +// Utility wrapper for android.graphics.FontConfig$Axis +class AxisHelper { +public: + AxisHelper(JNIEnv* env, jobject axis) : mEnv(env), mAxis(axis) {} + + jint getTag() const; + jfloat getStyleValue() const; + +private: + JNIEnv* mEnv; + jobject mAxis; +}; + +void init_FontUtils(JNIEnv* env); + +}; // namespace android + +#endif // _ANDROID_GRAPHICS_FONT_UTILS_H_ diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index c920b8d653ab3..0a0fce3ecfabf 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -17,12 +17,14 @@ #include "jni.h" #include "core_jni_helpers.h" +#include "FontUtils.h" #include "GraphicsJNI.h" #include "ScopedPrimitiveArray.h" #include "SkTypeface.h" #include #include #include +#include using namespace android; @@ -40,6 +42,23 @@ static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandl return reinterpret_cast(face); } +static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle, + jobject listOfAxis) { + std::vector variations; + ListHelper list(env, listOfAxis); + for (jint i = 0; i < list.size(); i++) { + jobject axisObject = list.get(i); + if (axisObject == nullptr) { + continue; + } + AxisHelper axis(env, axisObject); + variations.push_back(minikin::FontVariation(axis.getTag(), axis.getStyleValue())); + } + Typeface* baseTypeface = reinterpret_cast(familyHandle); + Typeface* result = Typeface::createFromTypefaceWithVariation(baseTypeface, variations); + return reinterpret_cast(result); +} + static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) { Typeface* family = reinterpret_cast(familyHandle); Typeface* face = Typeface::createWeightAlias(family, weight); @@ -77,6 +96,8 @@ static void Typeface_setDefault(JNIEnv *env, jobject, jlong faceHandle) { static const JNINativeMethod gTypefaceMethods[] = { { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface }, + { "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 }, diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 4ec564ac58099..b757842c4f3fb 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -22,6 +22,7 @@ import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; @@ -52,9 +53,12 @@ public class FontListParser { // Note that a well-formed variation contains a four-character tag and a float as styleValue, // with spacers in between. The tag is enclosd either by double quotes or single quotes. @VisibleForTesting - public static FontConfig.Axis[] parseFontVariationSettings(String settings) { - String[] settingList = settings.split(","); + public static ArrayList parseFontVariationSettings(@Nullable String settings) { ArrayList axisList = new ArrayList<>(); + if (settings == null) { + return axisList; + } + String[] settingList = settings.split(","); settingLoop: for (String setting : settingList) { int pos = 0; @@ -98,7 +102,7 @@ public class FontListParser { tagString.charAt(3)); axisList.add(new FontConfig.Axis(tag, styleValue)); } - return axisList.toArray(new FontConfig.Axis[axisList.size()]); + return axisList; } @VisibleForTesting diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 7815ae16e7e2c..4ee0c34139686 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -71,6 +71,7 @@ public class Paint { private LocaleList mLocales; private String mFontFeatureSettings; + private String mFontVariationSettings; private static final Object sCacheLock = new Object(); @@ -1493,6 +1494,37 @@ public class Paint { nSetFontFeatureSettings(mNativePaint, settings); } + /** + * Returns the font variation settings. + * + * @return the paint's currently set font variation settings. Default is null. + * + * @see #setFontVariationSettings(String) + */ + public String getFontVariationSettings() { + return mFontVariationSettings; + } + + /** + * Set font variation settings. + * + * @param settings font variation settings, e.g. "'wdth' 300, 'wght' 1.8" + * + * @see #getFontVariationSettings() + * + * @param settings the font variation settings. You can pass null or empty string as no + * variation settings. + */ + public void setFontVariationSettings(String settings) { + settings = TextUtils.nullIfEmpty(settings); + if (settings == mFontVariationSettings + || (settings != null && settings.equals(mFontVariationSettings))) { + return; + } + mFontVariationSettings = settings; + setTypeface(Typeface.createFromTypefaceWithVariation(mTypeface, settings)); + } + /** * Get the current value of hyphen edit. * diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 38e806134c93a..f1f141acf91a6 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -31,6 +31,7 @@ import android.util.Log; import android.util.LongSparseArray; import android.util.LruCache; import android.util.SparseArray; +import android.graphics.FontListParser; import com.android.internal.annotations.GuardedBy; @@ -349,6 +350,15 @@ public class Typeface { return typeface; } + /** @hide */ + public static Typeface createFromTypefaceWithVariation(Typeface family, + String fontVariationSettings) { + final long ni = family == null ? 0 : family.native_instance; + ArrayList axes = + FontListParser.parseFontVariationSettings(fontVariationSettings); + return new Typeface(nativeCreateFromTypefaceWithVariation(ni, axes)); + } + /** * Returns one of the default typeface objects, based on the specified style * @@ -625,6 +635,8 @@ public class Typeface { } private static native long nativeCreateFromTypeface(long native_instance, int style); + private static native long nativeCreateFromTypefaceWithVariation( + long native_instance, List 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); diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java index 2b4e6c27f193a..c7a46a3697720 100644 --- a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java +++ b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java @@ -18,9 +18,8 @@ package android.graphics; import android.test.suitebuilder.annotation.SmallTest; import android.text.FontConfig; -import junit.framework.TestCase; - import java.util.List; +import junit.framework.TestCase; public class VariationParserTest extends TestCase { @@ -28,92 +27,92 @@ public class VariationParserTest extends TestCase { @SmallTest public void testParseFontVariationSetting() { int tag = FontListParser.makeTag('w', 'd', 't', 'h'); - FontConfig.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1"); - assertEquals(tag, axis[0].getTag()); - assertEquals(1.0f, axis[0].getStyleValue()); + List axes = FontListParser.parseFontVariationSettings("'wdth' 1"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(1.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings("\"wdth\" 100"); - assertEquals(tag, axis[0].getTag()); - assertEquals(100.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("\"wdth\" 100"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(100.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings(" 'wdth' 100"); - assertEquals(tag, axis[0].getTag()); - assertEquals(100.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings(" 'wdth' 100"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(100.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5"); - assertEquals(tag, axis[0].getTag()); - assertEquals(0.5f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("\t'wdth' 0.5"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(0.5f, axes.get(0).getStyleValue()); tag = FontListParser.makeTag('A', 'X', ' ', ' '); - axis = FontListParser.parseFontVariationSettings("'AX ' 1"); - assertEquals(tag, axis[0].getTag()); - assertEquals(1.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("'AX ' 1"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(1.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings("'AX '\t1"); - assertEquals(tag, axis[0].getTag()); - assertEquals(1.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("'AX '\t1"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(1.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings("'AX '\n1"); - assertEquals(tag, axis[0].getTag()); - assertEquals(1.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("'AX '\n1"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(1.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings("'AX '\r1"); - assertEquals(tag, axis[0].getTag()); - assertEquals(1.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("'AX '\r1"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(1.0f, axes.get(0).getStyleValue()); - axis = FontListParser.parseFontVariationSettings("'AX '\r\t\n 1"); - assertEquals(tag, axis[0].getTag()); - assertEquals(1.0f, axis[0].getStyleValue()); + axes = FontListParser.parseFontVariationSettings("'AX '\r\t\n 1"); + assertEquals(tag, axes.get(0).getTag()); + assertEquals(1.0f, axes.get(0).getStyleValue()); // Test for invalid input - axis = FontListParser.parseFontVariationSettings(""); - assertEquals(0, axis.length); - axis = FontListParser.parseFontVariationSettings("invalid_form"); - assertEquals(0, axis.length); + axes = FontListParser.parseFontVariationSettings(""); + assertEquals(0, axes.size()); + axes = FontListParser.parseFontVariationSettings("invalid_form"); + assertEquals(0, axes.size()); // Test with invalid tag - axis = FontListParser.parseFontVariationSettings("'' 1"); - assertEquals(0, axis.length); - axis = FontListParser.parseFontVariationSettings("'invalid' 1"); - assertEquals(0, axis.length); + axes = FontListParser.parseFontVariationSettings("'' 1"); + assertEquals(0, axes.size()); + axes = FontListParser.parseFontVariationSettings("'invalid' 1"); + assertEquals(0, axes.size()); // Test with invalid styleValue - axis = FontListParser.parseFontVariationSettings("'wdth' "); - assertEquals(0, axis.length); - axis = FontListParser.parseFontVariationSettings("'wdth' x"); - assertEquals(0, axis.length); - axis = FontListParser.parseFontVariationSettings("'wdth' \t"); - assertEquals(0, axis.length); - axis = FontListParser.parseFontVariationSettings("'wdth' \n\r"); - assertEquals(0, axis.length); + axes = FontListParser.parseFontVariationSettings("'wdth' "); + assertEquals(0, axes.size()); + axes = FontListParser.parseFontVariationSettings("'wdth' x"); + assertEquals(0, axes.size()); + axes = FontListParser.parseFontVariationSettings("'wdth' \t"); + assertEquals(0, axes.size()); + axes = FontListParser.parseFontVariationSettings("'wdth' \n\r"); + assertEquals(0, axes.size()); } @SmallTest public void testParseFontVariationStyleSettings() { - FontConfig.Axis[] axis = + List axes = FontListParser.parseFontVariationSettings("'wdth' 10,'AX '\r1"); int tag1 = FontListParser.makeTag('w', 'd', 't', 'h'); int tag2 = FontListParser.makeTag('A', 'X', ' ', ' '); - assertEquals(tag1, axis[0].getTag()); - assertEquals(10.0f, axis[0].getStyleValue()); - assertEquals(tag2, axis[1].getTag()); - assertEquals(1.0f, axis[1].getStyleValue()); + assertEquals(tag1, axes.get(0).getTag()); + assertEquals(10.0f, axes.get(0).getStyleValue()); + assertEquals(tag2, axes.get(1).getTag()); + assertEquals(1.0f, axes.get(1).getStyleValue()); // Test only spacers are allowed before tag - axis = FontListParser.parseFontVariationSettings(" 'wdth' 10,ab'wdth' 1"); + axes = FontListParser.parseFontVariationSettings(" 'wdth' 10,ab'wdth' 1"); tag1 = FontListParser.makeTag('w', 'd', 't', 'h'); - assertEquals(tag1, axis[0].getTag()); - assertEquals(10.0f, axis[0].getStyleValue()); - assertEquals(1, axis.length); + assertEquals(tag1, axes.get(0).getTag()); + assertEquals(10.0f, axes.get(0).getStyleValue()); + assertEquals(1, axes.size()); } @SmallTest public void testInvalidTagCharacters() { - FontConfig.Axis[] axis = + List axes = FontListParser.parseFontVariationSettings("'\u0000\u0000\u0000\u0000' 10"); - assertEquals(0, axis.length); - axis = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10"); - assertEquals(0, axis.length); + assertEquals(0, axes.size()); + axes = FontListParser.parseFontVariationSettings("'\u3042\u3044\u3046\u3048' 10"); + assertEquals(0, axes.size()); } @SmallTest diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp index 956f66ed22cbd..6a003794fb283 100644 --- a/libs/hwui/hwui/MinikinSkia.cpp +++ b/libs/hwui/hwui/MinikinSkia.cpp @@ -17,7 +17,8 @@ #include "MinikinSkia.h" #include - +#include +#include #include #include @@ -86,6 +87,28 @@ int MinikinFontSkia::GetFontIndex() const { return mTtcIndex; } +minikin::MinikinFont* MinikinFontSkia::createFontWithVariation( + const std::vector& variations) const { + SkFontMgr::FontParameters params; + + int ttcIndex; + SkStreamAsset* stream = mTypeface->openStream(&ttcIndex); + LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed"); + + params.setCollectionIndex(ttcIndex); + std::vector skAxes; + skAxes.resize(variations.size()); + for (size_t i = 0; i < variations.size(); i++) { + skAxes[i].fTag = variations[i].axisTag; + skAxes[i].fStyleValue = SkFloatToScalar(variations[i].value); + } + params.setAxes(skAxes.data(), skAxes.size()); + sk_sp fm(SkFontMgr::RefDefault()); + sk_sp face(fm->createFromStream(stream, params)); + + return new MinikinFontSkia(std::move(face), mFontData, mFontSize, ttcIndex); +} + uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) { uint32_t flags = paint->getFlags(); SkPaint::Hinting hinting = paint->getHinting(); diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h index 3ee916c6e8b11..249b0cbe44de9 100644 --- a/libs/hwui/hwui/MinikinSkia.h +++ b/libs/hwui/hwui/MinikinSkia.h @@ -44,6 +44,8 @@ public: const void* GetFontData() const; size_t GetFontSize() const; int GetFontIndex() const; + minikin::MinikinFont* createFontWithVariation( + const std::vector&) const; static uint32_t packPaintFlags(const SkPaint* paint); static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags); diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index 9041b44db849f..b69b0cb29efef 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -62,7 +62,7 @@ Typeface* Typeface::resolveDefault(Typeface* src) { Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) { Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface; - if (result != 0) { + if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; result->fFontCollection->Ref(); result->fSkiaStyle = style; @@ -72,10 +72,30 @@ Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) { return result; } +Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src, + const std::vector& variations) { + Typeface* resolvedFace = Typeface::resolveDefault(src); + Typeface* result = new Typeface(); + if (result != nullptr) { + result->fFontCollection = + resolvedFace->fFontCollection->createCollectionWithVariation(variations); + if (result->fFontCollection == nullptr) { + // None of passed axes are supported by this collection. + // So we will reuse the same collection with incrementing reference count. + result->fFontCollection = resolvedFace->fFontCollection; + result->fFontCollection->Ref(); + } + result->fSkiaStyle = resolvedFace->fSkiaStyle; + result->fBaseWeight = resolvedFace->fBaseWeight; + resolveStyle(result); + } + return result; +} + Typeface* Typeface::createWeightAlias(Typeface* src, int weight) { Typeface* resolvedFace = Typeface::resolveDefault(src); Typeface* result = new Typeface; - if (result != 0) { + if (result != nullptr) { result->fFontCollection = resolvedFace->fFontCollection; result->fFontCollection->Ref(); result->fSkiaStyle = resolvedFace->fSkiaStyle; diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h index 1be630c1e9780..4392ebc36badf 100644 --- a/libs/hwui/hwui/Typeface.h +++ b/libs/hwui/hwui/Typeface.h @@ -43,6 +43,9 @@ struct ANDROID_API Typeface { static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style); + static Typeface* createFromTypefaceWithVariation(Typeface* src, + const std::vector& variations); + static Typeface* createWeightAlias(Typeface* src, int baseweight); static Typeface* createFromFamilies(const std::vector& families);