• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.text;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 
26 import android.graphics.Bitmap;
27 import android.graphics.Canvas;
28 import android.graphics.Paint;
29 import android.graphics.Path;
30 import android.graphics.Rect;
31 import android.graphics.RectF;
32 import android.support.test.filters.SmallTest;
33 import android.support.test.runner.AndroidJUnit4;
34 import android.text.Layout.Alignment;
35 import android.text.style.StrikethroughSpan;
36 
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 @SmallTest
45 @RunWith(AndroidJUnit4.class)
46 public 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
setup()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
testConstructor()72     public void testConstructor() {
73         new MockLayout(LAYOUT_TEXT, mTextPaint, mWidth, mAlign, mSpacingMult, mSpacingAdd);
74     }
75 
76     @Test(expected = IllegalArgumentException.class)
testConstructorNull()77     public void testConstructorNull() {
78         new MockLayout(null, null, -1, null, 0, 0);
79     }
80 
81     @Test
testGetText()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
testGetPaint()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
testGetWidth()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
testGetEllipsizedWidth()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
testIncreaseWidthTo()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
testGetHeight()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
testGetAlignment()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
testGetSpacingMultiplier()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
testGetSpacingAdd()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
testGetLineBounds()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
testGetLineForVertical()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
testGetLineForOffset()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
testGetLineEnd()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
testGetLineVisibleEnd()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
testGetLineBottom()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
testGetLineBaseline()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
testGetLineAscent()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
testGetParagraphAlignment()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
testGetParagraphLeft()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
testGetParagraphRight()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
testIsSpanned()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 {
MockLayout(CharSequence text, TextPaint paint, int width, Alignment align, float spacingmult, float spacingadd)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 
mockIsSpanned()298         protected boolean mockIsSpanned() {
299             return super.isSpanned();
300         }
301 
302         @Override
getBottomPadding()303         public int getBottomPadding() {
304             return 0;
305         }
306 
307         @Override
getEllipsisCount(int line)308         public int getEllipsisCount(int line) {
309             return 0;
310         }
311 
312         @Override
getEllipsisStart(int line)313         public int getEllipsisStart(int line) {
314             return 0;
315         }
316 
317         @Override
getLineContainsTab(int line)318         public boolean getLineContainsTab(int line) {
319             return false;
320         }
321 
322         @Override
getLineCount()323         public int getLineCount() {
324             return LINE_COUNT;
325         }
326 
327         @Override
getLineDescent(int line)328         public int getLineDescent(int line) {
329             return LINE_DESCENT;
330         }
331 
332         @Override
getLineDirections(int line)333         public Directions getLineDirections(int line) {
334             return Layout.DIRS_ALL_LEFT_TO_RIGHT;
335         }
336 
337         @Override
getLineStart(int line)338         public int getLineStart(int line) {
339             if (line < 0) {
340                 return 0;
341             }
342             return line;
343         }
344 
345         @Override
getLineTop(int line)346         public int getLineTop(int line) {
347             if (line < 0) {
348                 return 0;
349             }
350             return LINE_HEIGHT * (line);
351         }
352 
353         @Override
getParagraphDirection(int line)354         public int getParagraphDirection(int line) {
355             return 0;
356         }
357 
358         @Override
getTopPadding()359         public int getTopPadding() {
360             return 0;
361         }
362     }
363 
364     @Test
testGetLineWidth()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
testGetCursorPath()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
testDraw()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 
DrawCommand(String text, float x, float y)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 
MockCanvas(int width, int height)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
drawText(String text, int start, int end, float x, float y, Paint p)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
drawText(CharSequence text, int start, int end, float x, float y, Paint p)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
drawText(char[] text, int index, int count, float x, float y, Paint p)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
drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, Paint paint)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
drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, Paint paint)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 
getDrawCommands()464         List<DrawCommand> getDrawCommands() {
465             return mDrawCommands;
466         }
467     }
468 }
469 
470