Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 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.text.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotNull;
     22 import static org.junit.Assert.assertTrue;
     23 
     24 import android.content.Context;
     25 import android.content.res.AssetManager;
     26 import android.graphics.Bitmap;
     27 import android.graphics.Canvas;
     28 import android.graphics.Paint;
     29 import android.graphics.Rect;
     30 import android.graphics.Typeface;
     31 import android.graphics.text.MeasuredText;
     32 import android.text.PrecomputedText;
     33 import android.text.SpannableStringBuilder;
     34 import android.text.TextPaint;
     35 
     36 import androidx.test.InstrumentationRegistry;
     37 import androidx.test.filters.SmallTest;
     38 import androidx.test.runner.AndroidJUnit4;
     39 
     40 import org.junit.BeforeClass;
     41 import org.junit.Test;
     42 import org.junit.runner.RunWith;
     43 
     44 @SmallTest
     45 @RunWith(AndroidJUnit4.class)
     46 public class MeasuredTextTest {
     47     private static Paint sPaint;
     48 
     49     @BeforeClass
     50     public static void classSetUp() {
     51         sPaint = new Paint();
     52         Context context = InstrumentationRegistry.getTargetContext();
     53         AssetManager am = context.getAssets();
     54         Typeface tf = new Typeface.Builder(am, "fonts/layout/linebreak.ttf").build();
     55         sPaint.setTypeface(tf);
     56         sPaint.setTextSize(10.0f);  // Make 1em = 10px
     57     }
     58 
     59     @Test
     60     public void testBuilder() {
     61         String text = "Hello, World";
     62         new MeasuredText.Builder(text.toCharArray())
     63                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
     64     }
     65 
     66     @Test
     67     public void testBuilder_FromExistingMeasuredText() {
     68         String text = "Hello, World";
     69         final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
     70                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
     71         assertNotNull(new MeasuredText.Builder(mt)
     72                 .appendStyleRun(sPaint, text.length(), true /* isRtl */).build());
     73     }
     74 
     75     @Test(expected = IllegalArgumentException.class)
     76     public void testBuilder_FromExistingMeasuredText_differentLayoutParam() {
     77         String text = "Hello, World";
     78         final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
     79                 .setComputeLayout(false)
     80                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
     81         new MeasuredText.Builder(mt)
     82                 .appendStyleRun(sPaint, text.length(), true /* isRtl */).build();
     83     }
     84 
     85     @Test(expected = IllegalArgumentException.class)
     86     public void testBuilder_FromExistingMeasuredText_differentHyphenationParam() {
     87         String text = "Hello, World";
     88         final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
     89                 .setComputeHyphenation(false)
     90                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
     91         new MeasuredText.Builder(mt)
     92                 .setComputeHyphenation(true)
     93                 .appendStyleRun(sPaint, text.length(), true /* isRtl */).build();
     94     }
     95 
     96     @Test(expected = NullPointerException.class)
     97     public void testBuilder_NullText() {
     98         new MeasuredText.Builder((char[]) null);
     99     }
    100 
    101     @Test(expected = NullPointerException.class)
    102     public void testBuilder_NullMeasuredText() {
    103         new MeasuredText.Builder((MeasuredText) null);
    104     }
    105 
    106     @Test(expected = NullPointerException.class)
    107     public void testBuilder_NullPaint() {
    108         String text = "Hello, World";
    109         new MeasuredText.Builder(text.toCharArray()).appendStyleRun(null, text.length(), false);
    110     }
    111 
    112     @Test
    113     public void testGetWidth() {
    114         String text = "Hello, World";
    115         MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
    116                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
    117         assertEquals(0.0f, mt.getWidth(0, 0), 0.0f);
    118         assertEquals(10.0f, mt.getWidth(0, 1), 0.0f);
    119         assertEquals(20.0f, mt.getWidth(0, 2), 0.0f);
    120         assertEquals(10.0f, mt.getWidth(1, 2), 0.0f);
    121         assertEquals(20.0f, mt.getWidth(1, 3), 0.0f);
    122     }
    123 
    124     @Test(expected = IllegalArgumentException.class)
    125     public void testGetWidth_StartSmallerThanZero() {
    126         String text = "Hello, World";
    127         new MeasuredText.Builder(text.toCharArray())
    128                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    129                 .build()
    130                 .getWidth(-1, 0);
    131     }
    132 
    133     @Test(expected = IllegalArgumentException.class)
    134     public void testGetWidth_StartLargerThanLength() {
    135         String text = "Hello, World";
    136         new MeasuredText.Builder(text.toCharArray())
    137                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    138                 .build()
    139                 .getWidth(text.length() + 1, 0);
    140     }
    141 
    142     @Test(expected = IllegalArgumentException.class)
    143     public void testGetWidth_EndSmallerThanZero() {
    144         String text = "Hello, World";
    145         new MeasuredText.Builder(text.toCharArray())
    146                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    147                 .build()
    148                 .getWidth(0, -1);
    149     }
    150 
    151     @Test(expected = IllegalArgumentException.class)
    152     public void testGetWidth_EndLargerThanLength() {
    153         String text = "Hello, World";
    154         new MeasuredText.Builder(text.toCharArray())
    155                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    156                 .build()
    157                 .getWidth(0, text.length() + 1);
    158     }
    159 
    160     @Test(expected = IllegalArgumentException.class)
    161     public void testGetWidth_StartLargerThanEnd() {
    162         String text = "Hello, World";
    163         new MeasuredText.Builder(text.toCharArray())
    164                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    165                 .build()
    166                 .getWidth(1, 0);
    167     }
    168 
    169     @Test
    170     public void testGetBounds() {
    171         String text = "Hello, World";
    172         MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
    173                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
    174         final Rect emptyRect = new Rect(0, 0, 0, 0);
    175         final Rect singleCharRect = new Rect(0, -10, 10, 0);
    176         final Rect twoCharRect = new Rect(0, -10, 20, 0);
    177         Rect out = new Rect();
    178         mt.getBounds(0, 0, out);
    179         assertEquals(emptyRect, out);
    180         mt.getBounds(0, 1, out);
    181         assertEquals(singleCharRect, out);
    182         mt.getBounds(0, 2, out);
    183         assertEquals(twoCharRect, out);
    184         mt.getBounds(1, 2, out);
    185         assertEquals(singleCharRect, out);
    186         mt.getBounds(1, 3, out);
    187         assertEquals(twoCharRect, out);
    188     }
    189 
    190     @Test(expected = IllegalArgumentException.class)
    191     public void testGetBounds_StartSmallerThanZero() {
    192         String text = "Hello, World";
    193         Rect rect = new Rect();
    194         new MeasuredText.Builder(text.toCharArray())
    195                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    196                 .build()
    197                 .getBounds(-1, 0, rect);
    198     }
    199 
    200     @Test(expected = IllegalArgumentException.class)
    201     public void testGetBounds_StartLargerThanLength() {
    202         String text = "Hello, World";
    203         Rect rect = new Rect();
    204         new MeasuredText.Builder(text.toCharArray())
    205                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    206                 .build()
    207                 .getBounds(text.length() + 1, 0, rect);
    208     }
    209 
    210     @Test(expected = IllegalArgumentException.class)
    211     public void testGetBounds_EndSmallerThanZero() {
    212         String text = "Hello, World";
    213         Rect rect = new Rect();
    214         new MeasuredText.Builder(text.toCharArray())
    215                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    216                 .build()
    217                 .getBounds(0, -1, rect);
    218     }
    219 
    220     @Test(expected = IllegalArgumentException.class)
    221     public void testGetBounds_EndLargerThanLength() {
    222         String text = "Hello, World";
    223         Rect rect = new Rect();
    224         new MeasuredText.Builder(text.toCharArray())
    225                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    226                 .build()
    227                 .getBounds(0, text.length() + 1, rect);
    228     }
    229 
    230     @Test(expected = IllegalArgumentException.class)
    231     public void testGetBounds_StartLargerThanEnd() {
    232         String text = "Hello, World";
    233         Rect rect = new Rect();
    234         new MeasuredText.Builder(text.toCharArray())
    235                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    236                 .build()
    237                 .getBounds(1, 0, rect);
    238     }
    239 
    240     @Test(expected = NullPointerException.class)
    241     public void testGetBounds_NullRect() {
    242         String text = "Hello, World";
    243         Rect rect = new Rect();
    244         new MeasuredText.Builder(text.toCharArray())
    245                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    246                 .build()
    247                 .getBounds(0, 0, null);
    248     }
    249 
    250     @Test
    251     public void testGetCharWidthAt() {
    252         String text = "Hello, World";
    253         MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
    254                 .appendStyleRun(sPaint, text.length(), false /* isRtl */).build();
    255         assertEquals(10.0f, mt.getCharWidthAt(0), 0.0f);
    256         assertEquals(10.0f, mt.getCharWidthAt(1), 0.0f);
    257         assertEquals(10.0f, mt.getCharWidthAt(2), 0.0f);
    258         assertEquals(10.0f, mt.getCharWidthAt(3), 0.0f);
    259     }
    260 
    261     @Test(expected = IllegalArgumentException.class)
    262     public void testGetCharWidthAt_OffsetSmallerThanZero() {
    263         String text = "Hello, World";
    264         new MeasuredText.Builder(text.toCharArray())
    265                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    266                 .build()
    267                 .getCharWidthAt(-1);
    268     }
    269 
    270     @Test(expected = IllegalArgumentException.class)
    271     public void testGetCharWidthAt_OffsetLargerThanLength() {
    272         String text = "Hello, World";
    273         new MeasuredText.Builder(text.toCharArray())
    274                 .appendStyleRun(sPaint, text.length(), false /* isRtl */)
    275                 .build()
    276                 .getCharWidthAt(text.length());
    277     }
    278 
    279     @Test(expected = IllegalStateException.class)
    280     public void testBuilder_reuse_throw_exception() {
    281         String text = "Hello, World";
    282         MeasuredText.Builder b = new MeasuredText.Builder(text.toCharArray())
    283                 .appendStyleRun(sPaint, text.length(), false /* isRtl */);
    284         b.build();
    285         b.build();
    286     }
    287 
    288     @Test(expected = IllegalArgumentException.class)
    289     public void testBuilder_tooSmallLengthStyle() {
    290         String text = "Hello, World";
    291         new MeasuredText.Builder(text.toCharArray()).appendStyleRun(sPaint, -1, false /* isRtl */);
    292     }
    293 
    294     @Test(expected = IllegalArgumentException.class)
    295     public void testBuilder_tooLargeLengthStyle() {
    296         String text = "Hello, World";
    297         new MeasuredText.Builder(text.toCharArray())
    298                 .appendStyleRun(sPaint, text.length() + 1, false /* isRtl */);
    299     }
    300 
    301     @Test(expected = IllegalArgumentException.class)
    302     public void testBuilder_tooSmallLengthReplacement() {
    303         String text = "Hello, World";
    304         new MeasuredText.Builder(text.toCharArray()).appendReplacementRun(sPaint, -1, 1.0f);
    305     }
    306 
    307     @Test(expected = IllegalArgumentException.class)
    308     public void testBuilder_tooLargeLengthReplacement() {
    309         String text = "Hello, World";
    310         new MeasuredText.Builder(text.toCharArray())
    311                 .appendReplacementRun(sPaint, text.length() + 1, 1.0f);
    312     }
    313 
    314     @Test(expected = IllegalStateException.class)
    315     public void testBuilder_notEnoughStyle() {
    316         String text = "Hello, World";
    317         new MeasuredText.Builder(text.toCharArray())
    318                 .appendReplacementRun(sPaint, text.length() - 1, 1.0f).build();
    319     }
    320 
    321     public Bitmap makeBitmapFromSsb(String text, TextPaint paint, boolean isRtl) {
    322         // drawTetRun is not aware of multiple style text.
    323         final SpannableStringBuilder ssb = new SpannableStringBuilder(text);
    324         final Bitmap ssbBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    325         final Canvas ssbCanvas = new Canvas(ssbBitmap);
    326         ssbCanvas.save();
    327         ssbCanvas.translate(0, 0);
    328         ssbCanvas.drawTextRun(ssb, 0, ssb.length(), 0, ssb.length(),
    329                 0.0f /* x */, 240.0f /* y */, isRtl, paint);
    330         ssbCanvas.restore();
    331         return ssbBitmap;
    332     }
    333 
    334     public Bitmap makeBitmapFromMtWithSamePaint(String text, TextPaint paint, boolean isRtl) {
    335         // MeasuredText uses measured result if the given paint is equal to the applied one.
    336         final MeasuredText mt = new MeasuredText.Builder(text.toCharArray())
    337                 .appendStyleRun(paint, text.length(), isRtl)
    338                 .build();
    339         final Bitmap mtBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    340         final Canvas mtCanvas = new Canvas(mtBitmap);
    341         mtCanvas.save();
    342         mtCanvas.translate(0, 0);
    343         mtCanvas.drawTextRun(mt, 0, text.length(), 0, text.length(),
    344                 0.0f /* x */, 240.0f /* y */, isRtl, paint);
    345         mtCanvas.restore();
    346         return mtBitmap;
    347     }
    348 
    349     public Bitmap makeBitmapFromMtWithDifferentPaint(String text, TextPaint paint, boolean isRtl) {
    350         // If different paint is provided when drawing, MeasuredText discards the measured result
    351         // and recompute immediately. Thus the final output must be the same with given one.
    352         final MeasuredText mt2 = new MeasuredText.Builder(text.toCharArray())
    353                 .appendStyleRun(new Paint(), text.length(), isRtl)
    354                 .build();
    355         final Bitmap mt2Bitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    356         final Canvas mt2Canvas = new Canvas(mt2Bitmap);
    357         mt2Canvas.save();
    358         mt2Canvas.translate(0, 0);
    359         mt2Canvas.drawTextRun(mt2, 0, text.length(), 0, text.length(),
    360                 0.0f /* x */, 240.0f /* y */, isRtl, paint);
    361         mt2Canvas.restore();
    362         return mt2Bitmap;
    363     }
    364 
    365     public Bitmap makeBitmapFromPct(String text, TextPaint paint, boolean isRtl) {
    366         final PrecomputedText pct = PrecomputedText.create(
    367                 text, new PrecomputedText.Params.Builder(paint).build());
    368         final Bitmap pctBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    369         final Canvas pctCanvas = new Canvas(pctBitmap);
    370         pctCanvas.save();
    371         pctCanvas.translate(0, 0);
    372         pctCanvas.drawTextRun(pct, 0, text.length(), 0, text.length(),
    373                 0.0f /* x */, 240.0f /* y */, isRtl, paint);
    374         pctCanvas.restore();
    375         return pctBitmap;
    376     }
    377 
    378     @Test
    379     public void testCanvasDrawTextRun_sameOutputTestForLatinText() {
    380         final TextPaint paint = new TextPaint();
    381         paint.setTextSize(30.0f);
    382 
    383         final String text = "Hello, World";
    384 
    385         final Bitmap blankBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    386         final Bitmap ssbBitmap = makeBitmapFromSsb(text, paint, false);
    387         assertFalse(blankBitmap.sameAs(ssbBitmap));
    388 
    389         assertTrue(ssbBitmap.sameAs(makeBitmapFromMtWithSamePaint(text, paint, false)));
    390         assertTrue(ssbBitmap.sameAs(makeBitmapFromMtWithDifferentPaint(text, paint, false)));
    391         assertTrue(ssbBitmap.sameAs(makeBitmapFromPct(text, paint, false)));
    392     }
    393 
    394     @Test
    395     public void testCanvasDrawTextRun_sameOutputTestForCJKText() {
    396         final TextPaint paint = new TextPaint();
    397         paint.setTextSize(30.0f);
    398 
    399         final String text = "\u3042\u3044\u3046\u3048\u304A";
    400 
    401         final Bitmap blankBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    402         final Bitmap ssbBitmap = makeBitmapFromSsb(text, paint, false);
    403         assertFalse(blankBitmap.sameAs(ssbBitmap));
    404 
    405         assertTrue(ssbBitmap.sameAs(makeBitmapFromMtWithSamePaint(text, paint, false)));
    406         assertTrue(ssbBitmap.sameAs(makeBitmapFromMtWithDifferentPaint(text, paint, false)));
    407         assertTrue(ssbBitmap.sameAs(makeBitmapFromPct(text, paint, false)));
    408     }
    409 
    410     @Test
    411     public void testCanvasDrawTextRun_sameOutputTestForRTLText() {
    412         final TextPaint paint = new TextPaint();
    413         paint.setTextSize(30.0f);
    414 
    415         final String text = "\u05D0\u05D1\u05D2\u05D3\u05D4";
    416 
    417         final Bitmap blankBitmap = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
    418         final Bitmap ssbBitmap = makeBitmapFromSsb(text, paint, true);
    419         assertFalse(blankBitmap.sameAs(ssbBitmap));
    420 
    421         assertTrue(ssbBitmap.sameAs(makeBitmapFromMtWithSamePaint(text, paint, true)));
    422         assertTrue(ssbBitmap.sameAs(makeBitmapFromMtWithDifferentPaint(text, paint, true)));
    423         assertTrue(ssbBitmap.sameAs(makeBitmapFromPct(text, paint, true)));
    424     }
    425 }
    426