• 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 static org.junit.Assert.fail;
20 
21 import android.support.test.filters.SmallTest;
22 import android.support.test.runner.AndroidJUnit4;
23 import android.text.Layout.Directions;
24 import android.text.StaticLayoutTest.LayoutBuilder;
25 
26 import java.util.Arrays;
27 import java.util.Formatter;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 
31 @SmallTest
32 @RunWith(AndroidJUnit4.class)
33 public class StaticLayoutDirectionsTest {
34     private static final char ALEF = '\u05d0';
35 
dirs(int ... dirs)36     private static Directions dirs(int ... dirs) {
37         return new Directions(dirs);
38     }
39 
40     // constants from Layout that are package-protected
41     private static final int RUN_LENGTH_MASK = 0x03ffffff;
42     private static final int RUN_LEVEL_SHIFT = 26;
43     private static final int RUN_LEVEL_MASK = 0x3f;
44     private static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT;
45 
46     private static final Directions DIRS_ALL_LEFT_TO_RIGHT =
47         new Directions(new int[] { 0, RUN_LENGTH_MASK });
48     private static final Directions DIRS_ALL_RIGHT_TO_LEFT =
49         new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
50 
51     private static final int LVL1_1 = 1 | (1 << RUN_LEVEL_SHIFT);
52     private static final int LVL2_1 = 1 | (2 << RUN_LEVEL_SHIFT);
53     private static final int LVL2_2 = 2 | (2 << RUN_LEVEL_SHIFT);
54 
55     private static String[] texts = {
56         "",
57         " ",
58         "a",
59         "a1",
60         "aA",
61         "a1b",
62         "a1A",
63         "aA1",
64         "aAb",
65         "aA1B",
66         "aA1B2",
67 
68         // rtl
69         "A",
70         "A1",
71         "Aa",
72         "A1B",
73         "A1a",
74         "Aa1",
75         "AaB"
76     };
77 
78     // Expected directions are an array of start/length+level pairs,
79     // in visual order from the leading margin.
80     private static Directions[] expected = {
81         DIRS_ALL_LEFT_TO_RIGHT,
82         DIRS_ALL_LEFT_TO_RIGHT,
83         DIRS_ALL_LEFT_TO_RIGHT,
84         DIRS_ALL_LEFT_TO_RIGHT,
85         dirs(0, 1, 1, LVL1_1),
86         DIRS_ALL_LEFT_TO_RIGHT,
87         dirs(0, 2, 2, LVL1_1),
88         dirs(0, 1, 2, LVL2_1, 1, LVL1_1),
89         dirs(0, 1, 1, LVL1_1, 2, 1),
90         dirs(0, 1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
91         dirs(0, 1, 4, LVL2_1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1),
92 
93         // rtl
94         DIRS_ALL_RIGHT_TO_LEFT,
95         dirs(0, LVL1_1, 1, LVL2_1),
96         dirs(0, LVL1_1, 1, LVL2_1),
97         dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
98         dirs(0, LVL1_1, 1, LVL2_2),
99         dirs(0, LVL1_1, 1, LVL2_2),
100         dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1),
101     };
102 
pseudoBidiToReal(String src)103     private static String pseudoBidiToReal(String src) {
104         char[] chars = src.toCharArray();
105         for (int j = 0; j < chars.length; ++j) {
106             char c = chars[j];
107             if (c >= 'A' && c <= 'D') {
108                 chars[j] = (char)(ALEF + c - 'A');
109             }
110         }
111 
112         return new String(chars, 0, chars.length);
113     }
114 
115     @Test
testDirections()116     public void testDirections() {
117         StringBuilder buf = new StringBuilder("\n");
118         Formatter f = new Formatter(buf);
119 
120         LayoutBuilder b = StaticLayoutTest.builder();
121         for (int i = 0; i < texts.length; ++i) {
122             b.setText(pseudoBidiToReal(texts[i]));
123             checkDirections(b.build(), i, b.text, expected, f);
124         }
125         if (buf.length() > 1) {
126             fail(buf.toString());
127         }
128     }
129 
130     @Test
testTrailingWhitespace()131     public void testTrailingWhitespace() {
132         LayoutBuilder b = StaticLayoutTest.builder();
133         b.setText(pseudoBidiToReal("Ab   c"));
134         float width = b.paint.measureText(b.text, 0, 5);  // exclude 'c'
135         b.setWidth(Math.round(width));
136         Layout l = b.build();
137         if (l.getLineCount() != 2) {
138             throw new RuntimeException("expected 2 lines, got: " + l.getLineCount());
139         }
140         Directions result = l.getLineDirections(0);
141         Directions expected = dirs(0, LVL1_1, 1, LVL2_1, 2, 3 | (1 << Layout.RUN_LEVEL_SHIFT));
142         expectDirections("split line", expected, result);
143     }
144 
145     @Test
testNextToRightOf()146     public void testNextToRightOf() {
147         LayoutBuilder b = StaticLayoutTest.builder();
148         b.setText(pseudoBidiToReal("aA1B2"));
149         // visual a2B1A positions 04321
150         // 0: |a2B1A, strong is sol, after -> 0
151         // 1: a|2B1A, strong is a, after ->, 1
152         // 2: a2|B1A, strong is B, after -> 4
153         // 3: a2B|1A, strong is B, before -> 3
154         // 4: a2B1|A, strong is A, after -> 2
155         // 5: a2B1A|, strong is eol, before -> 5
156         int[] expected = { 0, 1, 4, 3, 2, 5 };
157         Layout l = b.build();
158         int n = 0;
159         for (int i = 1; i < expected.length; ++i) {
160             int t = l.getOffsetToRightOf(n);
161             if (t != expected[i]) {
162                 fail("offset[" + i + "] to right of: " + n + " expected: " +
163                         expected[i] + " got: " + t);
164             }
165             n = t;
166         }
167     }
168 
169     @Test
testNextToLeftOf()170     public void testNextToLeftOf() {
171         LayoutBuilder b = StaticLayoutTest.builder();
172         b.setText(pseudoBidiToReal("aA1B2"));
173         int[] expected = { 0, 1, 4, 3, 2, 5 };
174         Layout l = b.build();
175         int n = 5;
176         for (int i = expected.length - 1; --i >= 0;) {
177             int t = l.getOffsetToLeftOf(n);
178             if (t != expected[i]) {
179                 fail("offset[" + i + "] to left of: " + n + " expected: " +
180                         expected[i] + " got: " + t);
181             }
182             n = t;
183         }
184     }
185 
186     // utility for displaying arrays in hex
hexArray(int[] array)187     private static String hexArray(int[] array) {
188         StringBuilder sb = new StringBuilder();
189         sb.append('{');
190         for (int i : array) {
191             if (sb.length() > 1) {
192                 sb.append(", ");
193             }
194             sb.append(Integer.toHexString(i));
195         }
196         sb.append('}');
197         return sb.toString();
198     }
199 
checkDirections(Layout l, int i, String text, Directions[] expectedDirs, Formatter f)200     private void checkDirections(Layout l, int i, String text,
201             Directions[] expectedDirs, Formatter f) {
202         Directions expected = expectedDirs[i];
203         Directions result = l.getLineDirections(0);
204         if (!Arrays.equals(expected.mDirections, result.mDirections)) {
205             f.format("%n[%2d] '%s', %s != %s", i, text,
206                     hexArray(expected.mDirections),
207                     hexArray(result.mDirections));
208         }
209     }
210 
expectDirections(String msg, Directions expected, Directions result)211     private void expectDirections(String msg, Directions expected, Directions result) {
212         if (!Arrays.equals(expected.mDirections, result.mDirections)) {
213             fail("expected: " + hexArray(expected.mDirections) +
214                     " got: " + hexArray(result.mDirections));
215         }
216     }
217 }
218