1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.fonts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotEquals; 21 22 import android.graphics.Typeface; 23 import android.graphics.cts.R; 24 import android.platform.test.ravenwood.RavenwoodRule; 25 import android.text.TextPaint; 26 import android.util.Pair; 27 28 import com.android.ravenwood.common.RavenwoodCommonUtils; 29 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Locale; 35 import java.util.Map; 36 37 /** 38 * Provides a utility for testing fonts 39 * 40 * For the purpose of testing font selection of families or fallbacks, this class provies following 41 * regular font files. 42 * 43 * - ascii_a3em_weight100_upright.ttf 44 * 'a' has 3em width and others have 1em width. The metadata has weight=100, non-italic value. 45 * - ascii_b3em_weight100_italic.ttf 46 * 'b' has 3em width and others have 1em width. The metadata has weight=100, italic value. 47 * - ascii_c3em_weight200_upright.ttf 48 * 'c' has 3em width and others have 1em width. The metadata has weight=200, non-italic value. 49 * - ascii_d3em_weight200_italic.ttf 50 * 'd' has 3em width and others have 1em width. The metadata has weight=200, italic value. 51 * - ascii_e3em_weight300_upright.ttf 52 * 'e' has 3em width and others have 1em width. The metadata has weight=300, non-italic value. 53 * - ascii_f3em_weight300_italic.ttf 54 * 'f' has 3em width and others have 1em width. The metadata has weight=300, italic value. 55 * - ascii_g3em_weight400_upright.ttf 56 * 'g' has 3em width and others have 1em width. The metadata has weight=400, non-italic value. 57 * - ascii_h3em_weight400_italic.ttf 58 * 'h' has 3em width and others have 1em width. The metadata has weight=400, italic value. 59 * - ascii_i3em_weight500_upright.ttf 60 * 'i' has 3em width and others have 1em width. The metadata has weight=500, non-italic value. 61 * - ascii_j3em_weight500_italic.ttf 62 * 'j' has 3em width and others have 1em width. The metadata has weight=500, italic value. 63 * - ascii_k3em_weight600_upright.ttf 64 * 'k' has 3em width and others have 1em width. The metadata has weight=600, non-italic value. 65 * - ascii_l3em_weight600_italic.ttf 66 * 'l' has 3em width and others have 1em width. The metadata has weight=600, italic value. 67 * - ascii_m3em_weight700_upright.ttf 68 * 'm' has 3em width and others have 1em width. The metadata has weight=700, non-italic value. 69 * - ascii_n3em_weight700_italic.ttf 70 * 'n' has 3em width and others have 1em width. The metadata has weight=700, italic value. 71 * - ascii_o3em_weight800_upright.ttf 72 * 'o' has 3em width and others have 1em width. The metadata has weight=800, non-italic value. 73 * - ascii_p3em_weight800_italic.ttf 74 * 'p' has 3em width and others have 1em width. The metadata has weight=800, italic value. 75 * - ascii_q3em_weight900_upright.ttf 76 * 'q' has 3em width and others have 1em width. The metadata has weight=900, non-italic value. 77 * - ascii_r3em_weight900_italic.ttf 78 * 'r' has 3em width and others have 1em width. The metadata has weight=900, italic value. 79 * 80 * In addition to above font files, this class provides a font collection file and a variable font 81 * file. 82 * - ascii.ttc 83 * The collection of above 18 fonts with above order. 84 * - ascii_vf.ttf 85 * This font supports a-z characters and all characters has 1em width. This font supports 'wght', 86 * 'ital' axes but no effect for the glyph width. This font also supports 'Asc[a-z]' 26 axes which 87 * makes glyph width 3em. For example, 'Asca 1.0' makes a glyph width of 'a' 3em, 'Ascb 1.0' makes 88 * a glyph width of 'b' 3em. With these axes, above font can be replicated like 89 * - 'Asca' 1.0, 'wght' 100.0' is equivalent with ascii_a3em_width100_upright.ttf 90 * - 'Ascb' 1.0, 'wght' 100.0, 'ital' 1.0' is equivalent with ascii_b3em_width100_italic.ttf 91 */ 92 public class FontTestUtil { 93 private static final String FAMILY_SELECTION_FONT_PATH_IN_ASSET = "fonts/family_selection"; 94 private static final List<Pair<Integer, Boolean>> sStyleList; 95 private static final Map<Pair<Integer, Boolean>, String> sFontMap; 96 private static final Map<Pair<Integer, Boolean>, Integer> sTtcMap; 97 private static final Map<Pair<Integer, Boolean>, String> sVariationSettingsMap; 98 private static final Map<Pair<Integer, Boolean>, Integer> sResourceMap; 99 private static final String[] sFontList = { // Same order of ascii.ttc 100 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_a3em_weight100_upright.ttf", 101 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_b3em_weight100_italic.ttf", 102 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_c3em_weight200_upright.ttf", 103 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_d3em_weight200_italic.ttf", 104 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_e3em_weight300_upright.ttf", 105 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_f3em_weight300_italic.ttf", 106 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_g3em_weight400_upright.ttf", 107 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_h3em_weight400_italic.ttf", 108 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_i3em_weight500_upright.ttf", 109 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_j3em_weight500_italic.ttf", 110 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_k3em_weight600_upright.ttf", 111 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_l3em_weight600_italic.ttf", 112 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_m3em_weight700_upright.ttf", 113 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_n3em_weight700_italic.ttf", 114 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_o3em_weight800_upright.ttf", 115 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_p3em_weight800_italic.ttf", 116 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_q3em_weight900_upright.ttf", 117 FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ttf/ascii_r3em_weight900_italic.ttf", 118 }; 119 120 private static final String[] FONT_VARIATION_SETTING_LIST = { 121 "'Asca' 1.0, 'wght' 100.0", 122 "'Ascb' 1.0, 'wght' 100.0, 'ital' 1.0", 123 "'Ascc' 1.0, 'wght' 200.0", 124 "'Ascd' 1.0, 'wght' 200.0, 'ital' 1.0", 125 "'Asce' 1.0, 'wght' 300.0", 126 "'Ascf' 1.0, 'wght' 300.0, 'ital' 1.0", 127 "'Ascg' 1.0, 'wght' 400.0", 128 "'Asch' 1.0, 'wght' 400.0, 'ital' 1.0", 129 "'Asci' 1.0, 'wght' 500.0", 130 "'Ascj' 1.0, 'wght' 500.0, 'ital' 1.0", 131 "'Asck' 1.0, 'wght' 600.0", 132 "'Ascl' 1.0, 'wght' 600.0, 'ital' 1.0", 133 "'Ascm' 1.0, 'wght' 700.0", 134 "'Ascn' 1.0, 'wght' 700.0, 'ital' 1.0", 135 "'Asco' 1.0, 'wght' 800.0", 136 "'Ascp' 1.0, 'wght' 800.0, 'ital' 1.0", 137 "'Ascq' 1.0, 'wght' 900.0", 138 "'Ascr' 1.0, 'wght' 900.0, 'ital' 1.0", 139 }; 140 141 private static final int[] FONT_RESOURCE_ID_LIST = { 142 R.font.ascii_a3em_weight100_upright, 143 R.font.ascii_b3em_weight100_italic, 144 R.font.ascii_c3em_weight200_upright, 145 R.font.ascii_d3em_weight200_italic, 146 R.font.ascii_e3em_weight300_upright, 147 R.font.ascii_f3em_weight300_italic, 148 R.font.ascii_g3em_weight400_upright, 149 R.font.ascii_h3em_weight400_italic, 150 R.font.ascii_i3em_weight500_upright, 151 R.font.ascii_j3em_weight500_italic, 152 R.font.ascii_k3em_weight600_upright, 153 R.font.ascii_l3em_weight600_italic, 154 R.font.ascii_m3em_weight700_upright, 155 R.font.ascii_n3em_weight700_italic, 156 R.font.ascii_o3em_weight800_upright, 157 R.font.ascii_p3em_weight800_italic, 158 R.font.ascii_q3em_weight900_upright, 159 R.font.ascii_r3em_weight900_italic, 160 }; 161 162 private static final char[] CHAR_3EM_WIDTH = { 163 'a', 164 'b', 165 'c', 166 'd', 167 'e', 168 'f', 169 'g', 170 'h', 171 'i', 172 'j', 173 'k', 174 'l', 175 'm', 176 'n', 177 'o', 178 'p', 179 'q', 180 'r', 181 }; 182 183 static { 184 // Style list with the same order of sFontList. 185 ArrayList<Pair<Integer, Boolean>> styles = new ArrayList<>(); styles.add(new Pair<>(100, false))186 styles.add(new Pair<>(100, false)); styles.add(new Pair<>(100, true))187 styles.add(new Pair<>(100, true)); styles.add(new Pair<>(200, false))188 styles.add(new Pair<>(200, false)); styles.add(new Pair<>(200, true))189 styles.add(new Pair<>(200, true)); styles.add(new Pair<>(300, false))190 styles.add(new Pair<>(300, false)); styles.add(new Pair<>(300, true))191 styles.add(new Pair<>(300, true)); styles.add(new Pair<>(400, false))192 styles.add(new Pair<>(400, false)); styles.add(new Pair<>(400, true))193 styles.add(new Pair<>(400, true)); styles.add(new Pair<>(500, false))194 styles.add(new Pair<>(500, false)); styles.add(new Pair<>(500, true))195 styles.add(new Pair<>(500, true)); styles.add(new Pair<>(600, false))196 styles.add(new Pair<>(600, false)); styles.add(new Pair<>(600, true))197 styles.add(new Pair<>(600, true)); styles.add(new Pair<>(700, false))198 styles.add(new Pair<>(700, false)); styles.add(new Pair<>(700, true))199 styles.add(new Pair<>(700, true)); styles.add(new Pair<>(800, false))200 styles.add(new Pair<>(800, false)); styles.add(new Pair<>(800, true))201 styles.add(new Pair<>(800, true)); styles.add(new Pair<>(900, false))202 styles.add(new Pair<>(900, false)); styles.add(new Pair<>(900, true))203 styles.add(new Pair<>(900, true)); 204 sStyleList = Collections.unmodifiableList(styles); 205 206 HashMap<Pair<Integer, Boolean>, String> map = new HashMap<>(); 207 HashMap<Pair<Integer, Boolean>, Integer> ttcMap = new HashMap<>(); 208 HashMap<Pair<Integer, Boolean>, String> variationMap = new HashMap<>(); 209 HashMap<Pair<Integer, Boolean>, Integer> resourceMap = new HashMap<>(); 210 HashMap<Character, Pair<Integer, Boolean>> reverseMap = new HashMap<>(); 211 for (int i = 0; i < sFontList.length; ++i) { sStyleList.get(i)212 map.put(sStyleList.get(i), sFontList[i]); sStyleList.get(i)213 ttcMap.put(sStyleList.get(i), i); sStyleList.get(i)214 variationMap.put(sStyleList.get(i), FONT_VARIATION_SETTING_LIST[i]); sStyleList.get(i)215 resourceMap.put(sStyleList.get(i), FONT_RESOURCE_ID_LIST[i]); 216 } 217 sFontMap = Collections.unmodifiableMap(map); 218 sTtcMap = Collections.unmodifiableMap(ttcMap); 219 sVariationSettingsMap = Collections.unmodifiableMap(variationMap); 220 sResourceMap = Collections.unmodifiableMap(resourceMap); 221 } 222 223 /** 224 * Measure a character with 100px text size 225 */ measureChar(Typeface typeface, char c)226 private static float measureChar(Typeface typeface, char c) { 227 final TextPaint tp = new TextPaint(); 228 tp.setTextSize(100); 229 tp.setTypeface(typeface); 230 tp.setTextLocale(Locale.US); 231 return tp.measureText(new char[] { c }, 0, 1); 232 } 233 234 /** 235 * Returns a path to the font collection file in asset directory. 236 */ getTtcFontFileInAsset()237 public static String getTtcFontFileInAsset() { 238 return FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ascii.ttc"; 239 } 240 241 /** 242 * Returns a resource id for the font collection file. 243 */ getTtcFontFileResourceId()244 public static int getTtcFontFileResourceId() { 245 return R.font.ascii; 246 } 247 248 /** 249 * Returns a path to the variable font file in asset directory. 250 */ getVFFontInAsset()251 public static String getVFFontInAsset() { 252 return FAMILY_SELECTION_FONT_PATH_IN_ASSET + "/ascii_vf.ttf"; 253 } 254 255 /** 256 * Returns a resource id for the variable font. 257 */ getVFFontResourceId()258 public static int getVFFontResourceId() { 259 return R.font.ascii_vf; 260 } 261 262 /** 263 * Returns a ttc index of the specified style. 264 */ getTtcIndexFromStyle(int weight, boolean italic)265 public static int getTtcIndexFromStyle(int weight, boolean italic) { 266 return sTtcMap.get(new Pair<>(weight, italic)).intValue(); 267 } 268 269 /** 270 * Returns a variation settings string of the specified style. 271 */ getVarSettingsFromStyle(int weight, boolean italic)272 public static String getVarSettingsFromStyle(int weight, boolean italic) { 273 return sVariationSettingsMap.get(new Pair<>(weight, italic)); 274 } 275 276 /** 277 * Returns a font resource ID of the specific style. 278 */ getFontResourceIdFromStyle(int weight, boolean italic)279 public static int getFontResourceIdFromStyle(int weight, boolean italic) { 280 return sResourceMap.get(new Pair<>(weight, italic)); 281 } 282 283 /** 284 * Returns a font path from the specified style. 285 */ getFontPathFromStyle(int weight, boolean italic)286 public static String getFontPathFromStyle(int weight, boolean italic) { 287 return sFontMap.get(new Pair<>(weight, italic)); 288 } 289 290 /** 291 * Returns all supported styles. 292 * 293 * @return a pair of weight and style(uplight/italic) 294 */ getAllStyles()295 public static List<Pair<Integer, Boolean>> getAllStyles() { 296 return sStyleList; 297 } 298 299 /** 300 * Returns selected font index in the sStyleList array. 301 */ getSelectedFontStyle(Typeface typeface)302 private static int getSelectedFontStyle(Typeface typeface) { 303 int indexOf3Em = -1; 304 for (int i = 0; i < CHAR_3EM_WIDTH.length; ++i) { 305 if (measureChar(typeface, CHAR_3EM_WIDTH[i]) == 300.0f) { 306 assertEquals("A font has two 3em width character. Likely the wrong test setup.", 307 -1, indexOf3Em); 308 indexOf3Em = i; 309 } 310 } 311 assertNotEquals("No font has 3em width character. Likely the wrong test setup.", 312 -1, indexOf3Em); 313 return indexOf3Em; 314 } 315 316 /** 317 * Returns selected font's style. 318 */ getSelectedStyle(Typeface typeface)319 public static Pair<Integer, Boolean> getSelectedStyle(Typeface typeface) { 320 return sStyleList.get(getSelectedFontStyle(typeface)); 321 } 322 323 /** 324 * Returns selected font's file path. 325 * 326 * Note that this is valid only if the all Font objects in the FontFamily is created with 327 * AssetManager. 328 */ getSelectedFontPathInAsset(Typeface typeface)329 public static String getSelectedFontPathInAsset(Typeface typeface) { 330 return sFontList[getSelectedFontStyle(typeface)]; 331 } 332 333 /** 334 * Returns selected font's ttc index. 335 * 336 * Note that this is valid only if the all Font objects in the FontFamily is created with 337 * TTC font with ttcIndex. 338 */ getSelectedTtcIndex(Typeface typeface)339 public static int getSelectedTtcIndex(Typeface typeface) { 340 return getSelectedFontStyle(typeface); 341 } 342 343 /** 344 * Returns selected font's variation settings. 345 * 346 * Note that this is valid only if the all Font objects in the FontFamily is created with 347 * variable fonts with font variation settings. 348 */ getSelectedVariationSettings(Typeface typeface)349 public static String getSelectedVariationSettings(Typeface typeface) { 350 return FONT_VARIATION_SETTING_LIST[getSelectedFontStyle(typeface)]; 351 } 352 353 /** Returns the correct fonts directory, either on device or running in Ravenwood. */ getFontsDir()354 public static String getFontsDir() { 355 if (RavenwoodRule.isOnRavenwood()) { 356 return RavenwoodCommonUtils.getRavenwoodRuntimePath() + "/fonts/"; 357 } else { 358 return "/system/fonts/"; 359 } 360 } 361 } 362