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