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