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.cts; 18 19 import static android.text.TextDirectionHeuristics.LTR; 20 import static android.text.TextDirectionHeuristics.RTL; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertTrue; 26 import static org.junit.Assert.fail; 27 28 import android.content.Context; 29 import android.graphics.Color; 30 import android.graphics.Rect; 31 import android.graphics.Typeface; 32 import android.support.test.InstrumentationRegistry; 33 import android.support.test.filters.SmallTest; 34 import android.support.test.runner.AndroidJUnit4; 35 import android.text.Layout; 36 import android.text.PrecomputedText; 37 import android.text.PrecomputedText.Params; 38 import android.text.Spannable; 39 import android.text.SpannableStringBuilder; 40 import android.text.Spanned; 41 import android.text.TextDirectionHeuristics; 42 import android.text.TextPaint; 43 import android.text.style.BackgroundColorSpan; 44 import android.text.style.LocaleSpan; 45 import android.text.style.TextAppearanceSpan; 46 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 50 import java.util.Locale; 51 52 @SmallTest 53 @RunWith(AndroidJUnit4.class) 54 public class PrecomputedTextTest { 55 56 private static final CharSequence NULL_CHAR_SEQUENCE = null; 57 private static final String STRING = "Hello, World!"; 58 private static final String MULTIPARA_STRING = "Hello,\nWorld!"; 59 60 private static final int SPAN_START = 3; 61 private static final int SPAN_END = 7; 62 private static final LocaleSpan SPAN = new LocaleSpan(Locale.US); 63 private static final Spanned SPANNED; 64 static { 65 final SpannableStringBuilder ssb = new SpannableStringBuilder(STRING); ssb.setSpan(SPAN, SPAN_START, SPAN_END, Spanned.SPAN_INCLUSIVE_EXCLUSIVE)66 ssb.setSpan(SPAN, SPAN_START, SPAN_END, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 67 SPANNED = ssb; 68 } 69 70 private static final TextPaint PAINT = new TextPaint(); 71 72 @Test testParams_create()73 public void testParams_create() { 74 assertNotNull(new Params.Builder(PAINT).build()); 75 assertNotNull(new Params.Builder(PAINT) 76 .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE).build()); 77 assertNotNull(new Params.Builder(PAINT) 78 .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) 79 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL).build()); 80 assertNotNull(new Params.Builder(PAINT) 81 .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) 82 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) 83 .setTextDirection(LTR).build()); 84 } 85 86 @Test testParams_SetGet()87 public void testParams_SetGet() { 88 assertEquals(Layout.BREAK_STRATEGY_SIMPLE, new Params.Builder(PAINT) 89 .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE).build().getBreakStrategy()); 90 assertEquals(Layout.HYPHENATION_FREQUENCY_NONE, new Params.Builder(PAINT) 91 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE).build() 92 .getHyphenationFrequency()); 93 assertEquals(RTL, new Params.Builder(PAINT).setTextDirection(RTL).build() 94 .getTextDirection()); 95 } 96 97 @Test testParams_GetDefaultValues()98 public void testParams_GetDefaultValues() { 99 assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, 100 new Params.Builder(PAINT).build().getBreakStrategy()); 101 assertEquals(Layout.HYPHENATION_FREQUENCY_NORMAL, 102 new Params.Builder(PAINT).build().getHyphenationFrequency()); 103 assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, 104 new Params.Builder(PAINT).build().getTextDirection()); 105 } 106 107 @Test testParams_equals()108 public void testParams_equals() { 109 final Params base = new Params.Builder(PAINT) 110 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) 111 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) 112 .setTextDirection(LTR).build(); 113 114 assertFalse(base.equals(null)); 115 assertTrue(base.equals(base)); 116 assertFalse(base.equals(new Object())); 117 118 Params other = new Params.Builder(PAINT) 119 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) 120 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) 121 .setTextDirection(LTR).build(); 122 assertTrue(base.equals(other)); 123 assertTrue(other.equals(base)); 124 assertEquals(base.hashCode(), other.hashCode()); 125 126 other = new Params.Builder(PAINT) 127 .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) 128 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) 129 .setTextDirection(LTR).build(); 130 assertFalse(base.equals(other)); 131 assertFalse(other.equals(base)); 132 133 other = new Params.Builder(PAINT) 134 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) 135 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) 136 .setTextDirection(LTR).build(); 137 assertFalse(base.equals(other)); 138 assertFalse(other.equals(base)); 139 140 141 other = new Params.Builder(PAINT) 142 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) 143 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) 144 .setTextDirection(RTL).build(); 145 assertFalse(base.equals(other)); 146 assertFalse(other.equals(base)); 147 148 149 TextPaint anotherPaint = new TextPaint(PAINT); 150 anotherPaint.setTextSize(PAINT.getTextSize() * 2.0f); 151 other = new Params.Builder(anotherPaint) 152 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY) 153 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) 154 .setTextDirection(LTR).build(); 155 assertFalse(base.equals(other)); 156 assertFalse(other.equals(base)); 157 158 } 159 160 @Test testCreate_withNull()161 public void testCreate_withNull() { 162 final Params param = new Params.Builder(PAINT).build(); 163 try { 164 PrecomputedText.create(NULL_CHAR_SEQUENCE, param); 165 fail(); 166 } catch (NullPointerException e) { 167 // pass 168 } 169 try { 170 PrecomputedText.create(STRING, null); 171 fail(); 172 } catch (NullPointerException e) { 173 // pass 174 } 175 } 176 177 @Test testCharSequenceInteface()178 public void testCharSequenceInteface() { 179 final Params param = new Params.Builder(PAINT).build(); 180 final CharSequence s = PrecomputedText.create(STRING, param); 181 assertEquals(STRING.length(), s.length()); 182 assertEquals('H', s.charAt(0)); 183 assertEquals('e', s.charAt(1)); 184 assertEquals('l', s.charAt(2)); 185 assertEquals('l', s.charAt(3)); 186 assertEquals('o', s.charAt(4)); 187 assertEquals(',', s.charAt(5)); 188 assertEquals("Hello, World!", s.toString()); 189 190 final CharSequence s3 = s.subSequence(0, 3); 191 assertEquals(3, s3.length()); 192 assertEquals('H', s3.charAt(0)); 193 assertEquals('e', s3.charAt(1)); 194 assertEquals('l', s3.charAt(2)); 195 196 } 197 198 @Test testSpannedInterface_Spanned()199 public void testSpannedInterface_Spanned() { 200 final Params param = new Params.Builder(PAINT).build(); 201 final Spanned s = PrecomputedText.create(SPANNED, param); 202 final LocaleSpan[] spans = s.getSpans(0, s.length(), LocaleSpan.class); 203 assertNotNull(spans); 204 assertEquals(1, spans.length); 205 assertEquals(SPAN, spans[0]); 206 207 assertEquals(SPAN_START, s.getSpanStart(SPAN)); 208 assertEquals(SPAN_END, s.getSpanEnd(SPAN)); 209 assertTrue((s.getSpanFlags(SPAN) & Spanned.SPAN_INCLUSIVE_EXCLUSIVE) != 0); 210 211 assertEquals(SPAN_START, s.nextSpanTransition(0, s.length(), LocaleSpan.class)); 212 assertEquals(SPAN_END, s.nextSpanTransition(SPAN_START, s.length(), LocaleSpan.class)); 213 } 214 215 @Test testSpannedInterface_Spannable()216 public void testSpannedInterface_Spannable() { 217 final BackgroundColorSpan span = new BackgroundColorSpan(Color.RED); 218 final Params param = new Params.Builder(PAINT).build(); 219 final Spannable s = PrecomputedText.create(STRING, param); 220 assertEquals(0, s.getSpans(0, s.length(), BackgroundColorSpan.class).length); 221 222 s.setSpan(span, SPAN_START, SPAN_END, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 223 224 final BackgroundColorSpan[] spans = s.getSpans(0, s.length(), BackgroundColorSpan.class); 225 assertEquals(SPAN_START, s.getSpanStart(span)); 226 assertEquals(SPAN_END, s.getSpanEnd(span)); 227 assertTrue((s.getSpanFlags(span) & Spanned.SPAN_INCLUSIVE_EXCLUSIVE) != 0); 228 229 assertEquals(SPAN_START, s.nextSpanTransition(0, s.length(), BackgroundColorSpan.class)); 230 assertEquals(SPAN_END, 231 s.nextSpanTransition(SPAN_START, s.length(), BackgroundColorSpan.class)); 232 233 s.removeSpan(span); 234 assertEquals(0, s.getSpans(0, s.length(), BackgroundColorSpan.class).length); 235 } 236 237 @Test(expected = IllegalArgumentException.class) testSpannedInterface_Spannable_setSpan_MetricsAffectingSpan()238 public void testSpannedInterface_Spannable_setSpan_MetricsAffectingSpan() { 239 final Params param = new Params.Builder(PAINT).build(); 240 final Spannable s = PrecomputedText.create(SPANNED, param); 241 s.setSpan(SPAN, SPAN_START, SPAN_END, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 242 } 243 244 @Test(expected = IllegalArgumentException.class) testSpannedInterface_Spannable_removeSpan_MetricsAffectingSpan()245 public void testSpannedInterface_Spannable_removeSpan_MetricsAffectingSpan() { 246 final Params param = new Params.Builder(PAINT).build(); 247 final Spannable s = PrecomputedText.create(SPANNED, param); 248 s.removeSpan(SPAN); 249 } 250 251 @Test testSpannedInterface_String()252 public void testSpannedInterface_String() { 253 final Params param = new Params.Builder(PAINT).build(); 254 final Spanned s = PrecomputedText.create(STRING, param); 255 LocaleSpan[] spans = s.getSpans(0, s.length(), LocaleSpan.class); 256 assertNotNull(spans); 257 assertEquals(0, spans.length); 258 259 assertEquals(-1, s.getSpanStart(SPAN)); 260 assertEquals(-1, s.getSpanEnd(SPAN)); 261 assertEquals(0, s.getSpanFlags(SPAN)); 262 263 assertEquals(s.length(), s.nextSpanTransition(0, s.length(), LocaleSpan.class)); 264 } 265 266 @Test testGetParagraphCount()267 public void testGetParagraphCount() { 268 final Params param = new Params.Builder(PAINT).build(); 269 final PrecomputedText pm = PrecomputedText.create(STRING, param); 270 assertEquals(1, pm.getParagraphCount()); 271 assertEquals(0, pm.getParagraphStart(0)); 272 assertEquals(STRING.length(), pm.getParagraphEnd(0)); 273 274 final PrecomputedText pm1 = PrecomputedText.create(MULTIPARA_STRING, param); 275 assertEquals(2, pm1.getParagraphCount()); 276 assertEquals(0, pm1.getParagraphStart(0)); 277 assertEquals(7, pm1.getParagraphEnd(0)); 278 assertEquals(7, pm1.getParagraphStart(1)); 279 assertEquals(pm1.length(), pm1.getParagraphEnd(1)); 280 } 281 282 @Test testGetWidth()283 public void testGetWidth() { 284 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 285 286 // The test font has following coverage and width. 287 // U+0020: 10em 288 // U+002E (.): 10em 289 // U+0043 (C): 100em 290 // U+0049 (I): 1em 291 // U+004C (L): 50em 292 // U+0056 (V): 5em 293 // U+0058 (X): 10em 294 // U+005F (_): 0em 295 // U+FFFD (invalid surrogate will be replaced to this): 7em 296 // U+10331 (\uD800\uDF31): 10em 297 final Typeface tf = new Typeface.Builder(context.getAssets(), 298 "fonts/StaticLayoutLineBreakingTestFont.ttf").build(); 299 final TextPaint paint = new TextPaint(); 300 paint.setTypeface(tf); 301 paint.setTextSize(1); // Make 1em = 1px 302 303 final Params param = new Params.Builder(paint).build(); 304 assertEquals(0.0f, PrecomputedText.create("", param).getWidth(0, 0), 0.0f); 305 306 assertEquals(0.0f, PrecomputedText.create("I", param).getWidth(0, 0), 0.0f); 307 assertEquals(0.0f, PrecomputedText.create("I", param).getWidth(1, 1), 0.0f); 308 assertEquals(1.0f, PrecomputedText.create("I", param).getWidth(0, 1), 0.0f); 309 310 assertEquals(0.0f, PrecomputedText.create("V", param).getWidth(0, 0), 0.0f); 311 assertEquals(0.0f, PrecomputedText.create("V", param).getWidth(1, 1), 0.0f); 312 assertEquals(5.0f, PrecomputedText.create("V", param).getWidth(0, 1), 0.0f); 313 314 assertEquals(0.0f, PrecomputedText.create("IV", param).getWidth(0, 0), 0.0f); 315 assertEquals(0.0f, PrecomputedText.create("IV", param).getWidth(1, 1), 0.0f); 316 assertEquals(0.0f, PrecomputedText.create("IV", param).getWidth(2, 2), 0.0f); 317 assertEquals(1.0f, PrecomputedText.create("IV", param).getWidth(0, 1), 0.0f); 318 assertEquals(5.0f, PrecomputedText.create("IV", param).getWidth(1, 2), 0.0f); 319 assertEquals(6.0f, PrecomputedText.create("IV", param).getWidth(0, 2), 0.0f); 320 321 assertEquals(0.0f, PrecomputedText.create("I\nV", param).getWidth(0, 0), 0.0f); 322 assertEquals(0.0f, PrecomputedText.create("I\nV", param).getWidth(1, 1), 0.0f); 323 assertEquals(0.0f, PrecomputedText.create("I\nV", param).getWidth(2, 2), 0.0f); 324 assertEquals(0.0f, PrecomputedText.create("I\nV", param).getWidth(3, 3), 0.0f); 325 assertEquals(1.0f, PrecomputedText.create("I\nV", param).getWidth(0, 1), 0.0f); 326 assertEquals(1.0f, PrecomputedText.create("I\nV", param).getWidth(0, 2), 0.0f); 327 assertEquals(5.0f, PrecomputedText.create("I\nV", param).getWidth(2, 3), 0.0f); 328 } 329 330 @Test testGetWidth_multiStyle()331 public void testGetWidth_multiStyle() { 332 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 333 final SpannableStringBuilder ssb = new SpannableStringBuilder("II"); 334 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 1 /* text size */, 335 null /* color */, null /* link color */), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 336 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 5 /* text size */, 337 null /* color */, null /* link color */), 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 338 339 final Typeface tf = new Typeface.Builder(context.getAssets(), 340 "fonts/StaticLayoutLineBreakingTestFont.ttf").build(); 341 final TextPaint paint = new TextPaint(); 342 paint.setTypeface(tf); 343 paint.setTextSize(1); // Make 1em = 1px 344 345 final Params param = new Params.Builder(paint).build(); 346 347 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(0, 0), 0.0f); 348 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(1, 1), 0.0f); 349 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(2, 2), 0.0f); 350 351 assertEquals(1.0f, PrecomputedText.create(ssb, param).getWidth(0, 1), 0.0f); 352 assertEquals(5.0f, PrecomputedText.create(ssb, param).getWidth(1, 2), 0.0f); 353 354 assertEquals(6.0f, PrecomputedText.create(ssb, param).getWidth(0, 2), 0.0f); 355 } 356 357 @Test testGetWidth_multiStyle2()358 public void testGetWidth_multiStyle2() { 359 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 360 final SpannableStringBuilder ssb = new SpannableStringBuilder("IVI"); 361 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 1 /* text size */, 362 null /* color */, null /* link color */), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 363 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 5 /* text size */, 364 null /* color */, null /* link color */), 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 365 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 5 /* text size */, 366 null /* color */, null /* link color */), 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 367 368 final Typeface tf = new Typeface.Builder(context.getAssets(), 369 "fonts/StaticLayoutLineBreakingTestFont.ttf").build(); 370 final TextPaint paint = new TextPaint(); 371 paint.setTypeface(tf); 372 paint.setTextSize(1); // Make 1em = 1px 373 374 final Params param = new Params.Builder(paint).build(); 375 376 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(0, 0), 0.0f); 377 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(1, 1), 0.0f); 378 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(2, 2), 0.0f); 379 assertEquals(0.0f, PrecomputedText.create(ssb, param).getWidth(3, 3), 0.0f); 380 381 assertEquals(1.0f, PrecomputedText.create(ssb, param).getWidth(0, 1), 0.0f); 382 assertEquals(25.0f, PrecomputedText.create(ssb, param).getWidth(1, 2), 0.0f); 383 assertEquals(5.0f, PrecomputedText.create(ssb, param).getWidth(2, 3), 0.0f); 384 385 assertEquals(26.0f, PrecomputedText.create(ssb, param).getWidth(0, 2), 0.0f); 386 assertEquals(30.0f, PrecomputedText.create(ssb, param).getWidth(1, 3), 0.0f); 387 assertEquals(31.0f, PrecomputedText.create(ssb, param).getWidth(0, 3), 0.0f); 388 } 389 390 @Test(expected = IllegalArgumentException.class) testGetWidth_negative_start_offset()391 public void testGetWidth_negative_start_offset() { 392 final Params param = new Params.Builder(PAINT).build(); 393 PrecomputedText.create("a", param).getWidth(-1, 0); 394 } 395 396 @Test(expected = IllegalArgumentException.class) testGetWidth_negative_end_offset()397 public void testGetWidth_negative_end_offset() { 398 final Params param = new Params.Builder(PAINT).build(); 399 PrecomputedText.create("a", param).getWidth(0, -1); 400 } 401 402 @Test(expected = IllegalArgumentException.class) testGetWidth_index_out_of_bounds_start_offset()403 public void testGetWidth_index_out_of_bounds_start_offset() { 404 final Params param = new Params.Builder(PAINT).build(); 405 PrecomputedText.create("a", param).getWidth(2, 2); 406 } 407 408 @Test(expected = IllegalArgumentException.class) testGetWidth_index_out_of_bounds_end_offset()409 public void testGetWidth_index_out_of_bounds_end_offset() { 410 final Params param = new Params.Builder(PAINT).build(); 411 PrecomputedText.create("a", param).getWidth(0, 2); 412 } 413 414 @Test(expected = IllegalArgumentException.class) testGetWidth_reverse_offset()415 public void testGetWidth_reverse_offset() { 416 final Params param = new Params.Builder(PAINT).build(); 417 PrecomputedText.create("a", param).getWidth(1, 0); 418 } 419 420 @Test(expected = IllegalArgumentException.class) testGetWidth_across_paragraph_boundary()421 public void testGetWidth_across_paragraph_boundary() { 422 final Params param = new Params.Builder(PAINT).build(); 423 PrecomputedText.create("a\nb", param).getWidth(0, 3); 424 } 425 426 @Test testGetBounds()427 public void testGetBounds() { 428 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 429 430 // The test font has following coverage and width. 431 // U+0020: 10em 432 // U+002E (.): 10em 433 // U+0043 (C): 100em 434 // U+0049 (I): 1em 435 // U+004C (L): 50em 436 // U+0056 (V): 5em 437 // U+0058 (X): 10em 438 // U+005F (_): 0em 439 // U+FFFD (invalid surrogate will be replaced to this): 7em 440 // U+10331 (\uD800\uDF31): 10em 441 final Typeface tf = new Typeface.Builder(context.getAssets(), 442 "fonts/StaticLayoutLineBreakingTestFont.ttf").build(); 443 final TextPaint paint = new TextPaint(); 444 paint.setTypeface(tf); 445 paint.setTextSize(1); // Make 1em = 1px 446 447 final Params param = new Params.Builder(paint).build(); 448 final Rect rect = new Rect(); 449 450 rect.set(0, 0, 0, 0); 451 PrecomputedText.create("", param).getBounds(0, 0, rect); 452 assertEquals(new Rect(0, 0, 0, 0), rect); 453 454 rect.set(0, 0, 0, 0); 455 PrecomputedText.create("I", param).getBounds(0, 1, rect); 456 assertEquals(new Rect(0, -1, 1, 0), rect); 457 458 rect.set(0, 0, 0, 0); 459 PrecomputedText.create("I", param).getBounds(1, 1, rect); 460 assertEquals(new Rect(0, 0, 0, 0), rect); 461 462 rect.set(0, 0, 0, 0); 463 PrecomputedText.create("IV", param).getBounds(0, 0, rect); 464 assertEquals(new Rect(0, 0, 0, 0), rect); 465 466 rect.set(0, 0, 0, 0); 467 PrecomputedText.create("IV", param).getBounds(0, 0, rect); 468 assertEquals(new Rect(0, 0, 0, 0), rect); 469 470 rect.set(0, 0, 0, 0); 471 PrecomputedText.create("IV", param).getBounds(1, 1, rect); 472 assertEquals(new Rect(0, 0, 0, 0), rect); 473 474 rect.set(0, 0, 0, 0); 475 PrecomputedText.create("IV", param).getBounds(2, 2, rect); 476 assertEquals(new Rect(0, 0, 0, 0), rect); 477 478 rect.set(0, 0, 0, 0); 479 PrecomputedText.create("IV", param).getBounds(0, 1, rect); 480 assertEquals(new Rect(0, -1, 1, 0), rect); 481 482 rect.set(0, 0, 0, 0); 483 PrecomputedText.create("IV", param).getBounds(1, 2, rect); 484 assertEquals(new Rect(0, -5, 5, 0), rect); 485 486 rect.set(0, 0, 0, 0); 487 PrecomputedText.create("IV", param).getBounds(0, 2, rect); 488 assertEquals(new Rect(0, -5, 6, 0), rect); 489 } 490 491 @Test testGetBounds_multiStyle()492 public void testGetBounds_multiStyle() { 493 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 494 final SpannableStringBuilder ssb = new SpannableStringBuilder("II"); 495 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 1 /* text size */, 496 null /* color */, null /* link color */), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 497 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 5 /* text size */, 498 null /* color */, null /* link color */), 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 499 500 final Typeface tf = new Typeface.Builder(context.getAssets(), 501 "fonts/StaticLayoutLineBreakingTestFont.ttf").build(); 502 final TextPaint paint = new TextPaint(); 503 paint.setTypeface(tf); 504 paint.setTextSize(1); // Make 1em = 1px 505 506 final Params param = new Params.Builder(paint).build(); 507 final Rect rect = new Rect(); 508 509 rect.set(0, 0, 0, 0); 510 PrecomputedText.create(ssb, param).getBounds(0, 0, rect); 511 assertEquals(new Rect(0, 0, 0, 0), rect); 512 513 rect.set(0, 0, 0, 0); 514 PrecomputedText.create(ssb, param).getBounds(0, 1, rect); 515 assertEquals(new Rect(0, -1, 1, 0), rect); 516 517 rect.set(0, 0, 0, 0); 518 PrecomputedText.create(ssb, param).getBounds(1, 2, rect); 519 assertEquals(new Rect(0, -5, 5, 0), rect); 520 521 rect.set(0, 0, 0, 0); 522 PrecomputedText.create(ssb, param).getBounds(0, 2, rect); 523 assertEquals(new Rect(0, -5, 6, 0), rect); 524 } 525 526 @Test testGetBounds_multiStyle2()527 public void testGetBounds_multiStyle2() { 528 final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 529 final SpannableStringBuilder ssb = new SpannableStringBuilder("IVI"); 530 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 1 /* text size */, 531 null /* color */, null /* link color */), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 532 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 5 /* text size */, 533 null /* color */, null /* link color */), 1, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 534 ssb.setSpan(new TextAppearanceSpan(null /* family */, Typeface.NORMAL, 5 /* text size */, 535 null /* color */, null /* link color */), 2, 3, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 536 537 final Typeface tf = new Typeface.Builder(context.getAssets(), 538 "fonts/StaticLayoutLineBreakingTestFont.ttf").build(); 539 final TextPaint paint = new TextPaint(); 540 paint.setTypeface(tf); 541 paint.setTextSize(1); // Make 1em = 1px 542 543 final Params param = new Params.Builder(paint).build(); 544 final Rect rect = new Rect(); 545 546 rect.set(0, 0, 0, 0); 547 PrecomputedText.create(ssb, param).getBounds(0, 0, rect); 548 assertEquals(new Rect(0, 0, 0, 0), rect); 549 550 rect.set(0, 0, 0, 0); 551 PrecomputedText.create(ssb, param).getBounds(0, 1, rect); 552 assertEquals(new Rect(0, -1, 1, 0), rect); 553 554 rect.set(0, 0, 0, 0); 555 PrecomputedText.create(ssb, param).getBounds(1, 2, rect); 556 assertEquals(new Rect(0, -25, 25, 0), rect); 557 558 rect.set(0, 0, 0, 0); 559 PrecomputedText.create(ssb, param).getBounds(2, 3, rect); 560 assertEquals(new Rect(0, -5, 5, 0), rect); 561 562 rect.set(0, 0, 0, 0); 563 PrecomputedText.create(ssb, param).getBounds(0, 2, rect); 564 assertEquals(new Rect(0, -25, 26, 0), rect); 565 566 rect.set(0, 0, 0, 0); 567 PrecomputedText.create(ssb, param).getBounds(1, 3, rect); 568 assertEquals(new Rect(0, -25, 30, 0), rect); 569 570 rect.set(0, 0, 0, 0); 571 PrecomputedText.create(ssb, param).getBounds(0, 3, rect); 572 assertEquals(new Rect(0, -25, 31, 0), rect); 573 } 574 575 @Test(expected = IllegalArgumentException.class) testGetBounds_negative_start_offset()576 public void testGetBounds_negative_start_offset() { 577 final Rect rect = new Rect(); 578 final Params param = new Params.Builder(PAINT).build(); 579 PrecomputedText.create("a", param).getBounds(-1, 0, rect); 580 } 581 582 @Test(expected = IllegalArgumentException.class) testGetBounds_negative_end_offset()583 public void testGetBounds_negative_end_offset() { 584 final Rect rect = new Rect(); 585 final Params param = new Params.Builder(PAINT).build(); 586 PrecomputedText.create("a", param).getBounds(0, -1, rect); 587 } 588 589 @Test(expected = IllegalArgumentException.class) testGetBounds_index_out_of_bounds_start_offset()590 public void testGetBounds_index_out_of_bounds_start_offset() { 591 final Rect rect = new Rect(); 592 final Params param = new Params.Builder(PAINT).build(); 593 PrecomputedText.create("a", param).getBounds(2, 2, rect); 594 } 595 596 @Test(expected = IllegalArgumentException.class) testGetBounds_index_out_of_bounds_end_offset()597 public void testGetBounds_index_out_of_bounds_end_offset() { 598 final Rect rect = new Rect(); 599 final Params param = new Params.Builder(PAINT).build(); 600 PrecomputedText.create("a", param).getBounds(0, 2, rect); 601 } 602 603 @Test(expected = IllegalArgumentException.class) testGetBounds_reverse_offset()604 public void testGetBounds_reverse_offset() { 605 final Rect rect = new Rect(); 606 final Params param = new Params.Builder(PAINT).build(); 607 PrecomputedText.create("a", param).getBounds(1, 0, rect); 608 } 609 610 @Test(expected = NullPointerException.class) testGetBounds_null_rect()611 public void testGetBounds_null_rect() { 612 final Params param = new Params.Builder(PAINT).build(); 613 PrecomputedText.create("a", param).getBounds(0, 1, null); 614 } 615 616 @Test(expected = IllegalArgumentException.class) testGetBounds_across_paragraph_boundary()617 public void testGetBounds_across_paragraph_boundary() { 618 final Rect rect = new Rect(); 619 final Params param = new Params.Builder(PAINT).build(); 620 PrecomputedText.create("a\nb", param).getBounds(0, 3, rect); 621 } 622 623 } 624