Loading core/java/android/text/FontConfig.java +14 −2 Original line number Diff line number Diff line Loading @@ -761,11 +761,14 @@ public final class FontConfig implements Parcelable { public static final class NamedFamilyList implements Parcelable { private final List<FontFamily> mFamilies; private final String mName; private final @Nullable String mFallback; /** @hide */ public NamedFamilyList(@NonNull List<FontFamily> families, @NonNull String name) { public NamedFamilyList(@NonNull List<FontFamily> families, @NonNull String name, @Nullable String fallback) { mFamilies = families; mName = name; mFallback = fallback; } /** @hide */ Loading @@ -773,6 +776,7 @@ public final class FontConfig implements Parcelable { mFamilies = new ArrayList<>(); mFamilies.add(family); mName = family.getName(); mFallback = null; } /** Loading @@ -797,6 +801,11 @@ public final class FontConfig implements Parcelable { return mName; } /** @hide */ public @Nullable String getFallback() { return mFallback; } @Override public int describeContents() { return 0; Loading @@ -806,6 +815,7 @@ public final class FontConfig implements Parcelable { public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) { dest.writeTypedList(mFamilies, flags); dest.writeString8(mName); dest.writeString8(mFallback); } public static final @NonNull Creator<NamedFamilyList> CREATOR = new Creator<>() { Loading @@ -815,7 +825,8 @@ public final class FontConfig implements Parcelable { final List<FontFamily> families = new ArrayList<>(); source.readTypedList(families, FontFamily.CREATOR); String name = source.readString8(); return new NamedFamilyList(families, name); String fallback = source.readString8(); return new NamedFamilyList(families, name, fallback); } @Override Loading Loading @@ -843,6 +854,7 @@ public final class FontConfig implements Parcelable { return "NamedFamilyList{" + "mFamilies=" + mFamilies + ", mName='" + mName + '\'' + ", mFallback='" + mFallback + '\'' + '}'; } } Loading core/java/android/text/flags/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -231,3 +231,11 @@ flag { # Being read only because this is used in the performance critical path. is_fixed_read_only: true } flag { name: "custom_fallback_for_customization" namespace: "text" description: "Add fallback attribute for custom fallback for customization" bug: "430485331" } core/tests/coretests/src/android/graphics/FontListParserTest.java +5 −5 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ public final class FontListParserTest { Arrays.asList(new FontConfig.Font(new File("test.ttf"), null, "test", new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 0, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading Loading @@ -149,7 +149,7 @@ public final class FontListParserTest { new FontConfig.Font(new File("italic.ttf"), null, "test", new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC), 0, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading Loading @@ -178,7 +178,7 @@ public final class FontListParserTest { 0, "'wdth' 400.0,'wght' 700.0", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading @@ -199,7 +199,7 @@ public final class FontListParserTest { new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 1, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading @@ -219,7 +219,7 @@ public final class FontListParserTest { new FontConfig.Font(new File("test.ttc"), null, "test", new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 1, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.SystemFonts; import android.graphics.text.PositionedGlyphs; import android.graphics.text.TextRunShaper; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.text.FontConfig; Loading Loading @@ -1065,4 +1066,42 @@ public class TypefaceSystemFallbackTest { assertEquals(GLYPH_2EM_WIDTH, paint.measureText("b"), 0.0f); assertEquals(GLYPH_2EM_WIDTH, paint.measureText("c"), 0.0f); } @RequiresFlagsEnabled(Flags.FLAG_CUSTOM_FALLBACK_FOR_CUSTOMIZATION) @Test public void testBuildSystemFallback_fallbackAttribute() { final String xml = "<?xml version='1.0' encoding='UTF-8'?>" + "<familyset>" + " <family name='sans-serif'>" + " <font weight='400' style='normal'>fallback_capital.ttf</font>" + " </family>" + "</familyset>"; final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" + "<fonts-modification version='1'>" + " <family-list customizationType='new-named-family' name='custom-family' " + " fallback='fallback-family'>" + " <family>" + " <font weight='400' style='normal'>a3em.ttf</font>" + " </family>" + " </family-list>" + " <family-list customizationType='new-named-family' name='fallback-family'>" + " <family>" + " <font weight='400' style='normal'>fallback.ttf</font>" + " </family>" + " </family-list>" + "</fonts-modification>"; final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); buildSystemFallback(xml, oemXml, fontMap, fallbackMap); final Paint paint = new Paint(); Typeface testTypeface = fontMap.get("custom-family"); assertNotNull(testTypeface); paint.setTypeface(testTypeface); assertEquals("a3em.ttf", getFontName(paint, "a")); assertEquals("fallback.ttf", getFontName(paint, "x")); assertEquals("fallback_capital.ttf", getFontName(paint, "A")); } } graphics/java/android/graphics/FontListParser.java +14 −2 Original line number Diff line number Diff line Loading @@ -309,6 +309,12 @@ public class FontListParser { @Nullable Map<String, File> updatableFontMap, boolean allowNonExistingFile) throws XmlPullParserException, IOException { final String name = parser.getAttributeValue(null, "name"); final String fallback; if (com.android.text.flags.Flags.customFallbackForCustomization()) { fallback = parser.getAttributeValue(null, "fallback"); } else { fallback = null; } throwIfAttributeExists("lang", parser); throwIfAttributeExists("variant", parser); throwIfAttributeExists("ignore", parser); Loading @@ -318,7 +324,7 @@ public class FontListParser { if (family == null) { return null; } return new NamedFamilyList(Collections.singletonList(family), name); return new NamedFamilyList(Collections.singletonList(family), name, fallback); } /** Loading @@ -329,6 +335,12 @@ public class FontListParser { @Nullable Map<String, File> updatableFontMap, boolean allowNonExistingFile) throws XmlPullParserException, IOException { final String name = parser.getAttributeValue(null, "name"); final String fallback; if (com.android.text.flags.Flags.customFallbackForCustomization()) { fallback = parser.getAttributeValue(null, "fallback"); } else { fallback = null; } final List<FontConfig.FontFamily> familyList = new ArrayList<>(); while (keepReading(parser)) { if (parser.getEventType() != XmlPullParser.START_TAG) continue; Loading @@ -352,7 +364,7 @@ public class FontListParser { if (familyList.isEmpty()) { return null; } return new FontConfig.NamedFamilyList(familyList, name); return new FontConfig.NamedFamilyList(familyList, name, fallback); } /** Matches leading and trailing XML whitespace. */ Loading Loading
core/java/android/text/FontConfig.java +14 −2 Original line number Diff line number Diff line Loading @@ -761,11 +761,14 @@ public final class FontConfig implements Parcelable { public static final class NamedFamilyList implements Parcelable { private final List<FontFamily> mFamilies; private final String mName; private final @Nullable String mFallback; /** @hide */ public NamedFamilyList(@NonNull List<FontFamily> families, @NonNull String name) { public NamedFamilyList(@NonNull List<FontFamily> families, @NonNull String name, @Nullable String fallback) { mFamilies = families; mName = name; mFallback = fallback; } /** @hide */ Loading @@ -773,6 +776,7 @@ public final class FontConfig implements Parcelable { mFamilies = new ArrayList<>(); mFamilies.add(family); mName = family.getName(); mFallback = null; } /** Loading @@ -797,6 +801,11 @@ public final class FontConfig implements Parcelable { return mName; } /** @hide */ public @Nullable String getFallback() { return mFallback; } @Override public int describeContents() { return 0; Loading @@ -806,6 +815,7 @@ public final class FontConfig implements Parcelable { public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) { dest.writeTypedList(mFamilies, flags); dest.writeString8(mName); dest.writeString8(mFallback); } public static final @NonNull Creator<NamedFamilyList> CREATOR = new Creator<>() { Loading @@ -815,7 +825,8 @@ public final class FontConfig implements Parcelable { final List<FontFamily> families = new ArrayList<>(); source.readTypedList(families, FontFamily.CREATOR); String name = source.readString8(); return new NamedFamilyList(families, name); String fallback = source.readString8(); return new NamedFamilyList(families, name, fallback); } @Override Loading Loading @@ -843,6 +854,7 @@ public final class FontConfig implements Parcelable { return "NamedFamilyList{" + "mFamilies=" + mFamilies + ", mName='" + mName + '\'' + ", mFallback='" + mFallback + '\'' + '}'; } } Loading
core/java/android/text/flags/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -231,3 +231,11 @@ flag { # Being read only because this is used in the performance critical path. is_fixed_read_only: true } flag { name: "custom_fallback_for_customization" namespace: "text" description: "Add fallback attribute for custom fallback for customization" bug: "430485331" }
core/tests/coretests/src/android/graphics/FontListParserTest.java +5 −5 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ public final class FontListParserTest { Arrays.asList(new FontConfig.Font(new File("test.ttf"), null, "test", new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 0, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading Loading @@ -149,7 +149,7 @@ public final class FontListParserTest { new FontConfig.Font(new File("italic.ttf"), null, "test", new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC), 0, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading Loading @@ -178,7 +178,7 @@ public final class FontListParserTest { 0, "'wdth' 400.0,'wght' 700.0", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading @@ -199,7 +199,7 @@ public final class FontListParserTest { new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 1, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading @@ -219,7 +219,7 @@ public final class FontListParserTest { new FontConfig.Font(new File("test.ttc"), null, "test", new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), 1, "", null, FontConfig.Font.VAR_TYPE_AXES_NONE)), LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif"); LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT)), "sans-serif", null); FontConfig.NamedFamilyList family = readNamedFamily(xml); assertThat(family).isEqualTo(expected); } Loading
core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +39 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.SystemFonts; import android.graphics.text.PositionedGlyphs; import android.graphics.text.TextRunShaper; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.text.FontConfig; Loading Loading @@ -1065,4 +1066,42 @@ public class TypefaceSystemFallbackTest { assertEquals(GLYPH_2EM_WIDTH, paint.measureText("b"), 0.0f); assertEquals(GLYPH_2EM_WIDTH, paint.measureText("c"), 0.0f); } @RequiresFlagsEnabled(Flags.FLAG_CUSTOM_FALLBACK_FOR_CUSTOMIZATION) @Test public void testBuildSystemFallback_fallbackAttribute() { final String xml = "<?xml version='1.0' encoding='UTF-8'?>" + "<familyset>" + " <family name='sans-serif'>" + " <font weight='400' style='normal'>fallback_capital.ttf</font>" + " </family>" + "</familyset>"; final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>" + "<fonts-modification version='1'>" + " <family-list customizationType='new-named-family' name='custom-family' " + " fallback='fallback-family'>" + " <family>" + " <font weight='400' style='normal'>a3em.ttf</font>" + " </family>" + " </family-list>" + " <family-list customizationType='new-named-family' name='fallback-family'>" + " <family>" + " <font weight='400' style='normal'>fallback.ttf</font>" + " </family>" + " </family-list>" + "</fonts-modification>"; final ArrayMap<String, Typeface> fontMap = new ArrayMap<>(); final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>(); buildSystemFallback(xml, oemXml, fontMap, fallbackMap); final Paint paint = new Paint(); Typeface testTypeface = fontMap.get("custom-family"); assertNotNull(testTypeface); paint.setTypeface(testTypeface); assertEquals("a3em.ttf", getFontName(paint, "a")); assertEquals("fallback.ttf", getFontName(paint, "x")); assertEquals("fallback_capital.ttf", getFontName(paint, "A")); } }
graphics/java/android/graphics/FontListParser.java +14 −2 Original line number Diff line number Diff line Loading @@ -309,6 +309,12 @@ public class FontListParser { @Nullable Map<String, File> updatableFontMap, boolean allowNonExistingFile) throws XmlPullParserException, IOException { final String name = parser.getAttributeValue(null, "name"); final String fallback; if (com.android.text.flags.Flags.customFallbackForCustomization()) { fallback = parser.getAttributeValue(null, "fallback"); } else { fallback = null; } throwIfAttributeExists("lang", parser); throwIfAttributeExists("variant", parser); throwIfAttributeExists("ignore", parser); Loading @@ -318,7 +324,7 @@ public class FontListParser { if (family == null) { return null; } return new NamedFamilyList(Collections.singletonList(family), name); return new NamedFamilyList(Collections.singletonList(family), name, fallback); } /** Loading @@ -329,6 +335,12 @@ public class FontListParser { @Nullable Map<String, File> updatableFontMap, boolean allowNonExistingFile) throws XmlPullParserException, IOException { final String name = parser.getAttributeValue(null, "name"); final String fallback; if (com.android.text.flags.Flags.customFallbackForCustomization()) { fallback = parser.getAttributeValue(null, "fallback"); } else { fallback = null; } final List<FontConfig.FontFamily> familyList = new ArrayList<>(); while (keepReading(parser)) { if (parser.getEventType() != XmlPullParser.START_TAG) continue; Loading @@ -352,7 +364,7 @@ public class FontListParser { if (familyList.isEmpty()) { return null; } return new FontConfig.NamedFamilyList(familyList, name); return new FontConfig.NamedFamilyList(familyList, name, fallback); } /** Matches leading and trailing XML whitespace. */ Loading