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 android.graphics.Paint.CURSOR_AFTER;
20 import static android.graphics.Paint.CURSOR_AT;
21 import static android.graphics.Paint.CURSOR_AT_OR_AFTER;
22 import static android.graphics.Paint.CURSOR_AT_OR_BEFORE;
23 import static android.graphics.Paint.CURSOR_BEFORE;
24 
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNull;
28 import static org.junit.Assert.assertTrue;
29 
30 import android.content.Context;
31 import android.graphics.Bitmap;
32 import android.graphics.BitmapShader;
33 import android.graphics.BlendMode;
34 import android.graphics.Color;
35 import android.graphics.ColorFilter;
36 import android.graphics.ColorSpace;
37 import android.graphics.MaskFilter;
38 import android.graphics.Matrix;
39 import android.graphics.Paint;
40 import android.graphics.Paint.Align;
41 import android.graphics.Paint.Cap;
42 import android.graphics.Paint.Join;
43 import android.graphics.Paint.Style;
44 import android.graphics.Path;
45 import android.graphics.PathEffect;
46 import android.graphics.PorterDuff;
47 import android.graphics.PorterDuffXfermode;
48 import android.graphics.Rect;
49 import android.graphics.Shader;
50 import android.graphics.Typeface;
51 import android.graphics.Xfermode;
52 import android.os.LocaleList;
53 import android.text.SpannedString;
54 
55 import androidx.test.InstrumentationRegistry;
56 import androidx.test.filters.SmallTest;
57 import androidx.test.runner.AndroidJUnit4;
58 
59 import com.android.compatibility.common.util.CddTest;
60 import com.android.compatibility.common.util.ColorUtils;
61 
62 import org.junit.Test;
63 import org.junit.runner.RunWith;
64 
65 import java.util.Locale;
66 import java.util.function.BiConsumer;
67 import java.util.function.Function;
68 import java.util.function.Supplier;
69 
70 @SmallTest
71 @RunWith(AndroidJUnit4.class)
72 public class PaintTest {
73     private static final Typeface[] TYPEFACES = new Typeface[] {
74             Typeface.DEFAULT,
75             Typeface.DEFAULT_BOLD,
76             Typeface.MONOSPACE,
77             Typeface.SANS_SERIF,
78             Typeface.SERIF,
79     };
80 
81     @Test
testConstructor()82     public void testConstructor() {
83         new Paint();
84 
85         new Paint(1);
86 
87         Paint p = new Paint();
88         new Paint(p);
89     }
90 
91     @Test
testDefaultColor()92     public void testDefaultColor() {
93         Supplier<Paint> set = () -> {
94             Paint result = new Paint();
95             result.setColor(Color.BLUE);
96             assertEquals(Color.BLUE, result.getColor());
97             result.setShadowLayer(10.0f, 1.0f, 1.0f, Color.RED);
98             assertEquals(Color.RED, result.getShadowLayerColor());
99 
100             Paint def = new Paint();
101             result.set(def);
102             return result;
103         };
104         Supplier<Paint> reset = () -> {
105             Paint result = new Paint();
106             result.setColor(Color.GREEN);
107             assertEquals(Color.GREEN, result.getColor());
108             result.setShadowLayer(10.0f, 1.0f, 1.0f, Color.WHITE);
109             assertEquals(Color.WHITE, result.getShadowLayerColor());
110 
111             result.reset();
112             return result;
113         };
114         for (Paint p : new Paint[]{ new Paint(),
115                                     new Paint(1),
116                                     new Paint(new Paint()),
117                                     set.get(),
118                                     reset.get()}) {
119             assertEquals(Color.BLACK, p.getColor());
120             assertEquals(Color.TRANSPARENT, p.getShadowLayerColor());
121 
122             assertEquals(Color.BLACK, Color.toArgb(p.getColorLong()));
123             assertEquals(Color.TRANSPARENT, Color.toArgb(p.getShadowLayerColorLong()));
124         }
125     }
126 
127     @Test
testBreakText()128     public void testBreakText() {
129         String text = "HIJKLMN";
130         char[] textChars = text.toCharArray();
131         SpannedString textSpan = new SpannedString(text);
132 
133         Paint p = new Paint();
134 
135         // We need to turn off kerning in order to get accurate comparisons
136         p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG);
137 
138         float[] widths = new float[text.length()];
139         assertEquals(text.length(), p.getTextWidths(text, widths));
140 
141         float totalWidth = 0.0f;
142         for (int i = 0; i < text.length(); i++) {
143             totalWidth += widths[i];
144         }
145 
146         for (int i = 0; i < text.length(); i++) {
147             verifyBreakText(text, textChars, textSpan, i, i + 1, true, totalWidth, 1, widths[i]);
148         }
149 
150         // Measure empty string
151         verifyBreakText(text, textChars, textSpan, 0, 0, true, totalWidth, 0, 0);
152 
153         // Measure substring from front: "HIJ"
154         verifyBreakText(text, textChars, textSpan, 0, 3, true, totalWidth,
155                 3, widths[0] + widths[1] + widths[2]);
156 
157         // Reverse measure substring from front: "HIJ"
158         verifyBreakText(text, textChars, textSpan, 0, 3, false, totalWidth,
159                 3, widths[0] + widths[1] + widths[2]);
160 
161         // Measure substring from back: "MN"
162         verifyBreakText(text, textChars, textSpan, 5, 7, true, totalWidth,
163                 2, widths[5] + widths[6]);
164 
165         // Reverse measure substring from back: "MN"
166         verifyBreakText(text, textChars, textSpan, 5, 7, false, totalWidth,
167                 2, widths[5] + widths[6]);
168 
169         // Measure substring in the middle: "JKL"
170         verifyBreakText(text, textChars, textSpan, 2, 5, true, totalWidth,
171                 3, widths[2] + widths[3] + widths[4]);
172 
173         // Reverse measure substring in the middle: "JKL"
174         verifyBreakText(text, textChars, textSpan, 2, 5, false, totalWidth,
175                 3, widths[2] + widths[3] + widths[4]);
176 
177         // Measure substring in the middle and restrict width to the first 2 characters.
178         verifyBreakText(text, textChars, textSpan, 2, 5, true, widths[2] + widths[3],
179                 2, widths[2] + widths[3]);
180 
181         // Reverse measure substring in the middle and restrict width to the last 2 characters.
182         verifyBreakText(text, textChars, textSpan, 2, 5, false, widths[3] + widths[4],
183                 2, widths[3] + widths[4]);
184 
185         // a single Emoji (U+1f601)
186         String emoji = "\ud83d\ude01";
187         char[] emojiChars = emoji.toCharArray();
188         SpannedString emojiSpan = new SpannedString(emoji);
189 
190         float[] emojiWidths = new float[emoji.length()];
191         assertEquals(emoji.length(), p.getTextWidths(emoji, emojiWidths));
192 
193         // Measure substring with a cluster
194         verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, 0,
195                 0, 0);
196 
197         // Measure substring with a cluster
198         verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, true, emojiWidths[0],
199                 2, emojiWidths[0]);
200 
201         // Reverse measure substring with a cluster
202         verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, 0,
203                 0, 0);
204 
205         // Measure substring with a cluster
206         verifyBreakText(emoji, emojiChars, emojiSpan, 0, 2, false, emojiWidths[0],
207                 2, emojiWidths[0]);
208     }
209 
verifyBreakText(String text, char[] textChars, SpannedString textSpan, int start, int end, boolean measureForwards, float maxWidth, int expectedCount, float expectedWidth)210     private void verifyBreakText(String text, char[] textChars, SpannedString textSpan,
211             int start, int end, boolean measureForwards, float maxWidth, int expectedCount,
212             float expectedWidth) {
213         Paint p = new Paint();
214 
215         // We need to turn off kerning in order to get accurate comparisons
216         p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG);
217 
218         int count = end - start;
219         if (!measureForwards) {
220             count = -count;
221         }
222 
223         float[][] measured = new float[][] {
224             new float[1],
225             new float[1],
226             new float[1]
227         };
228         String textSlice = text.substring(start, end);
229         assertEquals(expectedCount, p.breakText(textSlice, measureForwards, maxWidth, measured[0]));
230         assertEquals(expectedCount, p.breakText(textChars, start, count, maxWidth, measured[1]));
231         assertEquals(expectedCount, p.breakText(textSpan, start, end, measureForwards, maxWidth,
232                 measured[2]));
233 
234         for (int i = 0; i < measured.length; i++) {
235             assertEquals("i: " + i, expectedWidth, measured[i][0], 0.0f);
236         }
237     }
238 
239     @Test
testSet()240     public void testSet() {
241         Paint p  = new Paint();
242         Paint p2 = new Paint();
243         ColorFilter c = new ColorFilter();
244         MaskFilter m  = new MaskFilter();
245         PathEffect e  = new PathEffect();
246         Shader s      = new Shader();
247         Typeface t    = Typeface.DEFAULT;
248         Xfermode x = new Xfermode();
249 
250         p.setColorFilter(c);
251         p.setMaskFilter(m);
252         p.setPathEffect(e);
253         p.setShader(s);
254         p.setTypeface(t);
255         p.setXfermode(x);
256         p2.set(p);
257         assertEquals(c, p2.getColorFilter());
258         assertEquals(m, p2.getMaskFilter());
259         assertEquals(e, p2.getPathEffect());
260         assertEquals(s, p2.getShader());
261         assertEquals(t, p2.getTypeface());
262         assertEquals(x, p2.getXfermode());
263 
264         p2.set(p2);
265         assertEquals(c, p2.getColorFilter());
266         assertEquals(m, p2.getMaskFilter());
267         assertEquals(e, p2.getPathEffect());
268         assertEquals(s, p2.getShader());
269         assertEquals(t, p2.getTypeface());
270         assertEquals(x, p2.getXfermode());
271 
272         p.setColorFilter(null);
273         p.setMaskFilter(null);
274         p.setPathEffect(null);
275         p.setShader(null);
276         p.setTypeface(null);
277         p.setXfermode(null);
278         p2.set(p);
279         assertNull(p2.getColorFilter());
280         assertNull(p2.getMaskFilter());
281         assertNull(p2.getPathEffect());
282         assertNull(p2.getShader());
283         assertNull(p2.getTypeface());
284         assertNull(p2.getXfermode());
285 
286         p2.set(p2);
287         assertNull(p2.getColorFilter());
288         assertNull(p2.getMaskFilter());
289         assertNull(p2.getPathEffect());
290         assertNull(p2.getShader());
291         assertNull(p2.getTypeface());
292         assertNull(p2.getXfermode());
293     }
294 
295     @Test
testAccessStrokeCap()296     public void testAccessStrokeCap() {
297         Paint p = new Paint();
298 
299         p.setStrokeCap(Cap.BUTT);
300         assertEquals(Cap.BUTT, p.getStrokeCap());
301 
302         p.setStrokeCap(Cap.ROUND);
303         assertEquals(Cap.ROUND, p.getStrokeCap());
304 
305         p.setStrokeCap(Cap.SQUARE);
306         assertEquals(Cap.SQUARE, p.getStrokeCap());
307     }
308 
309     @Test(expected=RuntimeException.class)
testSetStrokeCapNull()310     public void testSetStrokeCapNull() {
311         Paint p = new Paint();
312 
313         p.setStrokeCap(null);
314     }
315 
316     @Test
testAccessXfermode()317     public void testAccessXfermode() {
318         Paint p = new Paint();
319         Xfermode x = new Xfermode();
320 
321         assertEquals(x, p.setXfermode(x));
322         assertEquals(x, p.getXfermode());
323 
324         assertNull(p.setXfermode(null));
325         assertNull(p.getXfermode());
326     }
327 
328     @Test
testAccessShader()329     public void testAccessShader() {
330         Paint p = new Paint();
331         Shader s = new Shader();
332 
333         assertEquals(s, p.setShader(s));
334         assertEquals(s, p.getShader());
335 
336         assertNull(p.setShader(null));
337         assertNull(p.getShader());
338     }
339 
340     @Test
testShaderLocalMatrix()341     public void testShaderLocalMatrix() {
342         int width = 80;
343         int height = 120;
344         int[] color = new int[width * height];
345         Bitmap bitmap = Bitmap.createBitmap(color, width, height, Bitmap.Config.RGB_565);
346 
347         Paint p = new Paint();
348         Matrix m = new Matrix();
349         Shader s = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
350 
351         // set the shaders matrix to a non identity value and attach to paint
352         m.setScale(10, 0);
353         s.setLocalMatrix(m);
354         p.setShader(s);
355 
356         Matrix m2 = new Matrix();
357         assertTrue(p.getShader().getLocalMatrix(m2));
358         assertEquals(m, m2);
359 
360         // updated the matrix again and set it on the shader but NOT the paint
361         m.setScale(0, 10);
362         s.setLocalMatrix(m);
363 
364         // assert that the matrix on the paint's shader also changed
365         Matrix m3 = new Matrix();
366         assertTrue(p.getShader().getLocalMatrix(m3));
367         assertEquals(m, m3);
368     }
369 
370     @Test
testSetAntiAlias()371     public void testSetAntiAlias() {
372         Paint p = new Paint();
373 
374         p.setAntiAlias(false);
375         assertFalse(p.isAntiAlias());
376 
377         p.setAntiAlias(true);
378         assertTrue(p.isAntiAlias());
379     }
380 
381     @Test
testDefaultAntiAlias()382     public void testDefaultAntiAlias() {
383         Paint p = new Paint();
384         assertTrue(p.isAntiAlias());
385     }
386 
387     @Test
testAccessTypeface()388     public void testAccessTypeface() {
389         Paint p = new Paint();
390 
391         assertEquals(Typeface.DEFAULT, p.setTypeface(Typeface.DEFAULT));
392         assertEquals(Typeface.DEFAULT, p.getTypeface());
393 
394         assertEquals(Typeface.DEFAULT_BOLD, p.setTypeface(Typeface.DEFAULT_BOLD));
395         assertEquals(Typeface.DEFAULT_BOLD, p.getTypeface());
396 
397         assertEquals(Typeface.MONOSPACE, p.setTypeface(Typeface.MONOSPACE));
398         assertEquals(Typeface.MONOSPACE, p.getTypeface());
399 
400         assertNull(p.setTypeface(null));
401         assertNull(p.getTypeface());
402     }
403 
404     @Test
testAccessPathEffect()405     public void testAccessPathEffect() {
406         Paint p = new Paint();
407         PathEffect e = new PathEffect();
408 
409         assertEquals(e, p.setPathEffect(e));
410         assertEquals(e, p.getPathEffect());
411 
412         assertNull(p.setPathEffect(null));
413         assertNull(p.getPathEffect());
414     }
415 
416     @Test
testSetFakeBoldText()417     public void testSetFakeBoldText() {
418         Paint p = new Paint();
419 
420         p.setFakeBoldText(true);
421         assertTrue(p.isFakeBoldText());
422 
423         p.setFakeBoldText(false);
424         assertFalse(p.isFakeBoldText());
425     }
426 
427     @Test
testAccessStrokeJoin()428     public void testAccessStrokeJoin() {
429         Paint p = new Paint();
430 
431         p.setStrokeJoin(Join.BEVEL);
432         assertEquals(Join.BEVEL, p.getStrokeJoin());
433 
434         p.setStrokeJoin(Join.MITER);
435         assertEquals(Join.MITER, p.getStrokeJoin());
436 
437         p.setStrokeJoin(Join.ROUND);
438         assertEquals(Join.ROUND, p.getStrokeJoin());
439     }
440 
441     @Test(expected=RuntimeException.class)
testSetStrokeJoinNull()442     public void testSetStrokeJoinNull() {
443         Paint p = new Paint();
444 
445         p.setStrokeJoin(null);
446     }
447 
448     @Test
testAccessStyle()449     public void testAccessStyle() {
450         Paint p = new Paint();
451 
452         p.setStyle(Style.FILL);
453         assertEquals(Style.FILL, p.getStyle());
454 
455         p.setStyle(Style.FILL_AND_STROKE);
456         assertEquals(Style.FILL_AND_STROKE, p.getStyle());
457 
458         p.setStyle(Style.STROKE);
459         assertEquals(Style.STROKE, p.getStyle());
460     }
461 
462     @Test(expected=RuntimeException.class)
testSetStyleNull()463     public void testSetStyleNull() {
464         Paint p = new Paint();
465 
466         p.setStyle(null);
467     }
468 
469     @Test
testGetFontSpacing()470     public void testGetFontSpacing() {
471         Paint p = new Paint();
472 
473         for (Typeface typeface : TYPEFACES) {
474             p.setTypeface(typeface);
475 
476             p.setTextSize(10);
477             float spacing10 = p.getFontSpacing();
478             assertTrue(spacing10 > 0);
479 
480             p.setTextSize(20);
481             float spacing20 = p.getFontSpacing();
482             assertTrue(spacing20 > spacing10);
483         }
484     }
485 
486     @Test
testSetSubpixelText()487     public void testSetSubpixelText() {
488         Paint p = new Paint();
489 
490         p.setSubpixelText(true);
491         assertTrue(p.isSubpixelText());
492 
493         p.setSubpixelText(false);
494         assertFalse(p.isSubpixelText());
495     }
496 
497     @Test
testAccessTextScaleX()498     public void testAccessTextScaleX() {
499         Paint p = new Paint();
500 
501         p.setTextScaleX(2.0f);
502         assertEquals(2.0f, p.getTextScaleX(), 0.0f);
503 
504         p.setTextScaleX(1.0f);
505         assertEquals(1.0f, p.getTextScaleX(), 0.0f);
506 
507         p.setTextScaleX(0.0f);
508         assertEquals(0.0f, p.getTextScaleX(), 0.0f);
509 
510     }
511 
512     @Test
testAccessMaskFilter()513     public void testAccessMaskFilter() {
514         Paint p = new Paint();
515         MaskFilter m = new MaskFilter();
516 
517         assertEquals(m, p.setMaskFilter(m));
518         assertEquals(m, p.getMaskFilter());
519 
520         assertNull(p.setMaskFilter(null));
521         assertNull(p.getMaskFilter());
522     }
523 
524     @Test
testAccessColorFilter()525     public void testAccessColorFilter() {
526         Paint p = new Paint();
527         ColorFilter c = new ColorFilter();
528 
529         assertEquals(c, p.setColorFilter(c));
530         assertEquals(c, p.getColorFilter());
531 
532         assertNull(p.setColorFilter(null));
533         assertNull(p.getColorFilter());
534     }
535 
536     @Test
testSetARGB()537     public void testSetARGB() {
538         Paint p = new Paint();
539 
540         p.setARGB(0, 0, 0, 0);
541         assertEquals(0, p.getColor());
542 
543         p.setARGB(3, 3, 3, 3);
544         assertEquals((3 << 24) | (3 << 16) | (3 << 8) | 3, p.getColor());
545     }
546 
547     @Test
testAscent()548     public void testAscent() {
549         Paint p = new Paint();
550 
551         for (Typeface typeface : TYPEFACES) {
552             p.setTypeface(typeface);
553 
554             p.setTextSize(10);
555             float ascent10 = p.ascent();
556             assertTrue(ascent10 < 0);
557 
558             p.setTextSize(20);
559             float ascent20 = p.ascent();
560             assertTrue(ascent20 < ascent10);
561         }
562     }
563 
564     @Test
565     public void testAccessTextSkewX() {
566         Paint p = new Paint();
567 
568         p.setTextSkewX(1.0f);
569         assertEquals(1.0f, p.getTextSkewX(), 0.0f);
570 
571         p.setTextSkewX(0.0f);
572         assertEquals(0.0f, p.getTextSkewX(), 0.0f);
573 
574         p.setTextSkewX(-0.25f);
575         assertEquals(-0.25f, p.getTextSkewX(), 0.0f);
576     }
577 
578     @Test
579     public void testAccessTextSize() {
580         Paint p = new Paint();
581 
582         p.setTextSize(1.0f);
583         assertEquals(1.0f, p.getTextSize(), 0.0f);
584 
585         p.setTextSize(2.0f);
586         assertEquals(2.0f, p.getTextSize(), 0.0f);
587 
588         // text size should be greater than 0, so set -1 has no effect
589         p.setTextSize(-1.0f);
590         assertEquals(2.0f, p.getTextSize(), 0.0f);
591 
592         // text size should be greater than or equals to 0
593         p.setTextSize(0.0f);
594         assertEquals(0.0f, p.getTextSize(), 0.0f);
595     }
596 
597     @Test
598     public void testGetTextWidths() throws Exception {
599         String text = "HIJKLMN";
600         char[] textChars = text.toCharArray();
601         SpannedString textSpan = new SpannedString(text);
602 
603         // Test measuring the widths of the entire text
604         verifyGetTextWidths(text, textChars, textSpan, 0, 7);
605 
606         // Test measuring a substring of the text
607         verifyGetTextWidths(text, textChars, textSpan, 1, 3);
608 
609         // Test measuring a substring of zero length.
610         verifyGetTextWidths(text, textChars, textSpan, 3, 3);
611 
612         // Test measuring substrings from the front and back
613         verifyGetTextWidths(text, textChars, textSpan, 0, 2);
614         verifyGetTextWidths(text, textChars, textSpan, 4, 7);
615     }
616 
617     /** Tests all four overloads of getTextWidths are the same. */
618     private void verifyGetTextWidths(String text, char[] textChars, SpannedString textSpan,
619             int start, int end) {
620         Paint p = new Paint();
621         int count = end - start;
622         float[][] widths = new float[][] {
623             new float[count],
624             new float[count],
625             new float[count],
626             new float[count]
627         };
628 
629         String textSlice = text.substring(start, end);
630         assertEquals(count, p.getTextWidths(textSlice, widths[0]));
631         assertEquals(count, p.getTextWidths(textChars, start, count, widths[1]));
632         assertEquals(count, p.getTextWidths(textSpan, start, end, widths[2]));
633         assertEquals(count, p.getTextWidths(text, start, end, widths[3]));
634 
635         // Check that the widths returned by the overloads are the same.
636         for (int i = 0; i < count; i++) {
637             assertEquals(widths[0][i], widths[1][i], 0.0f);
638             assertEquals(widths[1][i], widths[2][i], 0.0f);
639             assertEquals(widths[2][i], widths[3][i], 0.0f);
640         }
641     }
642 
643     @Test
644     public void testSetStrikeThruText() {
645         Paint p = new Paint();
646 
647         p.setStrikeThruText(true);
648         assertTrue(p.isStrikeThruText());
649 
650         p.setStrikeThruText(false);
651         assertFalse(p.isStrikeThruText());
652     }
653 
654     @Test
655     public void testAccessTextAlign() {
656         Paint p = new Paint();
657 
658         p.setTextAlign(Align.CENTER);
659         assertEquals(Align.CENTER, p.getTextAlign());
660 
661         p.setTextAlign(Align.LEFT);
662         assertEquals(Align.LEFT, p.getTextAlign());
663 
664         p.setTextAlign(Align.RIGHT);
665         assertEquals(Align.RIGHT, p.getTextAlign());
666     }
667 
668     @Test
669     public void testAccessTextLocale() {
670         Paint p = new Paint();
671 
672         final Locale defaultLocale = Locale.getDefault();
673 
674         // Check default
675         assertEquals(defaultLocale, p.getTextLocale());
676 
677         // Check setter / getters
678         p.setTextLocale(Locale.US);
679         assertEquals(Locale.US, p.getTextLocale());
680         assertEquals(new LocaleList(Locale.US), p.getTextLocales());
681 
682         p.setTextLocale(Locale.CHINESE);
683         assertEquals(Locale.CHINESE, p.getTextLocale());
684         assertEquals(new LocaleList(Locale.CHINESE), p.getTextLocales());
685 
686         p.setTextLocale(Locale.JAPANESE);
687         assertEquals(Locale.JAPANESE, p.getTextLocale());
688         assertEquals(new LocaleList(Locale.JAPANESE), p.getTextLocales());
689 
690         p.setTextLocale(Locale.KOREAN);
691         assertEquals(Locale.KOREAN, p.getTextLocale());
692         assertEquals(new LocaleList(Locale.KOREAN), p.getTextLocales());
693 
694         // Check reverting back to default
695         p.setTextLocale(defaultLocale);
696         assertEquals(defaultLocale, p.getTextLocale());
697         assertEquals(new LocaleList(defaultLocale), p.getTextLocales());
698     }
699 
700     @Test(expected=IllegalArgumentException.class)
701     public void testSetTextLocaleNull() {
702         Paint p = new Paint();
703 
704         p.setTextLocale(null);
705     }
706 
707     @Test
708     public void testAccessTextLocales() {
709         Paint p = new Paint();
710 
711         final LocaleList defaultLocales = LocaleList.getDefault();
712 
713         // Check default
714         assertEquals(defaultLocales, p.getTextLocales());
715 
716         // Check setter / getters for a one-member locale list
717         p.setTextLocales(new LocaleList(Locale.CHINESE));
718         assertEquals(Locale.CHINESE, p.getTextLocale());
719         assertEquals(new LocaleList(Locale.CHINESE), p.getTextLocales());
720 
721         // Check setter / getters for a two-member locale list
722         p.setTextLocales(LocaleList.forLanguageTags("fr,de"));
723         assertEquals(Locale.forLanguageTag("fr"), p.getTextLocale());
724         assertEquals(LocaleList.forLanguageTags("fr,de"), p.getTextLocales());
725 
726         // Check reverting back to default
727         p.setTextLocales(defaultLocales);
728         assertEquals(defaultLocales, p.getTextLocales());
729     }
730 
731     @Test(expected=IllegalArgumentException.class)
732     public void testAccessTextLocalesNull() {
733         Paint p = new Paint();
734 
735         // Check that we cannot pass a null locale list
736         p.setTextLocales(null);
737     }
738 
739     @Test(expected=IllegalArgumentException.class)
740     public void testAccessTextLocalesEmpty() {
741         Paint p = new Paint();
742 
743         // Check that we cannot pass an empty locale list
744         p.setTextLocales(new LocaleList());
745     }
746 
747     @Test
748     public void testGetFillPath() {
749         Paint p = new Paint();
750         Path path1 = new Path();
751         Path path2 = new Path();
752 
753         assertTrue(path1.isEmpty());
754         assertTrue(path2.isEmpty());
755         p.getFillPath(path1, path2);
756         assertTrue(path1.isEmpty());
757         assertTrue(path2.isEmpty());
758 
759         // No setter
760     }
761 
762     @Test
763     public void testAccessAlpha() {
764         Paint p = new Paint();
765 
766         p.setAlpha(0);
767         assertEquals(0, p.getAlpha());
768 
769         p.setAlpha(255);
770         assertEquals(255, p.getAlpha());
771 
772         // set value should between 0 and 255, ensure return value is always in range
773         p.setAlpha(266);
774         assertTrue(0 <= p.getAlpha() && p.getAlpha() <= 255);
775 
776         // set value should between 0 and 255, ensure return value is always in range
777         p.setAlpha(-20);
778         assertTrue(0 <= p.getAlpha() && p.getAlpha() <= 255);
779     }
780 
781     @Test
782     public void testSetAlpha() {
783         for (ColorSpace.Named e : new ColorSpace.Named[] {
784                 ColorSpace.Named.SRGB,
785                 ColorSpace.Named.LINEAR_EXTENDED_SRGB,
786                 ColorSpace.Named.DISPLAY_P3}) {
787             ColorSpace cs = ColorSpace.get(e);
788 
789             // Arbitrary colors
790             final float red = .2f;
791             final float green = .7f;
792             final float blue = .9f;
793             final long desiredColor = Color.pack(red, green, blue, 1.0f, cs);
794 
795             Paint p = new Paint();
796             p.setColor(desiredColor);
797             final long origColor = p.getColorLong();
798             assertEquals(desiredColor, origColor);
799 
800             final float origRed = Color.red(origColor);
801             final float origGreen = Color.green(origColor);
802             final float origBlue = Color.blue(origColor);
803 
804             // There is a slight difference in the packed color.
805             assertEquals(red, Color.red(origColor), 0.002f);
806             assertEquals(green, Color.green(origColor), 0.002f);
807             assertEquals(blue, Color.blue(origColor), 0.002f);
808 
809             for (int alpha = 0; alpha <= 255; ++alpha) {
810                 p.setAlpha(alpha);
811                 assertEquals(alpha, p.getAlpha());
812 
813                 final long color = p.getColorLong();
814                 assertEquals(origRed, Color.red(color), 0.0f);
815                 assertEquals(origGreen, Color.green(color), 0.0f);
816                 assertEquals(origBlue, Color.blue(color), 0.0f);
817             }
818         }
819     }
820 
821     private void testIsFilterBitmap(Paint orig) {
822         Paint p = new Paint(orig);
823         assertEquals(orig.isFilterBitmap(), p.isFilterBitmap());
824 
825         p = new Paint();
826         p.set(orig);
827         assertEquals(orig.isFilterBitmap(), p.isFilterBitmap());
828     }
829 
830     @Test
831     public void testSetFilterBitmap() {
832         Paint p = new Paint();
833         assertTrue(p.isFilterBitmap());
834         testIsFilterBitmap(p);
835 
836         p.setFilterBitmap(true);
837         assertTrue(p.isFilterBitmap());
838 
839         p.setFilterBitmap(false);
840         assertFalse(p.isFilterBitmap());
841         testIsFilterBitmap(p);
842 
843         p.reset();
844         assertTrue(p.isFilterBitmap());
845 
846         p.setFilterBitmap(false);
847         assertFalse(p.isFilterBitmap());
848 
849         p.setFlags(Paint.FILTER_BITMAP_FLAG);
850         assertTrue(p.isFilterBitmap());
851 
852         p.setFlags(~Paint.FILTER_BITMAP_FLAG);
853         assertFalse(p.isFilterBitmap());
854     }
855 
856     @Test
857     public void testAccessColor() {
858         Paint p = new Paint();
859 
860         p.setColor(1);
861         assertEquals(1, p.getColor());
862 
863         p.setColor(0);
864         assertEquals(0, p.getColor());
865 
866         p.setColor(255);
867         assertEquals(255, p.getColor());
868 
869         p.setColor(-1);
870         assertEquals(-1, p.getColor());
871 
872         p.setColor(256);
873         assertEquals(256, p.getColor());
874     }
875 
876     @Test
877     public void testSetGetShadowLayer() {
878         Paint paint = new Paint();
879         paint.setShadowLayer(10, 1, 1, 0);
880         assertEquals(10, paint.getShadowLayerRadius(), 0.0f);
881         assertEquals(1, paint.getShadowLayerDx(), 0.0f);
882         assertEquals(1, paint.getShadowLayerDy(), 0.0f);
883         assertEquals(0, paint.getShadowLayerColor());
884     }
885 
886     @Test
887     public void testGetFontMetrics1() {
888         Paint p = new Paint();
889         Paint.FontMetrics fm = new Paint.FontMetrics();
890 
891         for (Typeface typeface : TYPEFACES) {
892             p.setTypeface(typeface);
893 
894             p.setTextSize(10);
895             p.getFontMetrics(fm);
896             assertEquals(p.ascent(), fm.ascent, 0.0f);
897             assertEquals(p.descent(), fm.descent, 0.0f);
898 
899             p.setTextSize(20);
900             p.getFontMetrics(fm);
901             assertEquals(p.ascent(), fm.ascent, 0.0f);
902             assertEquals(p.descent(), fm.descent, 0.0f);
903         }
904     }
905 
906     @Test
907     public void testGetFontMetrics2() {
908         Paint p = new Paint();
909 
910         for (Typeface typeface : TYPEFACES) {
911             p.setTypeface(typeface);
912 
913             p.setTextSize(10);
914             Paint.FontMetrics fm = p.getFontMetrics();
915             assertEquals(p.ascent(), fm.ascent, 0.0f);
916             assertEquals(p.descent(), fm.descent, 0.0f);
917 
918             p.setTextSize(20);
919             fm = p.getFontMetrics();
920             assertEquals(p.ascent(), fm.ascent, 0.0f);
921             assertEquals(p.descent(), fm.descent, 0.0f);
922         }
923     }
924 
925     @Test
926     public void testAccessStrokeMiter() {
927         Paint p = new Paint();
928 
929         p.setStrokeMiter(0.0f);
930         assertEquals(0.0f, p.getStrokeMiter(), 0.0f);
931 
932         p.setStrokeMiter(10.0f);
933         assertEquals(10.0f, p.getStrokeMiter(), 0.0f);
934 
935         // set value should be greater or equal to 0, set to -10.0f has no effect
936         p.setStrokeMiter(-10.0f);
937         assertEquals(10.0f, p.getStrokeMiter(), 0.0f);
938     }
939 
940     @Test
941     public void testClearShadowLayer() {
942         new Paint().clearShadowLayer();
943     }
944 
945     @Test
946     public void testSetUnderlineText() {
947         Paint p = new Paint();
948 
949         p.setUnderlineText(true);
950         assertTrue(p.isUnderlineText());
951 
952         p.setUnderlineText(false);
953         assertFalse(p.isUnderlineText());
954     }
955 
956     @Test
957     public void testSetDither() {
958         Paint p = new Paint();
959 
960         p.setDither(false);
961         assertFalse(p.isDither());
962 
963         p.setDither(true);
964         assertTrue(p.isDither());
965     }
966 
967     @Test
968     public void testDefaultDither() {
969         Paint p = new Paint();
970         assertFalse(p.isDither());
971     }
972 
973     @Test
974     public void testDescent() {
975         Paint p = new Paint();
976 
977         for (Typeface typeface : TYPEFACES) {
978             p.setTypeface(typeface);
979 
980             p.setTextSize(10);
981             float descent10 = p.descent();
982             assertTrue(descent10 > 0);
983 
984             p.setTextSize(20);
985             float descent20 = p.descent();
986             assertTrue(descent20 > descent10);
987         }
988     }
989 
990     @Test
991     public void testAccessFlags() {
992         Paint p = new Paint();
993 
994         p.setFlags(Paint.ANTI_ALIAS_FLAG);
995         assertEquals(Paint.ANTI_ALIAS_FLAG, p.getFlags());
996 
997         p.setFlags(Paint.DEV_KERN_TEXT_FLAG);
998         assertEquals(Paint.DEV_KERN_TEXT_FLAG, p.getFlags());
999     }
1000 
1001     @Test
1002     public void testAccessStrokeWidth() {
1003         Paint p = new Paint();
1004 
1005         p.setStrokeWidth(0.0f);
1006         assertEquals(0.0f, p.getStrokeWidth(), 0.0f);
1007 
1008         p.setStrokeWidth(10.0f);
1009         assertEquals(10.0f, p.getStrokeWidth(), 0.0f);
1010 
1011         // set value must greater or equal to 0, set -10.0f has no effect
1012         p.setStrokeWidth(-10.0f);
1013         assertEquals(10.0f, p.getStrokeWidth(), 0.0f);
1014     }
1015 
1016     @Test
1017     public void testSetFontFeatureSettings() {
1018         Paint p = new Paint();
1019         // Roboto font (system default) has "fi" ligature
1020         String text = "fi";
1021         float[] widths = new float[text.length()];
1022         p.getTextWidths(text, widths);
1023         assertTrue(widths[0] > 0.0f);
1024         assertEquals(0.0f, widths[1], 0.0f);
1025 
1026         // Disable ligature using OpenType feature
1027         p.setFontFeatureSettings("'liga' off");
1028         p.getTextWidths(text, widths);
1029         assertTrue(widths[0] > 0.0f);
1030         assertTrue(widths[1] > 0.0f);
1031 
1032         // Re-enable ligature
1033         p.setFontFeatureSettings("'liga' on");
1034         p.getTextWidths(text, widths);
1035         assertTrue(widths[0] > 0.0f);
1036         assertEquals(0.0f, widths[1], 0.0f);
1037     }
1038 
1039     @Test
1040     public void testSetFontVariationSettings_defaultTypeface() {
1041         new Paint().setFontVariationSettings("'wght' 400");
1042     }
1043 
1044     @Test
1045     public void testSetGetFontVariationSettings() {
1046         final Paint defaultPaint = new Paint();
1047 
1048         Paint p = new Paint();
1049         Context context = InstrumentationRegistry.getTargetContext();
1050         Typeface typeface = Typeface.createFromAsset(context.getAssets(),
1051                 "fonts/var_fonts/multiaxis.ttf");
1052         p.setTypeface(typeface);
1053 
1054         // multiaxis.ttf supports "wght", "PRIV", "PR12" axes.
1055 
1056         // The default variation settings should be null.
1057         assertNull(p.getFontVariationSettings());
1058 
1059         final String[] nonEffectiveSettings = {
1060                 "'slnt' 30",  // unsupported tag
1061                 "'BBBB' 1.0",  // unsupported tag
1062                 "'A   ' 1.0",  // unsupported tag
1063                 "'PR0 ' 1.3",  // unsupported tag
1064                 "'WGHT' 0.7",  // unsupported tag (case sensitive)
1065                 "'BBBB' 1.0, 'CCCC' 2.0",  // none of them are supported.
1066         };
1067 
1068         for (String notEffectiveSetting : nonEffectiveSettings) {
1069             if (!defaultPaint.setFontVariationSettings(notEffectiveSetting)) {
1070                 // Test only when the system font don't support the above axes. OEMs may add
1071                 // their fonts and these font may support above axes.
1072                 assertFalse("Must return false for " + notEffectiveSetting,
1073                         p.setFontVariationSettings(notEffectiveSetting));
1074                 assertNull("Must not change settings for " + notEffectiveSetting,
1075                         p.getFontVariationSettings());
1076             }
1077         }
1078 
1079         String retainSettings = "'wght' 400";
1080         assertTrue(p.setFontVariationSettings(retainSettings));
1081         for (String notEffectiveSetting : nonEffectiveSettings) {
1082             assertFalse(p.setFontVariationSettings(notEffectiveSetting));
1083             assertEquals("Must not change settings for " + notEffectiveSetting,
1084                     retainSettings, p.getFontVariationSettings());
1085         }
1086 
1087         // At least one axis is supported, the settings should be applied.
1088         final String[] effectiveSettings = {
1089                 "'wght' 300",  // supported tag
1090                 "'wght' 300, 'PRIV' 0.5",  // both are supported
1091                 "'PRIV' 1.0, 'BBBB' 0.4",  // 'BBBB' is unsupported
1092         };
1093 
1094         for (String effectiveSetting : effectiveSettings) {
1095             assertTrue("Must return true for " + effectiveSetting,
1096                     p.setFontVariationSettings(effectiveSetting));
1097             assertEquals(effectiveSetting, p.getFontVariationSettings());
1098         }
1099 
1100         p.setFontVariationSettings("");
1101         assertNull(p.getFontVariationSettings());
1102     }
1103 
1104     @Test
1105     public void testGetTextBounds() {
1106         Paint p = new Paint();
1107         p.setTextSize(10);
1108         String text1 = "hello";
1109         Rect bounds1 = new Rect();
1110         Rect bounds2 = new Rect();
1111         Rect bounds3 = new Rect();
1112         p.getTextBounds(text1, 0, text1.length(), bounds1);
1113         char[] textChars1 = text1.toCharArray();
1114         p.getTextBounds(textChars1, 0, textChars1.length, bounds2);
1115         CharSequence charSequence1 = new StringBuilder(text1);
1116         p.getTextBounds(charSequence1, 0, textChars1.length, bounds3);
1117         // verify that string and char array methods produce consistent results
1118         assertEquals(bounds1, bounds2);
1119         assertEquals(bounds2, bounds3);
1120         String text2 = "hello world";
1121 
1122         // verify substring produces consistent results
1123         p.getTextBounds(text2, 0, text1.length(), bounds2);
1124         assertEquals(bounds1, bounds2);
1125 
1126         // longer string is expected to have same left edge but be wider
1127         p.getTextBounds(text2, 0, text2.length(), bounds2);
1128         assertEquals(bounds1.left, bounds2.left);
1129         assertTrue(bounds2.right > bounds1.right);
1130 
1131         // bigger size implies bigger bounding rect
1132         p.setTextSize(20);
1133         p.getTextBounds(text1, 0, text1.length(), bounds2);
1134         assertTrue(bounds2.right > bounds1.right);
1135         assertTrue(bounds2.bottom - bounds2.top > bounds1.bottom - bounds1.top);
1136     }
1137 
1138     @Test
testReset()1139     public void testReset() {
1140         Paint p  = new Paint();
1141         ColorFilter c = new ColorFilter();
1142         MaskFilter m  = new MaskFilter();
1143         PathEffect e  = new PathEffect();
1144         Shader s      = new Shader();
1145         Typeface t    = Typeface.DEFAULT;
1146         Xfermode x = new Xfermode();
1147 
1148         p.setColorFilter(c);
1149         p.setMaskFilter(m);
1150         p.setPathEffect(e);
1151         p.setShader(s);
1152         p.setTypeface(t);
1153         p.setXfermode(x);
1154         p.setFlags(Paint.ANTI_ALIAS_FLAG);
1155         assertEquals(c, p.getColorFilter());
1156         assertEquals(m, p.getMaskFilter());
1157         assertEquals(e, p.getPathEffect());
1158         assertEquals(s, p.getShader());
1159         assertEquals(t, p.getTypeface());
1160         assertEquals(x, p.getXfermode());
1161         assertEquals(Paint.ANTI_ALIAS_FLAG, p.getFlags());
1162 
1163         p.reset();
1164         assertEquals(Paint.FILTER_BITMAP_FLAG | Paint.DEV_KERN_TEXT_FLAG
1165                     | Paint.EMBEDDED_BITMAP_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG,
1166                     p.getFlags());
1167         assertEquals(null, p.getColorFilter());
1168         assertEquals(null, p.getMaskFilter());
1169         assertEquals(null, p.getPathEffect());
1170         assertEquals(null, p.getShader());
1171         assertEquals(null, p.getTypeface());
1172         assertEquals(null, p.getXfermode());
1173     }
1174 
1175     @Test
testSetLinearText()1176     public void testSetLinearText() {
1177         Paint p = new Paint();
1178 
1179         p.setLinearText(true);
1180         assertTrue(p.isLinearText());
1181 
1182         p.setLinearText(false);
1183         assertFalse(p.isLinearText());
1184     }
1185 
1186     @Test
testGetFontMetricsInt1()1187     public void testGetFontMetricsInt1() {
1188         Paint p = new Paint();
1189         Paint.FontMetricsInt fmi = new Paint.FontMetricsInt();
1190 
1191         for (Typeface typeface : TYPEFACES) {
1192             p.setTypeface(typeface);
1193 
1194             p.setTextSize(10);
1195             p.getFontMetricsInt(fmi);
1196             assertEquals(Math.round(p.ascent()), fmi.ascent);
1197             assertEquals(Math.round(p.descent()), fmi.descent);
1198 
1199             p.setTextSize(20);
1200             p.getFontMetricsInt(fmi);
1201             assertEquals(Math.round(p.ascent()), fmi.ascent);
1202             assertEquals(Math.round(p.descent()), fmi.descent);
1203         }
1204     }
1205 
1206     @Test
testGetFontMetricsInt2()1207     public void testGetFontMetricsInt2() {
1208         Paint p = new Paint();
1209         Paint.FontMetricsInt fmi;
1210 
1211         for (Typeface typeface : TYPEFACES) {
1212             p.setTypeface(typeface);
1213 
1214             p.setTextSize(10);
1215             fmi = p.getFontMetricsInt();
1216             assertEquals(Math.round(p.ascent()), fmi.ascent);
1217             assertEquals(Math.round(p.descent()), fmi.descent);
1218 
1219             p.setTextSize(20);
1220             fmi = p.getFontMetricsInt();
1221             assertEquals(Math.round(p.ascent()), fmi.ascent);
1222             assertEquals(Math.round(p.descent()), fmi.descent);
1223         }
1224     }
1225 
1226     @Test
testMeasureText()1227     public void testMeasureText() {
1228         String text = "HIJKLMN";
1229         char[] textChars = text.toCharArray();
1230         SpannedString textSpan = new SpannedString(text);
1231 
1232         Paint p = new Paint();
1233 
1234         // We need to turn off kerning in order to get accurate comparisons
1235         p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG);
1236 
1237         float[] widths = new float[text.length()];
1238         for (int i = 0; i < widths.length; i++) {
1239             widths[i] = p.measureText(text, i, i + 1);
1240         }
1241 
1242         float totalWidth = 0;
1243         for (int i = 0; i < widths.length; i++) {
1244             totalWidth += widths[i];
1245         }
1246 
1247         // Test measuring the widths of the entire text
1248         verifyMeasureText(text, textChars, textSpan, 0, 7, totalWidth);
1249 
1250         // Test measuring a substring of the text
1251         verifyMeasureText(text, textChars, textSpan, 1, 3, widths[1] + widths[2]);
1252 
1253         // Test measuring a substring of zero length.
1254         verifyMeasureText(text, textChars, textSpan, 3, 3, 0);
1255 
1256         // Test measuring substrings from the front and back
1257         verifyMeasureText(text, textChars, textSpan, 0, 2, widths[0] + widths[1]);
1258         verifyMeasureText(text, textChars, textSpan, 4, 7, widths[4] + widths[5] + widths[6]);
1259     }
1260 
1261     @Test
testMeasureTextContext()1262     public void testMeasureTextContext() {
1263        Paint p = new Paint();
1264        // Arabic LAM, which is different width depending on context
1265        String shortString = "\u0644";
1266        String longString = "\u0644\u0644\u0644";
1267        char[] longChars = longString.toCharArray();
1268        SpannedString longSpanned = new SpannedString(longString);
1269        float width = p.measureText(shortString);
1270        // Verify that measurement of substring is consistent no matter what surrounds it.
1271        verifyMeasureText(longString, longChars, longSpanned, 0, 1, width);
1272        verifyMeasureText(longString, longChars, longSpanned, 1, 2, width);
1273        verifyMeasureText(longString, longChars, longSpanned, 2, 3, width);
1274     }
1275 
1276     @Test
testMeasureTextWithLongText()1277     public void testMeasureTextWithLongText() {
1278         final int MAX_COUNT = 65535;
1279         char[] longText = new char[MAX_COUNT];
1280         for (int n = 0; n < MAX_COUNT; n++) {
1281             longText[n] = 'm';
1282         }
1283 
1284         Paint p = new Paint();
1285         float width = p.measureText(longText, 0, 1);
1286         assertEquals(true, width > 0);
1287     }
1288 
1289     /** 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)1290     private void verifyMeasureText(String text, char[] textChars, SpannedString textSpan,
1291             int start, int end, float expectedWidth) {
1292         Paint p = new Paint();
1293 
1294         // We need to turn off kerning in order to get accurate comparisons
1295         p.setFlags(p.getFlags() & ~Paint.DEV_KERN_TEXT_FLAG);
1296 
1297         int count = end - start;
1298         float[] widths = new float[] {-1, -1, -1, -1};
1299 
1300         String textSlice = text.substring(start, end);
1301         widths[0] = p.measureText(textSlice);
1302         widths[1] = p.measureText(textChars, start, count);
1303         widths[2] = p.measureText(textSpan, start, end);
1304         widths[3] = p.measureText(text, start, end);
1305 
1306         // Check that the widths returned by the overloads are the same.
1307         assertEquals(widths[0], widths[1], 0.0f);
1308         assertEquals(widths[1], widths[2], 0.0f);
1309         assertEquals(widths[2], widths[3], 0.0f);
1310         assertEquals(widths[3], expectedWidth, 0.0f);
1311     }
1312 
1313     @Test
testGetTextPathCharArray()1314     public void testGetTextPathCharArray() {
1315         Path path = new Path();
1316 
1317         assertTrue(path.isEmpty());
1318         new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 0, 7, 0, 0, path);
1319         assertFalse(path.isEmpty());
1320     }
1321 
1322     @Test(expected=RuntimeException.class)
testGetTextPathCharArrayNegativeIndex()1323     public void testGetTextPathCharArrayNegativeIndex() {
1324         new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, -2, 7, 0, 0,
1325                 new Path());
1326     }
1327 
1328     @Test(expected=RuntimeException.class)
testGetTextPathCharArrayNegativeCount()1329     public void testGetTextPathCharArrayNegativeCount() {
1330         new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 0, -3, 0, 0,
1331                 new Path());
1332     }
1333 
1334     @Test(expected=RuntimeException.class)
testGetTextPathCharArrayCountTooHigh()1335     public void testGetTextPathCharArrayCountTooHigh() {
1336         new Paint().getTextPath(new char[] {'H', 'I', 'J', 'K', 'L', 'M', 'N'}, 3, 7, 0, 0,
1337                 new Path());
1338     }
1339 
1340     @Test
testGetTextPathString()1341     public void testGetTextPathString() {
1342         Path path = new Path();
1343 
1344         assertTrue(path.isEmpty());
1345         new Paint().getTextPath("HIJKLMN", 0, 7, 0, 0, path);
1346         assertFalse(path.isEmpty());
1347     }
1348 
1349     @Test(expected=RuntimeException.class)
testGetTextPathStringNegativeIndex()1350     public void testGetTextPathStringNegativeIndex() {
1351         new Paint().getTextPath("HIJKLMN", -2, 7, 0, 0, new Path());
1352     }
1353 
1354     @Test(expected=RuntimeException.class)
testGetTextPathStringNegativeCount()1355     public void testGetTextPathStringNegativeCount() {
1356         new Paint().getTextPath("HIJKLMN", 0, -3, 0, 0, new Path());
1357     }
1358 
1359     @Test(expected=RuntimeException.class)
testGetTextPathStringStartTooHigh()1360     public void testGetTextPathStringStartTooHigh() {
1361         new Paint().getTextPath("HIJKLMN", 7, 3, 0, 0, new Path());
1362     }
1363 
1364     @Test(expected=RuntimeException.class)
testGetTextPathStringCountTooHigh()1365     public void testGetTextPathStringCountTooHigh() {
1366         new Paint().getTextPath("HIJKLMN", 3, 9, 0, 0, new Path());
1367     }
1368 
1369     @CddTest(requirement="3.8.13/C-1-2")
1370     @Test
testHasGlyph()1371     public void testHasGlyph() {
1372         Paint p = new Paint();
1373 
1374         // This method tests both the logic of hasGlyph and the validity of fonts present
1375         // on the device.
1376         assertTrue(p.hasGlyph("A"));
1377         assertFalse(p.hasGlyph("\uFFFE"));  // U+FFFE is guaranteed to be a noncharacter
1378 
1379         // Roboto 2 (the default typeface) does have an "fi" glyph and is mandated by CDD
1380         assertTrue(p.hasGlyph("fi"));
1381         assertFalse(p.hasGlyph("ab"));  // but it does not contain an "ab" glyph
1382         assertTrue(p.hasGlyph("\u02E5\u02E9"));  // IPA tone mark ligature
1383 
1384         // variation selectors
1385         assertFalse(p.hasGlyph("a\uFE0F"));
1386         assertFalse(p.hasGlyph("a\uDB40\uDDEF"));  // UTF-16 encoding of U+E01EF
1387         assertFalse(p.hasGlyph("\u2229\uFE0F"));  // base character is in mathematical symbol font
1388         // Note: U+FE0F is variation selection, unofficially reserved for emoji
1389 
1390         // regional indicator symbols
1391         assertTrue(p.hasGlyph("\uD83C\uDDEF\uD83C\uDDF5"));   // "JP" U+1F1EF U+1F1F5
1392         assertFalse(p.hasGlyph("\uD83C\uDDFF\uD83C\uDDFF"));  // "ZZ" U+1F1FF U+1F1FF
1393 
1394         // Mongolian, which is an optional font, but if present, should support FVS
1395         if (p.hasGlyph("\u182D")) {
1396             assertTrue(p.hasGlyph("\u182D\u180B"));
1397         }
1398 
1399         // Emoji with variation selector support for both text and emoji presentation
1400         assertTrue(p.hasGlyph("\u231A\uFE0E"));  // WATCH + VS15
1401         assertTrue(p.hasGlyph("\u231A\uFE0F"));  // WATCH + VS16
1402 
1403         // Unicode 7.0, 8.0, and 9.0 emoji should be supported.
1404         assertTrue(p.hasGlyph("\uD83D\uDD75"));  // SLEUTH OR SPY is introduced in Unicode 7.0
1405         assertTrue(p.hasGlyph("\uD83C\uDF2E"));  // TACO is introduced in Unicode 8.0
1406         assertTrue(p.hasGlyph("\uD83E\uDD33"));  // SELFIE is introduced in Unicode 9.0
1407 
1408         // We don't require gender-neutral emoji, but if present, results must be consistent
1409         // whether VS is present or not.
1410         assertTrue(p.hasGlyph("\uD83D\uDC69\u200D\u2695") ==  // WOMAN, ZWJ, STAFF OF AESCULAPIUS
1411                 p.hasGlyph("\uD83D\uDC69\u200D\u2695\uFE0F"));  // above + VS16
1412     }
1413 
1414     @Test
testGetRunAdvance()1415     public void testGetRunAdvance() {
1416         Paint p = new Paint();
1417         {
1418             // LTR
1419             String string = "abcdef";
1420             {
1421                 final float width = p.getRunAdvance(string, 0, string.length(), 0,
1422                         string.length(), false, 0);
1423                 assertEquals(0.0f, width, 0.0f);
1424             }
1425             {
1426                 for (int i = 0; i < string.length(); i++) {
1427                     final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
1428                             false, i);
1429                     assertEquals(0.0f, width, 0.0f);
1430                 }
1431             }
1432             {
1433                 final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0,
1434                         string.length(), false, string.length() / 2);
1435                 final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0,
1436                         string.length(), false, string.length());
1437                 assertTrue(widthToMid > 0.0f);
1438                 assertTrue(widthToTail > widthToMid);
1439             }
1440             {
1441                 final float widthFromHead = p.getRunAdvance(string, 0, string.length(), 0,
1442                         string.length(), false, string.length());
1443                 final float widthFromSecond = p.getRunAdvance(string, 1, string.length(), 0,
1444                         string.length(), false, string.length());
1445                 assertTrue(widthFromHead > widthFromSecond);
1446             }
1447             {
1448                 float width = 0.0f;
1449                 for (int i = 0; i < string.length(); i++) {
1450                     width += p.getRunAdvance(string, i, i + 1, 0, string.length(), false, i + 1);
1451                 }
1452                 final float totalWidth = p.getRunAdvance(string, 0, string.length(), 0,
1453                         string.length(), false, string.length());
1454                 assertEquals(totalWidth, width, 1.0f);
1455             }
1456         }
1457         {
1458             // RTL
1459             String string = "\u0644\u063A\u0629 \u0639\u0631\u0628\u064A\u0629"; // Arabic
1460             {
1461                 final float width = p.getRunAdvance(string, 0, string.length(), 0,
1462                         string.length(), true, 0);
1463                 assertEquals(0.0f, width, 0.0f);
1464             }
1465             {
1466                 for (int i = 0; i < string.length(); i++) {
1467                     final float width = p.getRunAdvance(string, i, i + 1, 0, string.length(),
1468                             true, i);
1469                     assertEquals(0.0f, width, 0.0f);
1470                 }
1471             }
1472             {
1473                 final float widthToMid = p.getRunAdvance(string, 0, string.length(), 0,
1474                         string.length(), true, string.length() / 2);
1475                 final float widthToTail = p.getRunAdvance(string, 0, string.length(), 0,
1476                         string.length(), true, string.length());
1477                 assertTrue(widthToMid > 0.0f);
1478                 assertTrue(widthToTail > widthToMid);
1479             }
1480             {
1481                 final float widthFromHead = p.getRunAdvance(string, 0, string.length(), 0,
1482                         string.length(), true, string.length());
1483                 final float widthFromSecond = p.getRunAdvance(string, 1, string.length(), 0,
1484                         string.length(), true, string.length());
1485                 assertTrue(widthFromHead > widthFromSecond);
1486             }
1487         }
1488     }
1489 
1490     @Test(expected=IllegalArgumentException.class)
testGetRunAdvanceNullCharSequence()1491     public void testGetRunAdvanceNullCharSequence() {
1492         new Paint().getRunAdvance((CharSequence) null, 0, 0, 0, 0, false, 0);
1493     }
1494 
1495     @Test(expected=IllegalArgumentException.class)
testGetRunAdvanceNullCharArray()1496     public void testGetRunAdvanceNullCharArray() {
1497         new Paint().getRunAdvance((char[]) null, 0, 0, 0, 0, false, 0);
1498     }
1499 
1500     @Test(expected=IndexOutOfBoundsException.class)
testGetRunAdvanceTextLengthLessThenContextEnd()1501     public void testGetRunAdvanceTextLengthLessThenContextEnd() {
1502         final String string = "abcde";
1503 
1504         // text length < context end
1505         new Paint().getRunAdvance(string, 0, string.length(), 0, string.length() + 1, false,
1506                 string.length());
1507     }
1508 
1509     @Test(expected=IndexOutOfBoundsException.class)
testGetRunAdvanceContextEndLessThanEnd()1510     public void testGetRunAdvanceContextEndLessThanEnd() {
1511         final String string = "abcde";
1512 
1513         // context end < end
1514         new Paint().getRunAdvance(string, 0, string.length(), 0, string.length() - 1, false, 0);
1515     }
1516 
1517     @Test(expected=IndexOutOfBoundsException.class)
testGetRunAdvanceEndLessThanOffset()1518     public void testGetRunAdvanceEndLessThanOffset() {
1519         final String string = "abcde";
1520 
1521         // end < offset
1522         new Paint().getRunAdvance(string, 0, string.length() - 1, 0, string.length() - 1, false,
1523                 string.length());
1524     }
1525 
1526     @Test(expected=IndexOutOfBoundsException.class)
testGetRunAdvanceOffsetLessThanStart()1527     public void testGetRunAdvanceOffsetLessThanStart() {
1528         final String string = "abcde";
1529 
1530         // offset < start
1531         new Paint().getRunAdvance(string, 1, string.length(), 1, string.length(), false, 0);
1532     }
1533 
1534     @Test(expected=IndexOutOfBoundsException.class)
testGetRunAdvanceStartLessThanContextStart()1535     public void testGetRunAdvanceStartLessThanContextStart() {
1536         final String string = "abcde";
1537 
1538         // start < context start
1539         new Paint().getRunAdvance(string, 0, string.length(), 1, string.length(), false, 1);
1540     }
1541 
1542     @Test(expected=IndexOutOfBoundsException.class)
testGetRunAdvanceContextStartNegative()1543     public void testGetRunAdvanceContextStartNegative() {
1544         final String string = "abcde";
1545 
1546         // context start < 0
1547         new Paint().getRunAdvance(string, 0, string.length(), -1, string.length(), false, 0);
1548     }
1549 
1550     @Test
testGetRunAdvance_nonzeroIndex()1551     public void testGetRunAdvance_nonzeroIndex() {
1552         Paint p = new Paint();
1553         final String text = "Android powers hundreds of millions of mobile " +
1554                 "devices in more than 190 countries around the world. It's" +
1555                 "the largest installed base of any mobile platform and" +
1556                 "growing fast—every day another million users power up their" +
1557                 "Android devices for the first time and start looking for" +
1558                 "apps, games, and other digital content.";
1559         // Test offset index does not affect width.
1560         final float widthAndroidFirst = p.getRunAdvance(
1561                 text, 0, 7, 0, text.length(), false, 7);
1562         final float widthAndroidSecond = p.getRunAdvance(
1563                 text, 215, 222, 0, text.length(), false, 222);
1564         assertTrue(Math.abs(widthAndroidFirst - widthAndroidSecond) < 1);
1565     }
1566 
1567     @Test
1568     public void testGetRunAdvance_glyphDependingContext() {
1569         Paint p = new Paint();
1570         // Test the context change the character shape.
1571         // First character should be isolated form because the context ends at index 1.
1572         final float isolatedFormWidth = p.getRunAdvance("\u0644\u0644", 0, 1, 0, 1, true, 1);
1573         // First character should be initial form because the context ends at index 2.
1574         final float initialFormWidth = p.getRunAdvance("\u0644\u0644", 0, 1, 0, 2, true, 1);
1575         assertTrue(isolatedFormWidth > initialFormWidth);
1576     }
1577 
1578     @Test
testGetRunAdvance_arabic()1579     public void testGetRunAdvance_arabic() {
1580         Paint p = new Paint();
1581         // Test total width is equals to sum of each character's width.
1582         // "What is Unicode?" in Arabic.
1583         final String text =
1584                 "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
1585                 "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
1586                 "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
1587                 "\u062F\u061F";
1588         final float totalWidth = p.getRunAdvance(
1589                 text, 0, text.length(), 0, text.length(), true, text.length());
1590         float sumOfCharactersWidth = 0;
1591         for (int i = 0; i < text.length(); i++) {
1592             sumOfCharactersWidth += p.getRunAdvance(
1593                     text, i, i + 1, 0, text.length(), true, i + 1);
1594         }
1595         assertTrue(Math.abs(totalWidth - sumOfCharactersWidth) < 1);
1596     }
1597 
1598     @Test
1599     public void testGetOffsetForAdvance() {
1600         Paint p = new Paint();
1601         {
1602             // LTR
1603             String string = "abcdef";
1604             {
1605                 for (int offset = 0; offset <= string.length(); ++offset) {
1606                     final float widthToOffset = p.getRunAdvance(string, 0,
1607                             string.length(), 0, string.length(), false, offset);
1608                     final int restoredOffset = p.getOffsetForAdvance(string, 0,
1609                             string.length(), 0, string.length(), false, widthToOffset);
1610                     assertEquals(offset, restoredOffset);
1611                 }
1612             }
1613             {
1614                 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0,
1615                         string.length(), false, -10.0f);
1616                 assertEquals(0, offset);
1617             }
1618             {
1619                 final float widthToEnd = p.getRunAdvance(string, 0, string.length(), 0,
1620                         string.length(), true, string.length());
1621                 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0,
1622                         string.length(), true, widthToEnd + 10.0f);
1623                 assertEquals(string.length(), offset);
1624             }
1625         }
1626         {
1627             // RTL
1628             String string = "\u0639\u0631\u0628\u0649"; // Arabic
1629             {
1630                 for (int offset = 0; offset <= string.length(); ++offset) {
1631                     final float widthToOffset = p.getRunAdvance(string, 0,
1632                             string.length(), 0, string.length(), true, offset);
1633                     final int restoredOffset = p.getOffsetForAdvance(string, 0,
1634                             string.length(), 0, string.length(), true, widthToOffset);
1635                     assertEquals(offset, restoredOffset);
1636                 }
1637             }
1638             {
1639                 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0,
1640                         string.length(), true, -10.0f);
1641                 assertEquals(0, offset);
1642             }
1643             {
1644                 final float widthToEnd = p.getRunAdvance(string, 0, string.length(), 0,
1645                         string.length(), true, string.length());
1646                 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0,
1647                         string.length(), true, widthToEnd + 10.0f);
1648                 assertEquals(string.length(), offset);
1649             }
1650         }
1651     }
1652 
1653     @Test(expected=IllegalArgumentException.class)
1654     public void testGetOffsetForAdvanceNullCharSequence() {
1655         new Paint().getOffsetForAdvance((CharSequence) null, 0, 0, 0, 0, false, 0.0f);
1656     }
1657 
1658     @Test(expected=IllegalArgumentException.class)
1659     public void testGetOffsetForAdvanceNullCharArray() {
1660         new Paint().getOffsetForAdvance((char[]) null, 0, 0, 0, 0, false, 0.0f);
1661     }
1662 
1663     @Test(expected=IndexOutOfBoundsException.class)
1664     public void testGetOffsetForAdvanceContextStartNegative() {
1665         final String string = "abcde";
1666 
1667         // context start < 0
1668         new Paint().getOffsetForAdvance(string, -1, string.length(), 0, string.length(), false,
1669                 0.0f);
1670     }
1671 
1672     @Test(expected=IndexOutOfBoundsException.class)
1673     public void testGetOffsetForAdvanceStartLessThanContextStart() {
1674         final String string = "abcde";
1675 
1676         // start < context start
1677         new Paint().getOffsetForAdvance(string, 0, string.length(), 1, string.length(), false,
1678                 0.0f);
1679     }
1680 
1681     @Test(expected=IndexOutOfBoundsException.class)
1682     public void testGetOffsetForAdvanceEndLessThanStart() {
1683         final String string = "abcde";
1684 
1685         // end < start
1686         new Paint().getOffsetForAdvance(string, 1, 0, 0, 0, false, 0);
1687     }
1688 
1689     @Test(expected=IndexOutOfBoundsException.class)
1690     public void testGetOffsetForAdvanceContextEndLessThanEnd() {
1691         final String string = "abcde";
1692 
1693         // context end < end
1694         new Paint().getOffsetForAdvance(string, 0, string.length(), 0, string.length() - 1, false,
1695                 0.0f);
1696     }
1697 
1698     @Test(expected=IndexOutOfBoundsException.class)
1699     public void testGetOffsetForAdvanceTextLengthLessThanContextEnd() {
1700         final String string = "abcde";
1701 
1702         // text length < context end
1703         new Paint().getOffsetForAdvance(string, 0, string.length(), 0, string.length() + 1, false,
1704                 0.0f);
1705     }
1706 
1707     @Test
1708     public void testGetOffsetForAdvance_graphemeCluster() {
1709         Paint p = new Paint();
1710         {
1711             String string = "\uD83C\uDF37"; // U+1F337: TULIP
1712             {
1713                 final float widthToOffset = p.getRunAdvance(string, 0,
1714                         string.length(), 0, string.length(), false, 1);
1715                 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0,
1716                         string.length(), false, widthToOffset);
1717                 assertFalse(1 == offset);
1718                 assertTrue(0 == offset || string.length() == offset);
1719             }
1720         }
1721         {
1722             String string = "\uD83C\uDDFA\uD83C\uDDF8"; // US flag
1723             {
1724                 final float widthToOffset = p.getRunAdvance(string, 0,
1725                         string.length(), 0, string.length(), false, 2);
1726                 final int offset = p.getOffsetForAdvance(string, 0, string.length(), 0,
1727                         string.length(), false, widthToOffset);
1728                 assertFalse(2 == offset);
1729                 assertTrue(0 == offset || string.length() == offset);
1730             }
1731             {
1732                 final float widthToOffset = p.getRunAdvance(string, 0, 2, 0, 2, false, 2);
1733                 final int offset = p.getOffsetForAdvance(string, 0, 2,
1734                         0, 2, false, widthToOffset);
1735                 assertEquals(2, offset);
1736             }
1737         }
1738         {
1739             // HANGUL CHOSEONG KIYEOK, HANGUL JUNGSEONG A, HANDUL JONGSEONG KIYEOK
1740             String string = "\u1100\u1161\u11A8";
1741             {
1742                 for (int offset = 0; offset <= string.length(); ++offset) {
1743                     final float widthToOffset = p.getRunAdvance(string, 0,
1744                             string.length(), 0, string.length(), false, offset);
1745                     final int offsetForAdvance = p.getOffsetForAdvance(string, 0, string.length(),
1746                             0, string.length(), false, widthToOffset);
1747                     assertTrue(0 == offsetForAdvance || string.length() == offsetForAdvance);
1748                 }
1749                 for (int offset = 0; offset <= string.length(); ++offset) {
1750                     final float widthToOffset = p.getRunAdvance(string, 0, offset, 0, offset,
1751                             false, offset);
1752                     final int offsetForAdvance = p.getOffsetForAdvance(string, 0, string.length(),
1753                             0, string.length(), false, widthToOffset);
1754                     assertTrue(0 == offsetForAdvance || string.length() == offsetForAdvance);
1755                 }
1756                 for (int offset = 0; offset <= string.length(); ++offset) {
1757                     final float widthToOffset = p.getRunAdvance(string, 0, offset, 0, offset,
1758                             false, offset);
1759                     final int offsetForAdvance = p.getOffsetForAdvance(string, 0, offset, 0,
1760                             offset, false, widthToOffset);
1761                     assertEquals(offset, offsetForAdvance);
1762                 }
1763             }
1764         }
1765     }
1766 
1767     @Test
1768     public void testElegantText() {
1769         final Paint p = new Paint();
1770         p.setTextSize(10);
1771         assertFalse(p.isElegantTextHeight());
1772         final float nonElegantTop = p.getFontMetrics().top;
1773         final float nonElegantBottom = p.getFontMetrics().bottom;
1774 
1775         p.setElegantTextHeight(true);
1776         assertTrue(p.isElegantTextHeight());
1777         final float elegantTop = p.getFontMetrics().top;
1778         final float elegantBottom = p.getFontMetrics().bottom;
1779 
1780         assertTrue(elegantTop < nonElegantTop);
1781         assertTrue(elegantBottom > nonElegantBottom);
1782 
1783         p.setElegantTextHeight(false);
1784         assertFalse(p.isElegantTextHeight());
1785     }
1786 
1787     @Test
1788     public void testEqualsForTextMeasurment() {
1789         Paint p1 = new Paint();
1790         Paint p2 = new Paint();
1791 
1792         assertTrue(p1.equalsForTextMeasurement(p2));
1793     }
1794 
1795     @Test
1796     public void testEqualsForTextMeasurment_textSize() {
1797         Paint p1 = new Paint();
1798         Paint p2 = new Paint();
1799 
1800         p1.setTextSize(p2.getTextSize() * 2.0f);
1801         assertFalse(p1.equalsForTextMeasurement(p2));
1802         p1.setTextSize(p2.getTextSize());
1803         assertTrue(p1.equalsForTextMeasurement(p2));
1804     }
1805 
1806     @Test
1807     public void testEqualsForTextMeasurment_textSkew() {
1808         Paint p1 = new Paint();
1809         Paint p2 = new Paint();
1810 
1811         p1.setTextSkewX(p2.getTextSkewX() + 2.0f);
1812         assertFalse(p1.equalsForTextMeasurement(p2));
1813         p1.setTextSkewX(p2.getTextSkewX());
1814         assertTrue(p1.equalsForTextMeasurement(p2));
1815     }
1816 
1817     @Test
1818     public void testEqualsForTextMeasurment_textScale() {
1819         Paint p1 = new Paint();
1820         Paint p2 = new Paint();
1821 
1822         p1.setTextScaleX(p2.getTextScaleX() * 2.0f);
1823         assertFalse(p1.equalsForTextMeasurement(p2));
1824         p1.setTextScaleX(p2.getTextScaleX());
1825         assertTrue(p1.equalsForTextMeasurement(p2));
1826     }
1827 
1828     @Test
1829     public void testEqualsForTextMeasurment_letterSpacing() {
1830         Paint p1 = new Paint();
1831         Paint p2 = new Paint();
1832 
1833         p1.setLetterSpacing(p2.getLetterSpacing() + 2.0f);
1834         assertFalse(p1.equalsForTextMeasurement(p2));
1835         p1.setLetterSpacing(p2.getLetterSpacing());
1836         assertTrue(p1.equalsForTextMeasurement(p2));
1837     }
1838 
1839     @Test
1840     public void testEqualsForTextMeasurment_localeList() {
1841         Paint p1 = new Paint();
1842         Paint p2 = new Paint();
1843 
1844         LocaleList enUS = LocaleList.forLanguageTags("en-US");
1845         LocaleList jaJP = LocaleList.forLanguageTags("ja-JP");
1846         LocaleList differentLocale = p2.getTextLocales().equals(enUS) ? jaJP : enUS;
1847         p1.setTextLocales(differentLocale);
1848         assertFalse(p1.equalsForTextMeasurement(p2));
1849         p1.setTextLocales(p2.getTextLocales());
1850         assertTrue(p1.equalsForTextMeasurement(p2));
1851     }
1852 
1853     @Test
1854     public void testEqualsForTextMeasurment_typeface() {
1855         Paint p1 = new Paint();
1856         Paint p2 = new Paint();
1857 
1858         p1.setTypeface(Typeface.DEFAULT);
1859         p2.setTypeface(Typeface.SERIF);
1860         assertFalse(p1.equalsForTextMeasurement(p2));
1861         p1.setTypeface(p2.getTypeface());
1862         assertTrue(p1.equalsForTextMeasurement(p2));
1863     }
1864 
1865     @Test
1866     public void testWordSpacing() {
1867         Paint p = new Paint();
1868         assertEquals(0.0f, p.getWordSpacing(), 0.0f);  // The default value is 0.
1869         p.setWordSpacing(10.0f);
1870         assertEquals(10.0f, p.getWordSpacing(), 0.0f);
1871         p.setWordSpacing(20.0f);
1872         assertEquals(20.0f, p.getWordSpacing(), 0.0f);
1873     }
1874 
1875     @Test
1876     public void testStrikeThruPosition_notCrashes() {
1877         // We can't expect any values of strike-through position in CTS.
1878         // Just make sure calling that method doesn't crash the app.
1879         new Paint().getStrikeThruPosition();
1880     }
1881 
1882     @Test
1883     public void testStrikeThruThickness_notCrashes() {
1884         // We can't expect any values of strike-through thickness in CTS.
1885         // Just make sure calling that method doesn't crash the app.
1886         new Paint().getStrikeThruThickness();
1887     }
1888 
1889     @Test
1890     public void testUnderlinePosition_notCrashes() {
1891         // We can't expect any values of underline position in CTS.
1892         // Just make sure calling that method doesn't crash the app.
1893         new Paint().getUnderlinePosition();
1894     }
1895 
1896     @Test
1897     public void testUnderlineThickness_notCrashes() {
1898         // We can't expect any values of underline thickness in CTS.
1899         // Just make sure calling that method doesn't crash the app.
1900         new Paint().getUnderlineThickness();
1901     }
1902 
1903     @Test
1904     public void testSetGetHyphenEdit() {
1905         Paint paint = new Paint();
1906 
1907         // By default, no hyphen edit is specified.
1908         assertEquals(Paint.START_HYPHEN_EDIT_NO_EDIT, paint.getStartHyphenEdit());
1909         assertEquals(Paint.END_HYPHEN_EDIT_NO_EDIT, paint.getEndHyphenEdit());
1910 
1911         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
1912         assertEquals(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN, paint.getStartHyphenEdit());
1913         assertEquals(Paint.END_HYPHEN_EDIT_NO_EDIT, paint.getEndHyphenEdit());
1914         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1915         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
1916 
1917         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
1918         assertEquals(Paint.START_HYPHEN_EDIT_NO_EDIT, paint.getStartHyphenEdit());
1919         assertEquals(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN, paint.getEndHyphenEdit());
1920         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1921         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
1922 
1923         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
1924         assertEquals(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN, paint.getStartHyphenEdit());
1925         assertEquals(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN, paint.getEndHyphenEdit());
1926         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1927         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
1928     }
1929 
1930     @Test
1931     public void testHyphenEdit() {
1932         final Paint paint = new Paint();
1933         final Context context = InstrumentationRegistry.getTargetContext();
1934         // The hyphenation.ttf font supports following characters
1935         // - U+0061..U+007A (a..z): The glyph has 1em width.
1936         // - U+2010 (HYPHEN): The glyph has 2em width.
1937         // - U+058A (ARMENIAN HYPHEN): The glyph has 3em width.
1938         // - U+05BE (MAQAF): The glyph has 4em width.
1939         // - U+1400 (UCAS HYPHEN): The glyph has 5em width.
1940         paint.setTypeface(Typeface.createFromAsset(context.getAssets(),
1941                   "fonts/layout/hyphenation.ttf"));
1942         paint.setTextSize(10.0f);  // Make 1em = 10px
1943 
1944         assertEquals(30.0f, paint.measureText("abc", 0, 3), 0.0f);
1945 
1946         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1947         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
1948         assertEquals(50.0f, paint.measureText("abc", 0, 3), 0.0f);  // "abc-" in visual.
1949         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1950         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1951 
1952         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_INSERT_HYPHEN);
1953         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_HYPHEN);
1954         assertEquals(70.0f, paint.measureText("abc", 0, 3), 0.0f);  // "-abc-" in visual.
1955         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1956         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1957 
1958         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1959         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_ARMENIAN_HYPHEN);
1960         assertEquals(60.0f, paint.measureText("abc", 0, 3), 0.0f);  // "abcU+058A" in visual.
1961         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1962         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1963 
1964         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1965         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_MAQAF);
1966         assertEquals(70.0f, paint.measureText("abc", 0, 3), 0.0f);  // "abcU+05BE" in visual.
1967         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1968         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1969 
1970         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1971         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_UCAS_HYPHEN);
1972         assertEquals(80.0f, paint.measureText("abc", 0, 3), 0.0f);  // "abcU+1400" in visual.
1973         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1974         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1975 
1976         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1977         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_INSERT_ZWJ_AND_HYPHEN);
1978         // "abcU+200D-" in visual. Note that ZWJ is zero width.
1979         assertEquals(50.0f, paint.measureText("abc", 0, 3), 0.0f);
1980         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1981         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1982 
1983         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1984         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_REPLACE_WITH_HYPHEN);
1985         assertEquals(40.0f, paint.measureText("abc", 0, 3), 0.0f);  // "ab-" in visual.
1986         paint.setStartHyphenEdit(Paint.START_HYPHEN_EDIT_NO_EDIT);
1987         paint.setEndHyphenEdit(Paint.END_HYPHEN_EDIT_NO_EDIT);
1988     }
1989 
1990     @Test
1991     public void testGetTextRunAdvances() {
1992         final Paint paint = new Paint();
1993         final Context context = InstrumentationRegistry.getTargetContext();
1994         paint.setTypeface(Typeface.createFromAsset(context.getAssets(),
1995                   "fonts/layout/textrunadvances.ttf"));
1996         // The textrunadvances.ttf font supports following characters
1997         // - U+0061 (a): The glyph has 3em width.
1998         // - U+0062..U+0065 (b..e): The glyph has 1em width.
1999         // - U+1F600 (GRINNING FACE): The glyph has 3em width.
2000         paint.setTextSize(10.0f);  // Make 1em = 10px
2001 
2002         final char[] chars = { 'a', 'b', 'a', 'b' };
2003         final float[] buffer = new float[32];
2004 
2005         assertEquals(80.0f,
2006                 paint.getTextRunAdvances(chars, 0, 4, 0, 4, false /* isRtl */, buffer, 0), 0.0f);
2007         assertEquals(30.0f, buffer[0], 0.0f);
2008         assertEquals(10.0f, buffer[1], 0.0f);
2009         assertEquals(30.0f, buffer[2], 0.0f);
2010         assertEquals(10.0f, buffer[3], 0.0f);
2011 
2012         // Output offset test
2013         assertEquals(40.0f,
2014                 paint.getTextRunAdvances(chars, 1, 2, 1, 2, false /* isRtl */, buffer, 5), 0.0f);
2015         assertEquals(10.0f, buffer[5], 0.0f);
2016         assertEquals(30.0f, buffer[6], 0.0f);
2017 
2018         // Surrogate pairs
2019         final char[] chars2 = Character.toChars(0x1F600);
2020         assertEquals(30.0f,
2021                 paint.getTextRunAdvances(chars2, 0, 2, 0, 2, false /* isRtl */, buffer, 0), 0.0f);
2022         assertEquals(30.0f, buffer[0], 0.0f);
2023         assertEquals(0.0f, buffer[1], 0.0f);
2024     }
2025 
2026     private int getTextRunCursor(String text, int offset, int cursorOpt) {
2027         final int contextStart = 0;
2028         final int contextEnd = text.length();
2029         final int contextCount = text.length();
2030         Paint p = new Paint();
2031         int result = p.getTextRunCursor(new StringBuilder(text), // as a CharSequence
2032                 contextStart, contextEnd, false /* isRtl */, offset, cursorOpt);
2033         assertEquals(result, p.getTextRunCursor(text.toCharArray(),
2034                 contextStart, contextCount, false /* isRtl */, offset, cursorOpt));
2035         assertEquals(result, p.getTextRunCursor(new StringBuilder(text),  // as a CharSequence
2036                 contextStart, contextCount, true /* isRtl */, offset, cursorOpt));
2037         assertEquals(result, p.getTextRunCursor(text.toCharArray(),
2038                 contextStart, contextCount, true, offset, cursorOpt));
2039         return result;
2040     }
2041 
2042     @Test
2043     public void testGetRunCursor_CURSOR_AFTER() {
2044         assertEquals(1, getTextRunCursor("abc", 0, CURSOR_AFTER));
2045         assertEquals(2, getTextRunCursor("abc", 1, CURSOR_AFTER));
2046         assertEquals(3, getTextRunCursor("abc", 2, CURSOR_AFTER));
2047         assertEquals(3, getTextRunCursor("abc", 3, CURSOR_AFTER));
2048 
2049         // Surrogate pairs
2050         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 0, CURSOR_AFTER));
2051         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 1, CURSOR_AFTER));
2052         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 2, CURSOR_AFTER));
2053         assertEquals(4, getTextRunCursor("a\uD83D\uDE00c", 3, CURSOR_AFTER));
2054         assertEquals(4, getTextRunCursor("a\uD83D\uDE00c", 4, CURSOR_AFTER));
2055 
2056         // Combining marks
2057         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 0, CURSOR_AFTER));
2058         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 1, CURSOR_AFTER));
2059         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 2, CURSOR_AFTER));
2060         assertEquals(4, getTextRunCursor("a\u0061\u0302c", 3, CURSOR_AFTER));
2061         assertEquals(4, getTextRunCursor("a\u0061\u0302c", 4, CURSOR_AFTER));
2062     }
2063 
2064     @Test
2065     public void testGetRunCursor_CURSOR_AT() {
2066         assertEquals(0, getTextRunCursor("abc", 0, CURSOR_AT));
2067         assertEquals(1, getTextRunCursor("abc", 1, CURSOR_AT));
2068         assertEquals(2, getTextRunCursor("abc", 2, CURSOR_AT));
2069         assertEquals(3, getTextRunCursor("abc", 3, CURSOR_AT));
2070 
2071         // Surrogate pairs
2072         assertEquals(0, getTextRunCursor("a\uD83D\uDE00c", 0, CURSOR_AT));
2073         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 1, CURSOR_AT));
2074         assertEquals(-1, getTextRunCursor("a\uD83D\uDE00c", 2, CURSOR_AT));
2075         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 3, CURSOR_AT));
2076         assertEquals(4, getTextRunCursor("a\uD83D\uDE00c", 4, CURSOR_AT));
2077 
2078         // Combining marks
2079         assertEquals(0, getTextRunCursor("a\u0061\u0302c", 0, CURSOR_AT));
2080         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 1, CURSOR_AT));
2081         assertEquals(-1, getTextRunCursor("a\u0061\u0302c", 2, CURSOR_AT));
2082         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 3, CURSOR_AT));
2083         assertEquals(4, getTextRunCursor("a\u0061\u0302c", 4, CURSOR_AT));
2084     }
2085 
2086     @Test
2087     public void testGetRunCursor_CURSOR_AT_OR_AFTER() {
2088         assertEquals(0, getTextRunCursor("abc", 0, CURSOR_AT_OR_AFTER));
2089         assertEquals(1, getTextRunCursor("abc", 1, CURSOR_AT_OR_AFTER));
2090         assertEquals(2, getTextRunCursor("abc", 2, CURSOR_AT_OR_AFTER));
2091         assertEquals(3, getTextRunCursor("abc", 3, CURSOR_AT_OR_AFTER));
2092 
2093         // Surrogate pairs
2094         assertEquals(0, getTextRunCursor("a\uD83D\uDE00c", 0, CURSOR_AT_OR_AFTER));
2095         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 1, CURSOR_AT_OR_AFTER));
2096         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 2, CURSOR_AT_OR_AFTER));
2097         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 3, CURSOR_AT_OR_AFTER));
2098         assertEquals(4, getTextRunCursor("a\uD83D\uDE00c", 4, CURSOR_AT_OR_AFTER));
2099 
2100         // Combining marks
2101         assertEquals(0, getTextRunCursor("a\u0061\u0302c", 0, CURSOR_AT_OR_AFTER));
2102         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 1, CURSOR_AT_OR_AFTER));
2103         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 2, CURSOR_AT_OR_AFTER));
2104         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 3, CURSOR_AT_OR_AFTER));
2105         assertEquals(4, getTextRunCursor("a\u0061\u0302c", 4, CURSOR_AT_OR_AFTER));
2106     }
2107 
2108     @Test
2109     public void testGetRunCursor_CURSOR_AT_OR_BEFORE() {
2110         assertEquals(0, getTextRunCursor("abc", 0, CURSOR_AT_OR_BEFORE));
2111         assertEquals(1, getTextRunCursor("abc", 1, CURSOR_AT_OR_BEFORE));
2112         assertEquals(2, getTextRunCursor("abc", 2, CURSOR_AT_OR_BEFORE));
2113         assertEquals(3, getTextRunCursor("abc", 3, CURSOR_AT_OR_BEFORE));
2114 
2115         // Surrogate pairs
2116         assertEquals(0, getTextRunCursor("a\uD83D\uDE00c", 0, CURSOR_AT_OR_BEFORE));
2117         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 1, CURSOR_AT_OR_BEFORE));
2118         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 2, CURSOR_AT_OR_BEFORE));
2119         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 3, CURSOR_AT_OR_BEFORE));
2120         assertEquals(4, getTextRunCursor("a\uD83D\uDE00c", 4, CURSOR_AT_OR_BEFORE));
2121 
2122         // Combining marks
2123         assertEquals(0, getTextRunCursor("a\u0061\u0302c", 0, CURSOR_AT_OR_BEFORE));
2124         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 1, CURSOR_AT_OR_BEFORE));
2125         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 2, CURSOR_AT_OR_BEFORE));
2126         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 3, CURSOR_AT_OR_BEFORE));
2127         assertEquals(4, getTextRunCursor("a\u0061\u0302c", 4, CURSOR_AT_OR_BEFORE));
2128     }
2129 
2130     @Test
2131     public void testGetRunCursor_CURSOR_BEFORE() {
2132         assertEquals(0, getTextRunCursor("abc", 0, CURSOR_BEFORE));
2133         assertEquals(0, getTextRunCursor("abc", 1, CURSOR_BEFORE));
2134         assertEquals(1, getTextRunCursor("abc", 2, CURSOR_BEFORE));
2135         assertEquals(2, getTextRunCursor("abc", 3, CURSOR_BEFORE));
2136 
2137         // Surrogate pairs
2138         assertEquals(0, getTextRunCursor("a\uD83D\uDE00c", 0, CURSOR_BEFORE));
2139         assertEquals(0, getTextRunCursor("a\uD83D\uDE00c", 1, CURSOR_BEFORE));
2140         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 2, CURSOR_BEFORE));
2141         assertEquals(1, getTextRunCursor("a\uD83D\uDE00c", 3, CURSOR_BEFORE));
2142         assertEquals(3, getTextRunCursor("a\uD83D\uDE00c", 4, CURSOR_BEFORE));
2143 
2144         // Combining marks
2145         assertEquals(0, getTextRunCursor("a\u0061\u0302c", 0, CURSOR_BEFORE));
2146         assertEquals(0, getTextRunCursor("a\u0061\u0302c", 1, CURSOR_BEFORE));
2147         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 2, CURSOR_BEFORE));
2148         assertEquals(1, getTextRunCursor("a\u0061\u0302c", 3, CURSOR_BEFORE));
2149         assertEquals(3, getTextRunCursor("a\u0061\u0302c", 4, CURSOR_BEFORE));
2150     }
2151 
2152     @Test
2153     public void testGetBlendModeFromPorterDuffMode() {
2154         Paint p = new Paint();
2155         PorterDuff.Mode[] porterDuffModes = PorterDuff.Mode.values();
2156         for (PorterDuff.Mode mode : porterDuffModes) {
2157             p.setXfermode(new PorterDuffXfermode(mode));
2158             assertEquals(getBlendModeFromPorterDuffMode(mode), p.getBlendMode());
2159         }
2160 
2161     }
2162 
2163     private BlendMode getBlendModeFromPorterDuffMode(PorterDuff.Mode mode) {
2164         switch (mode) {
2165             case CLEAR: return BlendMode.CLEAR;
2166             case SRC: return BlendMode.SRC;
2167             case DST: return BlendMode.DST;
2168             case SRC_OVER: return BlendMode.SRC_OVER;
2169             case DST_OVER: return BlendMode.DST_OVER;
2170             case SRC_IN: return BlendMode.SRC_IN;
2171             case DST_IN: return BlendMode.DST_IN;
2172             case SRC_OUT: return BlendMode.SRC_OUT;
2173             case DST_OUT: return BlendMode.DST_OUT;
2174             case SRC_ATOP: return BlendMode.SRC_ATOP;
2175             case DST_ATOP: return BlendMode.DST_ATOP;
2176             case XOR: return BlendMode.XOR;
2177             case DARKEN: return BlendMode.DARKEN;
2178             case LIGHTEN: return BlendMode.LIGHTEN;
2179              // The odd one out, see b/73224934. PorterDuff.Mode.MULTIPLY was improperly mapped
2180             // to Skia's modulate
2181             case MULTIPLY: return BlendMode.MODULATE;
2182             case SCREEN: return BlendMode.SCREEN;
2183             case ADD: return BlendMode.PLUS;
2184             case OVERLAY: return BlendMode.OVERLAY;
2185             default: throw new IllegalArgumentException("Unknown PorterDuffmode: " + mode);
2186         }
2187     }
2188 
2189     private void testColorLongs(String methodName, BiConsumer<Paint, Long> setColor,
2190                                 Function<Paint, Integer> getColor,
2191                                 Function<Paint, Long> getColorLong) {
2192         // Pack SRGB colors into ColorLongs
2193         for (int color : new int[]{ Color.RED, Color.BLUE, Color.GREEN, Color.BLACK,
2194                 Color.WHITE, Color.TRANSPARENT }) {
2195             final Paint p = new Paint();
2196             final long longColor = Color.pack(color);
2197             setColor.accept(p, longColor);
2198 
2199             assertEquals(color, getColor.apply(p).intValue());
2200             assertEquals(longColor, getColorLong.apply(p).longValue());
2201         }
2202 
2203         // Arbitrary colors in various ColorSpaces
2204         for (int srgbColor : new int[]{ Color.argb(1.0f, .5f, .5f, .5f),
2205                                         Color.argb(1.0f, .3f, .6f, .9f),
2206                                         Color.argb(0.5f, .2f, .8f, .7f) }) {
2207             for (ColorSpace.Named e : ColorSpace.Named.values()) {
2208                 ColorSpace cs = ColorSpace.get(e);
2209                 if (cs.getModel() != ColorSpace.Model.RGB) {
2210                     continue;
2211                 }
2212                 if (((ColorSpace.Rgb) cs).getTransferParameters() == null) {
2213                     continue;
2214                 }
2215 
2216                 final long longColor = Color.convert(srgbColor, cs);
2217                 Paint p = new Paint();
2218                 setColor.accept(p, longColor);
2219                 assertEquals(longColor, getColorLong.apply(p).longValue());
2220 
2221                 // These tolerances were chosen by trial and error. It is expected that
2222                 // some conversions do not round-trip perfectly.
2223                 int tolerance = 0;
2224                 if (cs.equals(ColorSpace.get(ColorSpace.Named.SMPTE_C))) {
2225                     tolerance = 2;
2226                 }
2227                 int color = getColor.apply(p);
2228                 ColorUtils.verifyColor("Paint#" + methodName + " mismatch for " + cs, srgbColor,
2229                         color, tolerance);
2230             }
2231         }
2232     }
2233 
2234     @Test
2235     public void testSetColorLong() {
2236         testColorLongs("setColor", (p, c) -> p.setColor(c), (p) -> p.getColor(),
2237                 (p) -> p.getColorLong());
2238     }
2239 
2240     @Test(expected = IllegalArgumentException.class)
2241     public void testSetColorXYZ() {
2242         Paint p = new Paint();
2243         p.setColor(Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_XYZ)));
2244     }
2245 
2246     @Test(expected = IllegalArgumentException.class)
2247     public void testSetColorLAB() {
2248         Paint p = new Paint();
2249         p.setColor(Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_LAB)));
2250     }
2251 
2252     @Test(expected = IllegalArgumentException.class)
2253     public void testSetColorUnknown() {
2254         Paint p = new Paint();
2255         p.setColor(-1L);
2256     }
2257 
2258     @Test
2259     public void testSetShadowLayerLong() {
2260         testColorLongs("setShadowLayer", (p, c) -> p.setShadowLayer(10.0f, 1.0f, 1.0f, c),
2261                 (p) -> p.getShadowLayerColor(), (p) -> p.getShadowLayerColorLong());
2262     }
2263 
2264     @Test(expected = IllegalArgumentException.class)
testSetShadowLayerXYZ()2265     public void testSetShadowLayerXYZ() {
2266         Paint p = new Paint();
2267         p.setShadowLayer(10.0f, 1.0f, 1.0f,
2268                 Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_XYZ)));
2269     }
2270 
2271     @Test(expected = IllegalArgumentException.class)
testSetShadowLayerLAB()2272     public void testSetShadowLayerLAB() {
2273         Paint p = new Paint();
2274         p.setShadowLayer(10.0f, 1.0f, 1.0f,
2275                 Color.convert(Color.BLUE, ColorSpace.get(ColorSpace.Named.CIE_LAB)));
2276     }
2277 
2278     @Test(expected = IllegalArgumentException.class)
testSetShadowLayerUnknown()2279     public void testSetShadowLayerUnknown() {
2280         Paint p = new Paint();
2281         p.setShadowLayer(10.0f, 1.0f, 1.0f, -1L);
2282     }
2283 }
2284