blob: 6d610bbbf5e9c318909ba202d8eca9ec2db1fa27 [file] [log] [blame]
Roozbeh Pournader02f167c2017-06-06 11:31:33 -07001/*
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
17package android.text;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNull;
22import static org.junit.Assert.assertSame;
23import static org.junit.Assert.assertTrue;
24import static org.junit.Assert.fail;
25
26import android.graphics.Bitmap;
27import android.graphics.Canvas;
28import android.graphics.Paint;
29import android.graphics.Path;
30import android.graphics.Rect;
31import android.graphics.RectF;
32import android.support.test.filters.SmallTest;
33import android.support.test.runner.AndroidJUnit4;
34import android.text.Layout.Alignment;
35import android.text.style.StrikethroughSpan;
36
37import org.junit.Before;
38import org.junit.Test;
39import org.junit.runner.RunWith;
40
41import java.util.ArrayList;
42import java.util.List;
43
44@SmallTest
45@RunWith(AndroidJUnit4.class)
46public class LayoutTest {
47 private static final int LINE_COUNT = 5;
48 private static final int LINE_HEIGHT = 12;
49 private static final int LINE_DESCENT = 4;
50 private static final CharSequence LAYOUT_TEXT = "alwei\t;sdfs\ndf @";
51
52 private SpannableString mSpannedText;
53
54 private int mWidth;
55 private Layout.Alignment mAlign;
56 private float mSpacingMult;
57 private float mSpacingAdd;
58 private TextPaint mTextPaint;
59
60 @Before
61 public void setup() {
62 mTextPaint = new TextPaint();
63 mSpannedText = new SpannableString(LAYOUT_TEXT);
64 mSpannedText.setSpan(new StrikethroughSpan(), 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
65 mWidth = 11;
66 mAlign = Alignment.ALIGN_CENTER;
67 mSpacingMult = 1;
68 mSpacingAdd = 2;
69 }
70
71 @Test
72 public void testConstructor() {
73 new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
74 }
75
76 @Test(expected = IllegalArgumentException.class)
77 public void testConstructorNull() {
78 new MockLayout(null, null, -1, null, 0, 0);
79 }
80
81 @Test
82 public void testGetText() {
83 CharSequence text = "test case 1";
84 Layout layout = new MockLayout(text, mTextPaint, mWidth,
85 mAlign, mSpacingMult, mSpacingAdd);
86 assertEquals(text, layout.getText());
87
88 layout = new MockLayout(null, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
89 assertNull(layout.getText());
90 }
91
92 @Test
93 public void testGetPaint() {
94 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
95 mAlign, mSpacingMult, mSpacingAdd);
96
97 assertSame(mTextPaint, layout.getPaint());
98
99 layout = new MockLayout(LAYOUT_TEXT, null, mWidth, mAlign, mSpacingMult, mSpacingAdd);
100 assertNull(layout.getPaint());
101 }
102
103 @Test
104 public void testGetWidth() {
105 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 10,
106 mAlign, mSpacingMult, mSpacingAdd);
107 assertEquals(10, layout.getWidth());
108
109 layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingMult, mSpacingAdd);
110 assertEquals(0, layout.getWidth());
111 }
112
113 @Test
114 public void testGetEllipsizedWidth() {
115 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 15,
116 mAlign, mSpacingMult, mSpacingAdd);
117 assertEquals(15, layout.getEllipsizedWidth());
118
119 layout = new MockLayout(LAYOUT_TEXT, mTextPaint, 0, mAlign, mSpacingMult, mSpacingAdd);
120 assertEquals(0, layout.getEllipsizedWidth());
121 }
122
123 @Test
124 public void testIncreaseWidthTo() {
125 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
126 mAlign, mSpacingMult, mSpacingAdd);
127 int oldWidth = layout.getWidth();
128
129 layout.increaseWidthTo(oldWidth);
130 assertEquals(oldWidth, layout.getWidth());
131
132 try {
133 layout.increaseWidthTo(oldWidth - 1);
134 fail("should throw runtime exception attempted to reduce Layout width");
135 } catch (RuntimeException e) {
136 }
137
138 layout.increaseWidthTo(oldWidth + 1);
139 assertEquals(oldWidth + 1, layout.getWidth());
140 }
141
142 @Test
143 public void testGetHeight() {
144 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
145 mAlign, mSpacingMult, mSpacingAdd);
146 assertEquals(60, layout.getHeight());
147 }
148
149 @Test
150 public void testGetAlignment() {
151 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
152 mAlign, mSpacingMult, mSpacingAdd);
153 assertSame(mAlign, layout.getAlignment());
154
155 layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, null, mSpacingMult, mSpacingAdd);
156 assertNull(layout.getAlignment());
157 }
158
159 @Test
160 public void testGetSpacingMultiplier() {
161 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, -1, mSpacingAdd);
162 assertEquals(-1.0f, layout.getSpacingMultiplier(), 0.0f);
163
164 layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, 5, mSpacingAdd);
165 assertEquals(5.0f, layout.getSpacingMultiplier(), 0.0f);
166 }
167
168 @Test
169 public void testGetSpacingAdd() {
170 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, -1);
171 assertEquals(-1.0f, layout.getSpacingAdd(), 0.0f);
172
173 layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, 20);
174 assertEquals(20.0f, layout.getSpacingAdd(), 0.0f);
175 }
176
177 @Test
178 public void testGetLineBounds() {
179 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
180 mAlign, mSpacingMult, mSpacingAdd);
181 Rect bounds = new Rect();
182
183 assertEquals(32, layout.getLineBounds(2, bounds));
184 assertEquals(0, bounds.left);
185 assertEquals(mWidth, bounds.right);
186 assertEquals(24, bounds.top);
187 assertEquals(36, bounds.bottom);
188 }
189
190 @Test
191 public void testGetLineForVertical() {
192 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
193 mAlign, mSpacingMult, mSpacingAdd);
194 assertEquals(0, layout.getLineForVertical(-1));
195 assertEquals(0, layout.getLineForVertical(0));
196 assertEquals(0, layout.getLineForVertical(LINE_COUNT));
197 assertEquals(LINE_COUNT - 1, layout.getLineForVertical(1000));
198 }
199
200 @Test
201 public void testGetLineForOffset() {
202 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
203 mAlign, mSpacingMult, mSpacingAdd);
204 assertEquals(0, layout.getLineForOffset(-1));
205 assertEquals(1, layout.getLineForOffset(1));
206 assertEquals(LINE_COUNT - 1, layout.getLineForOffset(LINE_COUNT - 1));
207 assertEquals(LINE_COUNT - 1, layout.getLineForOffset(1000));
208 }
209
210 @Test
211 public void testGetLineEnd() {
212 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
213 mAlign, mSpacingMult, mSpacingAdd);
214 assertEquals(2, layout.getLineEnd(1));
215 }
216
217 @Test
218 public void testGetLineVisibleEnd() {
219 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
220 mAlign, mSpacingMult, mSpacingAdd);
221
222 assertEquals(2, layout.getLineVisibleEnd(1));
223 assertEquals(LINE_COUNT, layout.getLineVisibleEnd(LINE_COUNT - 1));
224 assertEquals(LAYOUT_TEXT.length(), layout.getLineVisibleEnd(LAYOUT_TEXT.length() - 1));
225 try {
226 layout.getLineVisibleEnd(LAYOUT_TEXT.length());
227 fail("should throw .StringIndexOutOfBoundsException here");
228 } catch (StringIndexOutOfBoundsException e) {
229 }
230 }
231
232 @Test
233 public void testGetLineBottom() {
234 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
235 mAlign, mSpacingMult, mSpacingAdd);
236 assertEquals(LINE_HEIGHT, layout.getLineBottom(0));
237 }
238
239 @Test
240 public void testGetLineBaseline() {
241 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
242 mAlign, mSpacingMult, mSpacingAdd);
243 assertEquals(8, layout.getLineBaseline(0));
244 }
245
246 @Test
247 public void testGetLineAscent() {
248 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
249 mAlign, mSpacingMult, mSpacingAdd);
250 assertEquals(-8, layout.getLineAscent(0));
251 }
252
253 @Test
254 public void testGetParagraphAlignment() {
255 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
256 mAlign, mSpacingMult, mSpacingAdd);
257 assertSame(mAlign, layout.getParagraphAlignment(0));
258
259 layout = new MockLayout(mSpannedText, mTextPaint, mWidth,
260 mAlign, mSpacingMult, mSpacingAdd);
261 assertSame(mAlign, layout.getParagraphAlignment(0));
262 assertSame(mAlign, layout.getParagraphAlignment(1));
263 }
264
265 @Test
266 public void testGetParagraphLeft() {
267 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
268 mAlign, mSpacingMult, mSpacingAdd);
269 assertEquals(0, layout.getParagraphLeft(0));
270 }
271
272 @Test
273 public void testGetParagraphRight() {
274 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
275 mAlign, mSpacingMult, mSpacingAdd);
276 assertEquals(mWidth, layout.getParagraphRight(0));
277 }
278
279 @Test
280 public void testIsSpanned() {
281 MockLayout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
282 mAlign, mSpacingMult, mSpacingAdd);
283 // default is not spanned text
284 assertFalse(layout.mockIsSpanned());
285
286 // try to create a spanned text
287 layout = new MockLayout(mSpannedText, mTextPaint, mWidth,
288 mAlign, mSpacingMult, mSpacingAdd);
289 assertTrue(layout.mockIsSpanned());
290 }
291
292 private static final class MockLayout extends Layout {
293 MockLayout(CharSequence text, TextPaint paint, int width,
294 Alignment align, float spacingmult, float spacingadd) {
295 super(text, paint, width, align, spacingmult, spacingadd);
296 }
297
298 protected boolean mockIsSpanned() {
299 return super.isSpanned();
300 }
301
302 @Override
303 public int getBottomPadding() {
304 return 0;
305 }
306
307 @Override
308 public int getEllipsisCount(int line) {
309 return 0;
310 }
311
312 @Override
313 public int getEllipsisStart(int line) {
314 return 0;
315 }
316
317 @Override
318 public boolean getLineContainsTab(int line) {
319 return false;
320 }
321
322 @Override
323 public int getLineCount() {
324 return LINE_COUNT;
325 }
326
327 @Override
328 public int getLineDescent(int line) {
329 return LINE_DESCENT;
330 }
331
332 @Override
333 public Directions getLineDirections(int line) {
334 return Layout.DIRS_ALL_LEFT_TO_RIGHT;
335 }
336
337 @Override
338 public int getLineStart(int line) {
339 if (line < 0) {
340 return 0;
341 }
342 return line;
343 }
344
345 @Override
346 public int getLineTop(int line) {
347 if (line < 0) {
348 return 0;
349 }
350 return LINE_HEIGHT * (line);
351 }
352
353 @Override
354 public int getParagraphDirection(int line) {
355 return 0;
356 }
357
358 @Override
359 public int getTopPadding() {
360 return 0;
361 }
362 }
363
364 @Test
365 public void testGetLineWidth() {
366 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
367 mAlign, mSpacingMult, mSpacingAdd);
368 for (int i = 0; i < LINE_COUNT; i++) {
369 int start = layout.getLineStart(i);
370 int end = layout.getLineEnd(i);
371 String text = LAYOUT_TEXT.toString().substring(start, end);
372 assertEquals(mTextPaint.measureText(text), layout.getLineWidth(i), 1.0f);
373 }
374 }
375
376 @Test
377 public void testGetCursorPath() {
378 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
379 mAlign, mSpacingMult, mSpacingAdd);
380 Path path = new Path();
381 final float epsilon = 1.0f;
382 for (int i = 0; i < LINE_COUNT; i++) {
383 layout.getCursorPath(i, path, LAYOUT_TEXT);
384 RectF bounds = new RectF();
385 path.computeBounds(bounds, false);
386 assertTrue(bounds.top >= layout.getLineTop(i) - epsilon);
387 assertTrue(bounds.bottom <= layout.getLineBottom(i) + epsilon);
388 }
389 }
390
391 @Test
392 public void testDraw() {
393 Layout layout = new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth,
394 mAlign, mSpacingMult, mSpacingAdd);
395 final int width = 256;
396 final int height = 256;
397 MockCanvas c = new MockCanvas(width, height);
398 layout.draw(c);
399 List<MockCanvas.DrawCommand> drawCommands = c.getDrawCommands();
400 assertEquals(LINE_COUNT, drawCommands.size());
401 for (int i = 0; i < LINE_COUNT; i++) {
402 MockCanvas.DrawCommand drawCommand = drawCommands.get(i);
403 int start = layout.getLineStart(i);
404 int end = layout.getLineEnd(i);
405 assertEquals(LAYOUT_TEXT.toString().substring(start, end), drawCommand.text);
406 float expected_y = (i + 1) * LINE_HEIGHT - LINE_DESCENT;
407 assertEquals(expected_y, drawCommand.y, 0.0f);
408 }
409 }
410
411 private final class MockCanvas extends Canvas {
412
413 class DrawCommand {
414 public final String text;
415 public final float x;
416 public final float y;
417
418 DrawCommand(String text, float x, float y) {
419 this.text = text;
420 this.x = x;
421 this.y = y;
422 }
423 }
424
425 List<DrawCommand> mDrawCommands;
426
427 MockCanvas(int width, int height) {
428 super();
429 mDrawCommands = new ArrayList<>();
430 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
431 setBitmap(bitmap);
432 }
433
434 // Drawing text with either drawText or drawTextRun is valid; we don't care which.
435 // We also don't care which of the string representations is used.
436
437 @Override
438 public void drawText(String text, int start, int end, float x, float y, Paint p) {
439 mDrawCommands.add(new DrawCommand(text.substring(start, end), x, y));
440 }
441
442 @Override
443 public void drawText(CharSequence text, int start, int end, float x, float y, Paint p) {
444 drawText(text.toString(), start, end, x, y, p);
445 }
446
447 @Override
448 public void drawText(char[] text, int index, int count, float x, float y, Paint p) {
449 mDrawCommands.add(new DrawCommand(new String(text, index, count), x, y));
450 }
451
452 @Override
453 public void drawTextRun(CharSequence text, int start, int end, int contextStart,
454 int contextEnd, float x, float y, boolean isRtl, Paint paint) {
455 drawText(text, start, end, x, y, paint);
456 }
457
458 @Override
459 public void drawTextRun(char[] text, int index, int count, int contextIndex,
460 int contextCount, float x, float y, boolean isRtl, Paint paint) {
461 drawText(text, index, count, x, y, paint);
462 }
463
464 List<DrawCommand> getDrawCommands() {
465 return mDrawCommands;
466 }
467 }
468}
469