blob: 465ea172b1c0805bdb6b990ce72b2e1c8630dff8 [file] [log] [blame]
/*
* 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
import android.text.FontConfig;
import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TypefaceSystemFallbackTest {
private static final String SYSTEM_FONT_DIR = "/system/fonts/";
private static final String SYSTEM_FONTS_XML = "/system/etc/fonts.xml";
private static final String[] TEST_FONT_FILES = {
"a3em.ttf", // Supports "a","b","c". The width of "a" is 3em, others are 1em.
"b3em.ttf", // Supports "a","b","c". The width of "b" is 3em, others are 1em.
"c3em.ttf", // Supports "a","b","c". The width of "c" is 3em, others are 1em.
"all2em.ttf", // Supports "a,","b","c". All of them have the same width of 2em.
"no_coverage.ttf", // This font doesn't support any characters.
};
private static final String TEST_FONTS_XML;
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;
private static final float GLYPH_3EM_WIDTH;
static {
final Context targetCtx = InstrumentationRegistry.getInstrumentation().getTargetContext();
final File cacheDir = new File(targetCtx.getCacheDir(), "TypefaceSystemFallbackTest");
if (!cacheDir.isDirectory()) {
cacheDir.mkdirs();
}
TEST_FONT_DIR = cacheDir.getAbsolutePath() + "/fonts/";
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();
final Paint paint = new Paint();
paint.setTypeface(new Typeface.Builder(am, "fonts/a3em.ttf").build());
GLYPH_3EM_WIDTH = paint.measureText("a");
GLYPH_1EM_WIDTH = paint.measureText("b");
paint.setTypeface(new Typeface.Builder(am, "fonts/all2em.ttf").build());
GLYPH_2EM_WIDTH = paint.measureText("a");
}
@Before
public void setUp() {
final AssetManager am =
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
for (final String fontFile : TEST_FONT_FILES) {
final String sourceInAsset = "fonts/" + fontFile;
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();
}
}
@After
public void tearDown() {
for (final String fontFile : TEST_FONT_FILES) {
final File outInCache = new File(TEST_FONT_DIR, fontFile);
outInCache.delete();
final File outOemInCache = new File(TEST_OEM_DIR, fontFile);
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);
}
}
private static void buildSystemFallback(String xml,
FontCustomizationParser.Result oemCustomization, ArrayMap<String, Typeface> fontMap,
ArrayMap<String, FontFamily[]> fallbackMap) {
try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
fos.write(xml.getBytes(Charset.forName("UTF-8")));
} catch (IOException e) {
throw new RuntimeException(e);
}
Map<String, File> updatableFontMap = new HashMap<>();
for (File file : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
updatableFontMap.put(file.getName(), file);
}
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
TEST_FONT_DIR, updatableFontMap, oemCustomization, fallbackMap);
Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
}
private static FontCustomizationParser.Result readFontCustomization(String oemXml) {
try (InputStream is = new ByteArrayInputStream(oemXml.getBytes(StandardCharsets.UTF_8))) {
return FontCustomizationParser.parse(is, TEST_OEM_DIR);
} catch (IOException | XmlPullParserException e) {
throw new RuntimeException(e);
}
}
@Test
public void testBuildSystemFallback() {
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
final FontCustomizationParser.Result oemCustomization =
new FontCustomizationParser.Result();
final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
SYSTEM_FONT_DIR, oemCustomization, fallbackMap);
assertNotNull(aliases);
assertFalse(fallbackMap.isEmpty());
Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
assertFalse(fontMap.isEmpty());
}
@Test
public void testBuildSystemFallback_NonExistentFontShouldBeIgnored() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " <font weight='400' style='normal'>NoSuchFont.ttf</font>"
+ " </family>"
+ " <family name='NoSuchFont'>"
+ " <font weight='400' style='normal'>NoSuchFont.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>NoSuchFont.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
assertEquals(1, fontMap.size());
assertTrue(fontMap.containsKey("sans-serif"));
assertEquals(1, fallbackMap.size());
assertTrue(fallbackMap.containsKey("sans-serif"));
}
@Test
public void testBuildSystemFallback_NamedFamily() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ " <family name='test'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ " <family name='test2'>"
+ " <font weight='400' style='normal'>c3em.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>all2em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
assertNotNull(sansSerifTypeface);
paint.setTypeface(sansSerifTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface testTypeface = fontMap.get("test");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface test2Typeface = fontMap.get("test2");
assertNotNull(test2Typeface);
paint.setTypeface(test2Typeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_defaultFallback() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='test'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>all2em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
assertNotNull(sansSerifTypeface);
paint.setTypeface(sansSerifTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface testTypeface = fontMap.get("test");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_namedFallbackFamily() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='test'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='test2'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal' fallbackFor='test'>a3em.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal' fallbackFor='test2'>b3em.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>all2em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
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);
final Typeface testTypeface = fontMap.get("test");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface test2Typeface = fontMap.get("test2");
assertNotNull(test2Typeface);
paint.setTypeface(test2Typeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_namedFallbackFamily2() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='test'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='test2'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal' fallbackFor='test'>a3em.ttf</font>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>all2em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
final Typeface sansSerifTypeface = fontMap.get("sans-serif");
assertNotNull(sansSerifTypeface);
paint.setTypeface(sansSerifTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface testTypeface = fontMap.get("test");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface test2Typeface = fontMap.get("test2");
assertNotNull(test2Typeface);
paint.setTypeface(test2Typeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_ImplicitSansSerifFallback() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ " <family name='test'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='test2'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>all2em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
final Typeface testTypeface = fontMap.get("test");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
final Typeface test2Typeface = fontMap.get("test2");
assertNotNull(test2Typeface);
paint.setTypeface(test2Typeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_ElegantFallback() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family variant='elegant'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ " <family variant='compact'>"
+ " <font weight='400' style='normal'>b3em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
final Typeface testTypeface = fontMap.get("serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
paint.setElegantTextHeight(true);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
paint.setElegantTextHeight(false);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_ElegantFallback_customFallback() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family variant='elegant'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " <font weight='400' style='normal' fallbackFor='serif'>b3em.ttf</font>"
+ " </family>"
+ " <family variant='compact'>"
+ " <font weight='400' style='normal'>c3em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
paint.setElegantTextHeight(true);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
paint.setElegantTextHeight(false);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("sans-serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
paint.setElegantTextHeight(true);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
paint.setElegantTextHeight(false);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_multiLingualFamilies() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family lang='de'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ " <family lang='it,fr'>"
+ " <font weight='400' style='normal'>b3em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
paint.setTypeface(fontMap.get("sans-serif"));
paint.setTextLocale(Locale.GERMANY);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
paint.setTextLocale(Locale.ITALY);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
paint.setTextLocale(Locale.FRANCE);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_ElegantFallback_customFallback_missingFile() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " <font weight='400' style='normal' fallbackFor='serif'>NoSuchFont.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal'>b3em.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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("sans-serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback_ElegantFallback_customFallback_missingFile2() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family name='serif'>"
+ " <font weight='400' style='normal'>no_coverage.ttf</font>"
+ " </family>"
+ " <family>"
+ " <font weight='400' style='normal' fallbackFor='serif'>NoSuchFont.ttf</font>"
+ " </family>"
+ " <family>"
+ " <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();
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("sans-serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback__Customization_new_named_family() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ "</familyset>";
final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<fonts-modification version='1'>"
+ " <family customizationType='new-named-family' name='google-sans'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
final FontCustomizationParser.Result oemCustomization =
readFontCustomization(oemXml);
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("sans-serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("google-sans");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback__Customization_new_named_family_override() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ "</familyset>";
final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<fonts-modification version='1'>"
+ " <family customizationType='new-named-family' name='sans-serif'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
final FontCustomizationParser.Result oemCustomization =
readFontCustomization(oemXml);
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("sans-serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback__Customization_additional_alias() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='sans-serif'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ "</familyset>";
final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<fonts-modification version='1'>"
+ " <family customizationType='new-named-family' name='google-sans'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " <font weight='700' style='normal'>c3em.ttf</font>"
+ " </family>"
+ " <alias name='another-google-sans' to='google-sans' />"
+ " <alias name='google-sans-bold' to='google-sans' weight='700' />"
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
final FontCustomizationParser.Result oemCustomization =
readFontCustomization(oemXml);
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("sans-serif");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("google-sans");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("another-google-sans");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("google-sans-bold");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test
public void testBuildSystemFallback__Customization_additional_alias_conflict_with_new_name() {
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<familyset>"
+ " <family name='named-family'>"
+ " <font weight='400' style='normal'>a3em.ttf</font>"
+ " </family>"
+ " <alias name='named-alias' to='named-family' />"
+ "</familyset>";
final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<fonts-modification version='1'>"
+ " <family customizationType='new-named-family' name='named-alias'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
final FontCustomizationParser.Result oemCustomization =
readFontCustomization(oemXml);
buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
final Paint paint = new Paint();
Typeface testTypeface = fontMap.get("named-family");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
testTypeface = fontMap.get("named-alias");
assertNotNull(testTypeface);
paint.setTypeface(testTypeface);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("a"), 0.0f);
assertEquals(GLYPH_3EM_WIDTH, paint.measureText("b"), 0.0f);
assertEquals(GLYPH_1EM_WIDTH, paint.measureText("c"), 0.0f);
}
@Test(expected = IllegalArgumentException.class)
public void testBuildSystemFallback__Customization_new_named_family_no_name_exception() {
final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<fonts-modification version='1'>"
+ " <family customizationType='new-named-family'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ "</fonts-modification>";
readFontCustomization(oemXml);
}
@Test(expected = IllegalArgumentException.class)
public void testBuildSystemFallback__Customization_new_named_family_dup_name_exception() {
final String oemXml = "<?xml version='1.0' encoding='UTF-8'?>"
+ "<fonts-modification version='1'>"
+ " <family customizationType='new-named-family' name='google-sans'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ " <family customizationType='new-named-family' name='google-sans'>"
+ " <font weight='400' style='normal'>b3em.ttf</font>"
+ " </family>"
+ "</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);
}
}