From 065c59beafb89d8a67f6cb39313fc812133d4445 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Tue, 25 Jul 2017 14:28:30 -0700 Subject: [PATCH] Revert "Implement family fallback." DO NOT MERGE This reverts commit 0d253e46aa0b4cb2ea56e220812aeab92de64ae1. The original CL changed Typeface internal methods and broke TypefaceCompatApi26Impl in support library which uses reflections. Ideally, TypefaceCompatApi26Impl must fall back to public API implementation but due to lack of method availability check, it ended up crashing the application. The original patch didn't change any behaviors in MR1, so reverting that change is the best solution for MR1. Bug: 64033594 Change-Id: Ie86afeb1b809e57915d62c1db5a70c8d210d2354 Test: N/A --- core/java/android/text/FontConfig.java | 8 +- core/tests/coretests/assets/fonts/a3em.ttf | Bin 1784 -> 0 bytes core/tests/coretests/assets/fonts/a3em.ttx | 187 ------- core/tests/coretests/assets/fonts/all2em.ttf | Bin 1780 -> 0 bytes core/tests/coretests/assets/fonts/all2em.ttx | 184 ------- core/tests/coretests/assets/fonts/b3em.ttf | Bin 1784 -> 0 bytes core/tests/coretests/assets/fonts/b3em.ttx | 187 ------- core/tests/coretests/assets/fonts/c3em.ttf | Bin 1784 -> 0 bytes core/tests/coretests/assets/fonts/c3em.ttx | 187 ------- .../coretests/assets/fonts/no_coverage.ttf | Bin 1768 -> 0 bytes .../coretests/assets/fonts/no_coverage.ttx | 180 ------- .../graphics/TypefaceSystemFallbackTest.java | 469 ----------------- .../java/android/graphics/FontListParser.java | 3 +- graphics/java/android/graphics/Typeface.java | 490 ++++++++---------- libs/hwui/hwui/Typeface.cpp | 2 +- 15 files changed, 209 insertions(+), 1688 deletions(-) delete mode 100644 core/tests/coretests/assets/fonts/a3em.ttf delete mode 100644 core/tests/coretests/assets/fonts/a3em.ttx delete mode 100644 core/tests/coretests/assets/fonts/all2em.ttf delete mode 100644 core/tests/coretests/assets/fonts/all2em.ttx delete mode 100644 core/tests/coretests/assets/fonts/b3em.ttf delete mode 100644 core/tests/coretests/assets/fonts/b3em.ttx delete mode 100644 core/tests/coretests/assets/fonts/c3em.ttf delete mode 100644 core/tests/coretests/assets/fonts/c3em.ttx delete mode 100644 core/tests/coretests/assets/fonts/no_coverage.ttf delete mode 100644 core/tests/coretests/assets/fonts/no_coverage.ttx delete mode 100644 core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java 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 a601ce2ed932468ecc3232eecb75bf167fdc9ab8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1784 zcmai#O>Yxd6o%jNI1nfw>V|HwA{Kza&@5;LT|g;_G$^j(gp^7FCeFk*^;c~NCx`_S z8^o#${s3D9%SuRPU9spABz^!3#I91hcAs-+CSeSyb2ayTpL_0m&e#eh?bSVna^=d& z>H78BV<|X-_GYyebv4j4{KHtPw+R}WGmX}s_5lOcGr$tar4dnACvqO#croR7(LgtwCj!8 zWwr9Y`0LN=jf3C)t1x_L(XakFXYqP{xBsir^x3UK$`KR38+|K%@q9;<{2qAh3h0xCVf)#wU+8F1+=FJ7H{k;vLQ438 z4(LwG7eCPN(qTPF_4~sobT;unpoQX9T~J3|ZK|h+YN|6GPDjulg-+{~zScKz3s_?4 zd9^vOM@$3iR3m2{>ny{R@=;TuahC46 z57wr?uj5`3=sD`>5N{P(ZAmo^c&9Z^N^Tx&!`E-$phIi8Rf$WmX^^Sy?M_3iR?W_> z@)ecFs#zq`&glCSdvL!|NrQVPIIZ{^BYI$6Fcc%Lq*WRILr&^=6eD_KQAykYZC2?J zy;Ws(*JMccv96&RlEGr~2(9AT$7)e4R5M6(eyV5r+u4bR+~+db{5X%6(-bpVL7HKo zf`0F1lk(Lp;jy60Oza}mX$il1)_Kh#&*-AhQbyyL{xaGhe8i0B?S!%}v77%j=qy(A zF&tv*O=idD(7N39cqH9OaBXaN*^nLYUxlb_YK)HKv6glxo6tTd*tga2(^VzHx@dh_ zht_n0?iKG*`g(0v(y7Cl_@h{X)~<^3fmm|MBtjAH_iv(*OVf 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 482f7552f5109ab5afa4a5da62b4611fccf11b78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1780 zcmai#zi$**5XZlJdj=B$>8PI^3W(rHTtEaVAOwVC9i0}_Pwd40Fh{o?MNvk?Un zLPDwd7bs{@QbvlR`~j9|D2zlwNrC7hnfmgXx4SlXfU-~f=GS-T&6}CkDvmANDd6LbwqGsH9_28#8{zS3U?)8U%X&UI3 z*=4!%Zk>Mq^ye?Xf3Glni$+`jo;82Hyw`hZG<)`{ka75gZ-?L6zN^V$o)&!U96w^p zgs?DA6(%%U_^oga-E2yOTbd4z8D=5_LM+dnXK{9EPG=P<4jnmclEWrOj|sL5|G+!M zZQaCj(_2D1BJEdEUqg#5L&w7*d*t^3oyEu(!p^f-H>he*+=pg`H{}BzLQ4694(e{k z7eCPN(P2Hx^asLcbT!2v)I#y9&a17CHq=$3n(FG4_Yt&5q0{gx> zW)V+2qvucT!rdX0gnOoSTJ||c^uW4cRgAQpWo7jra8lb>F`_5tmHPG3I`Ee10KH{p zQcYIL9@bSf10tBuXoXfl_OP1QGTHRAn4jv|=DRVXO`@ z`KGgDb7)=e_Nb8#HblEC9-oFZ7`P3L4ug7ZEoqR%joM7Kp;-{;Mhjr2VvIedB zST%fph3leEd*-}XmrSg_`4?c7Hs6)8irJhPvX9leZdEtz|M#!N - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 63948a22c11370a55b4f3d842fbe183cfb730785..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1784 zcmai#O>Yxd6o%jNI1r$Kx+x1bR}l-Sz_eLV1S}FLh%_j!;)Jx7LYX)ddn$inJ9UD( zsKf@bsJh?}bc+x>B&6~KvgndZ{D3Y{ca_q$`o_p>&XKV$M4(n%y za^=eT>H3}8Z&Gj??cHiK>Zqq@$d8dP)Ee6xP@dqG?e#cXKlEVtKI~K83w0FX--mbM z|KdGWZ}zu7ejJ>@{~_{6jdnGH@&tddO*W&gj*4EMWOuEo88==(_$rM*QS7vP{oxBu zO9x(?U6w2F%bnj(et-PRzY4=QhJN+WjN$d?PrYA^X3s$tG7e1mW_VFL@?u{za`QCw zvBR7$FNB4~;8#s(vhb+z4W{{&26r?aoHf^peSgby?^&K-S7?53&Y-XP~Xwfpm+$)I&aDc z`UENE3p%Fz8DD%$e?X`7Fw-9mpU~OV|CpAFw{=Zzb+oOn64g{!pWIKQJp-NAXZl=U zz%5~kp|fgnUKdOPbt;36(K%JnZDOf$K)`jOc-N!KxT(Ez8R4Kj5UcuVO?`43*;g zXdV8R=>WZDWl~L6$sX1XGy@_SCSRd-JbPFTwMI7mEaw09EPp#Y(JJ@82sS^?SIcRN znXDkqu}?v-dfB9WHY<26=_V7q40T$;Z;>^t1>`wh_fg7d9MfM$`=v+BdEQPa>jt~| ze+!+*YCcwnn0(XOu{pFZcYHn4ZlrZh_PT799q(TS)M#pqj@M%&>&|FGdz@h3R^q3t z3c|W*ec6Q8e5@LnAK|*_)1Enx>XM1ock~5Vr4742Rxz6s^Xy}_u3Od3_rv`wF}ZzK zN0)S-HSnuMoc%AeMQyLqkp+5kUFWhdH2W - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 badc3e29868fbd30d6f8e24a63165ce89b7b0242..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1784 zcmai#yKfX%6vn^VS%ZN9N(1ecML{B1hzk-03f{so@*=N|LnM=o*W=wq`(k&^+9*XN zH;5_)QfgWRWh5l1BZ`zn;t!xebV#P&{LY;j%q)qR(cJSs_uTKCyQ@IbUj3#}u3R}W zUB6j-CU?20Hs-p)N%ooWQ-3I1l8Y(*Pg6}>#k>e^8&Zob<3A;~{c>~{Kt(Nj%JyIz@H zRx980zn<;;`QVxN3d1)R{qo&ei`PHD_Wv-NKD$*&Iby;$qwl1BPj@t#o2Q}A9p-d- zAuP-XziUF1h5LmcG0i44xT)#jn7K~u_*k1hOfg;S>l{_>MX;Q@=;TuahmSA zkKRpxUdOp2&~wz$A>Jyo+LCG-@J?&&l$<=)hOgi5phIi8Rf$WmX^^Sy?M_3iR?W_- z@)ecFs#zq`_UQW^dvLd@q`^58oK}2|5k0Uj7>bcr(y9#qAv<+EiV;1rs3dNHHmh`q z-m0>?YceGJSl7@D$zU;ggjVtFW3{Lisu`p?|Ep*D)7g%O-2Y{;`EedCrzvK#f;7WA z1wHR&lk(Lp;jy4AOza}mX$il1-gBBmp3x!>;O**ro!}k% sw?v+un_2QFs$os$F}u}$G*`j)0v(y7Czo_Qy`kxE`RGsk|M>Lz7u5|D(*OVf 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 c884881c5026713114077979f52e202bc7d1b2e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1768 zcmai#&rcIk5XWcR@-u=r&o6`nCQuX;e;+^uMF>^O4>dtuN?F$Qmu;b7JeY7Hp8PwE zR})PP>d(>pz1-#slHt75c{S@UcWnJU!}2BX*;NejZ%&f+SKi*$e03vs zOBTUzqqpXY85hZL-ZHi3-Hj6as@~3I3T{4|`?Pf<$lsDE6)V;HYZ(H%qkd7Yyq~|k ze{=u%)fcxI!f!o1qFV z(jI#jyNzu!kj_0Ba{3k15&{v*^I*(PE=m zlL5Y4W)t%=Dn%*Drj*4OPgbQ0qdu%BkwbDyPRlt~vv{(|5h<`=nHV2wBt>i%n~^lO zH9Q%MyJ;~GS!c+Y7FY5hbJjNwvVe64%_Amh<5Cct^DR$NT1*tIW{%e*`mUu(P zh+~P2nNVwt=?6DYY?%zc<)Noca!x&Ul%Yo&qk5>uB|2t~Je&5shI6@8&%mQdyfRX5 z0UMvSkrj3dPM(zw%fDoiJ~0Np7}mxoQ^ER;)QC|who@>}lx$)%N2Kmiu{)MoJ%WkP zIfFVaS&l9}&@N~dU0DiQY5i;LRJ2ue>4`=KaaF7ayfUp}S5~TdqLr-RUBOZ#gT^#g zXc=S$uSPAwrW)q_ThAI#r#oup{*^)RkFnJ<(!-rhqfIdPAg@?mwMI4zAZFz{H+Bwb zWC7d^&xlN;Pso_flEPxR{VA+hZN!9K>kcUyXIA_jwxe`pnx2fwK=_5){}Fy4U+MqFpW`>V&lb`E 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; }