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