Merge "Check updatable font dir in FontListParser."
This commit is contained in:
committed by
Android (Google) Code Review
commit
55b6a818e0
@@ -67,6 +67,7 @@ public class TypefaceSystemFallbackTest {
|
||||
private static final String TEST_FONT_DIR;
|
||||
private static final String TEST_OEM_XML;
|
||||
private static final String TEST_OEM_DIR;
|
||||
private static final String TEST_UPDATABLE_FONT_DIR;
|
||||
|
||||
private static final float GLYPH_1EM_WIDTH;
|
||||
private static final float GLYPH_2EM_WIDTH;
|
||||
@@ -82,9 +83,11 @@ public class TypefaceSystemFallbackTest {
|
||||
TEST_FONTS_XML = new File(cacheDir, "fonts.xml").getAbsolutePath();
|
||||
TEST_OEM_DIR = cacheDir.getAbsolutePath() + "/oem_fonts/";
|
||||
TEST_OEM_XML = new File(cacheDir, "fonts_customization.xml").getAbsolutePath();
|
||||
TEST_UPDATABLE_FONT_DIR = cacheDir.getAbsolutePath() + "/updatable_fonts/";
|
||||
|
||||
new File(TEST_FONT_DIR).mkdirs();
|
||||
new File(TEST_OEM_DIR).mkdirs();
|
||||
new File(TEST_UPDATABLE_FONT_DIR).mkdirs();
|
||||
|
||||
final AssetManager am =
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
|
||||
@@ -103,18 +106,11 @@ public class TypefaceSystemFallbackTest {
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
|
||||
for (final String fontFile : TEST_FONT_FILES) {
|
||||
final String sourceInAsset = "fonts/" + fontFile;
|
||||
final File outInCache = new File(TEST_FONT_DIR, fontFile);
|
||||
try (InputStream is = am.open(sourceInAsset)) {
|
||||
Files.copy(is, outInCache.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
final File outOemInCache = new File(TEST_OEM_DIR, fontFile);
|
||||
try (InputStream is = am.open(sourceInAsset)) {
|
||||
Files.copy(is, outOemInCache.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
copyAssetToFile(sourceInAsset, new File(TEST_FONT_DIR, fontFile));
|
||||
copyAssetToFile(sourceInAsset, new File(TEST_OEM_DIR, fontFile));
|
||||
}
|
||||
for (final File fontFile : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
|
||||
fontFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +120,20 @@ public class TypefaceSystemFallbackTest {
|
||||
final File outInCache = new File(TEST_FONT_DIR, fontFile);
|
||||
outInCache.delete();
|
||||
final File outOemInCache = new File(TEST_OEM_DIR, fontFile);
|
||||
outInCache.delete();
|
||||
outOemInCache.delete();
|
||||
}
|
||||
for (final File fontFile : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
|
||||
fontFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyAssetToFile(String sourceInAsset, File out) {
|
||||
final AssetManager am =
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
|
||||
try (InputStream is = am.open(sourceInAsset)) {
|
||||
Files.copy(is, out.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +147,7 @@ public class TypefaceSystemFallbackTest {
|
||||
}
|
||||
|
||||
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
|
||||
TEST_FONT_DIR, oemCustomization, fallbackMap);
|
||||
TEST_FONT_DIR, TEST_UPDATABLE_FONT_DIR, oemCustomization, fallbackMap);
|
||||
Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
|
||||
}
|
||||
|
||||
@@ -835,4 +844,32 @@ public class TypefaceSystemFallbackTest {
|
||||
+ "</fonts-modification>";
|
||||
readFontCustomization(oemXml);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBuildSystemFallback_UpdatableFont() {
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='test'>"
|
||||
+ " <font weight='400' style='normal'>a3em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
final FontCustomizationParser.Result oemCustomization =
|
||||
new FontCustomizationParser.Result();
|
||||
|
||||
// Install all2em.ttf as a3em.ttf
|
||||
copyAssetToFile("fonts/all2em.ttf", new File(TEST_UPDATABLE_FONT_DIR, "a3em.ttf"));
|
||||
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
|
||||
|
||||
final Paint paint = new Paint();
|
||||
|
||||
final Typeface sansSerifTypeface = fontMap.get("test");
|
||||
assertNotNull(sansSerifTypeface);
|
||||
paint.setTypeface(sansSerifTypeface);
|
||||
assertEquals(GLYPH_2EM_WIDTH, paint.measureText("a"), 0.0f);
|
||||
assertEquals(GLYPH_2EM_WIDTH, paint.measureText("b"), 0.0f);
|
||||
assertEquals(GLYPH_2EM_WIDTH, paint.measureText("c"), 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.graphics;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.graphics.fonts.FontVariationAxis;
|
||||
import android.os.Build;
|
||||
@@ -25,6 +26,7 @@ import android.util.Xml;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
@@ -41,26 +43,26 @@ public class FontListParser {
|
||||
/* Parse fallback list (no names) */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
|
||||
return parse(in, "/system/fonts");
|
||||
return parse(in, "/system/fonts", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the fonts.xml
|
||||
*/
|
||||
public static FontConfig parse(InputStream in, String fontDir)
|
||||
throws XmlPullParserException, IOException {
|
||||
public static FontConfig parse(InputStream in, String fontDir,
|
||||
@Nullable String updatableFontDir) throws XmlPullParserException, IOException {
|
||||
try {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(in, null);
|
||||
parser.nextTag();
|
||||
return readFamilies(parser, fontDir);
|
||||
return readFamilies(parser, fontDir, updatableFontDir);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static FontConfig readFamilies(XmlPullParser parser, String fontDir)
|
||||
throws XmlPullParserException, IOException {
|
||||
private static FontConfig readFamilies(XmlPullParser parser, String fontDir,
|
||||
@Nullable String updatableFontDir) throws XmlPullParserException, IOException {
|
||||
List<FontConfig.Family> families = new ArrayList<>();
|
||||
List<FontConfig.Alias> aliases = new ArrayList<>();
|
||||
|
||||
@@ -69,7 +71,7 @@ public class FontListParser {
|
||||
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
||||
String tag = parser.getName();
|
||||
if (tag.equals("family")) {
|
||||
families.add(readFamily(parser, fontDir));
|
||||
families.add(readFamily(parser, fontDir, updatableFontDir));
|
||||
} else if (tag.equals("alias")) {
|
||||
aliases.add(readAlias(parser));
|
||||
} else {
|
||||
@@ -83,8 +85,8 @@ public class FontListParser {
|
||||
/**
|
||||
* Reads a family element
|
||||
*/
|
||||
public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir)
|
||||
throws XmlPullParserException, IOException {
|
||||
public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir,
|
||||
@Nullable String updatableFontDir) throws XmlPullParserException, IOException {
|
||||
final String name = parser.getAttributeValue(null, "name");
|
||||
final String lang = parser.getAttributeValue("", "lang");
|
||||
final String variant = parser.getAttributeValue(null, "variant");
|
||||
@@ -93,7 +95,7 @@ public class FontListParser {
|
||||
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
|
||||
final String tag = parser.getName();
|
||||
if (tag.equals("font")) {
|
||||
fonts.add(readFont(parser, fontDir));
|
||||
fonts.add(readFont(parser, fontDir, updatableFontDir));
|
||||
} else {
|
||||
skip(parser);
|
||||
}
|
||||
@@ -114,8 +116,8 @@ public class FontListParser {
|
||||
private static final Pattern FILENAME_WHITESPACE_PATTERN =
|
||||
Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
|
||||
|
||||
private static FontConfig.Font readFont(XmlPullParser parser, String fontDir)
|
||||
throws XmlPullParserException, IOException {
|
||||
private static FontConfig.Font readFont(XmlPullParser parser, String fontDir,
|
||||
@Nullable String updatableFontDir) throws XmlPullParserException, IOException {
|
||||
String indexStr = parser.getAttributeValue(null, "index");
|
||||
int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
|
||||
List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
|
||||
@@ -137,10 +139,22 @@ public class FontListParser {
|
||||
}
|
||||
}
|
||||
String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
|
||||
return new FontConfig.Font(fontDir + sanitizedName, index, axes.toArray(
|
||||
String fontName = findFontFile(sanitizedName, fontDir, updatableFontDir);
|
||||
return new FontConfig.Font(fontName, index, axes.toArray(
|
||||
new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
|
||||
}
|
||||
|
||||
private static String findFontFile(String fileName, String fontDir,
|
||||
@Nullable String updatableFontDir) {
|
||||
if (updatableFontDir != null) {
|
||||
String updatableFontName = updatableFontDir + fileName;
|
||||
if (new File(updatableFontName).exists()) {
|
||||
return updatableFontName;
|
||||
}
|
||||
}
|
||||
return fontDir + fileName;
|
||||
}
|
||||
|
||||
private static FontVariationAxis readAxis(XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
String tagStr = parser.getAttributeValue(null, "tag");
|
||||
|
||||
@@ -97,7 +97,7 @@ public class FontCustomizationParser {
|
||||
throw new IllegalArgumentException("customizationType must be specified");
|
||||
}
|
||||
if (customizationType.equals("new-named-family")) {
|
||||
out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir));
|
||||
out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir, null));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,9 @@ public final class SystemFonts {
|
||||
final FontCustomizationParser.Result oemCustomization =
|
||||
readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
|
||||
Map<String, FontFamily[]> map = new ArrayMap<>();
|
||||
buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", oemCustomization, map);
|
||||
// TODO: use updated fonts
|
||||
buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", null /* updatableFontDir */,
|
||||
oemCustomization, map);
|
||||
Set<Font> res = new HashSet<>();
|
||||
for (FontFamily[] families : map.values()) {
|
||||
for (FontFamily family : families) {
|
||||
@@ -226,13 +228,7 @@ public final class SystemFonts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the system fallback from xml file.
|
||||
*
|
||||
* @param xmlPath A full path string to the fonts.xml file.
|
||||
* @param fontDir A full path string to the system font directory. This must end with
|
||||
* slash('/').
|
||||
* @param fallbackMap An output system fallback map. Caller must pass empty map.
|
||||
* @return a list of aliases
|
||||
* @see #buildSystemFallback(String, String, String, FontCustomizationParser.Result, Map)
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@@ -240,9 +236,31 @@ public final class SystemFonts {
|
||||
@NonNull String fontDir,
|
||||
@NonNull FontCustomizationParser.Result oemCustomization,
|
||||
@NonNull Map<String, FontFamily[]> fallbackMap) {
|
||||
return buildSystemFallback(xmlPath, fontDir, null /* updatableFontDir */,
|
||||
oemCustomization, fallbackMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the system fallback from xml file.
|
||||
*
|
||||
* @param xmlPath A full path string to the fonts.xml file.
|
||||
* @param fontDir A full path string to the system font directory. This must end with
|
||||
* slash('/').
|
||||
* @param updatableFontDir A full path string to the updatable system font directory. This
|
||||
* must end with slash('/').
|
||||
* @param fallbackMap An output system fallback map. Caller must pass empty map.
|
||||
* @return a list of aliases
|
||||
* @hide
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
|
||||
@NonNull String fontDir,
|
||||
@Nullable String updatableFontDir,
|
||||
@NonNull FontCustomizationParser.Result oemCustomization,
|
||||
@NonNull Map<String, FontFamily[]> fallbackMap) {
|
||||
try {
|
||||
final FileInputStream fontsIn = new FileInputStream(xmlPath);
|
||||
final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir);
|
||||
final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir, updatableFontDir);
|
||||
|
||||
final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>();
|
||||
final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies();
|
||||
@@ -306,11 +324,17 @@ public final class SystemFonts {
|
||||
/** @hide */
|
||||
public static @NonNull Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
|
||||
initializePreinstalledFonts() {
|
||||
return initializeSystemFonts(null);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
|
||||
initializeSystemFonts(@Nullable String updatableFontDir) {
|
||||
final FontCustomizationParser.Result oemCustomization =
|
||||
readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
|
||||
Map<String, FontFamily[]> map = new ArrayMap<>();
|
||||
FontConfig.Alias[] aliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
|
||||
oemCustomization, map);
|
||||
updatableFontDir, oemCustomization, map);
|
||||
synchronized (LOCK) {
|
||||
sFamilyMap = map;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user