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
This commit is contained in:
Seigo Nonaka
2016-11-30 14:04:21 -08:00
parent ac2d178578
commit 9ff994d988
16 changed files with 304 additions and 86 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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.
*
* <pre>
* textView.setFontVariationSettings("'wdth' 1.0");
* textView.setFontVariationSettings("'AX ' 1.8, 'FB ' 2.0");
* </pre>
*
* @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.

View File

@@ -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 \

View File

@@ -30,6 +30,7 @@
#include <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include "Utils.h"
#include "FontUtils.h"
#include <hwui/MinikinSkia.h>
#include <hwui/Typeface.h>
@@ -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<SkFontMgr::FontParameters::Axis[]> 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;
}

View File

@@ -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 <jni.h>
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_

View File

@@ -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 <android_runtime/android_util_AssetManager.h>
#include <androidfw/AssetManager.h>
#include <hwui/Typeface.h>
#include <minikin/FontFamily.h>
using namespace android;
@@ -40,6 +42,23 @@ static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandl
return reinterpret_cast<jlong>(face);
}
static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
jobject listOfAxis) {
std::vector<minikin::FontVariation> 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<Typeface*>(familyHandle);
Typeface* result = Typeface::createFromTypefaceWithVariation(baseTypeface, variations);
return reinterpret_cast<jlong>(result);
}
static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
Typeface* family = reinterpret_cast<Typeface*>(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 },

View File

@@ -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<FontConfig.Axis> parseFontVariationSettings(@Nullable String settings) {
ArrayList<FontConfig.Axis> 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

View File

@@ -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.
*

View File

@@ -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<FontConfig.Axis> 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<FontConfig.Axis> 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);

View File

@@ -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<FontConfig.Axis> 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<FontConfig.Axis> 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<FontConfig.Axis> 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

View File

@@ -17,7 +17,8 @@
#include "MinikinSkia.h"
#include <log/log.h>
#include <SkFontDescriptor.h>
#include <SkFontMgr.h>
#include <SkPaint.h>
#include <SkTypeface.h>
@@ -86,6 +87,28 @@ int MinikinFontSkia::GetFontIndex() const {
return mTtcIndex;
}
minikin::MinikinFont* MinikinFontSkia::createFontWithVariation(
const std::vector<minikin::FontVariation>& 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<SkFontMgr::FontParameters::Axis> 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<SkFontMgr> fm(SkFontMgr::RefDefault());
sk_sp<SkTypeface> 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();

View File

@@ -44,6 +44,8 @@ public:
const void* GetFontData() const;
size_t GetFontSize() const;
int GetFontIndex() const;
minikin::MinikinFont* createFontWithVariation(
const std::vector<minikin::FontVariation>&) const;
static uint32_t packPaintFlags(const SkPaint* paint);
static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);

View File

@@ -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<minikin::FontVariation>& 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;

View File

@@ -43,6 +43,9 @@ struct ANDROID_API Typeface {
static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
static Typeface* createFromTypefaceWithVariation(Typeface* src,
const std::vector<minikin::FontVariation>& variations);
static Typeface* createWeightAlias(Typeface* src, int baseweight);
static Typeface* createFromFamilies(const std::vector<minikin::FontFamily*>& families);