• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package android.text;
18 
19 import android.text.Layout.Directions;
20 import android.text.StaticLayoutTest.LayoutBuilder;
21 
22 import java.util.Arrays;
23 import java.util.Formatter;
24 
25 import junit.framework.TestCase;
26 
27 public class StaticLayoutDirectionsTest extends TestCase {
28     private static final char ALEF = '\u05d0';
29 
dirs(int ... dirs)30     private static Directions dirs(int ... dirs) {
31         return new Directions(dirs);
32     }
33 
34     // constants from Layout that are package-protected
35     private static final int RUN_LENGTH_MASK = 0x03ffffff;
36     private static final int RUN_LEVEL_SHIFT = 26;
37     private static final int RUN_LEVEL_MASK = 0x3f;
38     private static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT;
39 
40     private static final Directions DIRS_ALL_LEFT_TO_RIGHT =
41         new Directions(new int[] { 0, RUN_LENGTH_MASK });
42     private static final Directions DIRS_ALL_RIGHT_TO_LEFT =
43         new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
44 
45     private static final int LVL1_1 = 1 | (1 << RUN_LEVEL_SHIFT);
46     private static final int LVL2_1 = 1 | (2 << RUN_LEVEL_SHIFT);
47     private static final int LVL2_2 = 2 | (2 << RUN_LEVEL_SHIFT);
48 
49     private static String[] texts = {
50         "",
51         " ",
52         "a",
53         "a1",
54         "aA",
55         "a1b",
56         "a1A",
57         "aA1",
58         "aAb",
59         "aA1B",
60         "aA1B2",
61 
62         // rtl
63         "A",
64         "A1",
65         "Aa",
66         "A1B",
67         "A1a",
68         "Aa1",
69         "AaB"
70     };
71 
72     // Expected directions are an array of start/length+level pairs,
73     // in visual order from the leading margin.
74     private static Directions[] expected = {
75         DIRS_ALL_LEFT_TO_RIGHT,
76         DIRS_ALL_LEFT_TO_RIGHT,
77         DIRS_ALL_LEFT_TO_RIGHT,
78         DIRS_ALL_LEFT_TO_RIGHT,
79         dirs(0, 1, 1, LVL1_1),
80         DIRS_ALL_LEFT_TO_RIGHT,
81         dirs(0, 2, 2, LVL1_1),
82         dirs(0, 1, 2, LVL2_1, 1, LVL1_1),
83         dirs(0, 1, 1, LVL1_1, 2, 1),
84         dirs(0, 1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
85         dirs(0, 1, 4, LVL2_1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
86 
87         // rtl
88         DIRS_ALL_RIGHT_TO_LEFT,
89         dirs(0, LVL1_1, 1, LVL2_1),
90         dirs(0, LVL1_1, 1, LVL2_1),
91         dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
92         dirs(0, LVL1_1, 1, LVL2_2),
93         dirs(0, LVL1_1, 1, LVL2_2),
94         dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
95     };
96 
pseudoBidiToReal(String src)97     private static String pseudoBidiToReal(String src) {
98         char[] chars = src.toCharArray();
99         for (int j = 0; j < chars.length; ++j) {
100             char c = chars[j];
101             if (c >= 'A' && c <= 'D') {
102                 chars[j] = (char)(ALEF + c - 'A');
103             }
104         }
105 
106         return new String(chars, 0, chars.length);
107     }
108 
109     // @SmallTest
testDirections()110     public void testDirections() {
111         StringBuilder buf = new StringBuilder("\n");
112         Formatter f = new Formatter(buf);
113 
114         LayoutBuilder b = StaticLayoutTest.builder();
115         for (int i = 0; i < texts.length; ++i) {
116             b.setText(pseudoBidiToReal(texts[i]));
117             checkDirections(b.build(), i, b.text, expected, f);
118         }
119         if (buf.length() > 1) {
120             fail(buf.toString());
121         }
122     }
123 
124     // @SmallTest
testTrailingWhitespace()125     public void testTrailingWhitespace() {
126         LayoutBuilder b = StaticLayoutTest.builder();
127         b.setText(pseudoBidiToReal("Ab   c"));
128         float width = b.paint.measureText(b.text, 0, 5);  // exclude 'c'
129         b.setWidth(Math.round(width));
130         Layout l = b.build();
131         if (l.getLineCount() != 2) {
132             throw new RuntimeException("expected 2 lines, got: " + l.getLineCount());
133         }
134         Directions result = l.getLineDirections(0);
135         Directions expected = dirs(0, LVL1_1, 1, LVL2_1, 2, 3 | (1 << Layout.RUN_LEVEL_SHIFT));
136         expectDirections("split line", expected, result);
137     }
138 
testNextToRightOf()139     public void testNextToRightOf() {
140         LayoutBuilder b = StaticLayoutTest.builder();
141         b.setText(pseudoBidiToReal("aA1B2"));
142         // visual a2B1A positions 04321
143         // 0: |a2B1A, strong is sol, after -> 0
144         // 1: a|2B1A, strong is a, after ->, 1
145         // 2: a2|B1A, strong is B, after -> 4
146         // 3: a2B|1A, strong is B, before -> 3
147         // 4: a2B1|A, strong is A, after -> 2
148         // 5: a2B1A|, strong is eol, before -> 5
149         int[] expected = { 0, 1, 4, 3, 2, 5 };
150         Layout l = b.build();
151         int n = 0;
152         for (int i = 1; i < expected.length; ++i) {
153             int t = l.getOffsetToRightOf(n);
154             if (t != expected[i]) {
155                 fail("offset[" + i + "] to right of: " + n + " expected: " +
156                         expected[i] + " got: " + t);
157             }
158             n = t;
159         }
160     }
161 
testNextToLeftOf()162     public void testNextToLeftOf() {
163         LayoutBuilder b = StaticLayoutTest.builder();
164         b.setText(pseudoBidiToReal("aA1B2"));
165         int[] expected = { 0, 1, 4, 3, 2, 5 };
166         Layout l = b.build();
167         int n = 5;
168         for (int i = expected.length - 1; --i >= 0;) {
169             int t = l.getOffsetToLeftOf(n);
170             if (t != expected[i]) {
171                 fail("offset[" + i + "] to left of: " + n + " expected: " +
172                         expected[i] + " got: " + t);
173             }
174             n = t;
175         }
176     }
177 
178     // utility, not really a test
179     /*
180     public void testMeasureText1() {
181         LayoutBuilder b = StaticLayoutTest.builder();
182         String text = "ABC"; // "abAB"
183         b.setText(pseudoBidiToReal(text));
184         Layout l = b.build();
185         Directions directions = l.getLineDirections(0);
186 
187         TextPaint workPaint = new TextPaint();
188 
189         int dir = -1; // LEFT_TO_RIGHT
190         boolean trailing = true;
191         boolean alt = true;
192         do {
193             dir = -dir;
194             do {
195                 trailing = !trailing;
196                 for (int offset = 0, end = b.text.length(); offset <= end; ++offset) {
197                     float width = Layout.measureText(b.paint,
198                             workPaint,
199                             b.text,
200                             0, offset, end,
201                             dir, directions,
202                             trailing, false,
203                             null);
204                     Log.i("BIDI", "dir: " + dir + " trail: " + trailing +
205                             " offset: " + offset + " width: " + width);
206                 }
207             } while (!trailing);
208         } while (dir > 0);
209     }
210     */
211 
212     // utility for displaying arrays in hex
hexArray(int[] array)213     private static String hexArray(int[] array) {
214         StringBuilder sb = new StringBuilder();
215         sb.append('{');
216         for (int i : array) {
217             if (sb.length() > 1) {
218                 sb.append(", ");
219             }
220             sb.append(Integer.toHexString(i));
221         }
222         sb.append('}');
223         return sb.toString();
224     }
225 
checkDirections(Layout l, int i, String text, Directions[] expectedDirs, Formatter f)226     private void checkDirections(Layout l, int i, String text,
227             Directions[] expectedDirs, Formatter f) {
228         Directions expected = expectedDirs[i];
229         Directions result = l.getLineDirections(0);
230         if (!Arrays.equals(expected.mDirections, result.mDirections)) {
231             f.format("%n[%2d] '%s', %s != %s", i, text,
232                     hexArray(expected.mDirections),
233                     hexArray(result.mDirections));
234         }
235     }
236 
expectDirections(String msg, Directions expected, Directions result)237     private void expectDirections(String msg, Directions expected, Directions result) {
238         if (!Arrays.equals(expected.mDirections, result.mDirections)) {
239             fail("expected: " + hexArray(expected.mDirections) +
240                     " got: " + hexArray(result.mDirections));
241         }
242     }
243 }
244