1 /* 2 * Copyright (C) 2008 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.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertTrue; 24 25 import android.content.Context; 26 import android.graphics.Bitmap; 27 import android.graphics.BitmapShader; 28 import android.graphics.ColorFilter; 29 import android.graphics.MaskFilter; 30 import android.graphics.Matrix; 31 import android.graphics.Paint; 32 import android.graphics.Paint.Align; 33 import android.graphics.Paint.Cap; 34 import android.graphics.Paint.Join; 35 import android.graphics.Paint.Style; 36 import android.graphics.Path; 37 import android.graphics.PathEffect; 38 import android.graphics.Rect; 39 import android.graphics.Shader; 40 import android.graphics.Typeface; 41 import android.graphics.Xfermode; 42 import android.graphics.fonts.FontVariationAxis; 43 import android.os.LocaleList; 44 import android.support.test.InstrumentationRegistry; 45 import android.support.test.filters.SmallTest; 46 import android.support.test.runner.AndroidJUnit4; 47 import android.text.SpannedString; 48 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 import java.util.Locale; 53 54 @SmallTest 55 @RunWith(AndroidJUnit4.class) 56 public class PaintTest { 57 private static final Typeface[] TYPEFACES = new Typeface[] { 58 Typeface.DEFAULT, 59 Typeface.DEFAULT_BOLD, 60 Typeface.MONOSPACE, 61 Typeface.SANS_SERIF, 62 Typeface.SERIF, 63 }; 64 65 @Test testConstructor()66 public void testConstructor() { 67 new Paint(); 68 69 new Paint(1); 70 71 Paint p = new Paint(); 72 new Paint(p); 73 } 74 75 @Test testBreakText()76 public void testBreakText() { 77 String text = "HIJKLMN"; 78 char[] textChars = text.toCharArray(); 79 SpannedString textSpan = new SpannedString(text); 80 81 Paint p = new Paint(); 82 83 // We need to turn off kerning in order to get accurate comparisons 84 p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG); 85 86 float[] widths = new float[text.length()]; 87 assertEquals(text.length(), p.getTextWidths(text, widths)); 88 89 float totalWidth = 0.0f; 90 for (int i = 0; i < text.length(); i++) { 91 totalWidth += widths[i]; 92 } 93 94 for (int i = 0; i < text.length(); i++) { 95 verifyBreakText(text, textChars, textSpan, i, i + 1, true, totalWidth, 1, widths[i]); 96 } 97 98 // Measure empty string 99 verifyBreakText(text, textChars, textSpan, 0, 0, true, totalWidth, 0, 0); 100 101 // Measure substring from front: "HIJ" 102 verifyBreakText(text, textChars, textSpan, 0, 3, true, totalWidth, 103 3, widths[0] + widths[1] + widths[2]); 104 105 // Reverse measure substring from front: "HIJ" 106 verifyBreakText(text, textChars, textSpan, 0, 3, false, totalWidth, 107 3, widths[0] + widths[1] + widths[2]); 108 109 // Measure substring from back: "MN" 110 verifyBreakText(text, textChars, textSpan, 5, 7, true, totalWidth, 111 2, widths[5] + widths[6]); 112 113 // Reverse measure substring from back: "MN" 114 verifyBreakText(text, textChars, textSpan, 5, 7, false, totalWidth, 115 2, widths[5] + widths[6]); 116 117 // Measure substring in the middle: "JKL" 118 verifyBreakText(text, textChars, textSpan, 2, 5, true, totalWidth, 119 3, widths[2] + widths[3] + widths[4]); 120 121 // Reverse measure substring in the middle: "JKL" 122 verifyBreakText(text, textChars, textSpan, 2, 5, false, totalWidth, 123 3, widths[2] + widths[3] + widths[4]); 124 125 // Measure substring in the middle and restrict width to the first 2 characters. 126 verifyBreakText(text, textChars, textSpan, 2, 5, true, widths[2] + widths[3], 127 2, widths[2] + widths[3]); 128 129 // Reverse measure substring in the middle and restrict width to the last 2 characters. 130 verifyBreakText(text, textChars, textSpan, 2, 5, false, widths[3] + widths[4], 131 2, widths[3] + widths[4]); 132 133 // a single Emoji (U+1f601) 134 String emoji = "\ud83d\ude01"; 135 char[] emojiChars = emoji.toCharArray(); 136 SpannedString emojiSpan = new SpannedString(emoji); 137 138 float[] emojiWidths = new float[emoji.length()]; 139 assertEquals(emoji.length(), p.getTextWidths(emoji, emojiWidths)); 140 141 // Measure substring with a cluster 142 verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, 0, 143 0, 0); 144 145 // Measure substring with a cluster 146 verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, emojiWidths[0], 147 2, emojiWidths[0]); 148 149 // Reverse measure substring with a cluster 150 verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, 0, 151 0, 0); 152 153 // Measure substring with a cluster 154 verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, emojiWidths[0], 155 2, emojiWidths[0]); 156 } 157 verifyBreakText(String text, char[] textChars, SpannedString textSpan, int start, int end, boolean measureForwards, float maxWidth, int expectedCount, float expectedWidth)158 private void verifyBreakText(String text, char[] textChars, SpannedString textSpan, 159 int start, int end, boolean measureForwards, float maxWidth, int expectedCount, 160 float expectedWidth) { 161 Paint p = new Paint(); 162 163 // We need to turn off kerning in order to get accurate comparisons 164 p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG); 165 166 int count = end - start; 167 if (!measureForwards) { 168 count = -count; 169 } 170 171 float[][] measured = new float[][] { 172 new float[1], 173 new float[1], 174 new float[1] 175 }; 176 String textSlice = text.substring(start, end); 177 assertEquals(expectedCount, p.breakText(textSlice, measureForwards, maxWidth, measured[0])); 178 assertEquals(expectedCount, p.breakText(textChars, start, count, maxWidth, measured[1])); 179 assertEquals(expectedCount, p.breakText(textSpan, start, end, measureForwards, maxWidth, 180 measured[2])); 181 182 for (int i = 0; i < measured.length; i++) { 183 assertEquals("i: " + i, expectedWidth, measured[i][0], 0.0f); 184 } 185 } 186 187 @Test testSet()188 public void testSet() { 189 Paint p = new Paint(); 190 Paint p2 = new Paint(); 191 ColorFilter c = new ColorFilter(); 192 MaskFilter m = new MaskFilter(); 193 PathEffect e = new PathEffect(); 194 Shader s = new Shader(); 195 Typeface t = Typeface.DEFAULT; 196 Xfermode x = new Xfermode(); 197 198 p.setColorFilter(c); 199 p.setMaskFilter(m); 200 p.setPathEffect(e); 201 p.setShader(s); 202 p.setTypeface(t); 203 p.setXfermode(x); 204 p2.set(p); 205 assertEquals(c, p2.getColorFilter()); 206 assertEquals(m, p2.getMaskFilter()); 207 assertEquals(e, p2.getPathEffect()); 208 assertEquals(s, p2.getShader()); 209 assertEquals(t, p2.getTypeface()); 210 assertEquals(x, p2.getXfermode()); 211 212 p2.set(p2); 213 assertEquals(c, p2.getColorFilter()); 214 assertEquals(m, p2.getMaskFilter()); 215 assertEquals(e, p2.getPathEffect()); 216 assertEquals(s, p2.getShader()); 217 assertEquals(t, p2.getTypeface()); 218 assertEquals(x, p2.getXfermode()); 219 220 p.setColorFilter(null); 221 p.setMaskFilter(null); 222 p.setPathEffect(null); 223 p.setShader(null); 224 p.setTypeface(null); 225 p.setXfermode(null); 226 p2.set(p); 227 assertNull(p2.getColorFilter()); 228 assertNull(p2.getMaskFilter()); 229 assertNull(p2.getPathEffect()); 230 assertNull(p2.getShader()); 231 assertNull(p2.getTypeface()); 232 assertNull(p2.getXfermode()); 233 234 p2.set(p2); 235 assertNull(p2.getColorFilter()); 236 assertNull(p2.getMaskFilter()); 237 assertNull(p2.getPathEffect()); 238 assertNull(p2.getShader()); 239 assertNull(p2.getTypeface()); 240 assertNull(p2.getXfermode()); 241 } 242 243 @Test testAccessStrokeCap()244 public void testAccessStrokeCap() { 245 Paint p = new Paint(); 246 247 p.setStrokeCap(Cap.BUTT); 248 assertEquals(Cap.BUTT, p.getStrokeCap()); 249 250 p.setStrokeCap(Cap.ROUND); 251 assertEquals(Cap.ROUND, p.getStrokeCap()); 252 253 p.setStrokeCap(Cap.SQUARE); 254 assertEquals(Cap.SQUARE, p.getStrokeCap()); 255 } 256 257 @Test(expected=RuntimeException.class) testSetStrokeCapNull()258 public void testSetStrokeCapNull() { 259 Paint p = new Paint(); 260 261 p.setStrokeCap(null); 262 } 263 264 @Test testAccessXfermode()265 public void testAccessXfermode() { 266 Paint p = new Paint(); 267 Xfermode x = new Xfermode(); 268 269 assertEquals(x, p.setXfermode(x)); 270 assertEquals(x, p.getXfermode()); 271 272 assertNull(p.setXfermode(null)); 273 assertNull(p.getXfermode()); 274 } 275 276 @Test testAccessShader()277 public void testAccessShader() { 278 Paint p = new Paint(); 279 Shader s = new Shader(); 280 281 assertEquals(s, p.setShader(s)); 282 assertEquals(s, p.getShader()); 283 284 assertNull(p.setShader(null)); 285 assertNull(p.getShader()); 286 } 287 288 @Test testShaderLocalMatrix()289 public void testShaderLocalMatrix() { 290 int width = 80; 291 int height = 120; 292 int[] color = new int[width * height]; 293 Bitmap bitmap = Bitmap.createBitmap(color, width, height, Bitmap.Config.RGB_565); 294 295 Paint p = new Paint(); 296 Matrix m = new Matrix(); 297 Shader s = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); 298 299 // set the shaders matrix to a non identity value and attach to paint 300 m.setScale(10, 0); 301 s.setLocalMatrix(m); 302 p.setShader(s); 303 304 Matrix m2 = new Matrix(); 305 assertTrue(p.getShader().getLocalMatrix(m2)); 306 assertEquals(m, m2); 307 308 // updated the matrix again and set it on the shader but NOT the paint 309 m.setScale(0, 10); 310 s.setLocalMatrix(m); 311 312 // assert that the matrix on the paint's shader also changed 313 Matrix m3 = new Matrix(); 314 assertTrue(p.getShader().getLocalMatrix(m3)); 315 assertEquals(m, m3); 316 } 317 318 @Test testSetAntiAlias()319 public void testSetAntiAlias() { 320 Paint p = new Paint(); 321 322 p.setAntiAlias(true); 323 assertTrue(p.isAntiAlias()); 324 325 p.setAntiAlias(false); 326 assertFalse(p.isAntiAlias()); 327 } 328 329 @Test testAccessTypeface()330 public void testAccessTypeface() { 331 Paint p = new Paint(); 332 333 assertEquals(Typeface.DEFAULT, p.setTypeface(Typeface.DEFAULT)); 334 assertEquals(Typeface.DEFAULT, p.getTypeface()); 335 336 assertEquals(Typeface.DEFAULT_BOLD, p.setTypeface(Typeface.DEFAULT_BOLD)); 337 assertEquals(Typeface.DEFAULT_BOLD, p.getTypeface()); 338 339 assertEquals(Typeface.MONOSPACE, p.setTypeface(Typeface.MONOSPACE)); 340 assertEquals(Typeface.MONOSPACE, p.getTypeface()); 341 342 assertNull(p.setTypeface(null)); 343 assertNull(p.getTypeface()); 344 } 345 346 @Test testAccessPathEffect()347 public void testAccessPathEffect() { 348 Paint p = new Paint(); 349 PathEffect e = new PathEffect(); 350 351 assertEquals(e, p.setPathEffect(e)); 352 assertEquals(e, p.getPathEffect()); 353 354 assertNull(p.setPathEffect(null)); 355 assertNull(p.getPathEffect()); 356 } 357 358 @Test testSetFakeBoldText()359 public void testSetFakeBoldText() { 360 Paint p = new Paint(); 361 362 p.setFakeBoldText(true); 363 assertTrue(p.isFakeBoldText()); 364 365 p.setFakeBoldText(false); 366 assertFalse(p.isFakeBoldText()); 367 } 368 369 @Test testAccessStrokeJoin()370 public void testAccessStrokeJoin() { 371 Paint p = new Paint(); 372 373 p.setStrokeJoin(Join.BEVEL); 374 assertEquals(Join.BEVEL, p.getStrokeJoin()); 375 376 p.setStrokeJoin(Join.MITER); 377 assertEquals(Join.MITER, p.getStrokeJoin()); 378 379 p.setStrokeJoin(Join.ROUND); 380 assertEquals(Join.ROUND, p.getStrokeJoin()); 381 } 382 383 @Test(expected=RuntimeException.class) testSetStrokeJoinNull()384 public void testSetStrokeJoinNull() { 385 Paint p = new Paint(); 386 387 p.setStrokeJoin(null); 388 } 389 390 @Test testAccessStyle()391 public void testAccessStyle() { 392 Paint p = new Paint(); 393 394 p.setStyle(Style.FILL); 395 assertEquals(Style.FILL, p.getStyle()); 396 397 p.setStyle(Style.FILL_AND_STROKE); 398 assertEquals(Style.FILL_AND_STROKE, p.getStyle()); 399 400 p.setStyle(Style.STROKE); 401 assertEquals(Style.STROKE, p.getStyle()); 402 } 403 404 @Test(expected=RuntimeException.class) testSetStyleNull()405 public void testSetStyleNull() { 406 Paint p = new Paint(); 407 408 p.setStyle(null); 409 } 410 411 @Test testGetFontSpacing()412 public void testGetFontSpacing() { 413 Paint p = new Paint(); 414 415 for (Typeface typeface : TYPEFACES) { 416 p.setTypeface(typeface); 417 418 p.setTextSize(10); 419 float spacing10 = p.getFontSpacing(); 420 assertTrue(spacing10 > 0); 421 422 p.setTextSize(20); 423 float spacing20 = p.getFontSpacing(); 424 assertTrue(spacing20 > spacing10); 425 } 426 } 427 428 @Test testSetSubpixelText()429 public void testSetSubpixelText() { 430 Paint p = new Paint(); 431 432 p.setSubpixelText(true); 433 assertTrue(p.isSubpixelText()); 434 435 p.setSubpixelText(false); 436 assertFalse(p.isSubpixelText()); 437 } 438 439 @Test testAccessTextScaleX()440 public void testAccessTextScaleX() { 441 Paint p = new Paint(); 442 443 p.setTextScaleX(2.0f); 444 assertEquals(2.0f, p.getTextScaleX(), 0.0f); 445 446 p.setTextScaleX(1.0f); 447 assertEquals(1.0f, p.getTextScaleX(), 0.0f); 448 449 p.setTextScaleX(0.0f); 450 assertEquals(0.0f, p.getTextScaleX(), 0.0f); 451 452 } 453 454 @Test testAccessMaskFilter()455 public void testAccessMaskFilter() { 456 Paint p = new Paint(); 457 MaskFilter m = new MaskFilter(); 458 459 assertEquals(m, p.setMaskFilter(m)); 460 assertEquals(m, p.getMaskFilter()); 461 462 assertNull(p.setMaskFilter(null)); 463 assertNull(p.getMaskFilter()); 464 } 465 466 @Test testAccessColorFilter()467 public void testAccessColorFilter() { 468 Paint p = new Paint(); 469 ColorFilter c = new ColorFilter(); 470 471 assertEquals(c, p.setColorFilter(c)); 472 assertEquals(c, p.getColorFilter()); 473 474 assertNull(p.setColorFilter(null)); 475 assertNull(p.getColorFilter()); 476 } 477 478 @Test testSetARGB()479 public void testSetARGB() { 480 Paint p = new Paint(); 481 482 p.setARGB(0, 0, 0, 0); 483 assertEquals(0, p.getColor()); 484 485 p.setARGB(3, 3, 3, 3); 486 assertEquals((3 << 24) | (3 << 16) | (3 << 8) | 3, p.getColor()); 487 } 488 489 @Test testAscent()490 public void testAscent() { 491 Paint p = new Paint(); 492 493 for (Typeface typeface : TYPEFACES) { 494 p.setTypeface(typeface); 495 496 p.setTextSize(10); 497 float ascent10 = p.ascent(); 498 assertTrue(ascent10 < 0); 499 500 p.setTextSize(20); 501 float ascent20 = p.ascent(); 502 assertTrue(ascent20 < ascent10); 503 } 504 } 505 506 @Test 507 public void testAccessTextSkewX() { 508 Paint p = new Paint(); 509 510 p.setTextSkewX(1.0f); 511 assertEquals(1.0f, p.getTextSkewX(), 0.0f); 512 513 p.setTextSkewX(0.0f); 514 assertEquals(0.0f, p.getTextSkewX(), 0.0f); 515 516 p.setTextSkewX(-0.25f); 517 assertEquals(-0.25f, p.getTextSkewX(), 0.0f); 518 } 519 520 @Test 521 public void testAccessTextSize() { 522 Paint p = new Paint(); 523 524 p.setTextSize(1.0f); 525 assertEquals(1.0f, p.getTextSize(), 0.0f); 526 527 p.setTextSize(2.0f); 528 assertEquals(2.0f, p.getTextSize(), 0.0f); 529 530 // text size should be greater than 0, so set -1 has no effect 531 p.setTextSize(-1.0f); 532 assertEquals(2.0f, p.getTextSize(), 0.0f); 533 534 // text size should be greater than or equals to 0 535 p.setTextSize(0.0f); 536 assertEquals(0.0f, p.getTextSize(), 0.0f); 537 } 538 539 @Test 540 public void testGetTextWidths() throws Exception { 541 String text = "HIJKLMN"; 542 char[] textChars = text.toCharArray(); 543 SpannedString textSpan = new SpannedString(text); 544 545 // Test measuring the widths of the entire text 546 verifyGetTextWidths(text, textChars, textSpan, 0, 7); 547 548 // Test measuring a substring of the text 549 verifyGetTextWidths(text, textChars, textSpan, 1, 3); 550 551 // Test measuring a substring of zero length. 552 verifyGetTextWidths(text, textChars, textSpan, 3, 3); 553 554 // Test measuring substrings from the front and back 555 verifyGetTextWidths(text, textChars, textSpan, 0, 2); 556 verifyGetTextWidths(text, textChars, textSpan, 4, 7); 557 } 558 559 /** Tests all four overloads of getTextWidths are the same. */ 560 private void verifyGetTextWidths(String text, char[] textChars, SpannedString textSpan, 561 int start, int end) { 562 Paint p = new Paint(); 563 int count = end - start; 564 float[][] widths = new float[][] { 565 new float[count], 566 new float[count], 567 new float[count], 568 new float[count] 569 }; 570 571 String textSlice = text.substring(start, end); 572 assertEquals(count, p.getTextWidths(textSlice, widths[0])); 573 assertEquals(count, p.getTextWidths(textChars, start, count, widths[1])); 574 assertEquals(count, p.getTextWidths(textSpan, start, end, widths[2])); 575 assertEquals(count, p.getTextWidths(text, start, end, widths[3])); 576 577 // Check that the widths returned by the overloads are the same. 578 for (int i = 0; i < count; i++) { 579 assertEquals(widths[0][i], widths[1][i], 0.0f); 580 assertEquals(widths[1][i], widths[2][i], 0.0f); 581 assertEquals(widths[2][i], widths[3][i], 0.0f); 582 } 583 } 584 585 @Test 586 public void testSetStrikeThruText() { 587 Paint p = new Paint(); 588 589 p.setStrikeThruText(true); 590 assertTrue(p.isStrikeThruText()); 591 592 p.setStrikeThruText(false); 593 assertFalse(p.isStrikeThruText()); 594 } 595 596 @Test 597 public void testAccessTextAlign() { 598 Paint p = new Paint(); 599 600 p.setTextAlign(Align.CENTER); 601 assertEquals(Align.CENTER, p.getTextAlign()); 602 603 p.setTextAlign(Align.LEFT); 604 assertEquals(Align.LEFT, p.getTextAlign()); 605 606 p.setTextAlign(Align.RIGHT); 607 assertEquals(Align.RIGHT, p.getTextAlign()); 608 } 609 610 @Test 611 public void testAccessTextLocale() { 612 Paint p = new Paint(); 613 614 final Locale defaultLocale = Locale.getDefault(); 615 616 // Check default 617 assertEquals(defaultLocale, p.getTextLocale()); 618 619 // Check setter / getters 620 p.setTextLocale(Locale.US); 621 assertEquals(Locale.US, p.getTextLocale()); 622 assertEquals(new LocaleList(Locale.US), p.getTextLocales()); 623 624 p.setTextLocale(Locale.CHINESE); 625 assertEquals(Locale.CHINESE, p.getTextLocale()); 626 assertEquals(new LocaleList(Locale.CHINESE), p.getTextLocales()); 627 628 p.setTextLocale(Locale.JAPANESE); 629 assertEquals(Locale.JAPANESE, p.getTextLocale()); 630 assertEquals(new LocaleList(Locale.JAPANESE), p.getTextLocales()); 631 632 p.setTextLocale(Locale.KOREAN); 633 assertEquals(Locale.KOREAN, p.getTextLocale()); 634 assertEquals(new LocaleList(Locale.KOREAN), p.getTextLocales()); 635 636 // Check reverting back to default 637 p.setTextLocale(defaultLocale); 638 assertEquals(defaultLocale, p.getTextLocale()); 639 assertEquals(new LocaleList(defaultLocale), p.getTextLocales()); 640 } 641 642 @Test(expected=IllegalArgumentException.class) 643 public void testSetTextLocaleNull() { 644 Paint p = new Paint(); 645 646 p.setTextLocale(null); 647 } 648 649 @Test 650 public void testAccessTextLocales() { 651 Paint p = new Paint(); 652 653 final LocaleList defaultLocales = LocaleList.getDefault(); 654 655 // Check default 656 assertEquals(defaultLocales, p.getTextLocales()); 657 658 // Check setter / getters for a one-member locale list 659 p.setTextLocales(new LocaleList(Locale.CHINESE)); 660 assertEquals(Locale.CHINESE, p.getTextLocale()); 661 assertEquals(new LocaleList(Locale.CHINESE), p.getTextLocales()); 662 663 // Check setter / getters for a two-member locale list 664 p.setTextLocales(LocaleList.forLanguageTags("fr,de")); 665 assertEquals(Locale.forLanguageTag("fr"), p.getTextLocale()); 666 assertEquals(LocaleList.forLanguageTags("fr,de"), p.getTextLocales()); 667 668 // Check reverting back to default 669 p.setTextLocales(defaultLocales); 670 assertEquals(defaultLocales, p.getTextLocales()); 671 } 672 673 @Test(expected=IllegalArgumentException.class) 674 public void testAccessTextLocalesNull() { 675 Paint p = new Paint(); 676 677 // Check that we cannot pass a null locale list 678 p.setTextLocales(null); 679 } 680 681 @Test(expected=IllegalArgumentException.class) 682 public void testAccessTextLocalesEmpty() { 683 Paint p = new Paint(); 684 685 // Check that we cannot pass an empty locale list 686 p.setTextLocales(new LocaleList()); 687 } 688 689 @Test 690 public void testGetFillPath() { 691 Paint p = new Paint(); 692 Path path1 = new Path(); 693 Path path2 = new Path(); 694 695 assertTrue(path1.isEmpty()); 696 assertTrue(path2.isEmpty()); 697 p.getFillPath(path1, path2); 698 assertTrue(path1.isEmpty()); 699 assertTrue(path2.isEmpty()); 700 701 // No setter 702 } 703 704 @Test 705 public void testAccessAlpha() { 706 Paint p = new Paint(); 707 708 p.setAlpha(0); 709 assertEquals(0, p.getAlpha()); 710 711 p.setAlpha(255); 712 assertEquals(255, p.getAlpha()); 713 714 // set value should between 0 and 255, so 266 is rounded to 10 715 p.setAlpha(266); 716 assertEquals(10, p.getAlpha()); 717 718 // set value should between 0 and 255, so -20 is rounded to 236 719 p.setAlpha(-20); 720 assertEquals(236, p.getAlpha()); 721 } 722 723 @Test 724 public void testSetFilterBitmap() { 725 Paint p = new Paint(); 726 727 p.setFilterBitmap(true); 728 assertTrue(p.isFilterBitmap()); 729 730 p.setFilterBitmap(false); 731 assertFalse(p.isFilterBitmap()); 732 } 733 734 @Test 735 public void testAccessColor() { 736 Paint p = new Paint(); 737 738 p.setColor(1); 739 assertEquals(1, p.getColor()); 740 741 p.setColor(0); 742 assertEquals(0, p.getColor()); 743 744 p.setColor(255); 745 assertEquals(255, p.getColor()); 746 747 p.setColor(-1); 748 assertEquals(-1, p.getColor()); 749 750 p.setColor(256); 751 assertEquals(256, p.getColor()); 752 } 753 754 @Test 755 public void testSetShadowLayer() { 756 new Paint().setShadowLayer(10, 1, 1, 0); 757 } 758 759 @Test 760 public void testGetFontMetrics1() { 761 Paint p = new Paint(); 762 Paint.FontMetrics fm = new Paint.FontMetrics(); 763 764 for (Typeface typeface : TYPEFACES) { 765 p.setTypeface(typeface); 766 767 p.setTextSize(10); 768 p.getFontMetrics(fm); 769 assertEquals(p.ascent(), fm.ascent, 0.0f); 770 assertEquals(p.descent(), fm.descent, 0.0f); 771 772 p.setTextSize(20); 773 p.getFontMetrics(fm); 774 assertEquals(p.ascent(), fm.ascent, 0.0f); 775 assertEquals(p.descent(), fm.descent, 0.0f); 776 } 777 } 778 779 @Test 780 public void testGetFontMetrics2() { 781 Paint p = new Paint(); 782 783 for (Typeface typeface : TYPEFACES) { 784 p.setTypeface(typeface); 785 786 p.setTextSize(10); 787 Paint.FontMetrics fm = p.getFontMetrics(); 788 assertEquals(p.ascent(), fm.ascent, 0.0f); 789 assertEquals(p.descent(), fm.descent, 0.0f); 790 791 p.setTextSize(20); 792 fm = p.getFontMetrics(); 793 assertEquals(p.ascent(), fm.ascent, 0.0f); 794 assertEquals(p.descent(), fm.descent, 0.0f); 795 } 796 } 797 798 @Test 799 public void testAccessStrokeMiter() { 800 Paint p = new Paint(); 801 802 p.setStrokeMiter(0.0f); 803 assertEquals(0.0f, p.getStrokeMiter(), 0.0f); 804 805 p.setStrokeMiter(10.0f); 806 assertEquals(10.0f, p.getStrokeMiter(), 0.0f); 807 808 // set value should be greater or equal to 0, set to -10.0f has no effect 809 p.setStrokeMiter(-10.0f); 810 assertEquals(10.0f, p.getStrokeMiter(), 0.0f); 811 } 812 813 @Test 814 public void testClearShadowLayer() { 815 new Paint().clearShadowLayer(); 816 } 817 818 @Test 819 public void testSetUnderlineText() { 820 Paint p = new Paint(); 821 822 p.setUnderlineText(true); 823 assertTrue(p.isUnderlineText()); 824 825 p.setUnderlineText(false); 826 assertFalse(p.isUnderlineText()); 827 } 828 829 @Test 830 public void testSetDither() { 831 Paint p = new Paint(); 832 833 p.setDither(true); 834 assertTrue(p.isDither()); 835 836 p.setDither(false); 837 assertFalse(p.isDither()); 838 } 839 840 @Test 841 public void testDescent() { 842 Paint p = new Paint(); 843 844 for (Typeface typeface : TYPEFACES) { 845 p.setTypeface(typeface); 846 847 p.setTextSize(10); 848 float descent10 = p.descent(); 849 assertTrue(descent10 > 0); 850 851 p.setTextSize(20); 852 float descent20 = p.descent(); 853 assertTrue(descent20 > descent10); 854 } 855 } 856 857 @Test 858 public void testAccessFlags() { 859 Paint p = new Paint(); 860 861 p.setFlags(Paint.ANTI_ALIAS_FLAG); 862 assertEquals(Paint.ANTI_ALIAS_FLAG, p.getFlags()); 863 864 p.setFlags(Paint.DEV_KERN_TEXT_FLAG); 865 assertEquals(Paint.DEV_KERN_TEXT_FLAG, p.getFlags()); 866 } 867 868 @Test 869 public void testAccessStrokeWidth() { 870 Paint p = new Paint(); 871 872 p.setStrokeWidth(0.0f); 873 assertEquals(0.0f, p.getStrokeWidth(), 0.0f); 874 875 p.setStrokeWidth(10.0f); 876 assertEquals(10.0f, p.getStrokeWidth(), 0.0f); 877 878 // set value must greater or equal to 0, set -10.0f has no effect 879 p.setStrokeWidth(-10.0f); 880 assertEquals(10.0f, p.getStrokeWidth(), 0.0f); 881 } 882 883 @Test 884 public void testSetFontFeatureSettings() { 885 Paint p = new Paint(); 886 // Roboto font (system default) has "fi" ligature 887 String text = "fi"; 888 float[] widths = new float[text.length()]; 889 p.getTextWidths(text, widths); 890 assertTrue(widths[0] > 0.0f); 891 assertEquals(0.0f, widths[1], 0.0f); 892 893 // Disable ligature using OpenType feature 894 p.setFontFeatureSettings("'liga' off"); 895 p.getTextWidths(text, widths); 896 assertTrue(widths[0] > 0.0f); 897 assertTrue(widths[1] > 0.0f); 898 899 // Re-enable ligature 900 p.setFontFeatureSettings("'liga' on"); 901 p.getTextWidths(text, widths); 902 assertTrue(widths[0] > 0.0f); 903 assertEquals(0.0f, widths[1], 0.0f); 904 } 905 906 @Test testSetFontVariationSettings_defaultTypeface()907 public void testSetFontVariationSettings_defaultTypeface() { 908 new Paint().setFontVariationSettings("'wght' 400"); 909 } 910 911 @Test testSetGetFontVariationSettings()912 public void testSetGetFontVariationSettings() { 913 final Paint defaultPaint = new Paint(); 914 915 Paint p = new Paint(); 916 Context context = InstrumentationRegistry.getTargetContext(); 917 Typeface typeface = Typeface.createFromAsset(context.getAssets(), "multiaxis.ttf"); 918 p.setTypeface(typeface); 919 920 // multiaxis.ttf supports "wght", "PRIV", "PR12" axes. 921 922 // The default variation settings should be null. 923 assertNull(p.getFontVariationSettings()); 924 925 final String[] nonEffectiveSettings = { 926 "'slnt' 30", // unsupported tag 927 "'BBBB' 1.0", // unsupported tag 928 "'A ' 1.0", // unsupported tag 929 "'PR0 ' 1.3", // unsupported tag 930 "'WGHT' 0.7", // unsupported tag (case sensitive) 931 "'BBBB' 1.0, 'CCCC' 2.0", // none of them are supported. 932 }; 933 934 for (String notEffectiveSetting : nonEffectiveSettings) { 935 if (!defaultPaint.setFontVariationSettings(notEffectiveSetting)) { 936 // Test only when the system font don't support the above axes. OEMs may add 937 // their fonts and these font may support above axes. 938 assertFalse("Must return false for " + notEffectiveSetting, 939 p.setFontVariationSettings(notEffectiveSetting)); 940 assertNull("Must not change settings for " + notEffectiveSetting, 941 p.getFontVariationSettings()); 942 } 943 } 944 945 String retainSettings = "'wght' 400"; 946 assertTrue(p.setFontVariationSettings(retainSettings)); 947 for (String notEffectiveSetting : nonEffectiveSettings) { 948 assertFalse(p.setFontVariationSettings(notEffectiveSetting)); 949 assertEquals("Must not change settings for " + notEffectiveSetting, 950 retainSettings, p.getFontVariationSettings()); 951 } 952 953 // At least one axis is supported, the settings should be applied. 954 final String[] effectiveSettings = { 955 "'wght' 300", // supported tag 956 "'wght' 300, 'PRIV' 0.5", // both are supported 957 "'PRIV' 1.0, 'BBBB' 0.4", // 'BBBB' is unsupported 958 }; 959 960 for (String effectiveSetting : effectiveSettings) { 961 assertTrue("Must return true for " + effectiveSetting, 962 p.setFontVariationSettings(effectiveSetting)); 963 assertEquals(effectiveSetting, p.getFontVariationSettings()); 964 } 965 966 p.setFontVariationSettings(""); 967 assertNull(p.getFontVariationSettings()); 968 } 969 970 @Test testGetTextBounds()971 public void testGetTextBounds() { 972 Paint p = new Paint(); 973 p.setTextSize(10); 974 String text1 = "hello"; 975 Rect bounds1 = new Rect(); 976 Rect bounds2 = new Rect(); 977 p.getTextBounds(text1, 0, text1.length(), bounds1); 978 char[] textChars1 = text1.toCharArray(); 979 p.getTextBounds(textChars1, 0, textChars1.length, bounds2); 980 // verify that string and char array methods produce consistent results 981 assertEquals(bounds1, bounds2); 982 String text2 = "hello world"; 983 984 // verify substring produces consistent results 985 p.getTextBounds(text2, 0, text1.length(), bounds2); 986 assertEquals(bounds1, bounds2); 987 988 // longer string is expected to have same left edge but be wider 989 p.getTextBounds(text2, 0, text2.length(), bounds2); 990 assertEquals(bounds1.left, bounds2.left); 991 assertTrue(bounds2.right > bounds1.right); 992 993 // bigger size implies bigger bounding rect 994 p.setTextSize(20); 995 p.getTextBounds(text1, 0, text1.length(), bounds2); 996 assertTrue(bounds2.right > bounds1.right); 997 assertTrue(bounds2.bottom - bounds2.top > bounds1.bottom - bounds1.top); 998 } 999 1000 @Test testReset()1001 public void testReset() { 1002 Paint p = new Paint(); 1003 ColorFilter c = new ColorFilter(); 1004 MaskFilter m = new MaskFilter(); 1005 PathEffect e = new PathEffect(); 1006 Shader s = new Shader(); 1007 Typeface t = Typeface.DEFAULT; 1008 Xfermode x = new Xfermode(); 1009 1010 p.setColorFilter(c); 1011 p.setMaskFilter(m); 1012 p.setPathEffect(e); 1013 p.setShader(s); 1014 p.setTypeface(t); 1015 p.setXfermode(x); 1016 p.setFlags(Paint.ANTI_ALIAS_FLAG); 1017 assertEquals(c, p.getColorFilter()); 1018 assertEquals(m, p.getMaskFilter()); 1019 assertEquals(e, p.getPathEffect()); 1020 assertEquals(s, p.getShader()); 1021 assertEquals(t, p.getTypeface()); 1022 assertEquals(x, p.getXfermode()); 1023 assertEquals(Paint.ANTI_ALIAS_FLAG, p.getFlags()); 1024 1025 p.reset(); 1026 assertEquals(Paint.DEV_KERN_TEXT_FLAG | Paint.EMBEDDED_BITMAP_TEXT_FLAG, p.getFlags()); 1027 assertEquals(null, p.getColorFilter()); 1028 assertEquals(null, p.getMaskFilter()); 1029 assertEquals(null, p.getPathEffect()); 1030 assertEquals(null, p.getShader()); 1031 assertEquals(null, p.getTypeface()); 1032 assertEquals(null, p.getXfermode()); 1033 } 1034 1035 @Test testSetLinearText()1036 public void testSetLinearText() { 1037 Paint p = new Paint(); 1038 1039 p.setLinearText(true); 1040 assertTrue(p.isLinearText()); 1041 1042 p.setLinearText(false); 1043 assertFalse(p.isLinearText()); 1044 } 1045 1046 @Test testGetFontMetricsInt1()1047 public void testGetFontMetricsInt1() { 1048 Paint p = new Paint(); 1049 Paint.FontMetricsInt fmi = new Paint.FontMetricsInt(); 1050 1051 for (Typeface typeface : TYPEFACES) { 1052 p.setTypeface(typeface); 1053 1054 p.setTextSize(10); 1055 p.getFontMetricsInt(fmi); 1056 assertEquals(Math.round(p.ascent()), fmi.ascent); 1057 assertEquals(Math.round(p.descent()), fmi.descent); 1058 1059 p.setTextSize(20); 1060 p.getFontMetricsInt(fmi); 1061 assertEquals(Math.round(p.ascent()), fmi.ascent); 1062 assertEquals(Math.round(p.descent()), fmi.descent); 1063 } 1064 } 1065 1066 @Test testGetFontMetricsInt2()1067 public void testGetFontMetricsInt2() { 1068 Paint p = new Paint(); 1069 Paint.FontMetricsInt fmi; 1070 1071 for (Typeface typeface : TYPEFACES) { 1072 p.setTypeface(typeface); 1073 1074 p.setTextSize(10); 1075 fmi = p.getFontMetricsInt(); 1076 assertEquals(Math.round(p.ascent()), fmi.ascent); 1077 assertEquals(Math.round(p.descent()), fmi.descent); 1078 1079 p.setTextSize(20); 1080 fmi = p.getFontMetricsInt(); 1081 assertEquals(Math.round(p.ascent()), fmi.ascent); 1082 assertEquals(Math.round(p.descent()), fmi.descent); 1083 } 1084 } 1085 1086 @Test testMeasureText()1087 public void testMeasureText() { 1088 String text = "HIJKLMN"; 1089 char[] textChars = text.toCharArray(); 1090 SpannedString textSpan = new SpannedString(text); 1091 1092 Paint p = new Paint(); 1093 1094 // We need to turn off kerning in order to get accurate comparisons 1095 p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG); 1096 1097 float[] widths = new float[text.length()]; 1098 for (int i = 0; i < widths.length; i++) { 1099 widths[i] = p.measureText(text, i, i + 1); 1100 } 1101 1102 float totalWidth = 0; 1103 for (int i = 0; i < widths.length; i++) { 1104 totalWidth += widths[i]; 1105 } 1106 1107 // Test measuring the widths of the entire text 1108 verifyMeasureText(text, textChars, textSpan, 0, 7, totalWidth); 1109 1110 // Test measuring a substring of the text 1111 verifyMeasureText(text, textChars, textSpan, 1, 3, widths[1] + widths[2]); 1112 1113 // Test measuring a substring of zero length. 1114 verifyMeasureText(text, textChars, textSpan, 3, 3, 0); 1115 1116 // Test measuring substrings from the front and back 1117 verifyMeasureText(text, textChars, textSpan, 0, 2, widths[0] + widths[1]); 1118 verifyMeasureText(text, textChars, textSpan, 4, 7, widths[4] + widths[5] + widths[6]); 1119 } 1120 1121 @Test testMeasureTextContext()1122 public void testMeasureTextContext() { 1123 Paint p = new Paint(); 1124 // Arabic LAM, which is different width depending on context 1125 String shortString = "\u0644"; 1126 String longString = "\u0644\u0644\u0644"; 1127 char[] longChars = longString.toCharArray(); 1128 SpannedString longSpanned = new SpannedString(longString); 1129 float width = p.measureText(shortString); 1130 // Verify that measurement of substring is consistent no matter what surrounds it. 1131 verifyMeasureText(longString, longChars, longSpanned, 0, 1, width); 1132 verifyMeasureText(longString, longChars, longSpanned, 1, 2, width); 1133 verifyMeasureText(longString, longChars, longSpanned, 2, 3, width); 1134 } 1135 1136 @Test testMeasureTextWithLongText()1137 public void testMeasureTextWithLongText() { 1138 final int MAX_COUNT = 65535; 1139 char[] longText = new char[MAX_COUNT]; 1140 for (int n = 0; n < MAX_COUNT; n++) { 1141 longText[n] = 'm'; 1142 } 1143 1144 Paint p = new Paint(); 1145 float width = p.measureText(longText, 0, 1); 1146 assertEquals(true, width > 0); 1147 } 1148 1149 /** Tests that all four overloads of measureText are the same and match some value. */ verifyMeasureText(String text, char[] textChars, SpannedString textSpan, int start, int end, float expectedWidth)1150 private void verifyMeasureText(String text, char[] textChars, SpannedString textSpan, 1151 int start, int end, float expectedWidth) { 1152 Paint p = new Paint(); 1153 1154 // We need to turn off kerning in order to get accurate comparisons 1155 p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG); 1156 1157 int count = end - start; 1158 float[] widths = new float[] {-1, -1, -1, -1}; 1159 1160 String textSlice = text.substring(start, end); 1161 widths[0] = p.measureText(textSlice); 1162 widths[1] = p.measureText(textChars, start, count); 1163 widths[2] = p.measureText(textSpan, start, end); 1164 widths[3] = p.measureText(text, start, end); 1165 1166 // Check that the widths returned by the overloads are the same. 1167 assertEquals(widths[0], widths[1], 0.0f); 1168 assertEquals(widths[1], widths[2], 0.0f); 1169 assertEquals(widths[2], widths[3], 0.0f); 1170 assertEquals(widths[3], expectedWidth, 0.0f); 1171 } 1172 1173 @Test testGetTextPathCharArray()1174 public void testGetTextPathCharArray() { 1175 Path path = new Path(); 1176 1177 assertTrue(path.isEmpty()); 1178 new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 0, 7, 0, 0, path); 1179 assertFalse(path.isEmpty()); 1180 } 1181 1182 @Test(expected=RuntimeException.class) testGetTextPathCharArrayNegativeIndex()1183 public void testGetTextPathCharArrayNegativeIndex() { 1184 new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, -2, 7, 0, 0, 1185 new Path()); 1186 } 1187 1188 @Test(expected=RuntimeException.class) testGetTextPathCharArrayNegativeCount()1189 public void testGetTextPathCharArrayNegativeCount() { 1190 new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 0, -3, 0, 0, 1191 new Path()); 1192 } 1193 1194 @Test(expected=RuntimeException.class) testGetTextPathCharArrayCountTooHigh()1195 public void testGetTextPathCharArrayCountTooHigh() { 1196 new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 3, 7, 0, 0, 1197 new Path()); 1198 } 1199 1200 @Test testGetTextPathString()1201 public void testGetTextPathString() { 1202 Path path = new Path(); 1203 1204 assertTrue(path.isEmpty()); 1205 new Paint().getTextPath("HIJKLMN", 0, 7, 0, 0, path); 1206 assertFalse(path.isEmpty()); 1207 } 1208 1209 @Test(expected=RuntimeException.class) testGetTextPathStringNegativeIndex()1210 public void testGetTextPathStringNegativeIndex() { 1211 new Paint().getTextPath("HIJKLMN", -2, 7, 0, 0, new Path()); 1212 } 1213 1214 @Test(expected=RuntimeException.class) testGetTextPathStringNegativeCount()1215 public void testGetTextPathStringNegativeCount() { 1216 new Paint().getTextPath("HIJKLMN", 0, -3, 0, 0, new Path()); 1217 } 1218 1219 @Test(expected=RuntimeException.class) testGetTextPathStringStartTooHigh()1220 public void testGetTextPathStringStartTooHigh() { 1221 new Paint().getTextPath("HIJKLMN", 7, 3, 0, 0, new Path()); 1222 } 1223 1224 @Test(expected=RuntimeException.class) testGetTextPathStringCountTooHigh()1225 public void testGetTextPathStringCountTooHigh() { 1226 new Paint().getTextPath("HIJKLMN", 3, 9, 0, 0, new Path()); 1227 } 1228 1229 @Test testHasGlyph()1230 public void testHasGlyph() { 1231 Paint p = new Paint(); 1232 1233 // This method tests both the logic of hasGlyph and the sanity of fonts present 1234 // on the device. 1235 assertTrue(p.hasGlyph("A")); 1236 assertFalse(p.hasGlyph("\uFFFE")); // U+FFFE is guaranteed to be a noncharacter 1237 1238 // Roboto 2 (the default typeface) does have an "fi" glyph and is mandated by CDD 1239 assertTrue(p.hasGlyph("fi")); 1240 assertFalse(p.hasGlyph("ab")); // but it does not contain an "ab" glyph 1241 assertTrue(p.hasGlyph("\u02E5\u02E9")); // IPA tone mark ligature 1242 1243 // variation selectors 1244 assertFalse(p.hasGlyph("a\uFE0F")); 1245 assertFalse(p.hasGlyph("a\uDB40\uDDEF")); // UTF-16 encoding of U+E01EF 1246 assertFalse(p.hasGlyph("\u2229\uFE0F")); // base character is in mathematical symbol font 1247 // Note: U+FE0F is variation selection, unofficially reserved for emoji 1248 1249 // regional indicator symbols 1250 assertTrue(p.hasGlyph("\uD83C\uDDEF\uD83C\uDDF5")); // "JP" U+1F1EF U+1F1F5 1251 assertFalse(p.hasGlyph("\uD83C\uDDFF\uD83C\uDDFF")); // "ZZ" U+1F1FF U+1F1FF 1252 1253 // Mongolian, which is an optional font, but if present, should support FVS 1254 if (p.hasGlyph("\u182D")) { 1255 assertTrue(p.hasGlyph("\u182D\u180B")); 1256 } 1257 1258 // Emoji with variation selector support for both text and emoji presentation 1259 assertTrue(p.hasGlyph("\u231A\uFE0E")); // WATCH + VS15 1260 assertTrue(p.hasGlyph("\u231A\uFE0F")); // WATCH + VS16 1261 1262 // Unicode 7.0, 8.0, and 9.0 emoji should be supported. 1263 assertTrue(p.hasGlyph("\uD83D\uDD75")); // SLEUTH OR SPY is introduced in Unicode 7.0 1264 assertTrue(p.hasGlyph("\uD83C\uDF2E")); // TACO is introduced in Unicode 8.0 1265 assertTrue(p.hasGlyph("\uD83E\uDD33")); // SELFIE is introduced in Unicode 9.0 1266 1267 // We don't require gender-neutral emoji, but if present, results must be consistent 1268 // whether VS is present or not. 1269 assertTrue(p.hasGlyph("\uD83D\uDC69\u200D\u2695") == // WOMAN, ZWJ, STAFF OF AESCULAPIUS 1270 p.hasGlyph("\uD83D\uDC69\u200D\u2695\uFE0F")); // above + VS16 1271 } 1272 1273 @Test testGetRunAdvance()1274 public void testGetRunAdvance() { 1275 Paint p = new Paint(); 1276 { 1277 // LTR 1278 String string = "abcdef"; 1279 { 1280 final float width = p.getRunAdvance(string, 0, string.length(), 0, 1281 string.length(), false, 0); 1282 assertEquals(0.0f, width, 0.0f); 1283 } 1284 { 1285 for (int i = 0; i < string.length(); i++) { 1286 final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(), 1287 false, i); 1288 assertEquals(0.0f, width, 0.0f); 1289 } 1290 } 1291 { 1292 final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0, 1293 string.length(), false, string.length() / 2); 1294 final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0, 1295 string.length(), false, string.length()); 1296 assertTrue(widthToMid > 0.0f); 1297 assertTrue(widthToTail > widthToMid); 1298 } 1299 { 1300 final float widthFromHead = p.getRunAdvance(string, 0, string.length(), 0, 1301 string.length(), false, string.length()); 1302 final float widthFromSecond = p.getRunAdvance(string, 1, string.length(), 0, 1303 string.length(), false, string.length()); 1304 assertTrue(widthFromHead > widthFromSecond); 1305 } 1306 { 1307 float width = 0.0f; 1308 for (int i = 0; i < string.length(); i++) { 1309 width += p.getRunAdvance(string, i, i + 1, 0, string.length(), false, i + 1); 1310 } 1311 final float totalWidth = p.getRunAdvance(string, 0, string.length(), 0, 1312 string.length(), false, string.length()); 1313 assertEquals(totalWidth, width, 1.0f); 1314 } 1315 } 1316 { 1317 // RTL 1318 String string = "\u0644\u063A\u0629 \u0639\u0631\u0628\u064A\u0629"; // Arabic 1319 { 1320 final float width = p.getRunAdvance(string, 0, string.length(), 0, 1321 string.length(), true, 0); 1322 assertEquals(0.0f, width, 0.0f); 1323 } 1324 { 1325 for (int i = 0; i < string.length(); i++) { 1326 final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(), 1327 true, i); 1328 assertEquals(0.0f, width, 0.0f); 1329 } 1330 } 1331 { 1332 final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0, 1333 string.length(), true, string.length() / 2); 1334 final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0, 1335 string.length(), true, string.length()); 1336 assertTrue(widthToMid > 0.0f); 1337 assertTrue(widthToTail > widthToMid); 1338 } 1339 { 1340 final float widthFromHead = p.getRunAdvance(string, 0, string.length(), 0, 1341 string.length(), true, string.length()); 1342 final float widthFromSecond = p.getRunAdvance(string, 1, string.length(), 0, 1343 string.length(), true, string.length()); 1344 assertTrue(widthFromHead > widthFromSecond); 1345 } 1346 } 1347 } 1348 1349 @Test(expected=IllegalArgumentException.class) testGetRunAdvanceNullCharSequence()1350 public void testGetRunAdvanceNullCharSequence() { 1351 new Paint().getRunAdvance((CharSequence) null, 0, 0, 0, 0, false, 0); 1352 } 1353 1354 @Test(expected=IllegalArgumentException.class) testGetRunAdvanceNullCharArray()1355 public void testGetRunAdvanceNullCharArray() { 1356 new Paint().getRunAdvance((char[]) null, 0, 0, 0, 0, false, 0); 1357 } 1358 1359 @Test(expected=IndexOutOfBoundsException.class) testGetRunAdvanceTextLengthLessThenContextEnd()1360 public void testGetRunAdvanceTextLengthLessThenContextEnd() { 1361 final String string = "abcde"; 1362 1363 // text length < context end 1364 new Paint().getRunAdvance(string, 0, string.length(), 0, string.length() + 1, false, 1365 string.length()); 1366 } 1367 1368 @Test(expected=IndexOutOfBoundsException.class) testGetRunAdvanceContextEndLessThanEnd()1369 public void testGetRunAdvanceContextEndLessThanEnd() { 1370 final String string = "abcde"; 1371 1372 // context end < end 1373 new Paint().getRunAdvance(string, 0, string.length(), 0, string.length() - 1, false, 0); 1374 } 1375 1376 @Test(expected=IndexOutOfBoundsException.class) testGetRunAdvanceEndLessThanOffset()1377 public void testGetRunAdvanceEndLessThanOffset() { 1378 final String string = "abcde"; 1379 1380 // end < offset 1381 new Paint().getRunAdvance(string, 0, string.length() - 1, 0, string.length() - 1, false, 1382 string.length()); 1383 } 1384 1385 @Test(expected=IndexOutOfBoundsException.class) testGetRunAdvanceOffsetLessThanStart()1386 public void testGetRunAdvanceOffsetLessThanStart() { 1387 final String string = "abcde"; 1388 1389 // offset < start 1390 new Paint().getRunAdvance(string, 1, string.length(), 1, string.length(), false, 0); 1391 } 1392 1393 @Test(expected=IndexOutOfBoundsException.class) testGetRunAdvanceStartLessThanContextStart()1394 public void testGetRunAdvanceStartLessThanContextStart() { 1395 final String string = "abcde"; 1396 1397 // start < context start 1398 new Paint().getRunAdvance(string, 0, string.length(), 1, string.length(), false, 1); 1399 } 1400 1401 @Test(expected=IndexOutOfBoundsException.class) testGetRunAdvanceContextStartNegative()1402 public void testGetRunAdvanceContextStartNegative() { 1403 final String string = "abcde"; 1404 1405 // context start < 0 1406 new Paint().getRunAdvance(string, 0, string.length(), -1, string.length(), false, 0); 1407 } 1408 1409 @Test testGetRunAdvance_nonzeroIndex()1410 public void testGetRunAdvance_nonzeroIndex() { 1411 Paint p = new Paint(); 1412 final String text = "Android powers hundreds of millions of mobile " + 1413 "devices in more than 190 countries around the world. It's" + 1414 "the largest installed base of any mobile platform and" + 1415 "growing fast—every day another million users power up their" + 1416 "Android devices for the first time and start looking for" + 1417 "apps, games, and other digital content."; 1418 // Test offset index does not affect width. 1419 final float widthAndroidFirst = p.getRunAdvance( 1420 text, 0, 7, 0, text.length(), false, 7); 1421 final float widthAndroidSecond = p.getRunAdvance( 1422 text, 215, 222, 0, text.length(), false, 222); 1423 assertTrue(Math.abs(widthAndroidFirst - widthAndroidSecond) < 1); 1424 } 1425 1426 @Test 1427 public void testGetRunAdvance_glyphDependingContext() { 1428 Paint p = new Paint(); 1429 // Test the context change the character shape. 1430 // First character should be isolated form because the context ends at index 1. 1431 final float isolatedFormWidth = p.getRunAdvance("\u0644\u0644", 0, 1, 0, 1, true, 1); 1432 // First character should be initial form because the context ends at index 2. 1433 final float initialFormWidth = p.getRunAdvance("\u0644\u0644", 0, 1, 0, 2, true, 1); 1434 assertTrue(isolatedFormWidth > initialFormWidth); 1435 } 1436 1437 @Test testGetRunAdvance_arabic()1438 public void testGetRunAdvance_arabic() { 1439 Paint p = new Paint(); 1440 // Test total width is equals to sum of each character's width. 1441 // "What is Unicode?" in Arabic. 1442 final String text = 1443 "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" + 1444 "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" + 1445 "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" + 1446 "\u062F\u061F"; 1447 final float totalWidth = p.getRunAdvance( 1448 text, 0, text.length(), 0, text.length(), true, text.length()); 1449 float sumOfCharactersWidth = 0; 1450 for (int i = 0; i < text.length(); i++) { 1451 sumOfCharactersWidth += p.getRunAdvance( 1452 text, i, i + 1, 0, text.length(), true, i + 1); 1453 } 1454 assertTrue(Math.abs(totalWidth - sumOfCharactersWidth) < 1); 1455 } 1456 1457 @Test 1458 public void testGetOffsetForAdvance() { 1459 Paint p = new Paint(); 1460 { 1461 // LTR 1462 String string = "abcdef"; 1463 { 1464 for (int offset = 0; offset <= string.length(); ++offset) { 1465 final float widthToOffset = p.getRunAdvance(string, 0, 1466 string.length(), 0, string.length(), false, offset); 1467 final int restoredOffset = p.getOffsetForAdvance(string, 0, 1468 string.length(), 0, string.length(), false, widthToOffset); 1469 assertEquals(offset, restoredOffset); 1470 } 1471 } 1472 { 1473 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0, 1474 string.length(), false, -10.0f); 1475 assertEquals(0, offset); 1476 } 1477 { 1478 final float widthToEnd = p.getRunAdvance(string, 0, string.length(), 0, 1479 string.length(), true, string.length()); 1480 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0, 1481 string.length(), true, widthToEnd + 10.0f); 1482 assertEquals(string.length(), offset); 1483 } 1484 } 1485 { 1486 // RTL 1487 String string = "\u0639\u0631\u0628\u0649"; // Arabic 1488 { 1489 for (int offset = 0; offset <= string.length(); ++offset) { 1490 final float widthToOffset = p.getRunAdvance(string, 0, 1491 string.length(), 0, string.length(), true, offset); 1492 final int restoredOffset = p.getOffsetForAdvance(string, 0, 1493 string.length(), 0, string.length(), true, widthToOffset); 1494 assertEquals(offset, restoredOffset); 1495 } 1496 } 1497 { 1498 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0, 1499 string.length(), true, -10.0f); 1500 assertEquals(0, offset); 1501 } 1502 { 1503 final float widthToEnd = p.getRunAdvance(string, 0, string.length(), 0, 1504 string.length(), true, string.length()); 1505 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0, 1506 string.length(), true, widthToEnd + 10.0f); 1507 assertEquals(string.length(), offset); 1508 } 1509 } 1510 } 1511 1512 @Test(expected=IllegalArgumentException.class) 1513 public void testGetOffsetForAdvanceNullCharSequence() { 1514 new Paint().getOffsetForAdvance((CharSequence) null, 0, 0, 0, 0, false, 0.0f); 1515 } 1516 1517 @Test(expected=IllegalArgumentException.class) 1518 public void testGetOffsetForAdvanceNullCharArray() { 1519 new Paint().getOffsetForAdvance((char[]) null, 0, 0, 0, 0, false, 0.0f); 1520 } 1521 1522 @Test(expected=IndexOutOfBoundsException.class) 1523 public void testGetOffsetForAdvanceContextStartNegative() { 1524 final String string = "abcde"; 1525 1526 // context start < 0 1527 new Paint().getOffsetForAdvance(string, -1, string.length(), 0, string.length(), false, 1528 0.0f); 1529 } 1530 1531 @Test(expected=IndexOutOfBoundsException.class) 1532 public void testGetOffsetForAdvanceStartLessThanContextStart() { 1533 final String string = "abcde"; 1534 1535 // start < context start 1536 new Paint().getOffsetForAdvance(string, 0, string.length(), 1, string.length(), false, 1537 0.0f); 1538 } 1539 1540 @Test(expected=IndexOutOfBoundsException.class) 1541 public void testGetOffsetForAdvanceEndLessThanStart() { 1542 final String string = "abcde"; 1543 1544 // end < start 1545 new Paint().getOffsetForAdvance(string, 1, 0, 0, 0, false, 0); 1546 } 1547 1548 @Test(expected=IndexOutOfBoundsException.class) 1549 public void testGetOffsetForAdvanceContextEndLessThanEnd() { 1550 final String string = "abcde"; 1551 1552 // context end < end 1553 new Paint().getOffsetForAdvance(string, 0, string.length(), 0, string.length() - 1, false, 1554 0.0f); 1555 } 1556 1557 @Test(expected=IndexOutOfBoundsException.class) 1558 public void testGetOffsetForAdvanceTextLengthLessThanContextEnd() { 1559 final String string = "abcde"; 1560 1561 // text length < context end 1562 new Paint().getOffsetForAdvance(string, 0, string.length(), 0, string.length() + 1, false, 1563 0.0f); 1564 } 1565 1566 @Test 1567 public void testGetOffsetForAdvance_graphemeCluster() { 1568 Paint p = new Paint(); 1569 { 1570 String string = "\uD83C\uDF37"; // U+1F337: TULIP 1571 { 1572 final float widthToOffset = p.getRunAdvance(string, 0, 1573 string.length(), 0, string.length(), false, 1); 1574 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0, 1575 string.length(), false, widthToOffset); 1576 assertFalse(1 == offset); 1577 assertTrue(0 == offset || string.length() == offset); 1578 } 1579 } 1580 { 1581 String string = "\uD83C\uDDFA\uD83C\uDDF8"; // US flag 1582 { 1583 final float widthToOffset = p.getRunAdvance(string, 0, 1584 string.length(), 0, string.length(), false, 2); 1585 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0, 1586 string.length(), false, widthToOffset); 1587 assertFalse(2 == offset); 1588 assertTrue(0 == offset || string.length() == offset); 1589 } 1590 { 1591 final float widthToOffset = p.getRunAdvance(string, 0, 2, 0, 2, false, 2); 1592 final int offset = p.getOffsetForAdvance(string, 0, 2, 1593 0, 2, false, widthToOffset); 1594 assertEquals(2, offset); 1595 } 1596 } 1597 { 1598 // HANGUL CHOSEONG KIYEOK, HANGUL JUNGSEONG A, HANDUL JONGSEONG KIYEOK 1599 String string = "\u1100\u1161\u11A8"; 1600 { 1601 for (int offset = 0; offset <= string.length(); ++offset) { 1602 final float widthToOffset = p.getRunAdvance(string, 0, 1603 string.length(), 0, string.length(), false, offset); 1604 final int offsetForAdvance = p.getOffsetForAdvance(string, 0, string.length(), 1605 0, string.length(), false, widthToOffset); 1606 assertTrue(0 == offsetForAdvance || string.length() == offsetForAdvance); 1607 } 1608 for (int offset = 0; offset <= string.length(); ++offset) { 1609 final float widthToOffset = p.getRunAdvance(string, 0, offset, 0, offset, 1610 false, offset); 1611 final int offsetForAdvance = p.getOffsetForAdvance(string, 0, string.length(), 1612 0, string.length(), false, widthToOffset); 1613 assertTrue(0 == offsetForAdvance || string.length() == offsetForAdvance); 1614 } 1615 for (int offset = 0; offset <= string.length(); ++offset) { 1616 final float widthToOffset = p.getRunAdvance(string, 0, offset, 0, offset, 1617 false, offset); 1618 final int offsetForAdvance = p.getOffsetForAdvance(string, 0, offset, 0, 1619 offset, false, widthToOffset); 1620 assertEquals(offset, offsetForAdvance); 1621 } 1622 } 1623 } 1624 } 1625 1626 @Test 1627 public void testElegantText() { 1628 final Paint p = new Paint(); 1629 p.setTextSize(10); 1630 assertFalse(p.isElegantTextHeight()); 1631 final float nonElegantTop = p.getFontMetrics().top; 1632 final float nonElegantBottom = p.getFontMetrics().bottom; 1633 1634 p.setElegantTextHeight(true); 1635 assertTrue(p.isElegantTextHeight()); 1636 final float elegantTop = p.getFontMetrics().top; 1637 final float elegantBottom = p.getFontMetrics().bottom; 1638 1639 assertTrue(elegantTop < nonElegantTop); 1640 assertTrue(elegantBottom > nonElegantBottom); 1641 1642 p.setElegantTextHeight(false); 1643 assertFalse(p.isElegantTextHeight()); 1644 } 1645 } 1646