Merge "Add support for gx font variation axes." into nyc-dev
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
#include <core_jni_helpers.h>
|
#include <core_jni_helpers.h>
|
||||||
|
|
||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
|
#include "SkFontMgr.h"
|
||||||
#include "SkRefCnt.h"
|
#include "SkRefCnt.h"
|
||||||
#include "SkTypeface.h"
|
#include "SkTypeface.h"
|
||||||
#include "GraphicsJNI.h"
|
#include "GraphicsJNI.h"
|
||||||
@@ -33,6 +34,8 @@
|
|||||||
#include <minikin/FontFamily.h>
|
#include <minikin/FontFamily.h>
|
||||||
#include "MinikinSkia.h"
|
#include "MinikinSkia.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
|
static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
|
||||||
@@ -69,13 +72,56 @@ static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr,
|
|||||||
return addSkTypeface(fontFamily, face);
|
return addSkTypeface(fontFamily, face);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
jmethodID mGet;
|
||||||
|
jmethodID mSize;
|
||||||
|
} gListClassInfo;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
jfieldID mTag;
|
||||||
|
jfieldID mStyleValue;
|
||||||
|
} gAxisClassInfo;
|
||||||
|
|
||||||
static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
|
static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
|
||||||
jstring path, jint ttcIndex, jint weight, jboolean isItalic) {
|
jstring path, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
|
||||||
NPE_CHECK_RETURN_ZERO(env, path);
|
NPE_CHECK_RETURN_ZERO(env, path);
|
||||||
|
|
||||||
|
// Declare axis native type.
|
||||||
|
std::unique_ptr<SkFontMgr::FontParameters::Axis[]> skiaAxes;
|
||||||
|
int skiaAxesLength = 0;
|
||||||
|
if (listOfAxis) {
|
||||||
|
jint listSize = env->CallIntMethod(listOfAxis, gListClassInfo.mSize);
|
||||||
|
|
||||||
|
skiaAxes.reset(new SkFontMgr::FontParameters::Axis[listSize]);
|
||||||
|
skiaAxesLength = listSize;
|
||||||
|
for (jint i = 0; i < listSize; ++i) {
|
||||||
|
jobject axisObject = env->CallObjectMethod(listOfAxis, gListClassInfo.mGet, i);
|
||||||
|
if (!axisObject) {
|
||||||
|
skiaAxes[i].fTag = 0;
|
||||||
|
skiaAxes[i].fStyleValue = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
jint tag = env->GetIntField(axisObject, gAxisClassInfo.mTag);
|
||||||
|
jfloat stylevalue = env->GetFloatField(axisObject, gAxisClassInfo.mStyleValue);
|
||||||
|
skiaAxes[i].fTag = tag;
|
||||||
|
skiaAxes[i].fStyleValue = SkFloatToScalar(stylevalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ScopedUtfChars str(env, path);
|
ScopedUtfChars str(env, path);
|
||||||
SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
|
SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
|
||||||
|
std::unique_ptr<SkStreamAsset> fontData(SkStream::NewFromFile(str.c_str()));
|
||||||
|
if (!fontData) {
|
||||||
|
ALOGE("addFont failed to open %s", str.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SkFontMgr::FontParameters params;
|
||||||
|
params.setCollectionIndex(ttcIndex);
|
||||||
|
params.setAxes(skiaAxes.get(), skiaAxesLength);
|
||||||
|
SkTypeface* face = fm->createFromStream(fontData.release(), params);
|
||||||
if (face == NULL) {
|
if (face == NULL) {
|
||||||
ALOGE("addFont failed to create font %s", str.c_str());
|
ALOGE("addFont failed to create font %s#%d", str.c_str(), ttcIndex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
|
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
|
||||||
@@ -129,15 +175,26 @@ static const JNINativeMethod gFontFamilyMethods[] = {
|
|||||||
{ "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
|
{ "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
|
||||||
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
|
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
|
||||||
{ "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont },
|
{ "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont },
|
||||||
{ "nAddFontWeightStyle", "(JLjava/lang/String;IIZ)Z", (void*)FontFamily_addFontWeightStyle },
|
{ "nAddFontWeightStyle", "(JLjava/lang/String;ILjava/util/List;IZ)Z",
|
||||||
|
(void*)FontFamily_addFontWeightStyle },
|
||||||
{ "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
|
{ "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
|
||||||
(void*)FontFamily_addFontFromAsset },
|
(void*)FontFamily_addFontFromAsset },
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_android_graphics_FontFamily(JNIEnv* env)
|
int register_android_graphics_FontFamily(JNIEnv* env)
|
||||||
{
|
{
|
||||||
return RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
|
int err = RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods,
|
||||||
NELEM(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/graphics/FontListParser$Axis");
|
||||||
|
gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I");
|
||||||
|
gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F");
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package android.graphics;
|
|||||||
|
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A family of typefaces with different styles.
|
* A family of typefaces with different styles.
|
||||||
*
|
*
|
||||||
@@ -62,8 +64,9 @@ public class FontFamily {
|
|||||||
return nAddFont(mNativePtr, path, ttcIndex);
|
return nAddFont(mNativePtr, path, ttcIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addFontWeightStyle(String path, int ttcIndex, int weight, boolean style) {
|
public boolean addFontWeightStyle(String path, int ttcIndex, List<FontListParser.Axis> axes,
|
||||||
return nAddFontWeightStyle(mNativePtr, path, ttcIndex, weight, style);
|
int weight, boolean style) {
|
||||||
|
return nAddFontWeightStyle(mNativePtr, path, ttcIndex, axes, weight, style);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addFontFromAsset(AssetManager mgr, String path) {
|
public boolean addFontFromAsset(AssetManager mgr, String path) {
|
||||||
@@ -74,7 +77,8 @@ public class FontFamily {
|
|||||||
private static native void nUnrefFamily(long nativePtr);
|
private static native void nUnrefFamily(long nativePtr);
|
||||||
private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex);
|
private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex);
|
||||||
private static native boolean nAddFontWeightStyle(long nativeFamily, String path,
|
private static native boolean nAddFontWeightStyle(long nativeFamily, String path,
|
||||||
int ttcIndex, int weight, boolean isItalic);
|
int ttcIndex, List<FontListParser.Axis> listOfAxis,
|
||||||
|
int weight, boolean isItalic);
|
||||||
private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
|
private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
|
||||||
String path);
|
String path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser for font config files.
|
* Parser for font config files.
|
||||||
@@ -42,15 +43,26 @@ public class FontListParser {
|
|||||||
public List<Alias> aliases;
|
public List<Alias> aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Axis {
|
||||||
|
Axis(int tag, float styleValue) {
|
||||||
|
this.tag = tag;
|
||||||
|
this.styleValue = styleValue;
|
||||||
|
}
|
||||||
|
public final int tag;
|
||||||
|
public final float styleValue;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Font {
|
public static class Font {
|
||||||
Font(String fontName, int ttcIndex, int weight, boolean isItalic) {
|
Font(String fontName, int ttcIndex, List<Axis> axes, int weight, boolean isItalic) {
|
||||||
this.fontName = fontName;
|
this.fontName = fontName;
|
||||||
this.ttcIndex = ttcIndex;
|
this.ttcIndex = ttcIndex;
|
||||||
|
this.axes = axes;
|
||||||
this.weight = weight;
|
this.weight = weight;
|
||||||
this.isItalic = isItalic;
|
this.isItalic = isItalic;
|
||||||
}
|
}
|
||||||
public String fontName;
|
public String fontName;
|
||||||
public int ttcIndex;
|
public int ttcIndex;
|
||||||
|
public final List<Axis> axes;
|
||||||
public int weight;
|
public int weight;
|
||||||
public boolean isItalic;
|
public boolean isItalic;
|
||||||
}
|
}
|
||||||
@@ -93,9 +105,10 @@ public class FontListParser {
|
|||||||
parser.require(XmlPullParser.START_TAG, null, "familyset");
|
parser.require(XmlPullParser.START_TAG, null, "familyset");
|
||||||
while (parser.next() != XmlPullParser.END_TAG) {
|
while (parser.next() != XmlPullParser.END_TAG) {
|
||||||
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
||||||
if (parser.getName().equals("family")) {
|
String tag = parser.getName();
|
||||||
|
if (tag.equals("family")) {
|
||||||
config.families.add(readFamily(parser));
|
config.families.add(readFamily(parser));
|
||||||
} else if (parser.getName().equals("alias")) {
|
} else if (tag.equals("alias")) {
|
||||||
config.aliases.add(readAlias(parser));
|
config.aliases.add(readAlias(parser));
|
||||||
} else {
|
} else {
|
||||||
skip(parser);
|
skip(parser);
|
||||||
@@ -114,14 +127,7 @@ public class FontListParser {
|
|||||||
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
||||||
String tag = parser.getName();
|
String tag = parser.getName();
|
||||||
if (tag.equals("font")) {
|
if (tag.equals("font")) {
|
||||||
String ttcIndexStr = parser.getAttributeValue(null, "index");
|
fonts.add(readFont(parser));
|
||||||
int ttcIndex = ttcIndexStr == null ? 0 : Integer.parseInt(ttcIndexStr);
|
|
||||||
String weightStr = parser.getAttributeValue(null, "weight");
|
|
||||||
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
|
|
||||||
boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
|
|
||||||
String filename = parser.nextText();
|
|
||||||
String fullFilename = "/system/fonts/" + filename;
|
|
||||||
fonts.add(new Font(fullFilename, ttcIndex, weight, isItalic));
|
|
||||||
} else {
|
} else {
|
||||||
skip(parser);
|
skip(parser);
|
||||||
}
|
}
|
||||||
@@ -129,6 +135,70 @@ public class FontListParser {
|
|||||||
return new Family(name, fonts, lang, variant);
|
return new Family(name, fonts, lang, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Matches leading and trailing XML whitespace. */
|
||||||
|
private static final Pattern FILENAME_WHITESPACE_PATTERN =
|
||||||
|
Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
|
||||||
|
|
||||||
|
private static Font readFont(XmlPullParser parser)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
String indexStr = parser.getAttributeValue(null, "index");
|
||||||
|
int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
|
||||||
|
List<Axis> axes = new ArrayList<Axis>();
|
||||||
|
String weightStr = parser.getAttributeValue(null, "weight");
|
||||||
|
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
|
||||||
|
boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
|
||||||
|
StringBuilder filename = new StringBuilder();
|
||||||
|
while (parser.next() != XmlPullParser.END_TAG) {
|
||||||
|
if (parser.getEventType() == XmlPullParser.TEXT) {
|
||||||
|
filename.append(parser.getText());
|
||||||
|
}
|
||||||
|
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
||||||
|
String tag = parser.getName();
|
||||||
|
if (tag.equals("axis")) {
|
||||||
|
axes.add(readAxis(parser));
|
||||||
|
} else {
|
||||||
|
skip(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String fullFilename = "/system/fonts/" +
|
||||||
|
FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
|
||||||
|
return new Font(fullFilename, index, axes, weight, isItalic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The 'tag' attribute value is read as four character values between 0 and 255 inclusive. */
|
||||||
|
private static final Pattern TAG_PATTERN = Pattern.compile("[\\x00-\\xFF]{4}");
|
||||||
|
|
||||||
|
/** The 'styleValue' attribute has an optional leading '-', followed by '<digits>',
|
||||||
|
* '<digits>.<digits>', or '.<digits>' where '<digits>' is one or more of [0-9].
|
||||||
|
*/
|
||||||
|
private static final Pattern STYLE_VALUE_PATTERN =
|
||||||
|
Pattern.compile("-?(([0-9]+(\\.[0-9]+)?)|(\\.[0-9]+))");
|
||||||
|
|
||||||
|
private static Axis readAxis(XmlPullParser parser)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
int tag = 0;
|
||||||
|
String tagStr = parser.getAttributeValue(null, "tag");
|
||||||
|
if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
|
||||||
|
tag = tagStr.charAt(0) << 24 +
|
||||||
|
tagStr.charAt(1) << 16 +
|
||||||
|
tagStr.charAt(2) << 8 +
|
||||||
|
tagStr.charAt(3);
|
||||||
|
} else {
|
||||||
|
throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
float styleValue = 0;
|
||||||
|
String styleValueStr = parser.getAttributeValue(null, "stylevalue");
|
||||||
|
if (styleValueStr != null && STYLE_VALUE_PATTERN.matcher(styleValueStr).matches()) {
|
||||||
|
styleValue = Float.parseFloat(styleValueStr);
|
||||||
|
} else {
|
||||||
|
throw new XmlPullParserException("Invalid styleValue attribute value.", parser, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
skip(parser); // axis tag is empty, ignore any contents and consume end tag
|
||||||
|
return new Axis(tag, styleValue);
|
||||||
|
}
|
||||||
|
|
||||||
private static Alias readAlias(XmlPullParser parser)
|
private static Alias readAlias(XmlPullParser parser)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
Alias alias = new Alias();
|
Alias alias = new Alias();
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
package android.graphics;
|
package android.graphics;
|
||||||
|
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.graphics.FontListParser.Family;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.LongSparseArray;
|
import android.util.LongSparseArray;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
@@ -262,7 +261,8 @@ public class Typeface {
|
|||||||
private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
|
private static FontFamily makeFamilyFromParsed(FontListParser.Family family) {
|
||||||
FontFamily fontFamily = new FontFamily(family.lang, family.variant);
|
FontFamily fontFamily = new FontFamily(family.lang, family.variant);
|
||||||
for (FontListParser.Font font : family.fonts) {
|
for (FontListParser.Font font : family.fonts) {
|
||||||
fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.weight, font.isItalic);
|
fontFamily.addFontWeightStyle(font.fontName, font.ttcIndex, font.axes,
|
||||||
|
font.weight, font.isItalic);
|
||||||
}
|
}
|
||||||
return fontFamily;
|
return fontFamily;
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ public class Typeface {
|
|||||||
// Note that the default typeface is always present in the fallback list;
|
// Note that the default typeface is always present in the fallback list;
|
||||||
// this is an enhancement from pre-Minikin behavior.
|
// this is an enhancement from pre-Minikin behavior.
|
||||||
for (int i = 0; i < fontConfig.families.size(); i++) {
|
for (int i = 0; i < fontConfig.families.size(); i++) {
|
||||||
Family f = fontConfig.families.get(i);
|
FontListParser.Family f = fontConfig.families.get(i);
|
||||||
if (i == 0 || f.name == null) {
|
if (i == 0 || f.name == null) {
|
||||||
familyList.add(makeFamilyFromParsed(f));
|
familyList.add(makeFamilyFromParsed(f));
|
||||||
}
|
}
|
||||||
@@ -295,7 +295,7 @@ public class Typeface {
|
|||||||
Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
|
Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
|
||||||
for (int i = 0; i < fontConfig.families.size(); i++) {
|
for (int i = 0; i < fontConfig.families.size(); i++) {
|
||||||
Typeface typeface;
|
Typeface typeface;
|
||||||
Family f = fontConfig.families.get(i);
|
FontListParser.Family f = fontConfig.families.get(i);
|
||||||
if (f.name != null) {
|
if (f.name != null) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// The first entry is the default typeface; no sense in
|
// The first entry is the default typeface; no sense in
|
||||||
@@ -324,11 +324,11 @@ public class Typeface {
|
|||||||
Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
|
Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
|
||||||
// TODO: normal in non-Minikin case, remove or make error when Minikin-only
|
// TODO: normal in non-Minikin case, remove or make error when Minikin-only
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
Log.e(TAG, "Error opening " + configFilename);
|
Log.e(TAG, "Error opening " + configFilename, e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Error reading " + configFilename);
|
Log.e(TAG, "Error reading " + configFilename, e);
|
||||||
} catch (XmlPullParserException e) {
|
} catch (XmlPullParserException e) {
|
||||||
Log.e(TAG, "XML parse exception for " + configFilename);
|
Log.e(TAG, "XML parse exception for " + configFilename, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -288,8 +288,10 @@ public class FontFamily_Delegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LayoutlibDelegate
|
@LayoutlibDelegate
|
||||||
/*package*/ static boolean nAddFontWeightStyle(long nativeFamily, final String path,
|
/*package*/ static boolean nAddFontWeightStyle(long nativeFamily,
|
||||||
|
final String path, final int index, final List<FontListParser.Axis> axes,
|
||||||
final int weight, final boolean isItalic) {
|
final int weight, final boolean isItalic) {
|
||||||
|
// 'index' and 'axes' are not supported by java.awt.Font
|
||||||
final FontFamily_Delegate delegate = getDelegate(nativeFamily);
|
final FontFamily_Delegate delegate = getDelegate(nativeFamily);
|
||||||
if (delegate != null) {
|
if (delegate != null) {
|
||||||
if (sFontLocation == null) {
|
if (sFontLocation == null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user