1 /* 2 * Copyright (C) 2009 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.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNotSame; 24 import static org.junit.Assert.assertNull; 25 import static org.junit.Assert.assertSame; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import android.content.Context; 30 import android.content.res.AssetManager; 31 import android.graphics.Paint; 32 import android.graphics.Typeface; 33 import android.graphics.Typeface.Builder; 34 import android.support.test.InstrumentationRegistry; 35 import android.support.test.filters.SmallTest; 36 import android.support.test.runner.AndroidJUnit4; 37 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import java.io.File; 43 import java.io.FileInputStream; 44 import java.io.FileOutputStream; 45 import java.io.IOException; 46 import java.io.InputStream; 47 import java.util.Locale; 48 49 @SmallTest 50 @RunWith(AndroidJUnit4.class) 51 public class TypefaceTest { 52 // generic family name for monospaced fonts 53 private static final String MONO = "monospace"; 54 private static final String DEFAULT = (String)null; 55 private static final String INVALID = "invalid-family-name"; 56 57 private static final float GLYPH_1EM_WIDTH; 58 private static final float GLYPH_3EM_WIDTH; 59 measureText(String text, Typeface typeface)60 private static float measureText(String text, Typeface typeface) { 61 final Paint paint = new Paint(); 62 // Fix the locale so that fix the locale based fallback. 63 paint.setTextLocale(Locale.US); 64 paint.setTypeface(typeface); 65 return paint.measureText(text); 66 } 67 68 static { 69 // 3em.ttf supports "a", "b", "c". The width of "a" is 3em, others are 1em. 70 final Context ctx = InstrumentationRegistry.getTargetContext(); 71 final Typeface typeface = ctx.getResources().getFont(R.font.a3em); 72 GLYPH_3EM_WIDTH = measureText("a", typeface); 73 GLYPH_1EM_WIDTH = measureText("b", typeface); 74 } 75 76 // list of family names to try when attempting to find a typeface with a given style 77 private static final String[] FAMILIES = 78 { (String) null, "monospace", "serif", "sans-serif", "cursive", "arial", "times" }; 79 80 private Context mContext; 81 82 /** 83 * Create a typeface of the given style. If the default font does not support the style, 84 * a number of generic families are tried. 85 * @return The typeface or null, if no typeface with the given style can be found. 86 */ createTypeface(int style)87 private static Typeface createTypeface(int style) { 88 for (String family : FAMILIES) { 89 Typeface tf = Typeface.create(family, style); 90 if (tf.getStyle() == style) { 91 return tf; 92 } 93 } 94 return null; 95 } 96 97 @Before setup()98 public void setup() { 99 mContext = InstrumentationRegistry.getTargetContext(); 100 } 101 102 @Test testIsBold()103 public void testIsBold() { 104 Typeface typeface = createTypeface(Typeface.BOLD); 105 if (typeface != null) { 106 assertEquals(Typeface.BOLD, typeface.getStyle()); 107 assertTrue(typeface.isBold()); 108 assertFalse(typeface.isItalic()); 109 } 110 111 typeface = createTypeface(Typeface.ITALIC); 112 if (typeface != null) { 113 assertEquals(Typeface.ITALIC, typeface.getStyle()); 114 assertFalse(typeface.isBold()); 115 assertTrue(typeface.isItalic()); 116 } 117 118 typeface = createTypeface(Typeface.BOLD_ITALIC); 119 if (typeface != null) { 120 assertEquals(Typeface.BOLD_ITALIC, typeface.getStyle()); 121 assertTrue(typeface.isBold()); 122 assertTrue(typeface.isItalic()); 123 } 124 125 typeface = createTypeface(Typeface.NORMAL); 126 if (typeface != null) { 127 assertEquals(Typeface.NORMAL, typeface.getStyle()); 128 assertFalse(typeface.isBold()); 129 assertFalse(typeface.isItalic()); 130 } 131 } 132 133 @Test testCreate()134 public void testCreate() { 135 Typeface typeface = Typeface.create(DEFAULT, Typeface.NORMAL); 136 assertNotNull(typeface); 137 typeface = Typeface.create(MONO, Typeface.BOLD); 138 assertNotNull(typeface); 139 typeface = Typeface.create(INVALID, Typeface.ITALIC); 140 assertNotNull(typeface); 141 142 typeface = Typeface.create(typeface, Typeface.NORMAL); 143 assertNotNull(typeface); 144 typeface = Typeface.create(typeface, Typeface.BOLD); 145 assertNotNull(typeface); 146 } 147 148 @Test testDefaultFromStyle()149 public void testDefaultFromStyle() { 150 Typeface typeface = Typeface.defaultFromStyle(Typeface.NORMAL); 151 assertNotNull(typeface); 152 typeface = Typeface.defaultFromStyle(Typeface.BOLD); 153 assertNotNull(typeface); 154 typeface = Typeface.defaultFromStyle(Typeface.ITALIC); 155 assertNotNull(typeface); 156 typeface = Typeface.defaultFromStyle(Typeface.BOLD_ITALIC); 157 assertNotNull(typeface); 158 } 159 160 @Test testConstants()161 public void testConstants() { 162 assertNotNull(Typeface.DEFAULT); 163 assertNotNull(Typeface.DEFAULT_BOLD); 164 assertNotNull(Typeface.MONOSPACE); 165 assertNotNull(Typeface.SANS_SERIF); 166 assertNotNull(Typeface.SERIF); 167 } 168 169 @Test(expected=NullPointerException.class) testCreateFromAssetNull()170 public void testCreateFromAssetNull() { 171 // input abnormal params. 172 Typeface.createFromAsset(null, null); 173 } 174 175 @Test(expected=NullPointerException.class) testCreateFromAssetNullPath()176 public void testCreateFromAssetNullPath() { 177 // input abnormal params. 178 Typeface.createFromAsset(mContext.getAssets(), null); 179 } 180 181 @Test(expected=RuntimeException.class) testCreateFromAssetInvalidPath()182 public void testCreateFromAssetInvalidPath() { 183 // input abnormal params. 184 Typeface.createFromAsset(mContext.getAssets(), "invalid path"); 185 } 186 187 @Test testCreateFromAsset()188 public void testCreateFromAsset() { 189 Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf"); 190 assertNotNull(typeface); 191 } 192 193 @Test(expected=NullPointerException.class) testCreateFromFileByFileReferenceNull()194 public void testCreateFromFileByFileReferenceNull() { 195 // input abnormal params. 196 Typeface.createFromFile((File) null); 197 } 198 199 @Test testCreateFromFileByFileReference()200 public void testCreateFromFileByFileReference() throws IOException { 201 File file = new File(obtainPath()); 202 Typeface typeface = Typeface.createFromFile(file); 203 assertNotNull(typeface); 204 } 205 206 @Test(expected=RuntimeException.class) testCreateFromFileWithInvalidPath()207 public void testCreateFromFileWithInvalidPath() throws IOException { 208 File file = new File("/invalid/path"); 209 Typeface.createFromFile(file); 210 } 211 212 @Test(expected=NullPointerException.class) testCreateFromFileByFileNameNull()213 public void testCreateFromFileByFileNameNull() throws IOException { 214 // input abnormal params. 215 Typeface.createFromFile((String) null); 216 } 217 218 @Test(expected=RuntimeException.class) testCreateFromFileByInvalidFileName()219 public void testCreateFromFileByInvalidFileName() throws IOException { 220 // input abnormal params. 221 Typeface.createFromFile("/invalid/path"); 222 } 223 224 @Test testCreateFromFileByFileName()225 public void testCreateFromFileByFileName() throws IOException { 226 Typeface typeface = Typeface.createFromFile(obtainPath()); 227 assertNotNull(typeface); 228 } 229 obtainPath()230 private String obtainPath() throws IOException { 231 File dir = mContext.getFilesDir(); 232 dir.mkdirs(); 233 File file = new File(dir, "test.jpg"); 234 if (!file.createNewFile()) { 235 if (!file.exists()) { 236 fail("Failed to create new File!"); 237 } 238 } 239 InputStream is = mContext.getAssets().open("samplefont.ttf"); 240 FileOutputStream fOutput = new FileOutputStream(file); 241 byte[] dataBuffer = new byte[1024]; 242 int readLength = 0; 243 while ((readLength = is.read(dataBuffer)) != -1) { 244 fOutput.write(dataBuffer, 0, readLength); 245 } 246 is.close(); 247 fOutput.close(); 248 return (file.getPath()); 249 } 250 251 @Test testInvalidCmapFont()252 public void testInvalidCmapFont() { 253 Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont.ttf"); 254 assertNotNull(typeface); 255 final String testString = "abcde"; 256 float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT); 257 float widthCustomTypeface = measureText(testString, typeface); 258 assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f); 259 } 260 261 @Test testInvalidCmapFont2()262 public void testInvalidCmapFont2() { 263 Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "bombfont2.ttf"); 264 assertNotNull(typeface); 265 final String testString = "abcde"; 266 float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT); 267 float widthCustomTypeface = measureText(testString, typeface); 268 assertEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f); 269 } 270 271 @Test testInvalidCmapFont_tooLargeCodePoints()272 public void testInvalidCmapFont_tooLargeCodePoints() { 273 // Following three font doen't have any coverage between U+0000..U+10FFFF. Just make sure 274 // they don't crash us. 275 final String[] INVALID_CMAP_FONTS = { 276 "out_of_unicode_start_cmap12.ttf", 277 "out_of_unicode_end_cmap12.ttf", 278 "too_large_start_cmap12.ttf", 279 "too_large_end_cmap12.ttf", 280 }; 281 for (final String file : INVALID_CMAP_FONTS) { 282 final Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), file); 283 assertNotNull(typeface); 284 } 285 } 286 287 @Test testInvalidCmapFont_unsortedEntries()288 public void testInvalidCmapFont_unsortedEntries() { 289 // Following two font files have glyph for U+0400 and U+0100 but the fonts must not be used 290 // due to invalid cmap data. For more details, see each ttx source file. 291 final String[] INVALID_CMAP_FONTS = { "unsorted_cmap4.ttf", "unsorted_cmap12.ttf" }; 292 for (final String file : INVALID_CMAP_FONTS) { 293 final Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), file); 294 assertNotNull(typeface); 295 final String testString = "\u0100\u0400"; 296 final float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT); 297 final float widthCustomTypeface = measureText(testString, typeface); 298 assertEquals(widthDefaultTypeface, widthCustomTypeface, 0.0f); 299 } 300 301 // Following two font files have glyph for U+0400 U+FE00 and U+0100 U+FE00 but the fonts 302 // must not be used due to invalid cmap data. For more details, see each ttx source file. 303 final String[] INVALID_CMAP_VS_FONTS = { 304 "unsorted_cmap14_default_uvs.ttf", 305 "unsorted_cmap14_non_default_uvs.ttf" 306 }; 307 for (final String file : INVALID_CMAP_VS_FONTS) { 308 final Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), file); 309 assertNotNull(typeface); 310 final String testString = "\u0100\uFE00\u0400\uFE00"; 311 final float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT); 312 final float widthCustomTypeface = measureText(testString, typeface); 313 assertEquals(widthDefaultTypeface, widthCustomTypeface, 0.0f); 314 } 315 } 316 317 @Test testCreateFromAsset_cachesTypeface()318 public void testCreateFromAsset_cachesTypeface() { 319 Typeface typeface1 = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf"); 320 assertNotNull(typeface1); 321 322 Typeface typeface2 = Typeface.createFromAsset(mContext.getAssets(), "samplefont.ttf"); 323 assertNotNull(typeface2); 324 assertSame("Same font asset should return same Typeface object", typeface1, typeface2); 325 326 Typeface typeface3 = Typeface.createFromAsset(mContext.getAssets(), "samplefont2.ttf"); 327 assertNotNull(typeface3); 328 assertNotSame("Different font asset should return different Typeface object", 329 typeface2, typeface3); 330 331 Typeface typeface4 = Typeface.createFromAsset(mContext.getAssets(), "samplefont3.ttf"); 332 assertNotNull(typeface4); 333 assertNotSame("Different font asset should return different Typeface object", 334 typeface2, typeface4); 335 assertNotSame("Different font asset should return different Typeface object", 336 typeface3, typeface4); 337 } 338 339 @Test testBadFont()340 public void testBadFont() { 341 Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), "ft45987.ttf"); 342 assertNotNull(typeface); 343 } 344 345 @Test testTypefaceBuilder_AssetSource()346 public void testTypefaceBuilder_AssetSource() { 347 Typeface typeface1 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build(); 348 assertNotNull(typeface1); 349 350 Typeface typeface2 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build(); 351 assertNotNull(typeface2); 352 assertSame("Same font asset should return same Typeface object", typeface1, typeface2); 353 354 Typeface typeface3 = new Typeface.Builder(mContext.getAssets(), "samplefont2.ttf").build(); 355 assertNotNull(typeface3); 356 assertNotSame("Different font asset should return different Typeface object", 357 typeface2, typeface3); 358 359 Typeface typeface4 = new Typeface.Builder(mContext.getAssets(), "samplefont3.ttf").build(); 360 assertNotNull(typeface4); 361 assertNotSame("Different font asset should return different Typeface object", 362 typeface2, typeface4); 363 assertNotSame("Different font asset should return different Typeface object", 364 typeface3, typeface4); 365 366 Typeface typeface5 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf") 367 .setFontVariationSettings("'wdth' 1.0").build(); 368 assertNotNull(typeface5); 369 assertNotSame("Different font font variation should return different Typeface object", 370 typeface2, typeface5); 371 372 Typeface typeface6 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf") 373 .setFontVariationSettings("'wdth' 2.0").build(); 374 assertNotNull(typeface6); 375 assertNotSame("Different font font variation should return different Typeface object", 376 typeface2, typeface6); 377 assertNotSame("Different font font variation should return different Typeface object", 378 typeface5, typeface6); 379 380 // TODO: Add ttc index case. Need TTC file for CTS. (b/36731640) 381 } 382 383 @Test testTypefaceBuilder_FileSource()384 public void testTypefaceBuilder_FileSource() { 385 try { 386 File file = new File(obtainPath()); 387 Typeface typeface1 = new Typeface.Builder(obtainPath()).build(); 388 assertNotNull(typeface1); 389 390 Typeface typeface2 = new Typeface.Builder(file).build(); 391 assertNotNull(typeface2); 392 393 Typeface typeface3 = new Typeface.Builder(file) 394 .setFontVariationSettings("'wdth' 1.0") 395 .build(); 396 assertNotNull(typeface3); 397 assertNotSame(typeface1, typeface3); 398 assertNotSame(typeface2, typeface3); 399 400 // TODO: Add ttc index case. Need TTC file for CTS. 401 } catch (IOException e) { 402 throw new RuntimeException(e); 403 } 404 } 405 406 @Test testTypefaceBuilder_fallback()407 public void testTypefaceBuilder_fallback() throws IOException { 408 final File validFile = new File(obtainPath()); 409 final File invalidFile = new File("/some/invalid/path/to/font/file"); 410 final AssetManager assets = mContext.getAssets(); 411 // By default, returns null if no fallback font is specified. 412 assertNull(new Typeface.Builder(invalidFile).build()); 413 414 assertNull(new Typeface.Builder(validFile) 415 .setTtcIndex(100 /* non-existing ttc index */).build()); 416 417 assertNull(new Typeface.Builder(assets, "invalid path").build()); 418 419 assertNull(new Typeface.Builder(assets, "samplefont.ttf") 420 .setTtcIndex(100 /* non-existing ttc index */).build()); 421 422 // If fallback is set, the builder never returns null. 423 assertNotNull(new Typeface.Builder(invalidFile).setFallback("").build()); 424 425 assertNotNull(new Typeface.Builder(invalidFile).setFallback("invalid name").build()); 426 427 Typeface sansSerifTypeface = new Typeface.Builder(invalidFile) 428 .setFallback("sans-serif").build(); 429 assertNotNull(sansSerifTypeface); 430 431 Typeface serifTypeface = new Typeface.Builder(invalidFile).setFallback("serif").build(); 432 assertNotNull(serifTypeface); 433 434 Typeface boldSansSerifTypeface = new Typeface.Builder(invalidFile) 435 .setFallback("sans-serif").setWeight(700).build(); 436 assertNotNull(boldSansSerifTypeface); 437 438 Typeface boldSerifTypeface = new Typeface.Builder(invalidFile) 439 .setFallback("serif").setWeight(700).build(); 440 assertNotNull(boldSerifTypeface); 441 442 Typeface italicSansSerifTypeface = new Typeface.Builder(invalidFile) 443 .setFallback("sans-serif").setItalic(true).build(); 444 assertNotNull(italicSansSerifTypeface); 445 446 Typeface italicSerifTypeface = new Typeface.Builder(invalidFile) 447 .setFallback("serif").setItalic(true).build(); 448 assertNotNull(italicSerifTypeface); 449 450 // All fallbacks should be different each other. 451 assertNotSame(sansSerifTypeface, serifTypeface); 452 assertNotSame(sansSerifTypeface, boldSansSerifTypeface); 453 assertNotSame(sansSerifTypeface, boldSerifTypeface); 454 assertNotSame(sansSerifTypeface, italicSansSerifTypeface); 455 assertNotSame(sansSerifTypeface, italicSerifTypeface); 456 assertNotSame(serifTypeface, boldSansSerifTypeface); 457 assertNotSame(serifTypeface, boldSerifTypeface); 458 assertNotSame(serifTypeface, italicSansSerifTypeface); 459 assertNotSame(serifTypeface, italicSerifTypeface); 460 assertNotSame(boldSansSerifTypeface, boldSerifTypeface); 461 assertNotSame(boldSansSerifTypeface, italicSansSerifTypeface); 462 assertNotSame(boldSansSerifTypeface, italicSerifTypeface); 463 assertNotSame(boldSerifTypeface, italicSansSerifTypeface); 464 assertNotSame(boldSerifTypeface, italicSerifTypeface); 465 assertNotSame(italicSansSerifTypeface, italicSerifTypeface); 466 467 // Cache should work for the same fallback. 468 assertSame(sansSerifTypeface, 469 new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif") 470 .setTtcIndex(100 /* non-existing ttc index */).build()); 471 assertSame(serifTypeface, 472 new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif") 473 .setTtcIndex(100 /* non-existing ttc index */).build()); 474 assertSame(boldSansSerifTypeface, 475 new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif") 476 .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build()); 477 assertSame(boldSerifTypeface, 478 new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif") 479 .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build()); 480 assertSame(italicSansSerifTypeface, 481 new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif") 482 .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build()); 483 assertSame(italicSerifTypeface, 484 new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif") 485 .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build()); 486 } 487 488 @Test testTypefaceBuilder_FileSourceFD()489 public void testTypefaceBuilder_FileSourceFD() { 490 try (FileInputStream fis = new FileInputStream(obtainPath())) { 491 assertNotNull(new Typeface.Builder(fis.getFD()).build()); 492 } catch (IOException e) { 493 throw new RuntimeException(e); 494 } 495 } 496 497 @Test testTypeface_SupportedCmapEncodingTest()498 public void testTypeface_SupportedCmapEncodingTest() { 499 // We support the following combinations of cmap platfrom/endcoding pairs. 500 String[] fontPaths = { 501 "CmapPlatform0Encoding0.ttf", // Platform ID == 0, Encoding ID == 0 502 "CmapPlatform0Encoding1.ttf", // Platform ID == 0, Encoding ID == 1 503 "CmapPlatform0Encoding2.ttf", // Platform ID == 0, Encoding ID == 2 504 "CmapPlatform0Encoding3.ttf", // Platform ID == 0, Encoding ID == 3 505 "CmapPlatform0Encoding4.ttf", // Platform ID == 0, Encoding ID == 4 506 "CmapPlatform0Encoding6.ttf", // Platform ID == 0, Encoding ID == 6 507 "CmapPlatform3Encoding1.ttf", // Platform ID == 3, Encoding ID == 1 508 "CmapPlatform3Encoding10.ttf", // Platform ID == 3, Encoding ID == 10 509 }; 510 511 for (String fontPath : fontPaths) { 512 Typeface typeface = Typeface.createFromAsset(mContext.getAssets(), fontPath); 513 assertNotNull(typeface); 514 final String testString = "a"; 515 float widthDefaultTypeface = measureText(testString, Typeface.DEFAULT); 516 float widthCustomTypeface = measureText(testString, typeface); 517 // The width of the glyph "a" from above fonts are 2em. 518 // So the width should be different from the default one. 519 assertNotEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f); 520 } 521 } 522 523 @Test testTypefaceBuilder_customFallback()524 public void testTypefaceBuilder_customFallback() { 525 final String fontPath = "samplefont2.ttf"; 526 final Typeface regularTypeface = new Typeface.Builder(mContext.getAssets(), fontPath) 527 .setWeight(400).build(); 528 final Typeface blackTypeface = new Typeface.Builder(mContext.getAssets(), fontPath) 529 .setWeight(900).build(); 530 531 // W is not supported by samplefont2.ttf 532 final String testString = "WWWWWWWWWWWWWWWWWWWWW"; 533 534 final Paint p = new Paint(); 535 p.setTextLocale(Locale.US); 536 p.setTextSize(128); 537 538 p.setTypeface(regularTypeface); 539 final float widthFromRegular = p.measureText(testString); 540 541 p.setTypeface(blackTypeface); 542 final float widthFromBlack = p.measureText(testString); 543 544 assertNotEquals(widthFromRegular, widthFromBlack, 1.0f); 545 } 546 547 @Test testTypefaceCreate_withExactWeight()548 public void testTypefaceCreate_withExactWeight() { 549 // multiweight_family has following fonts. 550 // - a3em.ttf with weight = 100, style=normal configuration. 551 // This font supports "a", "b", "c". The weight "a" is 3em, others are 1em. 552 // - b3em.ttf with weight = 400, style=normal configuration. 553 // This font supports "a", "b", "c". The weight "b" is 3em, others are 1em. 554 // - c3em.ttf with weight = 700, style=normal configuration. 555 // This font supports "a", "b", "c". The weight "c" is 3em, others are 1em. 556 final Typeface family = mContext.getResources().getFont(R.font.multiweight_family); 557 assertNotNull(family); 558 559 // By default, the font which weight is 400 is selected. 560 assertEquals(GLYPH_1EM_WIDTH, measureText("a", family), 0f); 561 assertEquals(GLYPH_3EM_WIDTH, measureText("b", family), 0f); 562 assertEquals(GLYPH_1EM_WIDTH, measureText("c", family), 0f); 563 564 // Draw with the font which weight is 100. 565 final Typeface thinFamily = Typeface.create(family, 100 /* weight */, false /* italic */); 566 assertEquals(GLYPH_3EM_WIDTH, measureText("a", thinFamily), 0f); 567 assertEquals(GLYPH_1EM_WIDTH, measureText("b", thinFamily), 0f); 568 assertEquals(GLYPH_1EM_WIDTH, measureText("c", thinFamily), 0f); 569 570 // Draw with the font which weight is 700. 571 final Typeface boldFamily = Typeface.create(family, 700 /* weight */, false /* italic */); 572 assertEquals(GLYPH_1EM_WIDTH, measureText("a", boldFamily), 0f); 573 assertEquals(GLYPH_1EM_WIDTH, measureText("b", boldFamily), 0f); 574 assertEquals(GLYPH_3EM_WIDTH, measureText("c", boldFamily), 0f); 575 } 576 577 @Test testTypefaceCreate_withExactStyle()578 public void testTypefaceCreate_withExactStyle() { 579 // multiweight_family has following fonts. 580 // - a3em.ttf with weight = 400, style=normal configuration. 581 // This font supports "a", "b", "c". The weight "a" is 3em, others are 1em. 582 // - b3em.ttf with weight = 400, style=italic configuration. 583 // This font supports "a", "b", "c". The weight "b" is 3em, others are 1em. 584 // - c3em.ttf with weight = 700, style=italic configuration. 585 // This font supports "a", "b", "c". The weight "c" is 3em, others are 1em. 586 final Typeface family = mContext.getResources().getFont(R.font.multistyle_family); 587 assertNotNull(family); 588 589 // By default, the normal style font which weight is 400 is selected. 590 assertEquals(GLYPH_3EM_WIDTH, measureText("a", family), 0f); 591 assertEquals(GLYPH_1EM_WIDTH, measureText("b", family), 0f); 592 assertEquals(GLYPH_1EM_WIDTH, measureText("c", family), 0f); 593 594 // Draw with the italic font. 595 final Typeface italicFamily = Typeface.create(family, 400 /* weight */, true /* italic */); 596 assertEquals(GLYPH_1EM_WIDTH, measureText("a", italicFamily), 0f); 597 assertEquals(GLYPH_3EM_WIDTH, measureText("b", italicFamily), 0f); 598 assertEquals(GLYPH_1EM_WIDTH, measureText("c", italicFamily), 0f); 599 600 // Draw with the italic font which weigth is 700. 601 final Typeface boldItalicFamily = 602 Typeface.create(family, 700 /* weight */, true /* italic */); 603 assertEquals(GLYPH_1EM_WIDTH, measureText("a", boldItalicFamily), 0f); 604 assertEquals(GLYPH_1EM_WIDTH, measureText("b", boldItalicFamily), 0f); 605 assertEquals(GLYPH_3EM_WIDTH, measureText("c", boldItalicFamily), 0f); 606 } 607 608 @Test testFontVariationSettings()609 public void testFontVariationSettings() { 610 // WeightEqualsEmVariableFont is a special font generating the outlines a glyph of 1/1000 611 // width of the given wght axis. For example, if 300 is given as the wght value to the font, 612 // the font will generate 0.3em of the glyph for the 'a'..'z' characters. 613 // The minimum, default, maximum value of 'wght' is 0, 0, 1000. 614 // No other axes are supported. 615 616 final AssetManager am = mContext.getAssets(); 617 final Paint paint = new Paint(); 618 paint.setTextSize(100); // Make 1em = 100px 619 620 // By default, WeightEqualsEmVariableFont has 0 'wght' value. 621 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf").build()); 622 assertEquals(0.0f, paint.measureText("a"), 0.0f); 623 624 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 625 .setFontVariationSettings("'wght' 100").build()); 626 assertEquals(10.0f, paint.measureText("a"), 0.0f); 627 628 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 629 .setFontVariationSettings("'wght' 300").build()); 630 assertEquals(30.0f, paint.measureText("a"), 0.0f); 631 632 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 633 .setFontVariationSettings("'wght' 800").build()); 634 assertEquals(80.0f, paint.measureText("a"), 0.0f); 635 636 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 637 .setFontVariationSettings("'wght' 550").build()); 638 assertEquals(55.0f, paint.measureText("a"), 0.0f); 639 } 640 641 @Test testFontVariationSettings_UnsupportedAxes()642 public void testFontVariationSettings_UnsupportedAxes() { 643 // WeightEqualsEmVariableFont is a special font generating the outlines a glyph of 1/1000 644 // width of the given wght axis. For example, if 300 is given as the wght value to the font, 645 // the font will generate 0.3em of the glyph for the 'a'..'z' characters. 646 // The minimum, default, maximum value of 'wght' is 0, 0, 1000. 647 // No other axes are supported. 648 649 final AssetManager am = mContext.getAssets(); 650 final Paint paint = new Paint(); 651 paint.setTextSize(100); // Make 1em = 100px 652 653 // Unsupported axes do not affect the result. 654 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 655 .setFontVariationSettings("'wght' 300, 'wdth' 10").build()); 656 assertEquals(30.0f, paint.measureText("a"), 0.0f); 657 658 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 659 .setFontVariationSettings("'wdth' 10, 'wght' 300").build()); 660 assertEquals(30.0f, paint.measureText("a"), 0.0f); 661 } 662 663 @Test testFontVariationSettings_OutOfRangeValue()664 public void testFontVariationSettings_OutOfRangeValue() { 665 // WeightEqualsEmVariableFont is a special font generating the outlines a glyph of 1/1000 666 // width of the given wght axis. For example, if 300 is given as the wght value to the font, 667 // the font will generate 0.3em of the glyph for the 'a'..'z' characters. 668 // The minimum, default, maximum value of 'wght' is 0, 0, 1000. 669 // No other axes are supported. 670 671 final AssetManager am = mContext.getAssets(); 672 final Paint paint = new Paint(); 673 paint.setTextSize(100); // Make 1em = 100px 674 675 // Out of range value needs to be clipped at the minimum or maximum values. 676 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 677 .setFontVariationSettings("'wght' -100").build()); 678 assertEquals(0.0f, paint.measureText("a"), 0.0f); 679 680 paint.setTypeface(new Typeface.Builder(am, "WeightEqualsEmVariableFont.ttf") 681 .setFontVariationSettings("'wght' 1300").build()); 682 assertEquals(100.0f, paint.measureText("a"), 0.0f); 683 } 684 685 @Test testTypefaceCreate_getWeight()686 public void testTypefaceCreate_getWeight() { 687 Typeface typeface = Typeface.DEFAULT; 688 assertEquals(400, typeface.getWeight()); 689 assertFalse(typeface.isItalic()); 690 691 typeface = Typeface.create(Typeface.DEFAULT, 100, false /* italic */); 692 assertEquals(100, typeface.getWeight()); 693 assertFalse(typeface.isItalic()); 694 695 typeface = Typeface.create(Typeface.DEFAULT, 100, true /* italic */); 696 assertEquals(100, typeface.getWeight()); 697 assertTrue(typeface.isItalic()); 698 699 typeface = Typeface.create(Typeface.DEFAULT, 400, false /* italic */); 700 assertEquals(400, typeface.getWeight()); 701 assertFalse(typeface.isItalic()); 702 703 typeface = Typeface.create(Typeface.DEFAULT, 400, true /* italic */); 704 assertEquals(400, typeface.getWeight()); 705 assertTrue(typeface.isItalic()); 706 707 typeface = Typeface.create(Typeface.DEFAULT, 700, false /* italic */); 708 assertEquals(700, typeface.getWeight()); 709 assertFalse(typeface.isItalic()); 710 711 typeface = Typeface.create(Typeface.DEFAULT, 700, true /* italic */); 712 assertEquals(700, typeface.getWeight()); 713 assertTrue(typeface.isItalic()); 714 715 // Non-standard weight. 716 typeface = Typeface.create(Typeface.DEFAULT, 250, false /* italic */); 717 assertEquals(250, typeface.getWeight()); 718 assertFalse(typeface.isItalic()); 719 720 typeface = Typeface.create(Typeface.DEFAULT, 250, true /* italic */); 721 assertEquals(250, typeface.getWeight()); 722 assertTrue(typeface.isItalic()); 723 724 } 725 726 @Test testTypefaceCreate_customFont_getWeight()727 public void testTypefaceCreate_customFont_getWeight() { 728 final AssetManager am = mContext.getAssets(); 729 730 Typeface typeface = new Builder(am, "ascii_a3em_weight100_upright.ttf").build(); 731 assertEquals(100, typeface.getWeight()); 732 assertFalse(typeface.isItalic()); 733 734 typeface = new Builder(am, "ascii_b3em_weight100_italic.ttf").build(); 735 assertEquals(100, typeface.getWeight()); 736 assertTrue(typeface.isItalic()); 737 738 } 739 740 @Test testTypefaceCreate_customFont_customWeight()741 public void testTypefaceCreate_customFont_customWeight() { 742 final AssetManager am = mContext.getAssets(); 743 Typeface typeface = new Builder(am, "ascii_a3em_weight100_upright.ttf") 744 .setWeight(400).build(); 745 assertEquals(400, typeface.getWeight()); 746 assertFalse(typeface.isItalic()); 747 748 typeface = new Builder(am, "ascii_b3em_weight100_italic.ttf").setWeight(400).build(); 749 assertEquals(400, typeface.getWeight()); 750 assertTrue(typeface.isItalic()); 751 } 752 753 @Test testTypefaceCreate_customFont_customItalic()754 public void testTypefaceCreate_customFont_customItalic() { 755 final AssetManager am = mContext.getAssets(); 756 757 Typeface typeface = new Builder(am, "ascii_a3em_weight100_upright.ttf") 758 .setItalic(true).build(); 759 assertEquals(100, typeface.getWeight()); 760 assertTrue(typeface.isItalic()); 761 762 typeface = new Builder(am, "ascii_b3em_weight100_italic.ttf").setItalic(false).build(); 763 assertEquals(100, typeface.getWeight()); 764 assertFalse(typeface.isItalic()); 765 } 766 } 767