diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index 029f66e1d670a..ed583907123b6 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -64,19 +64,17 @@ public final class FontConfig { private final int mWeight; private final boolean mIsItalic; private Uri mUri; - private final String mFallbackFor; /** * @hide */ public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes, - int weight, boolean isItalic, String fallbackFor) { + int weight, boolean isItalic) { mFontName = fontName; mTtcIndex = ttcIndex; mAxes = axes; mWeight = weight; mIsItalic = isItalic; - mFallbackFor = fallbackFor; } /** @@ -127,10 +125,6 @@ public final class FontConfig { public void setUri(@NonNull Uri uri) { mUri = uri; } - - public String getFallbackFor() { - return mFallbackFor; - } } /** diff --git a/core/tests/coretests/assets/fonts/a3em.ttf b/core/tests/coretests/assets/fonts/a3em.ttf deleted file mode 100644 index a601ce2ed9324..0000000000000 Binary files a/core/tests/coretests/assets/fonts/a3em.ttf and /dev/null differ diff --git a/core/tests/coretests/assets/fonts/a3em.ttx b/core/tests/coretests/assets/fonts/a3em.ttx deleted file mode 100644 index d3b9e16037641..0000000000000 --- a/core/tests/coretests/assets/fonts/a3em.ttx +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright (C) 2017 The Android Open Source Project - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. - - - http://www.apache.org/licenses/LICENSE-2.0 - - - - - - - - - - - - - - - - diff --git a/core/tests/coretests/assets/fonts/all2em.ttf b/core/tests/coretests/assets/fonts/all2em.ttf deleted file mode 100644 index 482f7552f5109..0000000000000 Binary files a/core/tests/coretests/assets/fonts/all2em.ttf and /dev/null differ diff --git a/core/tests/coretests/assets/fonts/all2em.ttx b/core/tests/coretests/assets/fonts/all2em.ttx deleted file mode 100644 index fe95ff04d1e34..0000000000000 --- a/core/tests/coretests/assets/fonts/all2em.ttx +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright (C) 2017 The Android Open Source Project - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. - - - http://www.apache.org/licenses/LICENSE-2.0 - - - - - - - - - - - - - - - - diff --git a/core/tests/coretests/assets/fonts/b3em.ttf b/core/tests/coretests/assets/fonts/b3em.ttf deleted file mode 100644 index 63948a22c1137..0000000000000 Binary files a/core/tests/coretests/assets/fonts/b3em.ttf and /dev/null differ diff --git a/core/tests/coretests/assets/fonts/b3em.ttx b/core/tests/coretests/assets/fonts/b3em.ttx deleted file mode 100644 index b5a77ef09bd3d..0000000000000 --- a/core/tests/coretests/assets/fonts/b3em.ttx +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright (C) 2017 The Android Open Source Project - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. - - - http://www.apache.org/licenses/LICENSE-2.0 - - - - - - - - - - - - - - - - diff --git a/core/tests/coretests/assets/fonts/c3em.ttf b/core/tests/coretests/assets/fonts/c3em.ttf deleted file mode 100644 index badc3e29868fb..0000000000000 Binary files a/core/tests/coretests/assets/fonts/c3em.ttf and /dev/null differ diff --git a/core/tests/coretests/assets/fonts/c3em.ttx b/core/tests/coretests/assets/fonts/c3em.ttx deleted file mode 100644 index f5ed8e556332b..0000000000000 --- a/core/tests/coretests/assets/fonts/c3em.ttx +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright (C) 2017 The Android Open Source Project - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. - - - http://www.apache.org/licenses/LICENSE-2.0 - - - - - - - - - - - - - - - - diff --git a/core/tests/coretests/assets/fonts/no_coverage.ttf b/core/tests/coretests/assets/fonts/no_coverage.ttf deleted file mode 100644 index c884881c50267..0000000000000 Binary files a/core/tests/coretests/assets/fonts/no_coverage.ttf and /dev/null differ diff --git a/core/tests/coretests/assets/fonts/no_coverage.ttx b/core/tests/coretests/assets/fonts/no_coverage.ttx deleted file mode 100644 index 3be5f8626bf14..0000000000000 --- a/core/tests/coretests/assets/fonts/no_coverage.ttx +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Copyright (C) 2017 The Android Open Source Project - - - Sample Font - - - Regular - - - Sample Font - - - SampleFont-Regular - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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. - - - http://www.apache.org/licenses/LICENSE-2.0 - - - - - - - - - - - - - - - - diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java deleted file mode 100644 index ca4f7d43caf42..0000000000000 --- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java +++ /dev/null @@ -1,469 +0,0 @@ -/* - * 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.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.util.ArrayMap; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; - -@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 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() + "/"; - TEST_FONTS_XML = new File(cacheDir, "fonts.xml").getAbsolutePath(); - - 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; - 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); - } - } - } - - @After - public void tearDown() { - for (final String fontFile : TEST_FONT_FILES) { - final File outInCache = new File(TEST_FONT_DIR, fontFile); - outInCache.delete(); - } - } - - private static void buildSystemFallback(String xml, - ArrayMap fontMap, ArrayMap fallbackMap) { - try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) { - fos.write(xml.getBytes(Charset.forName("UTF-8"))); - } catch (IOException e) { - throw new RuntimeException(e); - } - Typeface.buildSystemFallback(TEST_FONTS_XML, TEST_FONT_DIR, fontMap, fallbackMap); - } - - @Test - public void testBuildSystemFallback() { - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - Typeface.buildSystemFallback(SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, fontMap, fallbackMap); - - assertFalse(fontMap.isEmpty()); - assertFalse(fallbackMap.isEmpty()); - } - - @Test - public void testBuildSystemFallback_NonExistentFontShouldBeIgnored() { - final String xml = "" - + "" - + " " - + " a3em.ttf" - + " NoSuchFont.ttf" - + " " - + " " - + " NoSuchFont.ttf" - + " " - + " " - + " NoSuchFont.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " a3em.ttf" - + " " - + " " - + " b3em.ttf" - + " " - + " " - + " c3em.ttf" - + " " - + " " - + " all2em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " a3em.ttf" - + " " - + " " - + " all2em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " a3em.ttf" - + " " - + " " - + " b3em.ttf" - + " " - + " " - + " all2em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " a3em.ttf" - + " b3em.ttf" - + " " - + " " - + " all2em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " a3em.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " all2em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " a3em.ttf" - + " " - + " " - + " b3em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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 = "" - + "" - + " " - + " no_coverage.ttf" - + " " - + " " - + " no_coverage.ttf" - + " " - + " " - + " a3em.ttf" - + " b3em.ttf" - + " " - + " " - + " c3em.ttf" - + " " - + ""; - final ArrayMap fontMap = new ArrayMap<>(); - final ArrayMap fallbackMap = new ArrayMap<>(); - - buildSystemFallback(xml, 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); - } -} diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java index 80a9324d04f3c..7c07a302dfe99 100644 --- a/graphics/java/android/graphics/FontListParser.java +++ b/graphics/java/android/graphics/FontListParser.java @@ -111,7 +111,6 @@ public class FontListParser { String weightStr = parser.getAttributeValue(null, "weight"); int weight = weightStr == null ? 400 : Integer.parseInt(weightStr); boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style")); - String fallbackFor = parser.getAttributeValue(null, "fallbackFor"); StringBuilder filename = new StringBuilder(); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() == XmlPullParser.TEXT) { @@ -127,7 +126,7 @@ public class FontListParser { } String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll(""); return new FontConfig.Font(sanitizedName, index, - axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor); + axes.toArray(new FontVariationAxis[axes.size()]), weight, isItalic); } private static FontVariationAxis readAxis(XmlPullParser parser) diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 1d8b5830aa926..c4b56c333c646 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -38,7 +38,6 @@ import android.os.ResultReceiver; import android.provider.FontRequest; import android.provider.FontsContract; import android.text.FontConfig; -import android.util.ArrayMap; import android.util.Base64; import android.util.Log; import android.util.LongSparseArray; @@ -46,7 +45,6 @@ import android.util.LruCache; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import libcore.io.IoUtils; @@ -107,10 +105,12 @@ public class Typeface { private static final LruCache sDynamicTypefaceCache = new LruCache<>(16); static Typeface sDefaultTypeface; - static final Map sSystemFontMap; - static final Map sSystemFallbackMap; + static Map sSystemFontMap; + static FontFamily[] sFallbackFonts; private static final Object sLock = new Object(); + static final String FONTS_CONFIG = "fonts.xml"; + /** * @hide */ @@ -129,7 +129,6 @@ public class Typeface { // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp /** @hide */ public static final int RESOLVE_BY_FONT_TABLE = -1; - private static final String DEFAULT_FAMILY = "sans-serif"; // Style value for building typeface. private static final int STYLE_NORMAL = 0; @@ -164,27 +163,28 @@ public class Typeface { */ @Nullable public static Typeface createFromResources(AssetManager mgr, String path, int cookie) { - synchronized (sDynamicTypefaceCache) { - final String key = Builder.createAssetUid( - mgr, path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */, - DEFAULT_FAMILY); - Typeface typeface = sDynamicTypefaceCache.get(key); - if (typeface != null) return typeface; + if (sFallbackFonts != null) { + synchronized (sDynamicTypefaceCache) { + final String key = Builder.createAssetUid( + mgr, path, 0 /* ttcIndex */, null /* axes */, + RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */); + Typeface typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; - FontFamily fontFamily = new FontFamily(); - // TODO: introduce ttc index and variation settings to resource type font. - if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, - 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, - RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { - if (!fontFamily.freeze()) { - return null; + FontFamily fontFamily = new FontFamily(); + // TODO: introduce ttc index and variation settings to resource type font. + if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */, + 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */, + RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) { + if (!fontFamily.freeze()) { + return null; + } + FontFamily[] families = {fontFamily}; + typeface = createFromFamiliesWithDefault(families, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + sDynamicTypefaceCache.put(key, typeface); + return typeface; } - FontFamily[] families = {fontFamily}; - typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - sDynamicTypefaceCache.put(key, typeface); - return typeface; } } return null; @@ -197,57 +197,61 @@ public class Typeface { @Nullable public static Typeface createFromResources( FamilyResourceEntry entry, AssetManager mgr, String path) { - if (entry instanceof ProviderResourceEntry) { - final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry; - // Downloadable font - List> givenCerts = providerEntry.getCerts(); - List> certs = new ArrayList<>(); - if (givenCerts != null) { - for (int i = 0; i < givenCerts.size(); i++) { - List certSet = givenCerts.get(i); - List byteArraySet = new ArrayList<>(); - for (int j = 0; j < certSet.size(); j++) { - byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT)); + if (sFallbackFonts != null) { + if (entry instanceof ProviderResourceEntry) { + final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry; + // Downloadable font + List> givenCerts = providerEntry.getCerts(); + List> certs = new ArrayList<>(); + if (givenCerts != null) { + for (int i = 0; i < givenCerts.size(); i++) { + List certSet = givenCerts.get(i); + List byteArraySet = new ArrayList<>(); + for (int j = 0; j < certSet.size(); j++) { + byteArraySet.add(Base64.decode(certSet.get(j), Base64.DEFAULT)); + } + certs.add(byteArraySet); } - certs.add(byteArraySet); + } + // Downloaded font and it wasn't cached, request it again and return a + // default font instead (nothing we can do now). + FontRequest request = new FontRequest(providerEntry.getAuthority(), + providerEntry.getPackage(), providerEntry.getQuery(), certs); + Typeface typeface = FontsContract.getFontSync(request); + return typeface == null ? DEFAULT : typeface; + } + + Typeface typeface = findFromCache(mgr, path); + if (typeface != null) return typeface; + + // family is FontFamilyFilesResourceEntry + final FontFamilyFilesResourceEntry filesEntry = + (FontFamilyFilesResourceEntry) entry; + + FontFamily fontFamily = new FontFamily(); + for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { + // TODO: Add ttc and variation font support. (b/37853920) + if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(), + 0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */, + fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) { + return null; } } - // Downloaded font and it wasn't cached, request it again and return a - // default font instead (nothing we can do now). - FontRequest request = new FontRequest(providerEntry.getAuthority(), - providerEntry.getPackage(), providerEntry.getQuery(), certs); - Typeface typeface = FontsContract.getFontSync(request); - return typeface == null ? DEFAULT : typeface; - } - - Typeface typeface = findFromCache(mgr, path); - if (typeface != null) return typeface; - - // family is FontFamilyFilesResourceEntry - final FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) entry; - - FontFamily fontFamily = new FontFamily(); - for (final FontFileResourceEntry fontFile : filesEntry.getEntries()) { - // TODO: Add ttc and variation font support. (b/37853920) - if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(), - 0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */, - fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) { + if (!fontFamily.freeze()) { return null; } + FontFamily[] familyChain = { fontFamily }; + typeface = createFromFamiliesWithDefault(familyChain, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + synchronized (sDynamicTypefaceCache) { + final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, + null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */, + RESOLVE_BY_FONT_TABLE /* italic */); + sDynamicTypefaceCache.put(key, typeface); + } + return typeface; } - if (!fontFamily.freeze()) { - return null; - } - FontFamily[] familyChain = { fontFamily }; - typeface = createFromFamiliesWithDefault(familyChain, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - synchronized (sDynamicTypefaceCache) { - final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, - null /* axes */, RESOLVE_BY_FONT_TABLE /* weight */, - RESOLVE_BY_FONT_TABLE /* italic */, DEFAULT_FAMILY); - sDynamicTypefaceCache.put(key, typeface); - } - return typeface; + return null; } /** @@ -257,8 +261,7 @@ public class Typeface { public static Typeface findFromCache(AssetManager mgr, String path) { synchronized (sDynamicTypefaceCache) { final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */, - DEFAULT_FAMILY); + RESOLVE_BY_FONT_TABLE /* weight */, RESOLVE_BY_FONT_TABLE /* italic */); Typeface typeface = sDynamicTypefaceCache.get(key); if (typeface != null) { return typeface; @@ -495,7 +498,7 @@ public class Typeface { * @return Unique id for a given AssetManager and asset path. */ private static String createAssetUid(final AssetManager mgr, String path, int ttcIndex, - @Nullable FontVariationAxis[] axes, int weight, int italic, String fallback) { + @Nullable FontVariationAxis[] axes, int weight, int italic) { final SparseArray pkgs = mgr.getAssignedPackageIdentifiers(); final StringBuilder builder = new StringBuilder(); final int size = pkgs.size(); @@ -510,11 +513,7 @@ public class Typeface { builder.append(Integer.toString(weight)); builder.append("-"); builder.append(Integer.toString(italic)); - // Family name may contain hyphen. Use double hyphen for avoiding key conflicts before - // and after appending falblack name. - builder.append("--"); - builder.append(fallback); - builder.append("--"); + builder.append("-"); if (axes != null) { for (FontVariationAxis axis : axes) { builder.append(axis.getTag()); @@ -594,15 +593,13 @@ public class Typeface { return resolveFallbackTypeface(); } FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return createFromFamiliesWithDefault(families, mWeight, mItalic); } catch (IOException e) { return resolveFallbackTypeface(); } } else if (mAssetManager != null) { // Builder is created with asset manager. final String key = createAssetUid( - mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic, - mFallbackFamilyName); + mAssetManager, mPath, mTtcIndex, mAxes, mWeight, mItalic); synchronized (sLock) { Typeface typeface = sDynamicTypefaceCache.get(key); if (typeface != null) return typeface; @@ -616,8 +613,7 @@ public class Typeface { return resolveFallbackTypeface(); } FontFamily[] families = { fontFamily }; - typeface = createFromFamiliesWithDefault(families, mFallbackFamilyName, - mWeight, mItalic); + typeface = createFromFamiliesWithDefault(families, mWeight, mItalic); sDynamicTypefaceCache.put(key, typeface); return typeface; } @@ -631,8 +627,7 @@ public class Typeface { return resolveFallbackTypeface(); } FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return createFromFamiliesWithDefault(families, mWeight, mItalic); } else if (mFonts != null) { final FontFamily fontFamily = new FontFamily(); boolean atLeastOneFont = false; @@ -658,8 +653,7 @@ public class Typeface { } fontFamily.freeze(); FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, mFallbackFamilyName, mWeight, - mItalic); + return createFromFamiliesWithDefault(families, mWeight, mItalic); } // Must not reach here. @@ -679,7 +673,10 @@ public class Typeface { * @return The best matching typeface. */ public static Typeface create(String familyName, int style) { - return create(sSystemFontMap.get(familyName), style); + if (sSystemFontMap != null) { + return create(sSystemFontMap.get(familyName), style); + } + return null; } /** @@ -754,33 +751,34 @@ public class Typeface { if (path == null) { throw new NullPointerException(); // for backward compatibility } - synchronized (sLock) { - Typeface typeface = new Builder(mgr, path).build(); - if (typeface != null) return typeface; + if (sFallbackFonts != null) { + synchronized (sLock) { + Typeface typeface = new Builder(mgr, path).build(); + if (typeface != null) return typeface; - final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, - null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, - DEFAULT_FAMILY); - typeface = sDynamicTypefaceCache.get(key); - if (typeface != null) return typeface; + final String key = Builder.createAssetUid(mgr, path, 0 /* ttcIndex */, + null /* axes */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + typeface = sDynamicTypefaceCache.get(key); + if (typeface != null) return typeface; - final FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */, - 0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, - null /* axes */)) { - // Due to backward compatibility, even if the font is not supported by our font - // stack, we need to place the empty font at the first place. The typeface with - // empty font behaves different from default typeface especially in fallback - // font selection. - fontFamily.allowUnsupportedFont(); - fontFamily.freeze(); - final FontFamily[] families = { fontFamily }; - typeface = createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - sDynamicTypefaceCache.put(key, typeface); - return typeface; - } else { - fontFamily.abortCreation(); + final FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */, + 0 /* ttc index */, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, + null /* axes */)) { + // Due to backward compatibility, even if the font is not supported by our font + // stack, we need to place the empty font at the first place. The typeface with + // empty font behaves different from default typeface especially in fallback + // font selection. + fontFamily.allowUnsupportedFont(); + fontFamily.freeze(); + final FontFamily[] families = { fontFamily }; + typeface = createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE); + sDynamicTypefaceCache.put(key, typeface); + return typeface; + } else { + fontFamily.abortCreation(); + } } } throw new RuntimeException("Font asset not found " + path); @@ -817,20 +815,22 @@ public class Typeface { * @return The new typeface. */ public static Typeface createFromFile(@Nullable String path) { - final FontFamily fontFamily = new FontFamily(); - if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) { - // Due to backward compatibility, even if the font is not supported by our font - // stack, we need to place the empty font at the first place. The typeface with - // empty font behaves different from default typeface especially in fallback font - // selection. - fontFamily.allowUnsupportedFont(); - fontFamily.freeze(); - FontFamily[] families = { fontFamily }; - return createFromFamiliesWithDefault(families, DEFAULT_FAMILY, - RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); - } else { - fontFamily.abortCreation(); + if (sFallbackFonts != null) { + final FontFamily fontFamily = new FontFamily(); + if (fontFamily.addFont(path, 0 /* ttcIndex */, null /* axes */, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)) { + // Due to backward compatibility, even if the font is not supported by our font + // stack, we need to place the empty font at the first place. The typeface with + // empty font behaves different from default typeface especially in fallback font + // selection. + fontFamily.allowUnsupportedFont(); + fontFamily.freeze(); + FontFamily[] families = { fontFamily }; + return createFromFamiliesWithDefault(families, RESOLVE_BY_FONT_TABLE, + RESOLVE_BY_FONT_TABLE); + } else { + fontFamily.abortCreation(); + } } throw new RuntimeException("Font not found " + path); } @@ -852,8 +852,6 @@ public class Typeface { /** * Create a new typeface from an array of font families, including * also the font families in the fallback list. - * @param fallbackName the family name. If given families don't support characters, the - * characters will be rendered with this family. * @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that * case, the table information in the first family's font is used. If the first * family has multiple fonts, the closest to the regular weight and upright font @@ -865,17 +863,13 @@ public class Typeface { * @param families array of font families */ private static Typeface createFromFamiliesWithDefault(FontFamily[] families, - String fallbackName, int weight, int italic) { - FontFamily[] fallback = sSystemFallbackMap.get(fallbackName); - if (fallback == null) { - fallback = sSystemFallbackMap.get(DEFAULT_FAMILY); - } - long[] ptrArray = new long[families.length + fallback.length]; + int weight, int italic) { + long[] ptrArray = new long[families.length + sFallbackFonts.length]; for (int i = 0; i < families.length; i++) { ptrArray[i] = families[i].mNativePtr; } - for (int i = 0; i < fallback.length; i++) { - ptrArray[i + families.length] = fallback[i].mNativePtr; + for (int i = 0; i < sFallbackFonts.length; i++) { + ptrArray[i + families.length] = sFallbackFonts[i].mNativePtr; } return new Typeface(nativeCreateFromArray(ptrArray, weight, italic)); } @@ -891,189 +885,113 @@ public class Typeface { mWeight = nativeGetWeight(ni); } - private static @Nullable ByteBuffer mmap(String fullPath) { - try (FileInputStream file = new FileInputStream(fullPath)) { - final FileChannel fileChannel = file.getChannel(); - final long fontSize = fileChannel.size(); - return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); - } catch (IOException e) { - Log.e(TAG, "Error mapping font file " + fullPath); - return null; - } - } - - private static @Nullable FontFamily createFontFamily( - String familyName, List fonts, String languageTag, int variant, - Map cache, String fontDir) { - final FontFamily family = new FontFamily(languageTag, variant); - for (int i = 0; i < fonts.size(); i++) { - final FontConfig.Font font = fonts.get(i); - final String fullPath = fontDir + font.getFontName(); - ByteBuffer buffer = cache.get(fullPath); - if (buffer == null) { - if (cache.containsKey(fullPath)) { - continue; // Already failed to mmap. Skip it. - } - buffer = mmap(fullPath); - cache.put(fullPath, buffer); - if (buffer == null) { + private static FontFamily makeFamilyFromParsed(FontConfig.Family family, + Map bufferForPath) { + FontFamily fontFamily = new FontFamily(family.getLanguage(), family.getVariant()); + for (FontConfig.Font font : family.getFonts()) { + String fullPathName = "/system/fonts/" + font.getFontName(); + ByteBuffer fontBuffer = bufferForPath.get(fullPathName); + if (fontBuffer == null) { + try (FileInputStream file = new FileInputStream(fullPathName)) { + FileChannel fileChannel = file.getChannel(); + long fontSize = fileChannel.size(); + fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); + bufferForPath.put(fullPathName, fontBuffer); + } catch (IOException e) { + Log.e(TAG, "Error mapping font file " + fullPathName); continue; } } - if (!family.addFontFromBuffer(buffer, font.getTtcIndex(), font.getAxes(), + if (!fontFamily.addFontFromBuffer(fontBuffer, font.getTtcIndex(), font.getAxes(), font.getWeight(), font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL)) { - Log.e(TAG, "Error creating font " + fullPath + "#" + font.getTtcIndex()); + Log.e(TAG, "Error creating font " + fullPathName + "#" + font.getTtcIndex()); } } - if (!family.freeze()) { - Log.e(TAG, "Unable to load Family: " + familyName + " : " + languageTag); + if (!fontFamily.freeze()) { + // Treat as system error since reaching here means that a system pre-installed font + // can't be used by our font stack. + Log.e(TAG, "Unable to load Family: " + family.getName() + ":" + family.getLanguage()); return null; } - return family; + return fontFamily; } - private static void pushFamilyToFallback(FontConfig.Family xmlFamily, - ArrayMap> fallbackMap, - Map cache, - String fontDir) { - - final String languageTag = xmlFamily.getLanguage(); - final int variant = xmlFamily.getVariant(); - - final ArrayList defaultFonts = new ArrayList<>(); - final ArrayMap> specificFallbackFonts = new ArrayMap<>(); - - // Collect default fallback and specific fallback fonts. - for (final FontConfig.Font font : xmlFamily.getFonts()) { - final String fallbackName = font.getFallbackFor(); - if (fallbackName == null) { - defaultFonts.add(font); - } else { - ArrayList fallback = specificFallbackFonts.get(fallbackName); - if (fallback == null) { - fallback = new ArrayList<>(); - specificFallbackFonts.put(fallbackName, fallback); - } - fallback.add(font); - } - } - - final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( - xmlFamily.getName(), defaultFonts, languageTag, variant, cache, fontDir); - - // Insert family into fallback map. - for (int i = 0; i < fallbackMap.size(); i++) { - final ArrayList fallback = - specificFallbackFonts.get(fallbackMap.keyAt(i)); - if (fallback == null) { - if (defaultFamily != null) { - fallbackMap.valueAt(i).add(defaultFamily); - } - } else { - final FontFamily family = createFontFamily( - xmlFamily.getName(), fallback, languageTag, variant, cache, fontDir); - if (family != null) { - fallbackMap.valueAt(i).add(family); - } - } - } - } - - /** - * Build the system fallback from xml file. + /* + * (non-Javadoc) * - * @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 fontMap An output system font map. Caller must pass empty map. - * @param fallbackMap An output system fallback map. Caller must pass empty map. - * @hide + * This should only be called once, from the static class initializer block. */ - @VisibleForTesting - public static void buildSystemFallback(String xmlPath, String fontDir, - ArrayMap fontMap, ArrayMap fallbackMap) { + private static void init() { + // Load font config and initialize Minikin state + File systemFontConfigLocation = getSystemFontConfigLocation(); + File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG); try { - final FileInputStream fontsIn = new FileInputStream(xmlPath); - final FontConfig fontConfig = FontListParser.parse(fontsIn); + FileInputStream fontsIn = new FileInputStream(configFilename); + FontConfig fontConfig = FontListParser.parse(fontsIn); - final HashMap bufferCache = new HashMap(); - final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies(); + Map bufferForPath = new HashMap(); - final ArrayMap> fallbackListMap = new ArrayMap<>(); - // First traverse families which have a 'name' attribute to create fallback map. - for (final FontConfig.Family xmlFamily : xmlFamilies) { - final String familyName = xmlFamily.getName(); - if (familyName == null) { - continue; - } - final FontFamily family = createFontFamily( - xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()), - xmlFamily.getLanguage(), xmlFamily.getVariant(), bufferCache, fontDir); - if (family == null) { - continue; - } - final ArrayList fallback = new ArrayList<>(); - fallback.add(family); - fallbackListMap.put(familyName, fallback); - } - - // Then, add fallback fonts to the each fallback map. - for (int i = 0; i < xmlFamilies.length; i++) { - final FontConfig.Family xmlFamily = xmlFamilies[i]; - // The first family (usually the sans-serif family) is always placed immediately - // after the primary family in the fallback. - if (i == 0 || xmlFamily.getName() == null) { - pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir); + List familyList = new ArrayList(); + // Note that the default typeface is always present in the fallback list; + // this is an enhancement from pre-Minikin behavior. + for (int i = 0; i < fontConfig.getFamilies().length; i++) { + FontConfig.Family f = fontConfig.getFamilies()[i]; + if (i == 0 || f.getName() == null) { + FontFamily family = makeFamilyFromParsed(f, bufferForPath); + if (family != null) { + familyList.add(family); + } } } + sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]); + setDefault(Typeface.createFromFamilies(sFallbackFonts)); - // Build the font map and fallback map. - for (int i = 0; i < fallbackListMap.size(); i++) { - final String fallbackName = fallbackListMap.keyAt(i); - final List familyList = fallbackListMap.valueAt(i); - final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]); - - fallbackMap.put(fallbackName, families); - final long[] ptrArray = new long[families.length]; - for (int j = 0; j < families.length; j++) { - ptrArray[j] = families[j].mNativePtr; + Map systemFonts = new HashMap(); + for (int i = 0; i < fontConfig.getFamilies().length; i++) { + Typeface typeface; + FontConfig.Family f = fontConfig.getFamilies()[i]; + if (f.getName() != null) { + if (i == 0) { + // The first entry is the default typeface; no sense in + // duplicating the corresponding FontFamily. + typeface = sDefaultTypeface; + } else { + FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath); + if (fontFamily == null) { + continue; + } + FontFamily[] families = { fontFamily }; + typeface = Typeface.createFromFamiliesWithDefault(families, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE); + } + systemFonts.put(f.getName(), typeface); } - fontMap.put(fallbackName, new Typeface(nativeCreateFromArray( - ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE))); } - - // Insert alias to font maps. - for (final FontConfig.Alias alias : fontConfig.getAliases()) { - Typeface base = fontMap.get(alias.getToName()); + for (FontConfig.Alias alias : fontConfig.getAliases()) { + Typeface base = systemFonts.get(alias.getToName()); Typeface newFace = base; int weight = alias.getWeight(); if (weight != 400) { newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); } - fontMap.put(alias.getName(), newFace); + systemFonts.put(alias.getName(), newFace); } + sSystemFontMap = systemFonts; + } catch (RuntimeException e) { Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e); // TODO: normal in non-Minikin case, remove or make error when Minikin-only } catch (FileNotFoundException e) { - Log.e(TAG, "Error opening " + xmlPath, e); + Log.e(TAG, "Error opening " + configFilename, e); } catch (IOException e) { - Log.e(TAG, "Error reading " + xmlPath, e); + Log.e(TAG, "Error reading " + configFilename, e); } catch (XmlPullParserException e) { - Log.e(TAG, "XML parse exception for " + xmlPath, e); + Log.e(TAG, "XML parse exception for " + configFilename, e); } } static { - final ArrayMap systemFontMap = new ArrayMap<>(); - final ArrayMap systemFallbackMap = new ArrayMap<>(); - buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", systemFontMap, - systemFallbackMap); - sSystemFontMap = Collections.unmodifiableMap(systemFontMap); - sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap); - - setDefault(sSystemFontMap.get(DEFAULT_FAMILY)); - + init(); // Set up defaults and typefaces exposed in public API DEFAULT = create((String) null, 0); DEFAULT_BOLD = create((String) null, Typeface.BOLD); @@ -1090,6 +1008,10 @@ public class Typeface { } + private static File getSystemFontConfigLocation() { + return new File("/system/etc/"); + } + @Override protected void finalize() throws Throwable { try { diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp index d96e376b0b706..f66bb045373c2 100644 --- a/libs/hwui/hwui/Typeface.cpp +++ b/libs/hwui/hwui/Typeface.cpp @@ -68,7 +68,7 @@ static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style Typeface* gDefaultTypeface = NULL; Typeface* Typeface::resolveDefault(Typeface* src) { - LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr); + LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr); return src == nullptr ? gDefaultTypeface : src; }