StaticLayoutTest.java revision 6ad5a7a7c78799ecb306cb97d979bdb98cc52d15
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 17package android.text; 18 19import android.graphics.Paint.FontMetricsInt; 20import android.test.suitebuilder.annotation.SmallTest; 21import android.text.Layout.Alignment; 22import static android.text.Layout.Alignment.*; 23import android.util.Log; 24 25import junit.framework.TestCase; 26 27/** 28 * Tests StaticLayout vertical metrics behavior. 29 */ 30public class StaticLayoutTest extends TestCase { 31 32 /** 33 * Basic test showing expected behavior and relationship between font 34 * metrics and line metrics. 35 */ 36 @SmallTest 37 public void testGetters1() { 38 LayoutBuilder b = builder(); 39 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 40 41 // check default paint 42 Log.i("TG1:paint", fmi.toString()); 43 44 Layout l = b.build(); 45 assertVertMetrics(l, 0, 0, 46 fmi.ascent, fmi.descent); 47 48 // other quick metrics 49 assertEquals(0, l.getLineStart(0)); 50 assertEquals(Layout.DIR_LEFT_TO_RIGHT, l.getParagraphDirection(0)); 51 assertEquals(false, l.getLineContainsTab(0)); 52 assertEquals(Layout.DIRS_ALL_LEFT_TO_RIGHT, l.getLineDirections(0)); 53 assertEquals(0, l.getEllipsisCount(0)); 54 assertEquals(0, l.getEllipsisStart(0)); 55 assertEquals(b.width, l.getEllipsizedWidth()); 56 } 57 58 /** 59 * Basic test showing effect of includePad = true with 1 line. 60 * Top and bottom padding are affected, as is the line descent and height. 61 */ 62 @SmallTest 63 public void testGetters2() { 64 LayoutBuilder b = builder() 65 .setIncludePad(true); 66 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 67 68 Layout l = b.build(); 69 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 70 fmi.top, fmi.bottom); 71 } 72 73 /** 74 * Basic test showing effect of includePad = true wrapping to 2 lines. 75 * Ascent of top line and descent of bottom line are affected. 76 */ 77 @SmallTest 78 public void testGetters3() { 79 LayoutBuilder b = builder() 80 .setIncludePad(true) 81 .setWidth(50); 82 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 83 84 Layout l = b.build(); 85 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 86 fmi.top, fmi.descent, 87 fmi.ascent, fmi.bottom); 88 } 89 90 /** 91 * Basic test showing effect of includePad = true wrapping to 3 lines. 92 * First line ascent is top, bottom line descent is bottom. 93 */ 94 @SmallTest 95 public void testGetters4() { 96 LayoutBuilder b = builder() 97 .setText("This is a longer test") 98 .setIncludePad(true) 99 .setWidth(50); 100 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 101 102 Layout l = b.build(); 103 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 104 fmi.top, fmi.descent, 105 fmi.ascent, fmi.descent, 106 fmi.ascent, fmi.bottom); 107 } 108 109 /** 110 * Basic test showing effect of includePad = true wrapping to 3 lines and 111 * large text. See effect of leading. Currently, we don't expect there to 112 * even be non-zero leading. 113 */ 114 @SmallTest 115 public void testGetters5() { 116 LayoutBuilder b = builder() 117 .setText("This is a longer test") 118 .setIncludePad(true) 119 .setWidth(150); 120 b.paint.setTextSize(36); 121 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 122 123 if (fmi.leading == 0) { // nothing to test 124 Log.i("TG5", "leading is 0, skipping test"); 125 return; 126 } 127 128 // So far, leading is not used, so this is the same as TG4. If we start 129 // using leading, this will fail. 130 Layout l = b.build(); 131 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 132 fmi.top, fmi.descent, 133 fmi.ascent, fmi.descent, 134 fmi.ascent, fmi.bottom); 135 } 136 137 /** 138 * Basic test showing effect of includePad = true, spacingAdd = 2, wrapping 139 * to 3 lines. 140 */ 141 @SmallTest 142 public void testGetters6() { 143 int spacingAdd = 2; // int so expressions return int 144 LayoutBuilder b = builder() 145 .setText("This is a longer test") 146 .setIncludePad(true) 147 .setWidth(50) 148 .setSpacingAdd(spacingAdd); 149 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 150 151 Layout l = b.build(); 152 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 153 fmi.top, fmi.descent + spacingAdd, 154 fmi.ascent, fmi.descent + spacingAdd, 155 fmi.ascent, fmi.bottom + spacingAdd); 156 } 157 158 /** 159 * Basic test showing effect of includePad = true, spacingAdd = 2, 160 * spacingMult = 1.5, wrapping to 3 lines. 161 */ 162 @SmallTest 163 public void testGetters7() { 164 LayoutBuilder b = builder() 165 .setText("This is a longer test") 166 .setIncludePad(true) 167 .setWidth(50) 168 .setSpacingAdd(2) 169 .setSpacingMult(1.5f); 170 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 171 Scaler s = new Scaler(b.spacingMult, b.spacingAdd); 172 173 Layout l = b.build(); 174 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 175 fmi.top, fmi.descent + s.scale(fmi.descent - fmi.top), 176 fmi.ascent, fmi.descent + s.scale(fmi.descent - fmi.ascent), 177 fmi.ascent, fmi.bottom + s.scale(fmi.bottom - fmi.ascent)); 178 } 179 180 /** 181 * Basic test showing effect of includePad = true, spacingAdd = 0, 182 * spacingMult = 0.8 when wrapping to 3 lines. 183 */ 184 @SmallTest 185 public void testGetters8() { 186 LayoutBuilder b = builder() 187 .setText("This is a longer test") 188 .setIncludePad(true) 189 .setWidth(50) 190 .setSpacingAdd(2) 191 .setSpacingMult(.8f); 192 FontMetricsInt fmi = b.paint.getFontMetricsInt(); 193 Scaler s = new Scaler(b.spacingMult, b.spacingAdd); 194 195 Layout l = b.build(); 196 assertVertMetrics(l, fmi.top - fmi.ascent, fmi.bottom - fmi.descent, 197 fmi.top, fmi.descent + s.scale(fmi.descent - fmi.top), 198 fmi.ascent, fmi.descent + s.scale(fmi.descent - fmi.ascent), 199 fmi.ascent, fmi.bottom + s.scale(fmi.bottom - fmi.ascent)); 200 } 201 202 // ----- test utility classes and methods ----- 203 204 // Models the effect of the scale and add parameters. I think the current 205 // implementation misbehaves. 206 private static class Scaler { 207 private final float sMult; 208 private final float sAdd; 209 210 Scaler(float sMult, float sAdd) { 211 this.sMult = sMult - 1; 212 this.sAdd = sAdd; 213 } 214 215 public int scale(float height) { 216 int altVal = (int)(height * sMult + sAdd + 0.5); // existing impl 217 int rndVal = Math.round(height * sMult + sAdd); 218 if (altVal != rndVal) { 219 Log.i("Scale", "expected scale: " + rndVal + 220 " != returned scale: " + altVal); 221 } 222 return altVal; // existing implementation 223 } 224 } 225 226 private static LayoutBuilder builder() { 227 return new LayoutBuilder(); 228 } 229 230 private static class LayoutBuilder { 231 String text = "This is a test"; 232 TextPaint paint = new TextPaint(); // default 233 int width = 100; 234 Alignment align = ALIGN_NORMAL; 235 float spacingMult = 1; 236 float spacingAdd = 0; 237 boolean includePad = false; 238 239 LayoutBuilder setText(String text) { 240 this.text = text; 241 return this; 242 } 243 244 LayoutBuilder setPaint(TextPaint paint) { 245 this.paint = paint; 246 return this; 247 } 248 249 LayoutBuilder setWidth(int width) { 250 this.width = width; 251 return this; 252 } 253 254 LayoutBuilder setAlignment(Alignment align) { 255 this.align = align; 256 return this; 257 } 258 259 LayoutBuilder setSpacingMult(float spacingMult) { 260 this.spacingMult = spacingMult; 261 return this; 262 } 263 264 LayoutBuilder setSpacingAdd(float spacingAdd) { 265 this.spacingAdd = spacingAdd; 266 return this; 267 } 268 269 LayoutBuilder setIncludePad(boolean includePad) { 270 this.includePad = includePad; 271 return this; 272 } 273 274 Layout build() { 275 return new StaticLayout(text, paint, width, align, spacingMult, 276 spacingAdd, includePad); 277 } 278 } 279 280 private void assertVertMetrics(Layout l, int topPad, int botPad, int... values) { 281 assertTopBotPadding(l, topPad, botPad); 282 assertLinesMetrics(l, values); 283 } 284 285 private void assertLinesMetrics(Layout l, int... values) { 286 // sanity check 287 if ((values.length & 0x1) != 0) { 288 throw new IllegalArgumentException(String.valueOf(values.length)); 289 } 290 291 int lines = values.length >> 1; 292 assertEquals(lines, l.getLineCount()); 293 294 int t = 0; 295 for (int i = 0, n = 0; i < lines; ++i, n += 2) { 296 int a = values[n]; 297 int d = values[n+1]; 298 int h = -a + d; 299 assertLineMetrics(l, i, t, a, d, h); 300 t += h; 301 } 302 303 assertEquals(t, l.getHeight()); 304 } 305 306 private void assertLineMetrics(Layout l, int line, 307 int top, int ascent, int descent, int height) { 308 String info = "line " + line; 309 assertEquals(info, top, l.getLineTop(line)); 310 assertEquals(info, ascent, l.getLineAscent(line)); 311 assertEquals(info, descent, l.getLineDescent(line)); 312 assertEquals(info, height, l.getLineBottom(line) - top); 313 } 314 315 private void assertTopBotPadding(Layout l, int topPad, int botPad) { 316 assertEquals(topPad, l.getTopPadding()); 317 assertEquals(botPad, l.getBottomPadding()); 318 } 319} 320