diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/content/res/Resources.java | 31 | ||||
| -rw-r--r-- | core/java/android/content/res/ResourcesImpl.java | 32 | ||||
| -rw-r--r-- | core/jni/android/graphics/FontFamily.cpp | 21 | ||||
| -rw-r--r-- | graphics/java/android/graphics/FontFamily.java | 9 | ||||
| -rw-r--r-- | graphics/java/android/graphics/FontResourcesParser.java | 113 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Typeface.java | 27 |
9 files changed, 225 insertions, 11 deletions
diff --git a/api/current.txt b/api/current.txt index c3a831621c45..a6ec9ec288ea 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10681,6 +10681,7 @@ package android.content.res { method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException; method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme); + method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException; method public float getFraction(int, int, int); method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String); method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException; diff --git a/api/system-current.txt b/api/system-current.txt index ccfbf019354f..0581957cedca 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11199,6 +11199,7 @@ package android.content.res { method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException; method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme); + method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException; method public float getFraction(int, int, int); method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String); method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException; diff --git a/api/test-current.txt b/api/test-current.txt index b26760b13f34..7967717fdb96 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -10713,6 +10713,7 @@ package android.content.res { method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException; method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException; method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme); + method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException; method public float getFraction(int, int, int); method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String); method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index ad113075c96b..c3185a7cad05 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -40,6 +40,7 @@ import android.annotation.StyleableRes; import android.annotation.XmlRes; import android.content.pm.ActivityInfo; import android.graphics.Movie; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable.ConstantState; import android.graphics.drawable.DrawableInflater; @@ -333,7 +334,35 @@ public class Resources { return res; } throw new NotFoundException("String resource ID #0x" - + Integer.toHexString(id)); + + Integer.toHexString(id)); + } + + /** + * Return the Typeface value associated with a particular resource ID. + * {@more} + * + * @param id The desired resource identifier, as generated by the aapt + * tool. This integer encodes the package, type, and resource + * entry. The value 0 is an invalid identifier. + * + * @throws NotFoundException Throws NotFoundException if the given ID does not exist. + * + * @return Typeface The Typeface data associated with the resource. + */ + @NonNull public Typeface getFont(@StringRes int id) throws NotFoundException { + final TypedValue value = obtainTempTypedValue(); + try { + final ResourcesImpl impl = mResourcesImpl; + impl.getValue(id, value, true); + Typeface typeface = impl.loadFont(value, id); + if (typeface != null) { + return typeface; + } + } finally { + releaseTempTypedValue(value); + } + throw new NotFoundException("Font resource ID #0x" + + Integer.toHexString(id)); } /** diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index eb010e46ea91..05892e0ad660 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -31,6 +31,7 @@ import android.annotation.StyleableRes; import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo.Config; import android.content.res.Resources.NotFoundException; +import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.icu.text.PluralRules; @@ -47,6 +48,7 @@ import android.util.Xml; import android.view.Display; import android.view.DisplayAdjustments; +import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Locale; @@ -740,6 +742,36 @@ public class ResourcesImpl { } /** + * Loads a font from XML or resources stream. + */ + @Nullable + public Typeface loadFont(TypedValue value, int id) { + if (value.string == null) { + throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" + + Integer.toHexString(id) + ") is not a Font: " + value); + } + + final String file = value.string.toString(); + + if (DEBUG_LOAD) { + Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file); + } + + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); + try { + if (file.endsWith(".xml")) { + // TODO handle xml type font definitions + } else { + return Typeface.createFromResources( + mAssets, value.string.toString(), value.assetCookie); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } + return null; + } + + /** * Given the value and id, we can get the XML filename as in value.data, based on that, we * first try to load CSL from the cache. If not found, try to get from the constant state. * Last, parse the XML and generate the CSL. diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp index 15e7165210ae..2504e540ff14 100644 --- a/core/jni/android/graphics/FontFamily.cpp +++ b/core/jni/android/graphics/FontFamily.cpp @@ -190,8 +190,8 @@ static void releaseAsset(const void* ptr, void* context) { delete static_cast<Asset*>(context); } -static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPtr, - jobject jassetMgr, jstring jpath) { +static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong familyPtr, + jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset) { NPE_CHECK_RETURN_ZERO(env, jassetMgr); NPE_CHECK_RETURN_ZERO(env, jpath); @@ -201,7 +201,18 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt } ScopedUtfChars str(env, jpath); - Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); + if (str.c_str() == nullptr) { + return false; + } + + Asset* asset; + if (isAsset) { + asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); + } else { + asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(), + Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER); + } + if (NULL == asset) { return false; } @@ -234,8 +245,8 @@ static const JNINativeMethod gFontFamilyMethods[] = { { "nAddFont", "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont }, { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z", (void*)FontFamily_addFontWeightStyle }, - { "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z", - (void*)FontFamily_addFontFromAsset }, + { "nAddFontFromAssetManager", "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZ)Z", + (void*)FontFamily_addFontFromAssetManager }, }; int register_android_graphics_FontFamily(JNIEnv* env) diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java index e48bf7956df3..cd5071e87e9e 100644 --- a/graphics/java/android/graphics/FontFamily.java +++ b/graphics/java/android/graphics/FontFamily.java @@ -85,8 +85,9 @@ public class FontFamily { return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style); } - public boolean addFontFromAsset(AssetManager mgr, String path) { - return nAddFontFromAsset(mNativePtr, mgr, path); + public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie, + boolean isAsset) { + return nAddFontFromAssetManager(mNativePtr, mgr, path, cookie, isAsset); } private static native long nCreateFamily(String lang, int variant); @@ -95,6 +96,6 @@ public class FontFamily { private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font, int ttcIndex, List<FontListParser.Axis> listOfAxis, int weight, boolean isItalic); - private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr, - String path); + private static native boolean nAddFontFromAssetManager(long nativeFamily, AssetManager mgr, + String path, int cookie, boolean isAsset); } diff --git a/graphics/java/android/graphics/FontResourcesParser.java b/graphics/java/android/graphics/FontResourcesParser.java new file mode 100644 index 000000000000..b4109cfa3296 --- /dev/null +++ b/graphics/java/android/graphics/FontResourcesParser.java @@ -0,0 +1,113 @@ +/* + * 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. + */ +package android.graphics; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Parser for xml type font resources. + * @hide + */ +public class FontResourcesParser { + private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; + + /* Parse fallback list (no names) */ + public static FontListParser.Config parse(XmlPullParser parser) + throws XmlPullParserException, IOException { + int type; + //noinspection StatementWithEmptyBody + while ((type=parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + // Empty loop. + } + + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + return readFamilies(parser); + } + + private static FontListParser.Config readFamilies(XmlPullParser parser) + throws XmlPullParserException, IOException { + FontListParser.Config config = new FontListParser.Config(); + parser.require(XmlPullParser.START_TAG, null, "font-family"); + String tag = parser.getName(); + if (tag.equals("font-family")) { + config.families.add(readFamily(parser)); + } else { + skip(parser); + } + return config; + } + + private static FontListParser.Family readFamily(XmlPullParser parser) + throws XmlPullParserException, IOException { + String name = parser.getAttributeValue(null, "name"); + String lang = parser.getAttributeValue(null, "lang"); + String variant = parser.getAttributeValue(null, "variant"); + List<FontListParser.Font> fonts = new ArrayList<>(); + while (parser.next() != XmlPullParser.END_TAG) { + if (parser.getEventType() != XmlPullParser.START_TAG) continue; + String tag = parser.getName(); + if (tag.equals("font")) { + fonts.add(readFont(parser)); + } else { + skip(parser); + } + } + return new FontListParser.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 FontListParser.Font readFont(XmlPullParser parser) + throws XmlPullParserException, IOException { + + List<FontListParser.Axis> axes = new ArrayList<>(); + + String weightStr = parser.getAttributeValue(ANDROID_NAMESPACE, "fontWeight"); + int weight = weightStr == null ? 400 : Integer.parseInt(weightStr); + + boolean isItalic = "italic".equals( + parser.getAttributeValue(ANDROID_NAMESPACE, "fontStyle")); + + String filename = parser.getAttributeValue(ANDROID_NAMESPACE, "font"); + String fullFilename = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); + return new FontListParser.Font(fullFilename, 0, axes, weight, isItalic); + } + + private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException { + int depth = 1; + while (depth > 0) { + switch (parser.next()) { + case XmlPullParser.START_TAG: + depth++; + break; + case XmlPullParser.END_TAG: + depth--; + break; + } + } + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 2886f0dd4a2e..eebe538ccab8 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -16,6 +16,7 @@ package android.graphics; +import android.annotation.NonNull; import android.content.res.AssetManager; import android.util.Log; import android.util.LongSparseArray; @@ -109,6 +110,30 @@ public class Typeface { } /** + * @hide + * Used by Resources. + */ + @NonNull + public static Typeface createFromResources(AssetManager mgr, String path, int cookie) { + if (sFallbackFonts != null) { + synchronized (sDynamicTypefaceCache) { + final String key = createAssetUid(mgr, path); + Typeface typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; + + FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */)) { + FontFamily[] families = { fontFamily }; + typeface = createFromFamiliesWithDefault(families); + sDynamicTypefaceCache.put(key, typeface); + return typeface; + } + } + } + throw new RuntimeException("Font resource not found " + path); + } + + /** * Create a typeface object given a family name, and option style information. * If null is passed for the name, then the "default" font will be chosen. * The resulting typeface object can be queried (getStyle()) to discover what @@ -195,7 +220,7 @@ public class Typeface { if (typeface != null) return typeface; FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFontFromAsset(mgr, path)) { + if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */)) { FontFamily[] families = { fontFamily }; typeface = createFromFamiliesWithDefault(families); sDynamicTypefaceCache.put(key, typeface); |