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