16ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt/*
26ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * Copyright (C) 2010 The Android Open Source Project
36ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt *
46ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * Licensed under the Apache License, Version 2.0 (the "License"); you may not
56ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * use this file except in compliance with the License. You may obtain a copy of
66ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * the License at
76ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt *
86ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * http://www.apache.org/licenses/LICENSE-2.0
96ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt *
106ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * Unless required by applicable law or agreed to in writing, software
116ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
126ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
136ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * License for the specific language governing permissions and limitations under
146ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * the License.
156ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt */
166ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
176ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltpackage android.text;
186ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
196ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltimport android.graphics.Paint.FontMetricsInt;
206ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltimport android.test.suitebuilder.annotation.SmallTest;
216ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltimport android.text.Layout.Alignment;
226ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltimport static android.text.Layout.Alignment.*;
23f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonakaimport android.text.TextPaint;
24f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonakaimport android.text.method.EditorState;
256ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltimport android.util.Log;
266ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
276ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltimport junit.framework.TestCase;
286ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
296ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt/**
306ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt * Tests StaticLayout vertical metrics behavior.
3108209a767b7d960f5396df3aa45913b2194c46beDoug Felt *
3208209a767b7d960f5396df3aa45913b2194c46beDoug Felt * Requires disabling access checks in the vm since this calls package-private
3308209a767b7d960f5396df3aa45913b2194c46beDoug Felt * APIs.
3408209a767b7d960f5396df3aa45913b2194c46beDoug Felt *
3508209a767b7d960f5396df3aa45913b2194c46beDoug Felt * @Suppress
366ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt */
376ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Feltpublic class StaticLayoutTest extends TestCase {
38f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    private static final int DEFAULT_OUTER_WIDTH = 150;
39f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_CENTER;
40f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    private static final float SPACE_MULTI = 1.0f;
41f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    private static final float SPACE_ADD = 0.0f;
426ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
436ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
446ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing expected behavior and relationship between font
456ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * metrics and line metrics.
466ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
4708209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
486ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters1() {
496ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder();
506ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
516ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
526ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        // check default paint
536ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Log.i("TG1:paint", fmi.toString());
546ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
556ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
566ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, 0, 0,
576ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.descent);
586ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
596ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        // other quick metrics
606ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(0, l.getLineStart(0));
616ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(Layout.DIR_LEFT_TO_RIGHT, l.getParagraphDirection(0));
626ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(false, l.getLineContainsTab(0));
636ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(Layout.DIRS_ALL_LEFT_TO_RIGHT, l.getLineDirections(0));
646ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(0, l.getEllipsisCount(0));
656ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(0, l.getEllipsisStart(0));
666ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(b.width, l.getEllipsizedWidth());
676ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
686ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
696ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
706ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true with 1 line.
716ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Top and bottom padding are affected, as is the line descent and height.
726ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
7308209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
746ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters2() {
756ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
766ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true);
776ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
786ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
796ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
806ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
816ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.top, fmi.bottom);
826ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
836ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
846ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
856ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true wrapping to 2 lines.
866ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Ascent of top line and descent of bottom line are affected.
876ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
8808209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
896ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters3() {
906ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
916ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true)
926ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setWidth(50);
936ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
946ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
956ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l =  b.build();
966ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
976ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            fmi.top, fmi.descent,
986ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            fmi.ascent, fmi.bottom);
996ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
1006ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1016ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
1026ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true wrapping to 3 lines.
1036ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * First line ascent is top, bottom line descent is bottom.
1046ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
10508209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
1066ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters4() {
1076ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
1086ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setText("This is a longer test")
1096ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true)
1106ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setWidth(50);
1116ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
1126ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1136ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
1146ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
1156ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.top, fmi.descent,
1166ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.descent,
1176ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.bottom);
1186ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
1196ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1206ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
1216ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true wrapping to 3 lines and
1226ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * large text. See effect of leading. Currently, we don't expect there to
1236ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * even be non-zero leading.
1246ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
12508209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
1266ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters5() {
1276ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
1286ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setText("This is a longer test")
1296ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true)
1306ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setWidth(150);
1316ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        b.paint.setTextSize(36);
1326ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
1336ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1346ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        if (fmi.leading == 0) { // nothing to test
1356ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            Log.i("TG5", "leading is 0, skipping test");
1366ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return;
1376ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
1386ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1396ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        // So far, leading is not used, so this is the same as TG4.  If we start
1406ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        // using leading, this will fail.
1416ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
1426ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
1436ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.top, fmi.descent,
1446ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.descent,
1456ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.bottom);
1466ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
1476ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1486ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
1496ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true, spacingAdd = 2, wrapping
1506ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * to 3 lines.
1516ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
15208209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
1536ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters6() {
1546ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        int spacingAdd = 2; // int so expressions return int
1556ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
1566ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setText("This is a longer test")
1576ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true)
1586ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setWidth(50)
1596ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setSpacingAdd(spacingAdd);
1606ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
1616ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1626ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
1636ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
1646ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.top, fmi.descent + spacingAdd,
1656ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.descent + spacingAdd,
1666ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.bottom + spacingAdd);
1676ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
1686ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1696ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
1706ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true, spacingAdd = 2,
1716ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * spacingMult = 1.5, wrapping to 3 lines.
1726ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
17308209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
1746ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters7() {
1756ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
1766ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setText("This is a longer test")
1776ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true)
1786ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setWidth(50)
1796ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setSpacingAdd(2)
1806ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setSpacingMult(1.5f);
1816ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
1826ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Scaler s = new Scaler(b.spacingMult, b.spacingAdd);
1836ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1846ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
1856ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
1866ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.top, fmi.descent + s.scale(fmi.descent - fmi.top),
1876ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.descent + s.scale(fmi.descent - fmi.ascent),
1886ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.bottom + s.scale(fmi.bottom - fmi.ascent));
1896ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
1906ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
1916ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    /**
1926ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * Basic test showing effect of includePad = true, spacingAdd = 0,
1936ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     * spacingMult = 0.8 when wrapping to 3 lines.
1946ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt     */
19508209a767b7d960f5396df3aa45913b2194c46beDoug Felt    //@SmallTest
1966ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    public void testGetters8() {
1976ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder b = builder()
1986ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setText("This is a longer test")
1996ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setIncludePad(true)
2006ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setWidth(50)
2016ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setSpacingAdd(2)
2026ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            .setSpacingMult(.8f);
2036ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        FontMetricsInt fmi = b.paint.getFontMetricsInt();
2046ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Scaler s = new Scaler(b.spacingMult, b.spacingAdd);
2056ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2066ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Layout l = b.build();
2076ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent,
2086ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.top, fmi.descent + s.scale(fmi.descent - fmi.top),
2096ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.descent + s.scale(fmi.descent - fmi.ascent),
2106ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                fmi.ascent, fmi.bottom + s.scale(fmi.bottom - fmi.ascent));
2116ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
2126ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2136ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    // ----- test utility classes and methods -----
2146ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2156ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    // Models the effect of the scale and add parameters.  I think the current
2166ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    // implementation misbehaves.
2176ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    private static class Scaler {
2186ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        private final float sMult;
2196ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        private final float sAdd;
2206ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2216ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Scaler(float sMult, float sAdd) {
2226ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.sMult = sMult - 1;
2236ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.sAdd = sAdd;
2246ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2256ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2266ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        public int scale(float height) {
2271065758a0f8966a8597a61492112f7859a7050a4Doug Felt            int altVal = (int)(height * sMult + sAdd + 0.5);
2286ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            int rndVal = Math.round(height * sMult + sAdd);
2296ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            if (altVal != rndVal) {
2306ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                Log.i("Scale", "expected scale: " + rndVal +
2316ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                        " != returned scale: " + altVal);
2326ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            }
2331065758a0f8966a8597a61492112f7859a7050a4Doug Felt            return rndVal;
2346ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2356ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
2366ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2379f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt    /* package */ static LayoutBuilder builder() {
2386ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        return new LayoutBuilder();
2396ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
2406ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2419f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt    /* package */ static class LayoutBuilder {
2426ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        String text = "This is a test";
2436ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        TextPaint paint = new TextPaint(); // default
2446ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        int width = 100;
2456ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        Alignment align = ALIGN_NORMAL;
2466ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        float spacingMult = 1;
2476ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        float spacingAdd = 0;
2486ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        boolean includePad = false;
2496ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2506ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setText(String text) {
2516ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.text = text;
2526ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2536ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2546ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2556ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setPaint(TextPaint paint) {
2566ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.paint = paint;
2576ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2586ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2596ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2606ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setWidth(int width) {
2616ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.width = width;
2626ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2636ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2646ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2656ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setAlignment(Alignment align) {
2666ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.align = align;
2676ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2686ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2696ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2706ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setSpacingMult(float spacingMult) {
2716ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.spacingMult = spacingMult;
2726ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2736ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2746ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2756ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setSpacingAdd(float spacingAdd) {
2766ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.spacingAdd = spacingAdd;
2776ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2786ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2796ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2806ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        LayoutBuilder setIncludePad(boolean includePad) {
2816ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            this.includePad = includePad;
2826ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return this;
2836ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2846ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2856ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt       Layout build() {
2866ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            return  new StaticLayout(text, paint, width, align, spacingMult,
2876ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt                spacingAdd, includePad);
2886ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
2896ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
2906ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2916ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    private void assertVertMetrics(Layout l, int topPad, int botPad, int... values) {
2926ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertTopBotPadding(l, topPad, botPad);
2936ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertLinesMetrics(l, values);
2946ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
2956ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
2966ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    private void assertLinesMetrics(Layout l, int... values) {
2976ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        // sanity check
2986ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        if ((values.length & 0x1) != 0) {
2996ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            throw new IllegalArgumentException(String.valueOf(values.length));
3006ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
3016ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
3026ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        int lines = values.length >> 1;
3036ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(lines, l.getLineCount());
3046ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
3056ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        int t = 0;
3066ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        for (int i = 0, n = 0; i < lines; ++i, n += 2) {
3076ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            int a = values[n];
3086ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            int d = values[n+1];
3096ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            int h = -a + d;
3106ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            assertLineMetrics(l, i, t, a, d, h);
3116ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            t += h;
3126ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        }
3136ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
3146ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(t, l.getHeight());
3156ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
3166ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
3176ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    private void assertLineMetrics(Layout l, int line,
3186ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt            int top, int ascent, int descent, int height) {
3196ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        String info = "line " + line;
3206ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(info, top, l.getLineTop(line));
3216ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(info, ascent, l.getLineAscent(line));
3226ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(info, descent, l.getLineDescent(line));
3236ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(info, height, l.getLineBottom(line) - top);
3246ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
3256ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt
3266ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    private void assertTopBotPadding(Layout l, int topPad, int botPad) {
3276ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(topPad, l.getTopPadding());
3286ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt        assertEquals(botPad, l.getBottomPadding());
3296ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt    }
330f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka
331f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    private void moveCursorToRightCursorableOffset(EditorState state, TextPaint paint) {
332f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        assertEquals("The editor has selection", state.mSelectionStart, state.mSelectionEnd);
333f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        final Layout layout = builder().setText(state.mText.toString()).setPaint(paint).build();
334f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        final int newOffset = layout.getOffsetToRightOf(state.mSelectionStart);
335f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.mSelectionStart = state.mSelectionEnd = newOffset;
336f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    }
337f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka
338f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    private void moveCursorToLeftCursorableOffset(EditorState state, TextPaint paint) {
339f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        assertEquals("The editor has selection", state.mSelectionStart, state.mSelectionEnd);
340f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        final Layout layout = builder().setText(state.mText.toString()).setPaint(paint).build();
341f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        final int newOffset = layout.getOffsetToLeftOf(state.mSelectionStart);
342f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.mSelectionStart = state.mSelectionEnd = newOffset;
343f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    }
344f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka
345f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    /**
346f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka     * Tests for keycap, variation selectors, flags are in CTS.
347f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka     * See {@link android.text.cts.StaticLayoutTest}.
348f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka     */
349f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    public void testEmojiOffset() {
350f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        EditorState state = new EditorState();
351f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        TextPaint paint = new TextPaint();
352f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka
353f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        // Odd numbered regional indicator symbols.
354f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        // U+1F1E6 is REGIONAL INDICATOR SYMBOL LETTER A, U+1F1E8 is REGIONAL INDICATOR SYMBOL
355f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        // LETTER C.
356f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
357f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
358f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+1F1E6 U+1F1E8 | U+1F1E6 U+1F1E8 U+1F1E6");
359f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
360f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 | U+1F1E6");
361f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
362f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 |");
363f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
364f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6 |");
365f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
366f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 | U+1F1E6");
367f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
368f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+1F1E6 U+1F1E8 | U+1F1E6 U+1F1E8 U+1F1E6");
369f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
370f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
371f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
372f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| U+1F1E6 U+1F1E8 U+1F1E6 U+1F1E8 U+1F1E6");
373f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
374f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka
375f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        // Zero width sequence
376f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        final String zwjSequence = "U+1F468 U+200D U+2764 U+FE0F U+200D U+1F468";
377f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
378f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
379f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals(zwjSequence + " | " + zwjSequence + " " + zwjSequence);
380f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
381f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals(zwjSequence + " " + zwjSequence + " | " + zwjSequence);
382f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
383f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals(zwjSequence + " " + zwjSequence + " " + zwjSequence + " |");
384f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
385f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals(zwjSequence + " " + zwjSequence + " " + zwjSequence + " |");
386f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
387f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals(zwjSequence + " " + zwjSequence + " | " + zwjSequence);
388f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
389f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals(zwjSequence + " | " + zwjSequence + " " + zwjSequence);
390f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
391f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
392f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
393f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.assertEquals("| " + zwjSequence + " " + zwjSequence + " " + zwjSequence);
394f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
395f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka
396f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        // Emoji modifiers
397f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        // U+261D is WHITE UP POINTING INDEX, U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
398f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
399f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
400f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+261D U+1F3FB | U+261D U+1F3FB U+261D U+1F3FB");
401f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
402f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+261D U+1F3FB U+261D U+1F3FB | U+261D U+1F3FB");
403f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
404f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB |");
405f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToRightCursorableOffset(state, paint);
406f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB |");
407f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
408f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+261D U+1F3FB U+261D U+1F3FB | U+261D U+1F3FB");
409f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
410f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("U+261D U+1F3FB | U+261D U+1F3FB U+261D U+1F3FB");
411f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
412f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
413f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
414f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        state.setByString("| U+261D U+1F3FB U+261D U+1F3FB U+261D U+1F3FB");
415f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka        moveCursorToLeftCursorableOffset(state, paint);
416f4afb095a0073f91c877a79e68b03e7939a9d76dSeigo Nonaka    }
4176ad5a7a7c78799ecb306cb97d979bdb98cc52d15Doug Felt}
418