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.text.cts;
     18 
     19 import static com.android.compatibility.common.util.WidgetTestUtils.sameCharSequence;
     20 
     21 import static org.junit.Assert.assertEquals;
     22 import static org.junit.Assert.assertFalse;
     23 import static org.junit.Assert.assertNotNull;
     24 import static org.junit.Assert.assertNull;
     25 import static org.junit.Assert.assertSame;
     26 import static org.junit.Assert.assertTrue;
     27 import static org.mockito.Matchers.any;
     28 import static org.mockito.Matchers.anyFloat;
     29 import static org.mockito.Matchers.anyInt;
     30 import static org.mockito.Matchers.eq;
     31 import static org.mockito.Mockito.reset;
     32 import static org.mockito.Mockito.spy;
     33 import static org.mockito.Mockito.times;
     34 import static org.mockito.Mockito.verify;
     35 
     36 import android.graphics.Bitmap;
     37 import android.graphics.Bitmap.Config;
     38 import android.graphics.Canvas;
     39 import android.graphics.Paint;
     40 import android.os.LocaleList;
     41 import android.text.BoringLayout;
     42 import android.text.BoringLayout.Metrics;
     43 import android.text.Layout;
     44 import android.text.Layout.Alignment;
     45 import android.text.PrecomputedText;
     46 import android.text.TextDirectionHeuristic;
     47 import android.text.TextDirectionHeuristics;
     48 import android.text.TextPaint;
     49 import android.text.TextUtils;
     50 
     51 import androidx.test.filters.SmallTest;
     52 import androidx.test.runner.AndroidJUnit4;
     53 
     54 import org.junit.Before;
     55 import org.junit.Test;
     56 import org.junit.runner.RunWith;
     57 
     58 @SmallTest
     59 @RunWith(AndroidJUnit4.class)
     60 public class BoringLayoutTest {
     61     private static final float SPACING_MULT_NO_SCALE = 1.0f;
     62     private static final float SPACING_ADD_NO_SCALE = 0.0f;
     63     private static final int DEFAULT_OUTER_WIDTH = 100;
     64     private static final int METRICS_TOP = 10;
     65     private static final int METRICS_ASCENT = 20;
     66     private static final int METRICS_DESCENT = 40;
     67     private static final int METRICS_BOTTOM = 50;
     68     private static final int METRICS_WIDTH = 50;
     69     private static final int METRICS_LEADING = 50;
     70 
     71     private static final CharSequence DEFAULT_CHAR_SEQUENCE = "default";
     72     private static final TextPaint DEFAULT_PAINT = new TextPaint();
     73     private static final Layout.Alignment DEFAULT_ALIGN = Layout.Alignment.ALIGN_CENTER;
     74     private static final Metrics DEFAULT_METRICS = createMetrics(
     75             METRICS_TOP,
     76             METRICS_ASCENT,
     77             METRICS_DESCENT,
     78             METRICS_BOTTOM,
     79             METRICS_WIDTH,
     80             METRICS_LEADING);
     81 
     82     private BoringLayout mBoringLayout;
     83 
     84     @Before
     85     public void setup() {
     86         mBoringLayout = makeDefaultBoringLayout();
     87     }
     88 
     89     @Test
     90     public void testConstructors() {
     91         new BoringLayout(DEFAULT_CHAR_SEQUENCE,
     92                 DEFAULT_PAINT,
     93                 DEFAULT_OUTER_WIDTH,
     94                 DEFAULT_ALIGN,
     95                 SPACING_MULT_NO_SCALE,
     96                 SPACING_ADD_NO_SCALE,
     97                 DEFAULT_METRICS,
     98                 true);
     99 
    100         new BoringLayout(DEFAULT_CHAR_SEQUENCE,
    101                 DEFAULT_PAINT,
    102                 DEFAULT_OUTER_WIDTH,
    103                 DEFAULT_ALIGN,
    104                 SPACING_MULT_NO_SCALE,
    105                 SPACING_ADD_NO_SCALE,
    106                 DEFAULT_METRICS,
    107                 true,
    108                 TextUtils.TruncateAt.START,
    109                 DEFAULT_OUTER_WIDTH);
    110     }
    111 
    112     private void verifyMultAddScale(float spacingMult, float spacingAdd) {
    113         final int height = METRICS_BOTTOM - METRICS_TOP;
    114 
    115         BoringLayout boringLayout = makeBoringLayout(spacingMult, spacingAdd);
    116         assertEquals(height, boringLayout.getHeight());
    117         assertEquals(height + METRICS_TOP, boringLayout.getLineDescent(0));
    118     }
    119 
    120     @Test
    121     public void testScale() {
    122         // no scale
    123         verifyMultAddScale(1.0f, 0.0f);
    124 
    125         // test line spacing multiplier
    126         verifyMultAddScale(2.0f, 0.0f);
    127         verifyMultAddScale(0.5f, 0.0f);
    128 
    129         // test line spacing add
    130         verifyMultAddScale(1.0f, 1.5f);
    131         verifyMultAddScale(1.0f, -1.6f);
    132         verifyMultAddScale(1.0f, 1.4f);
    133         verifyMultAddScale(1.0f, -1.4f);
    134         verifyMultAddScale(1.0f, 3.0f);
    135         verifyMultAddScale(1.0f, -3.0f);
    136     }
    137 
    138     @Test
    139     public void testPreconditions() {
    140         assertEquals(1, mBoringLayout.getLineCount());
    141         assertEquals(0, mBoringLayout.getLineTop(0));
    142         assertEquals(mBoringLayout.getHeight(), mBoringLayout.getLineTop(1));
    143         assertEquals(mBoringLayout.getHeight(), mBoringLayout.getLineTop(10));
    144         assertEquals(0, mBoringLayout.getLineStart(0));
    145         assertEquals(DEFAULT_CHAR_SEQUENCE.length(), mBoringLayout.getLineStart(1));
    146         assertEquals(DEFAULT_CHAR_SEQUENCE.length(), mBoringLayout.getLineStart(10));
    147         assertEquals(Layout.DIR_LEFT_TO_RIGHT, mBoringLayout.getParagraphDirection(0));
    148         assertFalse(mBoringLayout.getLineContainsTab(0));
    149         assertEquals((float) METRICS_WIDTH, mBoringLayout.getLineMax(0), 0.0f);
    150         assertEquals(Layout.DIR_LEFT_TO_RIGHT, mBoringLayout.getParagraphDirection(0));
    151         assertEquals(0, mBoringLayout.getEllipsisCount(0));
    152         mBoringLayout.ellipsized(0, 1);
    153         assertEquals(1, mBoringLayout.getEllipsisCount(0));
    154         mBoringLayout.ellipsized(1, 2);
    155         assertEquals(1, mBoringLayout.getEllipsisStart(0));
    156     }
    157 
    158     @Test
    159     public void testReplaceOrMake() {
    160         String source = "This is a SpannableString.";
    161         BoringLayout layout_1 = mBoringLayout.replaceOrMake(
    162                 source,
    163                 DEFAULT_PAINT,
    164                 DEFAULT_OUTER_WIDTH,
    165                 DEFAULT_ALIGN,
    166                 SPACING_MULT_NO_SCALE,
    167                 SPACING_ADD_NO_SCALE,
    168                 DEFAULT_METRICS,
    169                 true);
    170         assertSame(mBoringLayout, layout_1);
    171 
    172         layout_1 = mBoringLayout.replaceOrMake(
    173                 source,
    174                 DEFAULT_PAINT,
    175                 DEFAULT_OUTER_WIDTH,
    176                 DEFAULT_ALIGN,
    177                 SPACING_MULT_NO_SCALE,
    178                 SPACING_ADD_NO_SCALE,
    179                 DEFAULT_METRICS,
    180                 true,
    181                 TextUtils.TruncateAt.START,
    182                 100);
    183         assertSame(mBoringLayout, layout_1);
    184         assertEquals(100, mBoringLayout.getEllipsizedWidth());
    185     }
    186 
    187 
    188     @Test
    189     public void testAlignment() {
    190         BoringLayout boringLayout = makeBoringLayoutAlign(Layout.Alignment.ALIGN_NORMAL);
    191         assertEquals(0.0f, boringLayout.getLineLeft(0), 0.0f);
    192         assertEquals((float) DEFAULT_METRICS.width, boringLayout.getLineRight(0), 0.0f);
    193 
    194         boringLayout = makeBoringLayoutAlign(Layout.Alignment.ALIGN_CENTER);
    195         int expectedWidth = DEFAULT_OUTER_WIDTH - METRICS_WIDTH;
    196         assertEquals((float) expectedWidth / 2, boringLayout.getLineLeft(0), 0.0f);
    197         expectedWidth = DEFAULT_OUTER_WIDTH + METRICS_WIDTH;
    198         assertEquals((float) expectedWidth / 2, boringLayout.getLineRight(0), 0.0f);
    199 
    200         boringLayout = makeBoringLayoutAlign(Layout.Alignment.ALIGN_OPPOSITE);
    201         expectedWidth = DEFAULT_OUTER_WIDTH - METRICS_WIDTH;
    202         assertEquals((float) expectedWidth, boringLayout.getLineLeft(0), 0.0f);
    203         assertEquals((float) DEFAULT_OUTER_WIDTH, boringLayout.getLineRight(0), 0.0f);
    204     }
    205 
    206     @Test
    207     public void testGetLineDescent_withIncludePadding() {
    208         final int height = METRICS_BOTTOM - METRICS_TOP;
    209         assertEquals(height + METRICS_TOP, mBoringLayout.getLineDescent(0));
    210     }
    211 
    212     @Test
    213     public void testGetLineDescent_withoutIncludePadding() {
    214         BoringLayout boringLayout = new BoringLayout(
    215                 DEFAULT_CHAR_SEQUENCE,
    216                 DEFAULT_PAINT,
    217                 DEFAULT_OUTER_WIDTH,
    218                 DEFAULT_ALIGN,
    219                 SPACING_MULT_NO_SCALE,
    220                 SPACING_ADD_NO_SCALE,
    221                 DEFAULT_METRICS,
    222                 false);
    223 
    224         final int height = METRICS_DESCENT - METRICS_ASCENT;
    225         assertEquals(height + METRICS_ASCENT, boringLayout.getLineDescent(0));
    226     }
    227 
    228     @Test
    229     public void testIncludePadding() {
    230         assertEquals(METRICS_TOP - METRICS_ASCENT, mBoringLayout.getTopPadding());
    231         assertEquals(METRICS_BOTTOM - METRICS_DESCENT, mBoringLayout.getBottomPadding());
    232         assertEquals(METRICS_BOTTOM - METRICS_TOP, mBoringLayout.getHeight());
    233 
    234         BoringLayout boringLayout = new BoringLayout(
    235                 DEFAULT_CHAR_SEQUENCE,
    236                 DEFAULT_PAINT,
    237                 DEFAULT_OUTER_WIDTH,
    238                 DEFAULT_ALIGN,
    239                 SPACING_MULT_NO_SCALE,
    240                 SPACING_ADD_NO_SCALE,
    241                 DEFAULT_METRICS,
    242                 false);
    243 
    244         assertEquals(0, boringLayout.getTopPadding());
    245         assertEquals(0, boringLayout.getBottomPadding());
    246         assertEquals(METRICS_DESCENT - METRICS_ASCENT, boringLayout.getHeight());
    247     }
    248 
    249     @Test
    250     public void testIsBoringString() {
    251         TextPaint paint = new TextPaint();
    252         assertNotNull(BoringLayout.isBoring("hello android", paint));
    253 
    254         Metrics metrics = new Metrics();
    255         metrics.width = 100;
    256         assertNotNull(BoringLayout.isBoring("hello android", paint, metrics));
    257 
    258         assertNull(BoringLayout.isBoring("\u0590 \u0591", paint));
    259         assertNull(BoringLayout.isBoring("hello \t android", paint));
    260         assertNull(BoringLayout.isBoring("hello \n android", paint));
    261         assertNull(BoringLayout.isBoring("hello \n\n\n android", paint));
    262         assertNull(BoringLayout.isBoring("\nhello \n android\n", paint));
    263         assertNull(BoringLayout.isBoring("hello android\n\n\n", paint));
    264     }
    265 
    266     @Test
    267     public void testIsBoring_resetsFontMetrics() {
    268         int someInt = 100;
    269         String text = "some text";
    270 
    271         TextPaint paint = new TextPaint();
    272         Paint.FontMetricsInt paintMetrics = paint.getFontMetricsInt();
    273         Metrics changedMetrics = new Metrics();
    274         changedMetrics.top = paintMetrics.top - someInt;
    275         changedMetrics.ascent = paintMetrics.ascent - someInt;
    276         changedMetrics.bottom = paintMetrics.bottom + someInt;
    277         changedMetrics.descent = paintMetrics.descent + someInt;
    278         changedMetrics.leading = paintMetrics.leading + someInt;
    279 
    280         Metrics expectedMetrics = BoringLayout.isBoring(text, paint, (Metrics) null);
    281         Metrics actualMetrics = BoringLayout.isBoring(text, paint, changedMetrics);
    282 
    283         assertNotNull(actualMetrics);
    284         assertNotNull(expectedMetrics);
    285         assertEquals(expectedMetrics.top, actualMetrics.top);
    286         assertEquals(expectedMetrics.ascent, actualMetrics.ascent);
    287         assertEquals(expectedMetrics.bottom, actualMetrics.bottom);
    288         assertEquals(expectedMetrics.descent, actualMetrics.descent);
    289         assertEquals(expectedMetrics.leading, actualMetrics.leading);
    290     }
    291 
    292     @Test
    293     public void testGetLineDirections() {
    294         assertNotNull(mBoringLayout.getLineDirections(0));
    295         assertNotNull(mBoringLayout.getLineDirections(2));
    296     }
    297 
    298     @Test
    299     public void testMake() {
    300         BoringLayout boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
    301                 DEFAULT_PAINT,
    302                 DEFAULT_OUTER_WIDTH,
    303                 DEFAULT_ALIGN,
    304                 SPACING_MULT_NO_SCALE,
    305                 SPACING_ADD_NO_SCALE,
    306                 DEFAULT_METRICS,
    307                 true);
    308         assertNotNull(boringLayout);
    309 
    310         boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
    311                 DEFAULT_PAINT,
    312                 DEFAULT_OUTER_WIDTH,
    313                 DEFAULT_ALIGN,
    314                 SPACING_MULT_NO_SCALE,
    315                 SPACING_ADD_NO_SCALE,
    316                 DEFAULT_METRICS,
    317                 true,
    318                 TextUtils.TruncateAt.START,
    319                 DEFAULT_OUTER_WIDTH);
    320         assertNotNull(boringLayout);
    321     }
    322 
    323     @Test
    324     public void testDraw() {
    325         BoringLayout boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
    326                 DEFAULT_PAINT,
    327                 DEFAULT_OUTER_WIDTH,
    328                 Alignment.ALIGN_NORMAL,
    329                 SPACING_MULT_NO_SCALE,
    330                 SPACING_ADD_NO_SCALE,
    331                 DEFAULT_METRICS,
    332                 true);
    333 
    334         Bitmap mutableBitmap = Bitmap.createBitmap(10, 28, Config.ARGB_8888);
    335         Canvas canvas = spy(new Canvas(mutableBitmap));
    336         boringLayout.draw(canvas, null, null, 0);
    337         verify(canvas, times(1)).drawText(eq(DEFAULT_CHAR_SEQUENCE.toString()),
    338                 anyFloat(), anyFloat(), any(Paint.class));
    339 
    340         reset(canvas);
    341         boringLayout = BoringLayout.make(DEFAULT_CHAR_SEQUENCE,
    342                 DEFAULT_PAINT,
    343                 DEFAULT_OUTER_WIDTH,
    344                 Alignment.ALIGN_OPPOSITE,
    345                 SPACING_MULT_NO_SCALE,
    346                 SPACING_ADD_NO_SCALE,
    347                 DEFAULT_METRICS,
    348                 true);
    349         boringLayout.draw(canvas, null, null, 0);
    350         verify(canvas, times(1)).drawText(sameCharSequence(DEFAULT_CHAR_SEQUENCE),
    351                 anyInt(), anyInt(), anyFloat(), anyFloat(), any(Paint.class));
    352     }
    353 
    354     private static Bitmap drawToBitmap(Layout l) {
    355         final Bitmap bmp = Bitmap.createBitmap(l.getWidth(), l.getHeight(), Bitmap.Config.RGB_565);
    356         final Canvas c = new Canvas(bmp);
    357 
    358         c.save();
    359         c.translate(0, 0);
    360         l.draw(c);
    361         c.restore();
    362         return bmp;
    363     }
    364 
    365     private static String textPaintToString(TextPaint p) {
    366         return "{"
    367             + "mTextSize=" + p.getTextSize() + ", "
    368             + "mTextSkewX=" + p.getTextSkewX() + ", "
    369             + "mTextScaleX=" + p.getTextScaleX() + ", "
    370             + "mLetterSpacing=" + p.getLetterSpacing() + ", "
    371             + "mFlags=" + p.getFlags() + ", "
    372             + "mTextLocales=" + p.getTextLocales() + ", "
    373             + "mFontVariationSettings=" + p.getFontVariationSettings() + ", "
    374             + "mTypeface=" + p.getTypeface() + ", "
    375             + "mFontFeatureSettings=" + p.getFontFeatureSettings()
    376             + "}";
    377     }
    378 
    379     private static String directionToString(TextDirectionHeuristic dir) {
    380         if (dir == TextDirectionHeuristics.LTR) {
    381             return "LTR";
    382         } else if (dir == TextDirectionHeuristics.RTL) {
    383             return "RTL";
    384         } else if (dir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
    385             return "FIRSTSTRONG_LTR";
    386         } else if (dir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
    387             return "FIRSTSTRONG_RTL";
    388         } else if (dir == TextDirectionHeuristics.ANYRTL_LTR) {
    389             return "ANYRTL_LTR";
    390         } else {
    391             throw new RuntimeException("Unknown Direction");
    392         }
    393     }
    394 
    395     static class LayoutParam {
    396         final int mStrategy;
    397         final int mFrequency;
    398         final TextPaint mPaint;
    399         final TextDirectionHeuristic mDir;
    400 
    401         LayoutParam(int strategy, int frequency, TextPaint paint, TextDirectionHeuristic dir) {
    402             mStrategy = strategy;
    403             mFrequency = frequency;
    404             mPaint = new TextPaint(paint);
    405             mDir = dir;
    406         }
    407 
    408         @Override
    409         public String toString() {
    410             return "{"
    411                 + "mStrategy=" + mStrategy + ", "
    412                 + "mFrequency=" + mFrequency + ", "
    413                 + "mPaint=" + textPaintToString(mPaint) + ", "
    414                 + "mDir=" + directionToString(mDir)
    415                 + "}";
    416 
    417         }
    418 
    419         PrecomputedText getPrecomputedText(CharSequence text) {
    420             PrecomputedText.Params param = new PrecomputedText.Params.Builder(mPaint)
    421                     .setBreakStrategy(mStrategy)
    422                     .setHyphenationFrequency(mFrequency)
    423                     .setTextDirection(mDir).build();
    424             return PrecomputedText.create(text, param);
    425         }
    426     };
    427 
    428     void assertSameDrawOutput(
    429             CharSequence text,
    430             LayoutParam measuredTextParam,
    431             TextPaint layoutPaint) {
    432         String msg = "BoringLayout#draw for String and PrecomputedText with " + measuredTextParam
    433                 + " must output the same BMP.";
    434 
    435         final BoringLayout.Metrics metricsWithString = BoringLayout.isBoring(text, layoutPaint);
    436         final Layout layoutWithString = BoringLayout.make(
    437                 text, layoutPaint, metricsWithString.width, Alignment.ALIGN_NORMAL,
    438                 SPACING_MULT_NO_SCALE, SPACING_ADD_NO_SCALE, DEFAULT_METRICS,
    439                 true /* include padding */);
    440 
    441         final PrecomputedText precomputed = measuredTextParam.getPrecomputedText(text);
    442         final BoringLayout.Metrics metricsWithPrecomputed = BoringLayout.isBoring(
    443                 precomputed, layoutPaint);
    444         final Layout layoutWithPrecomputed = BoringLayout.make(
    445                 precomputed, layoutPaint, metricsWithPrecomputed.width, Alignment.ALIGN_NORMAL,
    446                 SPACING_MULT_NO_SCALE, SPACING_ADD_NO_SCALE, DEFAULT_METRICS,
    447                 true /* include padding */);
    448 
    449         assertEquals(msg, layoutWithString.getHeight(), layoutWithPrecomputed.getHeight(), 0.0f);
    450 
    451         final Bitmap expectedBMP = drawToBitmap(layoutWithString);
    452         final Bitmap resultBMP = drawToBitmap(layoutWithPrecomputed);
    453 
    454         assertTrue(msg, resultBMP.sameAs(expectedBMP));
    455     }
    456 
    457     @Test
    458     public void testPrecomputedText() {
    459         int[] breaks = {
    460             Layout.BREAK_STRATEGY_SIMPLE,
    461             Layout.BREAK_STRATEGY_HIGH_QUALITY,
    462             Layout.BREAK_STRATEGY_BALANCED,
    463         };
    464 
    465         int[] frequencies = {
    466             Layout.HYPHENATION_FREQUENCY_NORMAL,
    467             Layout.HYPHENATION_FREQUENCY_FULL,
    468             Layout.HYPHENATION_FREQUENCY_NONE,
    469         };
    470 
    471         TextDirectionHeuristic[] dirs = {
    472             TextDirectionHeuristics.LTR,
    473             TextDirectionHeuristics.RTL,
    474             TextDirectionHeuristics.FIRSTSTRONG_LTR,
    475             TextDirectionHeuristics.FIRSTSTRONG_RTL,
    476             TextDirectionHeuristics.ANYRTL_LTR,
    477         };
    478 
    479         float[] textSizes = {
    480             8.0f, 16.0f, 32.0f
    481         };
    482 
    483         LocaleList[] locales = {
    484             LocaleList.forLanguageTags("en-US"),
    485             LocaleList.forLanguageTags("ja-JP"),
    486             LocaleList.forLanguageTags("en-US,ja-JP"),
    487         };
    488 
    489         String onelineText = "Hello, World.";
    490 
    491         TextPaint paint = new TextPaint();
    492 
    493         // If the PrecomputedText is created with the same Paint, the draw result must be the same.
    494         for (int b : breaks) {
    495             for (int f : frequencies) {
    496                 for (TextDirectionHeuristic dir : dirs) {
    497                     for (float textSize : textSizes) {
    498                         for (LocaleList locale : locales) {
    499                             paint.setTextSize(textSize);
    500                             paint.setTextLocales(locale);
    501 
    502                             assertSameDrawOutput(onelineText, new LayoutParam(b, f, paint, dir),
    503                                     paint);
    504                         }
    505                     }
    506                 }
    507             }
    508         }
    509 
    510         // Even if the parameters are different, the output of the static layout must be
    511         // same bitmap.
    512         for (int bi = 0; bi < breaks.length; bi++) {
    513             for (int fi = 0; fi < frequencies.length; fi++) {
    514                 for (int diri = 0; diri < dirs.length; diri++) {
    515                     for (int sizei = 0; sizei < textSizes.length; sizei++) {
    516                         for (int localei = 0; localei < locales.length; localei++) {
    517                             TextPaint precomputedPaint = new TextPaint();
    518                             TextPaint layoutPaint = new TextPaint();
    519 
    520                             precomputedPaint.setTextSize(textSizes[sizei]);
    521                             layoutPaint.setTextSize(textSizes[(sizei + 1) % textSizes.length]);
    522 
    523                             precomputedPaint.setTextLocales(locales[localei]);
    524                             layoutPaint.setTextLocales(locales[(localei + 1) % locales.length]);
    525 
    526                             int b = breaks[bi];
    527 
    528                             int f = frequencies[fi];
    529 
    530                             TextDirectionHeuristic dir = dirs[diri];
    531 
    532                             assertSameDrawOutput(onelineText,
    533                                     new LayoutParam(b, f, precomputedPaint, dir),
    534                                     layoutPaint);
    535                         }
    536                     }
    537                 }
    538             }
    539         }
    540     }
    541 
    542     private static Metrics createMetrics(
    543             final int top,
    544             final int ascent,
    545             final int descent,
    546             final int bottom,
    547             final int width,
    548             final int leading) {
    549 
    550         final Metrics metrics = new Metrics();
    551 
    552         metrics.top = top;
    553         metrics.ascent = ascent;
    554         metrics.descent = descent;
    555         metrics.bottom = bottom;
    556         metrics.width = width;
    557         metrics.leading = leading;
    558 
    559         return metrics;
    560     }
    561 
    562     private static BoringLayout makeDefaultBoringLayout() {
    563         return new BoringLayout(DEFAULT_CHAR_SEQUENCE,
    564                                 DEFAULT_PAINT,
    565                                 DEFAULT_OUTER_WIDTH,
    566                                 DEFAULT_ALIGN,
    567                                 SPACING_MULT_NO_SCALE,
    568                                 SPACING_ADD_NO_SCALE,
    569                                 DEFAULT_METRICS,
    570                                 true);
    571     }
    572 
    573     private static BoringLayout makeBoringLayout(float spacingMult,float spacingAdd) {
    574         return new BoringLayout(DEFAULT_CHAR_SEQUENCE,
    575                                 DEFAULT_PAINT,
    576                                 DEFAULT_OUTER_WIDTH,
    577                                 DEFAULT_ALIGN,
    578                                 spacingMult,
    579                                 spacingAdd,
    580                                 DEFAULT_METRICS,
    581                                 true);
    582     }
    583 
    584     private static BoringLayout makeBoringLayoutAlign(Alignment align) {
    585         return new BoringLayout(DEFAULT_CHAR_SEQUENCE,
    586                                 DEFAULT_PAINT,
    587                                 DEFAULT_OUTER_WIDTH,
    588                                 align,
    589                                 SPACING_MULT_NO_SCALE,
    590                                 SPACING_ADD_NO_SCALE,
    591                                 DEFAULT_METRICS,
    592                                 true);
    593     }
    594 }
    595