Merge "Check updatable font dir in FontListParser."

This commit is contained in:
TreeHugger Robot
2021-01-12 05:18:59 +00:00
committed by Android (Google) Code Review
4 changed files with 113 additions and 38 deletions

View File

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

View File

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

View File

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

View File

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