1 /* 2 * Copyright (C) 2017 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.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 24 import android.graphics.Canvas; 25 import android.graphics.Paint; 26 import android.graphics.Typeface; 27 import android.platform.test.annotations.Presubmit; 28 import android.text.Layout.TabStops; 29 import android.text.style.AbsoluteSizeSpan; 30 import android.text.style.ReplacementSpan; 31 import android.text.style.TabStopSpan; 32 33 import androidx.test.filters.SmallTest; 34 import androidx.test.filters.Suppress; 35 import androidx.test.platform.app.InstrumentationRegistry; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import java.util.Arrays; 42 43 @Presubmit 44 @SmallTest 45 @RunWith(AndroidJUnit4.class) 46 public class TextLineTest { stretchesToFullWidth(CharSequence line)47 private boolean stretchesToFullWidth(CharSequence line) { 48 final TextPaint paint = new TextPaint(); 49 final TextLine tl = TextLine.obtain(); 50 tl.set(paint, line, 0, line.length(), Layout.DIR_LEFT_TO_RIGHT, 51 Layout.DIRS_ALL_LEFT_TO_RIGHT, false /* hasTabs */, null /* tabStops */, 52 0, 0 /* no ellipsis */, false /* useFallbackLinespace */); 53 final float originalWidth = tl.metrics(null, null, false, null); 54 final float expandedWidth = 2 * originalWidth; 55 56 tl.justify(Layout.JUSTIFICATION_MODE_INTER_WORD, expandedWidth); 57 final float newWidth = tl.metrics(null, null, false, null); 58 TextLine.recycle(tl); 59 return Math.abs(newWidth - expandedWidth) < 0.5; 60 } 61 62 @Test testJustify_spaces()63 public void testJustify_spaces() { 64 // There are no spaces to stretch. 65 assertFalse(stretchesToFullWidth("text")); 66 67 assertTrue(stretchesToFullWidth("one space")); 68 assertTrue(stretchesToFullWidth("exactly two spaces")); 69 assertTrue(stretchesToFullWidth("up to three spaces")); 70 } 71 72 // NBSP should also stretch when it's not used as a base for a combining mark. This doesn't work 73 // yet (b/68204709). 74 @Suppress disabledTestJustify_NBSP()75 public void disabledTestJustify_NBSP() { 76 final char nbsp = '\u00A0'; 77 assertTrue(stretchesToFullWidth("non-breaking" + nbsp + "space")); 78 assertTrue(stretchesToFullWidth("mix" + nbsp + "and match")); 79 80 final char combining_acute = '\u0301'; 81 assertFalse(stretchesToFullWidth("combining" + nbsp + combining_acute + "acute")); 82 } 83 84 // The test font has following coverage and width. 85 // U+0020: 10em 86 // U+002E (.): 10em 87 // U+0043 (C): 100em 88 // U+0049 (I): 1em 89 // U+004C (L): 50em 90 // U+0056 (V): 5em 91 // U+0058 (X): 10em 92 // U+005F (_): 0em 93 // U+05D0 : 1em // HEBREW LETTER ALEF 94 // U+05D1 : 5em // HEBREW LETTER BET 95 // U+FFFD (invalid surrogate will be replaced to this): 7em 96 // U+10331 (\uD800\uDF31): 10em 97 private static final Typeface TYPEFACE = Typeface.createFromAsset( 98 InstrumentationRegistry.getInstrumentation().getTargetContext().getAssets(), 99 "fonts/StaticLayoutLineBreakingTestFont.ttf"); 100 101 // The test font has following coverage and width. 102 // U+0020: 1em 103 // U+0049 (I): 1em 104 // U+0066 (f): 0.5em 105 // U+0069 (i): 0.5em 106 // ligature fi: 2em 107 // U+10331 (\uD800\uDF31): 10em 108 private static final Typeface TYPEFACE_LIGATURE = Typeface.createFromAsset( 109 InstrumentationRegistry.getInstrumentation().getTargetContext().getAssets(), 110 "fonts/ligature.ttf"); 111 getTextLine(CharSequence str, TextPaint paint, TabStops tabStops)112 private TextLine getTextLine(CharSequence str, TextPaint paint, TabStops tabStops) { 113 Layout layout = 114 StaticLayout.Builder.obtain(str, 0, str.length(), paint, Integer.MAX_VALUE) 115 .build(); 116 TextLine tl = TextLine.obtain(); 117 tl.set(paint, str, 0, str.length(), 118 TextDirectionHeuristics.FIRSTSTRONG_LTR.isRtl(str, 0, str.length()) ? -1 : 1, 119 layout.getLineDirections(0), tabStops != null, tabStops, 120 0, 0 /* no ellipsis */, false /* useFallbackLineSpacing */); 121 return tl; 122 } 123 getTextLine(CharSequence str, TextPaint paint)124 private TextLine getTextLine(CharSequence str, TextPaint paint) { 125 return getTextLine(str, paint, null); 126 } 127 assertMeasurements(final TextLine tl, final int length, boolean trailing, final float[] expected)128 private void assertMeasurements(final TextLine tl, final int length, boolean trailing, 129 final float[] expected) { 130 for (int offset = 0; offset <= length; ++offset) { 131 assertEquals(expected[offset], tl.measure(offset, trailing, null, null, null), 0.0f); 132 } 133 134 final boolean[] trailings = new boolean[length + 1]; 135 Arrays.fill(trailings, trailing); 136 final float[] allMeasurements = tl.measureAllOffsets(trailings, null); 137 assertArrayEquals(expected, allMeasurements, 0.0f); 138 } 139 140 @Test testMeasure_LTR()141 public void testMeasure_LTR() { 142 final TextPaint paint = new TextPaint(); 143 paint.setTypeface(TYPEFACE); 144 paint.setTextSize(10.0f); // make 1em = 10px 145 146 TextLine tl = getTextLine("IIIIIV", paint); 147 assertMeasurements(tl, 6, false, 148 new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f}); 149 assertMeasurements(tl, 6, true, 150 new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f}); 151 } 152 153 @Test testMeasure_RTL()154 public void testMeasure_RTL() { 155 final TextPaint paint = new TextPaint(); 156 paint.setTypeface(TYPEFACE); 157 paint.setTextSize(10.0f); // make 1em = 10px 158 159 TextLine tl = getTextLine("\u05D0\u05D0\u05D0\u05D0\u05D0\u05D1", paint); 160 assertMeasurements(tl, 6, false, 161 new float[]{0.0f, -10.0f, -20.0f, -30.0f, -40.0f, -50.0f, -100.0f}); 162 assertMeasurements(tl, 6, true, 163 new float[]{0.0f, -10.0f, -20.0f, -30.0f, -40.0f, -50.0f, -100.0f}); 164 } 165 166 @Test testMeasure_BiDi()167 public void testMeasure_BiDi() { 168 final TextPaint paint = new TextPaint(); 169 paint.setTypeface(TYPEFACE); 170 paint.setTextSize(10.0f); // make 1em = 10px 171 172 TextLine tl = getTextLine("II\u05D0\u05D0II", paint); 173 assertMeasurements(tl, 6, false, 174 new float[]{0.0f, 10.0f, 40.0f, 30.0f, 40.0f, 50.0f, 60.0f}); 175 assertMeasurements(tl, 6, true, 176 new float[]{0.0f, 10.0f, 20.0f, 30.0f, 20.0f, 50.0f, 60.0f}); 177 } 178 179 private static final String LRI = "\u2066"; // LEFT-TO-RIGHT ISOLATE 180 private static final String RLI = "\u2067"; // RIGHT-TO-LEFT ISOLATE 181 private static final String PDI = "\u2069"; // POP DIRECTIONAL ISOLATE 182 183 @Test testMeasure_BiDi2()184 public void testMeasure_BiDi2() { 185 final TextPaint paint = new TextPaint(); 186 paint.setTypeface(TYPEFACE); 187 paint.setTextSize(10.0f); // make 1em = 10px 188 189 TextLine tl = getTextLine("I" + RLI + "I\u05D0\u05D0" + PDI + "I", paint); 190 assertMeasurements(tl, 7, false, 191 new float[]{0.0f, 10.0f, 30.0f, 30.0f, 20.0f, 40.0f, 40.0f, 50.0f}); 192 assertMeasurements(tl, 7, true, 193 new float[]{0.0f, 10.0f, 10.0f, 40.0f, 20.0f, 10.0f, 40.0f, 50.0f}); 194 } 195 196 @Test testMeasure_BiDi3()197 public void testMeasure_BiDi3() { 198 final TextPaint paint = new TextPaint(); 199 paint.setTypeface(TYPEFACE); 200 paint.setTextSize(10.0f); // make 1em = 10px 201 202 TextLine tl = getTextLine("\u05D0" + LRI + "\u05D0II" + PDI + "\u05D0", paint); 203 assertMeasurements(tl, 7, false, 204 new float[]{0.0f, -10.0f, -30.0f, -30.0f, -20.0f, -40.0f, -40.0f, -50.0f}); 205 assertMeasurements(tl, 7, true, 206 new float[]{0.0f, -10.0f, -10.0f, -40.0f, -20.0f, -10.0f, -40.0f, -50.0f}); 207 } 208 209 @Test testMeasure_Tab_LTR()210 public void testMeasure_Tab_LTR() { 211 final Object[] spans = { new TabStopSpan.Standard(100) }; 212 final TabStops stops = new TabStops(100, spans); 213 final TextPaint paint = new TextPaint(); 214 paint.setTypeface(TYPEFACE); 215 paint.setTextSize(10.0f); // make 1em = 10px 216 217 TextLine tl = getTextLine("II\tII", paint, stops); 218 assertMeasurements(tl, 5, false, 219 new float[]{0.0f, 10.0f, 20.0f, 100.0f, 110.0f, 120.0f}); 220 assertMeasurements(tl, 5, true, 221 new float[]{0.0f, 10.0f, 20.0f, 100.0f, 110.0f, 120.0f}); 222 } 223 224 @Test testMeasure_Tab_RTL()225 public void testMeasure_Tab_RTL() { 226 final Object[] spans = { new TabStopSpan.Standard(100) }; 227 final TabStops stops = new TabStops(100, spans); 228 final TextPaint paint = new TextPaint(); 229 paint.setTypeface(TYPEFACE); 230 paint.setTextSize(10.0f); // make 1em = 10px 231 232 TextLine tl = getTextLine("\u05D0\u05D0\t\u05D0\u05D0", paint, stops); 233 assertMeasurements(tl, 5, false, 234 new float[]{0.0f, -10.0f, -20.0f, -100.0f, -110.0f, -120.0f}); 235 assertMeasurements(tl, 5, true, 236 new float[]{0.0f, -10.0f, -20.0f, -100.0f, -110.0f, -120.0f}); 237 } 238 239 @Test testMeasure_Tab_BiDi()240 public void testMeasure_Tab_BiDi() { 241 final Object[] spans = { new TabStopSpan.Standard(100) }; 242 final TabStops stops = new TabStops(100, spans); 243 final TextPaint paint = new TextPaint(); 244 paint.setTypeface(TYPEFACE); 245 paint.setTextSize(10.0f); // make 1em = 10px 246 247 TextLine tl = getTextLine("I\u05D0\tI\u05D0", paint, stops); 248 assertMeasurements(tl, 5, false, 249 new float[]{0.0f, 20.0f, 20.0f, 100.0f, 120.0f, 120.0f}); 250 assertMeasurements(tl, 5, true, 251 new float[]{0.0f, 10.0f, 10.0f, 100.0f, 110.0f, 110.0f}); 252 } 253 254 @Test testMeasure_Tab_BiDi2()255 public void testMeasure_Tab_BiDi2() { 256 final Object[] spans = { new TabStopSpan.Standard(100) }; 257 final TabStops stops = new TabStops(100, spans); 258 final TextPaint paint = new TextPaint(); 259 paint.setTypeface(TYPEFACE); 260 paint.setTextSize(10.0f); // make 1em = 10px 261 262 TextLine tl = getTextLine("\u05D0I\t\u05D0I", paint, stops); 263 assertMeasurements(tl, 5, false, 264 new float[]{0.0f, -20.0f, -20.0f, -100.0f, -120.0f, -120.0f}); 265 assertMeasurements(tl, 5, true, 266 new float[]{0.0f, -10.0f, -10.0f, -100.0f, -110.0f, -110.0f}); 267 } 268 269 @Test testMeasure_wordSpacing()270 public void testMeasure_wordSpacing() { 271 final TextPaint paint = new TextPaint(); 272 paint.setTypeface(TYPEFACE); 273 paint.setTextSize(10.0f); // make 1em = 10px 274 paint.setWordSpacing(10.0f); 275 276 TextLine tl = getTextLine("I I", paint); 277 assertMeasurements(tl, 3, false, 278 new float[]{0.0f, 10.0f, 120.0f, 130.0f}); 279 assertMeasurements(tl, 3, true, 280 new float[]{0.0f, 10.0f, 120.0f, 130.0f}); 281 } 282 283 @Test testMeasure_surrogate()284 public void testMeasure_surrogate() { 285 final TextPaint paint = new TextPaint(); 286 paint.setTypeface(TYPEFACE); 287 paint.setTextSize(10.0f); // make 1em = 10px 288 289 TextLine tl = getTextLine("I\uD800\uDF31I", paint); 290 assertMeasurements(tl, 4, false, 291 new float[]{0.0f, 10.0f, 110.0f, 110.0f, 120.0f}); 292 assertMeasurements(tl, 4, true, 293 new float[]{0.0f, 10.0f, 110.0f, 110.0f, 120.0f}); 294 } 295 296 @Test testMeasure_ligature()297 public void testMeasure_ligature() { 298 final TextPaint paint = new TextPaint(); 299 paint.setTypeface(TYPEFACE_LIGATURE); 300 paint.setTextSize(10.0f); // make 1em = 10px 301 302 TextLine tl = getTextLine("IfiI", paint); 303 assertMeasurements(tl, 4, false, 304 new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f}); 305 assertMeasurements(tl, 4, true, 306 new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f}); 307 } 308 309 @Test testHandleRun_ellipsizedReplacementSpan_isSkipped()310 public void testHandleRun_ellipsizedReplacementSpan_isSkipped() { 311 final Spannable text = new SpannableStringBuilder("This is a... text"); 312 313 // Setup a replacement span that the measurement should not interact with. 314 final TestReplacementSpan span = new TestReplacementSpan(); 315 text.setSpan(span, 9, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 316 317 final TextLine tl = TextLine.obtain(); 318 tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT, 319 false /* hasTabs */, null /* tabStops */, 9, 12, 320 false /* useFallbackLineSpacing */); 321 tl.measure(text.length(), false /* trailing */, null /* fmi */, null, null); 322 323 assertFalse(span.mIsUsed); 324 } 325 326 @Test testHandleRun_notEllipsizedReplacementSpan_isNotSkipped()327 public void testHandleRun_notEllipsizedReplacementSpan_isNotSkipped() { 328 final Spannable text = new SpannableStringBuilder("This is a... text"); 329 330 // Setup a replacement span that the measurement should not interact with. 331 final TestReplacementSpan span = new TestReplacementSpan(); 332 text.setSpan(span, 1, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 333 334 final TextLine tl = TextLine.obtain(); 335 tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT, 336 false /* hasTabs */, null /* tabStops */, 9, 12, 337 false /* useFallbackLineSpacing */); 338 tl.measure(text.length(), false /* trailing */, null /* fmi */, null, null); 339 340 assertTrue(span.mIsUsed); 341 } 342 343 @Test testHandleRun_halfEllipsizedReplacementSpan_isNotSkipped()344 public void testHandleRun_halfEllipsizedReplacementSpan_isNotSkipped() { 345 final Spannable text = new SpannableStringBuilder("This is a... text"); 346 347 // Setup a replacement span that the measurement should not interact with. 348 final TestReplacementSpan span = new TestReplacementSpan(); 349 text.setSpan(span, 7, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 350 351 final TextLine tl = TextLine.obtain(); 352 tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT, 353 false /* hasTabs */, null /* tabStops */, 9, 12, 354 false /* useFallbackLineSpacing */); 355 tl.measure(text.length(), false /* trailing */, null /* fmi */, null, null); 356 assertTrue(span.mIsUsed); 357 } 358 359 @Test testMeasureAllBounds_LTR()360 public void testMeasureAllBounds_LTR() { 361 final TextPaint paint = new TextPaint(); 362 paint.setTypeface(TYPEFACE); 363 paint.setTextSize(10.0f); // make 1em = 10px 364 365 TextLine tl = getTextLine("IIIIIV", paint); 366 float[] bounds = new float[12]; 367 float[] advances = new float[6]; 368 tl.measureAllBounds(bounds, advances); 369 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 20.0f, 20.0f, 30.0f, 30.0f, 40.0f, 370 40.0f, 50.0f, 50.0f, 100.0f}, bounds, 0.0f); 371 assertArrayEquals(new float[] {10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 50.0f}, advances, 0.0f); 372 } 373 374 @Test testMeasureAllBounds_LTR_StyledText()375 public void testMeasureAllBounds_LTR_StyledText() { 376 final TextPaint paint = new TextPaint(); 377 paint.setTypeface(TYPEFACE); 378 paint.setTextSize(10.0f); // make 1em = 10px 379 SpannableString text = new SpannableString("IIIIIV"); 380 text.setSpan(new AbsoluteSizeSpan(5), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 381 382 TextLine tl = getTextLine(text, paint); 383 float[] bounds = new float[12]; 384 float[] advances = new float[6]; 385 tl.measureAllBounds(bounds, advances); 386 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 15.0f, 15.0f, 20.0f, 20.0f, 30.0f, 387 30.0f, 40.0f, 40.0f, 90.0f}, bounds, 0.0f); 388 assertArrayEquals(new float[] {10.0f, 5.0f, 5.0f, 10.0f, 10.0f, 50.0f}, advances, 0.0f); 389 } 390 391 @Test testMeasureAllBounds_RTL()392 public void testMeasureAllBounds_RTL() { 393 final TextPaint paint = new TextPaint(); 394 paint.setTypeface(TYPEFACE); 395 paint.setTextSize(10.0f); // make 1em = 10px 396 397 TextLine tl = getTextLine("\u05D0\u05D0\u05D0\u05D0\u05D0\u05D1", paint); 398 float[] bounds = new float[12]; 399 float[] advances = new float[6]; 400 tl.measureAllBounds(bounds, advances); 401 assertArrayEquals(new float[] {-10.0f, 0.0f, -20.0f, -10.0f, -30.0f, -20.0f, -40.0f, -30.0f, 402 -50.0f, -40.0f, -100.0f, -50.0f}, bounds, 0.0f); 403 assertArrayEquals(new float[] {10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 50.0f}, advances, 0.0f); 404 } 405 406 407 @Test testMeasureAllBounds_RTL_StyledText()408 public void testMeasureAllBounds_RTL_StyledText() { 409 final TextPaint paint = new TextPaint(); 410 paint.setTypeface(TYPEFACE); 411 paint.setTextSize(10.0f); // make 1em = 10px 412 SpannableString text = new SpannableString("\u05D0\u05D0\u05D0\u05D0\u05D0\u05D1"); 413 text.setSpan(new AbsoluteSizeSpan(5), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 414 415 TextLine tl = getTextLine(text, paint); 416 float[] bounds = new float[12]; 417 float[] advances = new float[6]; 418 tl.measureAllBounds(bounds, advances); 419 assertArrayEquals(new float[] {-10.0f, 0.0f, -15.0f, -10.0f, -20.0f, -15.0f, 420 -30.0f, -20.0f, -40.0f, -30.0f, -90.0f, -40.0f}, bounds, 0.0f); 421 assertArrayEquals(new float[] {10.0f, 5.0f, 5.0f, 10.0f, 10.0f, 50.0f}, advances, 0.0f); 422 } 423 424 @Test testMeasureAllBounds_BiDi()425 public void testMeasureAllBounds_BiDi() { 426 final TextPaint paint = new TextPaint(); 427 paint.setTypeface(TYPEFACE); 428 paint.setTextSize(10.0f); // make 1em = 10px 429 430 TextLine tl = getTextLine("II\u05D0\u05D0II", paint); 431 float[] bounds = new float[12]; 432 float[] advances = new float[6]; 433 tl.measureAllBounds(bounds, advances); 434 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 20.0f, 30.0f, 40.0f, 20.0f, 30.0f, 435 40.0f, 50.0f, 50.0f, 60.0f}, bounds, 0.0f); 436 assertArrayEquals(new float[] {10.0f, 10.0f, 10.0f, 10.0f, 10.0f, 10.0f}, advances, 0.0f); 437 } 438 439 @Test testMeasureAllBounds_BiDi2()440 public void testMeasureAllBounds_BiDi2() { 441 final TextPaint paint = new TextPaint(); 442 paint.setTypeface(TYPEFACE); 443 paint.setTextSize(10.0f); // make 1em = 10px 444 445 TextLine tl = getTextLine("I" + RLI + "I\u05D0\u05D0" + PDI + "I", paint); 446 float[] bounds = new float[14]; 447 float[] advances = new float[7]; 448 tl.measureAllBounds(bounds, advances); 449 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 10.0f, 30.0f, 40.0f, 20.0f, 30.0f, 450 10.0f, 20.0f, 40.0f, 40.0f, 40.0f, 50.0f}, bounds, 0.0f); 451 assertArrayEquals(new float[] {10.0f, 0.0f, 10.0f, 10.0f, 10.0f, 0.0f, 10.0f}, advances, 452 0.0f); 453 } 454 455 @Test testMeasureAllBounds_BiDi3()456 public void testMeasureAllBounds_BiDi3() { 457 final TextPaint paint = new TextPaint(); 458 paint.setTypeface(TYPEFACE); 459 paint.setTextSize(10.0f); // make 1em = 10px 460 461 TextLine tl = getTextLine("\u05D0" + LRI + "\u05D0II" + PDI + "\u05D0", paint); 462 float[] bounds = new float[14]; 463 float[] advances = new float[7]; 464 tl.measureAllBounds(bounds, advances); 465 assertArrayEquals(new float[] {-10.0f, 0.0f, -10.0f, -10.0f, -40.0f, -30.0f, 466 -30.0f, -20.0f, -20.0f, -10.0f, -40.0f, -40.0f, -50.0f, -40.0f}, bounds, 0.0f); 467 assertArrayEquals(new float[] {10.0f, 0.0f, 10.0f, 10.0f, 10.0f, 0.0f, 10.0f}, advances, 468 0.0f); 469 } 470 471 @Test testMeasureAllBounds_styled_BiDi()472 public void testMeasureAllBounds_styled_BiDi() { 473 final TextPaint paint = new TextPaint(); 474 paint.setTypeface(TYPEFACE); 475 paint.setTextSize(10.0f); // make 1em = 10px 476 477 SpannableString text = new SpannableString("II\u05D0\u05D0II"); 478 text.setSpan(new AbsoluteSizeSpan(5), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 479 480 TextLine tl = getTextLine(text, paint); 481 float[] bounds = new float[12]; 482 float[] advances = new float[6]; 483 tl.measureAllBounds(bounds, advances); 484 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 15.0f, 25.0f, 30.0f, 485 15.0f, 25.0f, 30.0f, 40.0f, 40.0f, 50.0f}, bounds, 0.0f); 486 assertArrayEquals(new float[] {10.0f, 5.0f, 5.0f, 10.0f, 10.0f, 10.0f}, advances, 0.0f); 487 } 488 489 @Test testMeasureAllBounds_Tab_LTR()490 public void testMeasureAllBounds_Tab_LTR() { 491 final Object[] spans = { new TabStopSpan.Standard(100) }; 492 final TabStops stops = new TabStops(100, spans); 493 final TextPaint paint = new TextPaint(); 494 paint.setTypeface(TYPEFACE); 495 paint.setTextSize(10.0f); // make 1em = 10px 496 497 TextLine tl = getTextLine("II\tII", paint, stops); 498 float[] bounds = new float[10]; 499 float[] advances = new float[5]; 500 tl.measureAllBounds(bounds, advances); 501 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 20.0f, 20.0f, 100.0f, 100.0f, 110.0f, 502 110.0f, 120.0f}, bounds, 0.0f); 503 assertArrayEquals(new float[] {10.0f, 10.0f, 80.0f, 10.0f, 10.0f}, advances, 0.0f); 504 } 505 506 @Test testMeasureAllBounds_Tab_RTL()507 public void testMeasureAllBounds_Tab_RTL() { 508 final Object[] spans = { new TabStopSpan.Standard(100) }; 509 final TabStops stops = new TabStops(100, spans); 510 final TextPaint paint = new TextPaint(); 511 paint.setTypeface(TYPEFACE); 512 paint.setTextSize(10.0f); // make 1em = 10px 513 514 TextLine tl = getTextLine("\u05D0\u05D0\t\u05D0\u05D0", paint, stops); 515 float[] bounds = new float[10]; 516 float[] advances = new float[5]; 517 tl.measureAllBounds(bounds, advances); 518 assertArrayEquals(new float[] {-10.0f, 0.0f, -20.0f, -10.0f, -100.0f, -20.0f, 519 -110.0f, -100.0f, -120.0f, -110.0f}, bounds, 0.0f); 520 assertArrayEquals(new float[] {10.0f, 10.0f, 80.0f, 10.0f, 10.0f}, advances, 0.0f); 521 } 522 523 @Test testMeasureAllBounds_Tab_BiDi()524 public void testMeasureAllBounds_Tab_BiDi() { 525 final Object[] spans = { new TabStopSpan.Standard(100) }; 526 final TabStops stops = new TabStops(100, spans); 527 final TextPaint paint = new TextPaint(); 528 paint.setTypeface(TYPEFACE); 529 paint.setTextSize(10.0f); // make 1em = 10px 530 531 TextLine tl = getTextLine("I\u05D0\tI\u05D0", paint, stops); 532 float[] bounds = new float[10]; 533 float[] advances = new float[5]; 534 tl.measureAllBounds(bounds, advances); 535 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 20.0f, 20.0f, 100.0f, 536 100.0f, 110.0f, 110.0f, 120.0f}, bounds, 0.0f); 537 assertArrayEquals(new float[] {10.0f, 10.0f, 80.0f, 10.0f, 10.0f}, advances, 0.0f); 538 } 539 540 @Test testMeasureAllBounds_Tab_BiDi2()541 public void testMeasureAllBounds_Tab_BiDi2() { 542 final Object[] spans = { new TabStopSpan.Standard(100) }; 543 final TabStops stops = new TabStops(100, spans); 544 final TextPaint paint = new TextPaint(); 545 paint.setTypeface(TYPEFACE); 546 paint.setTextSize(10.0f); // make 1em = 10px 547 548 TextLine tl = getTextLine("\u05D0I\t\u05D0I", paint, stops); 549 float[] bounds = new float[10]; 550 float[] advances = new float[5]; 551 tl.measureAllBounds(bounds, advances); 552 assertArrayEquals(new float[] {-10.0f, 0.0f, -20.0f, -10.0f, -100.0f, -20.0f, 553 -110.0f, -100.0f, -120.0f, -110.0f}, bounds, 0.0f); 554 assertArrayEquals(new float[] {10.0f, 10.0f, 80.0f, 10.0f, 10.0f}, advances, 0.0f); 555 } 556 557 @Test testMeasureAllBounds_replacement_LTR()558 public void testMeasureAllBounds_replacement_LTR() { 559 final TextPaint paint = new TextPaint(); 560 paint.setTypeface(TYPEFACE); 561 paint.setTextSize(10.0f); // make 1em = 10px 562 563 SpannableString text = new SpannableString("IIIII"); 564 text.setSpan(new TestReplacementSpan(5), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 565 566 TextLine tl = getTextLine(text, paint); 567 float[] bounds = new float[10]; 568 float[] advances = new float[5]; 569 tl.measureAllBounds(bounds, advances); 570 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 15.0f, 15.0f, 15.0f, 571 15.0f, 25.0f, 25.0f, 35.0f}, bounds, 0.0f); 572 assertArrayEquals(new float[] {10.0f, 5.0f, 0.0f, 10.0f, 10.0f}, advances, 0.0f); 573 } 574 575 @Test testMeasureAllBounds_replacement_RTL()576 public void testMeasureAllBounds_replacement_RTL() { 577 final TextPaint paint = new TextPaint(); 578 paint.setTypeface(TYPEFACE); 579 paint.setTextSize(10.0f); // make 1em = 10px 580 581 SpannableString text = new SpannableString("\u05D0\u05D0\u05D0\u05D0\u05D0"); 582 text.setSpan(new TestReplacementSpan(5), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 583 584 TextLine tl = getTextLine(text, paint); 585 float[] bounds = new float[10]; 586 float[] advances = new float[5]; 587 tl.measureAllBounds(bounds, advances); 588 assertArrayEquals(new float[] {-10.0f, 0.0f, -15.0f, -10.0f, -15.0f, -15.0f, 589 -25.0f, -15.0f, -35.0f, -25.0f}, bounds, 0.0f); 590 assertArrayEquals(new float[] {10.0f, 5.0f, 0.0f, 10.0f, 10.0f}, advances, 0.0f); 591 } 592 593 @Test testMeasureAllBounds_replacement_BiDi()594 public void testMeasureAllBounds_replacement_BiDi() { 595 final TextPaint paint = new TextPaint(); 596 paint.setTypeface(TYPEFACE); 597 paint.setTextSize(10.0f); // make 1em = 10px 598 599 SpannableString text = new SpannableString("II\u05D0\u05D0II"); 600 text.setSpan(new TestReplacementSpan(5), 1, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 601 602 TextLine tl = getTextLine(text, paint); 603 float[] bounds = new float[12]; 604 float[] advances = new float[6]; 605 tl.measureAllBounds(bounds, advances); 606 assertArrayEquals(new float[] {0.0f, 10.0f, 10.0f, 15.0f, 15.0f, 15.0f, 607 15.0f, 25.0f, 25.0f, 35.0f, 35.0f, 45.0f}, bounds, 0.0f); 608 assertArrayEquals(new float[] {10.0f, 5.0f, 0.0f, 10.0f, 10.0f, 10.0f}, advances, 0.0f); 609 } 610 611 private static class TestReplacementSpan extends ReplacementSpan { 612 boolean mIsUsed; 613 private final int mWidth; 614 TestReplacementSpan()615 TestReplacementSpan() { 616 mWidth = 0; 617 } 618 TestReplacementSpan(int width)619 TestReplacementSpan(int width) { 620 mWidth = width; 621 } 622 623 @Override getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm)624 public int getSize(Paint paint, CharSequence text, int start, int end, 625 Paint.FontMetricsInt fm) { 626 mIsUsed = true; 627 return mWidth; 628 } 629 630 @Override draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)631 public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, 632 int y, 633 int bottom, Paint paint) { 634 mIsUsed = true; 635 } 636 } 637 } 638