diff options
| -rw-r--r-- | core/jni/android/graphics/FontFamily.cpp | 71 | ||||
| -rw-r--r-- | graphics/java/android/graphics/FontFamily.java | 10 | ||||
| -rw-r--r-- | graphics/java/android/graphics/FontListParser.java | 92 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Typeface.java | 14 | ||||
| -rw-r--r-- | tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java | 4 |
5 files changed, 162 insertions, 29 deletions
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 7c8dbe8ecf23..149ff557645d 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -20,6 +20,7 @@ #include <core_jni_helpers.h> #include "SkData.h" +#include "SkFontMgr.h" #include "SkRefCnt.h" #include "SkTypeface.h" #include "GraphicsJNI.h" @@ -33,6 +34,8 @@ #include <minikin/FontFamily.h> #include "MinikinSkia.h" +#include <memory> + namespace android { 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); } +static struct { + jmethodID mGet; + jmethodID mSize; +} gListClassInfo; + +static struct { + jfieldID mTag; + jfieldID mStyleValue; +} gAxisClassInfo; + 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); + + // 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); - 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) { - ALOGE("addFont failed to create font %s", str.c_str()); + ALOGE("addFont failed to create font %s#%d", str.c_str(), ttcIndex); return false; } FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); @@ -129,15 +175,26 @@ static const JNINativeMethod gFontFamilyMethods[] = { { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create }, { "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, { "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", - (void*)FontFamily_addFontFromAsset }, + (void*)FontFamily_addFontFromAsset }, }; int register_android_graphics_FontFamily(JNIEnv* env) { - return RegisterMethodsOrDie(env, "android/graphics/FontFamily", gFontFamilyMethods, - NELEM(gFontFamilyMethods)); + 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/graphics/FontListParser$Axis"); + gAxisClassInfo.mTag = GetFieldIDOrDie(env, axisClass, "tag", "I"); + gAxisClassInfo.mStyleValue = GetFieldIDOrDie(env, axisClass, "styleValue", "F"); + + return err; } } diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index 6309ed36eb51..3897c3bf45d8 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -18,6 +18,8 @@ package android.graphics; import android.content.res.AssetManager; +import java.util.List; + /** * A family of typefaces with different styles. * @@ -62,8 +64,9 @@ public class FontFamily { return nAddFont(mNativePtr, path, ttcIndex); } - public boolean addFontWeightStyle(String path, int ttcIndex, int weight, boolean style) { - return nAddFontWeightStyle(mNativePtr, path, ttcIndex, weight, style); + public boolean addFontWeightStyle(String path, int ttcIndex, List<FontListParser.Axis> axes, + int weight, boolean style) { + return nAddFontWeightStyle(mNativePtr, path, ttcIndex, axes, weight, style); } public boolean addFontFromAsset(AssetManager mgr, String path) { @@ -74,7 +77,8 @@ public class FontFamily { private static native void nUnrefFamily(long nativePtr); private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex); 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, String path); } diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 774f6b8922e0..8f7c6a62a4a3 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; /** * Parser for font config files. @@ -42,15 +43,26 @@ public class FontListParser { 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 { - 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.ttcIndex = ttcIndex; + this.axes = axes; this.weight = weight; this.isItalic = isItalic; } public String fontName; public int ttcIndex; + public final List<Axis> axes; public int weight; public boolean isItalic; } @@ -93,9 +105,10 @@ public class FontListParser { parser.require(XmlPullParser.START_TAG, null, "familyset"); while (parser.next() != XmlPullParser.END_TAG) { 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)); - } else if (parser.getName().equals("alias")) { + } else if (tag.equals("alias")) { config.aliases.add(readAlias(parser)); } else { skip(parser); @@ -114,14 +127,7 @@ public class FontListParser { if (parser.getEventType() != XmlPullParser.START_TAG) continue; String tag = parser.getName(); if (tag.equals("font")) { - String ttcIndexStr = parser.getAttributeValue(null, "index"); - 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)); + fonts.add(readFont(parser)); } else { skip(parser); } @@ -129,6 +135,70 @@ public class FontListParser { 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) throws XmlPullParserException, IOException { Alias alias = new Alias(); diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 1294323ce69b..345f257c9371 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -17,7 +17,6 @@ package android.graphics; import android.content.res.AssetManager; -import android.graphics.FontListParser.Family; import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; @@ -262,7 +261,8 @@ public class Typeface { private static FontFamily makeFamilyFromParsed(FontListParser.Family family) { FontFamily fontFamily = new FontFamily(family.lang, family.variant); 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; } @@ -284,7 +284,7 @@ public class Typeface { // Note that the default typeface is always present in the fallback list; // this is an enhancement from pre-Minikin behavior. 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) { familyList.add(makeFamilyFromParsed(f)); } @@ -295,7 +295,7 @@ public class Typeface { Map<String, Typeface> systemFonts = new HashMap<String, Typeface>(); for (int i = 0; i < fontConfig.families.size(); i++) { Typeface typeface; - Family f = fontConfig.families.get(i); + FontListParser.Family f = fontConfig.families.get(i); if (f.name != null) { if (i == 0) { // 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); // TODO: normal in non-Minikin case, remove or make error when Minikin-only } catch (FileNotFoundException e) { - Log.e(TAG, "Error opening " + configFilename); + Log.e(TAG, "Error opening " + configFilename, e); } catch (IOException e) { - Log.e(TAG, "Error reading " + configFilename); + Log.e(TAG, "Error reading " + configFilename, e); } catch (XmlPullParserException e) { - Log.e(TAG, "XML parse exception for " + configFilename); + Log.e(TAG, "XML parse exception for " + configFilename, e); } } diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java index c7b24bcb352d..b6588b65b5ae 100644 --- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -288,8 +288,10 @@ public class FontFamily_Delegate { } @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) { + // 'index' and 'axes' are not supported by java.awt.Font final FontFamily_Delegate delegate = getDelegate(nativeFamily); if (delegate != null) { if (sFontLocation == null) { |