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.cts; 18 19 import android.test.AndroidTestCase; 20 import android.text.Editable; 21 import android.text.GetChars; 22 import android.text.GraphicsOperations; 23 import android.text.Layout.Alignment; 24 import android.text.TextUtils.TruncateAt; 25 import android.text.SpannableString; 26 import android.text.SpannableStringBuilder; 27 import android.text.SpannedString; 28 import android.text.StaticLayout; 29 import android.text.TextDirectionHeuristics; 30 import android.text.TextPaint; 31 import android.text.TextUtils; 32 33 import java.text.Normalizer; 34 import java.util.ArrayList; 35 import java.util.List; 36 37 public class StaticLayoutTest extends AndroidTestCase { 38 private static final float SPACE_MULTI = 1.0f; 39 private static final float SPACE_ADD = 0.0f; 40 private static final int DEFAULT_OUTER_WIDTH = 150; 41 42 private static final int LAST_LINE = 5; 43 private static final int LINE_COUNT = 6; 44 private static final int LARGER_THAN_LINE_COUNT = 50; 45 46 /* the first line must have one tab. the others not. totally 6 lines 47 */ 48 private static final CharSequence LAYOUT_TEXT = "CharSe\tq\nChar" 49 + "Sequence\nCharSequence\nHelllo\n, world\nLongLongLong"; 50 51 private static final CharSequence LAYOUT_TEXT_SINGLE_LINE = "CharSequence"; 52 53 private static final int VERTICAL_BELOW_TEXT = 1000; 54 55 private static final Alignment DEFAULT_ALIGN = Alignment.ALIGN_CENTER; 56 57 private static final int ELLIPSIZE_WIDTH = 8; 58 59 private StaticLayout mDefaultLayout; 60 private TextPaint mDefaultPaint; 61 62 @Override setUp()63 protected void setUp() throws Exception { 64 super.setUp(); 65 if (mDefaultPaint == null) { 66 mDefaultPaint = new TextPaint(); 67 } 68 if (mDefaultLayout == null) { 69 mDefaultLayout = createDefaultStaticLayout(); 70 } 71 } 72 createDefaultStaticLayout()73 private StaticLayout createDefaultStaticLayout() { 74 return new StaticLayout(LAYOUT_TEXT, mDefaultPaint, 75 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 76 } 77 createEllipsizeStaticLayout()78 private StaticLayout createEllipsizeStaticLayout() { 79 return new StaticLayout(LAYOUT_TEXT, 0, LAYOUT_TEXT.length(), mDefaultPaint, 80 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true, 81 TextUtils.TruncateAt.MIDDLE, ELLIPSIZE_WIDTH); 82 } 83 createEllipsizeStaticLayout(CharSequence text, TextUtils.TruncateAt ellipsize, int maxLines)84 private StaticLayout createEllipsizeStaticLayout(CharSequence text, 85 TextUtils.TruncateAt ellipsize, int maxLines) { 86 return new StaticLayout(text, 0, text.length(), 87 mDefaultPaint, DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, 88 TextDirectionHeuristics.FIRSTSTRONG_LTR, 89 SPACE_MULTI, SPACE_ADD, true /* include pad */, 90 ellipsize, 91 ELLIPSIZE_WIDTH, 92 maxLines); 93 } 94 95 96 97 /** 98 * Constructor test 99 */ testConstructor()100 public void testConstructor() { 101 new StaticLayout(LAYOUT_TEXT, mDefaultPaint, DEFAULT_OUTER_WIDTH, 102 DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 103 104 new StaticLayout(LAYOUT_TEXT, 0, LAYOUT_TEXT.length(), mDefaultPaint, 105 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 106 107 new StaticLayout(LAYOUT_TEXT, 0, LAYOUT_TEXT.length(), mDefaultPaint, 108 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, false, null, 0); 109 110 try { 111 new StaticLayout(null, null, -1, null, 0, 0, true); 112 fail("should throw NullPointerException here"); 113 } catch (NullPointerException e) { 114 } 115 } 116 testBuilder()117 public void testBuilder() { 118 { 119 // Obtain. 120 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 121 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 122 StaticLayout layout = builder.build(); 123 // Check values passed to obtain(). 124 assertEquals(LAYOUT_TEXT, layout.getText()); 125 assertEquals(mDefaultPaint, layout.getPaint()); 126 assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth()); 127 // Check default values. 128 assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, 129 layout.getTextDirectionHeuristic()); 130 assertEquals(Alignment.ALIGN_NORMAL, layout.getAlignment()); 131 assertEquals(0.0f, layout.getSpacingAdd()); 132 assertEquals(1.0f, layout.getSpacingMultiplier()); 133 assertEquals(DEFAULT_OUTER_WIDTH, layout.getEllipsizedWidth()); 134 } 135 { 136 // Obtain with null objects. 137 StaticLayout.Builder builder = StaticLayout.Builder.obtain(null, 0, 0, null, 0); 138 try { 139 StaticLayout layout = builder.build(); 140 fail("should throw NullPointerException here"); 141 } catch (NullPointerException e) { 142 } 143 } 144 { 145 // setText. 146 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 147 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 148 builder.setText(LAYOUT_TEXT_SINGLE_LINE); 149 StaticLayout layout = builder.build(); 150 assertEquals(LAYOUT_TEXT_SINGLE_LINE, layout.getText()); 151 } 152 { 153 // setAlignment. 154 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 155 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 156 builder.setAlignment(DEFAULT_ALIGN); 157 StaticLayout layout = builder.build(); 158 assertEquals(DEFAULT_ALIGN, layout.getAlignment()); 159 } 160 { 161 // setTextDirection. 162 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 163 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 164 builder.setTextDirection(TextDirectionHeuristics.RTL); 165 StaticLayout layout = builder.build(); 166 // Always returns TextDirectionHeuristics.FIRSTSTRONG_LTR. 167 assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, 168 layout.getTextDirectionHeuristic()); 169 } 170 { 171 // setLineSpacing. 172 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 173 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 174 builder.setLineSpacing(1.0f, 2.0f); 175 StaticLayout layout = builder.build(); 176 assertEquals(1.0f, layout.getSpacingAdd()); 177 assertEquals(2.0f, layout.getSpacingMultiplier()); 178 } 179 { 180 // setEllipsizedWidth and setEllipsize. 181 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 182 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 183 builder.setEllipsize(TruncateAt.END); 184 builder.setEllipsizedWidth(ELLIPSIZE_WIDTH); 185 StaticLayout layout = builder.build(); 186 assertEquals(ELLIPSIZE_WIDTH, layout.getEllipsizedWidth()); 187 assertEquals(DEFAULT_OUTER_WIDTH, layout.getWidth()); 188 assertTrue(layout.getEllipsisCount(0) == 0); 189 assertTrue(layout.getEllipsisCount(5) > 0); 190 } 191 { 192 // setMaxLines. 193 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 194 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 195 builder.setMaxLines(1); 196 builder.setEllipsize(TruncateAt.END); 197 StaticLayout layout = builder.build(); 198 assertTrue(layout.getEllipsisCount(0) > 0); 199 assertEquals(1, layout.getLineCount()); 200 } 201 { 202 // Setter methods that cannot be directly tested. 203 // setBreakStrategy, setHyphenationFrequency, setIncludePad, and setIndents. 204 StaticLayout.Builder builder = StaticLayout.Builder.obtain(LAYOUT_TEXT, 0, 205 LAYOUT_TEXT.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH); 206 builder.setBreakStrategy(StaticLayout.BREAK_STRATEGY_HIGH_QUALITY); 207 builder.setHyphenationFrequency(StaticLayout.HYPHENATION_FREQUENCY_FULL); 208 builder.setIncludePad(true); 209 builder.setIndents(null, null); 210 StaticLayout layout = builder.build(); 211 assertNotNull(layout); 212 } 213 } 214 215 /* 216 * Get the line number corresponding to the specified vertical position. 217 * If you ask for a position above 0, you get 0. above 0 means pixel above the fire line 218 * if you ask for a position in the range of the height, return the pixel in line 219 * if you ask for a position below the bottom of the text, you get the last line. 220 * Test 4 values containing -1, 0, normal number and > count 221 */ testGetLineForVertical()222 public void testGetLineForVertical() { 223 assertEquals(0, mDefaultLayout.getLineForVertical(-1)); 224 assertEquals(0, mDefaultLayout.getLineForVertical(0)); 225 assertTrue(mDefaultLayout.getLineForVertical(50) > 0); 226 assertEquals(LAST_LINE, mDefaultLayout.getLineForVertical(VERTICAL_BELOW_TEXT)); 227 } 228 229 /** 230 * Return the number of lines of text in this layout. 231 */ testGetLineCount()232 public void testGetLineCount() { 233 assertEquals(LINE_COUNT, mDefaultLayout.getLineCount()); 234 } 235 236 /* 237 * Return the vertical position of the top of the specified line. 238 * If the specified line is one beyond the last line, returns the bottom of the last line. 239 * A line of text contains top and bottom in height. this method just get the top of a line 240 * Test 4 values containing -1, 0, normal number and > count 241 */ testGetLineTop()242 public void testGetLineTop() { 243 assertTrue(mDefaultLayout.getLineTop(0) >= 0); 244 assertTrue(mDefaultLayout.getLineTop(1) > mDefaultLayout.getLineTop(0)); 245 246 try { 247 mDefaultLayout.getLineTop(-1); 248 fail("should throw ArrayIndexOutOfBoundsException"); 249 } catch (ArrayIndexOutOfBoundsException e) { 250 } 251 252 try { 253 mDefaultLayout.getLineTop(LARGER_THAN_LINE_COUNT ); 254 fail("should throw ArrayIndexOutOfBoundsException"); 255 } catch (ArrayIndexOutOfBoundsException e) { 256 } 257 } 258 259 /** 260 * Return the descent of the specified line. 261 * This method just like getLineTop, descent means the bottom pixel of the line 262 * Test 4 values containing -1, 0, normal number and > count 263 */ testGetLineDescent()264 public void testGetLineDescent() { 265 assertTrue(mDefaultLayout.getLineDescent(0) > 0); 266 assertTrue(mDefaultLayout.getLineDescent(1) > 0); 267 268 try { 269 mDefaultLayout.getLineDescent(-1); 270 fail("should throw ArrayIndexOutOfBoundsException"); 271 } catch (ArrayIndexOutOfBoundsException e) { 272 } 273 274 try { 275 mDefaultLayout.getLineDescent(LARGER_THAN_LINE_COUNT ); 276 fail("should throw ArrayIndexOutOfBoundsException"); 277 } catch (ArrayIndexOutOfBoundsException e) { 278 } 279 } 280 281 /** 282 * Returns the primary directionality of the paragraph containing the specified line. 283 * By default, each line should be same 284 */ testGetParagraphDirection()285 public void testGetParagraphDirection() { 286 assertEquals(mDefaultLayout.getParagraphDirection(0), 287 mDefaultLayout.getParagraphDirection(1)); 288 try { 289 mDefaultLayout.getParagraphDirection(-1); 290 fail("should throw ArrayIndexOutOfBoundsException"); 291 } catch (ArrayIndexOutOfBoundsException e) { 292 } 293 294 try { 295 mDefaultLayout.getParagraphDirection(LARGER_THAN_LINE_COUNT); 296 fail("should throw ArrayIndexOutOfBoundsException"); 297 } catch (ArrayIndexOutOfBoundsException e) { 298 } 299 } 300 301 /** 302 * Return the text offset of the beginning of the specified line. 303 * If the specified line is one beyond the last line, returns the end of the last line. 304 * Test 4 values containing -1, 0, normal number and > count 305 * Each line's offset must >= 0 306 */ testGetLineStart()307 public void testGetLineStart() { 308 assertTrue(mDefaultLayout.getLineStart(0) >= 0); 309 assertTrue(mDefaultLayout.getLineStart(1) >= 0); 310 311 try { 312 mDefaultLayout.getLineStart(-1); 313 fail("should throw ArrayIndexOutOfBoundsException"); 314 } catch (ArrayIndexOutOfBoundsException e) { 315 } 316 317 try { 318 mDefaultLayout.getLineStart(LARGER_THAN_LINE_COUNT); 319 fail("should throw ArrayIndexOutOfBoundsException"); 320 } catch (ArrayIndexOutOfBoundsException e) { 321 } 322 } 323 324 /* 325 * Returns whether the specified line contains one or more tabs. 326 */ testGetContainsTab()327 public void testGetContainsTab() { 328 assertTrue(mDefaultLayout.getLineContainsTab(0)); 329 assertFalse(mDefaultLayout.getLineContainsTab(1)); 330 331 try { 332 mDefaultLayout.getLineContainsTab(-1); 333 fail("should throw ArrayIndexOutOfBoundsException"); 334 } catch (ArrayIndexOutOfBoundsException e) { 335 } 336 337 try { 338 mDefaultLayout.getLineContainsTab(LARGER_THAN_LINE_COUNT ); 339 fail("should throw ArrayIndexOutOfBoundsException"); 340 } catch (ArrayIndexOutOfBoundsException e) { 341 } 342 } 343 344 /** 345 * Returns an array of directionalities for the specified line. 346 * The array alternates counts of characters in left-to-right 347 * and right-to-left segments of the line. 348 * We can not check the return value, for Directions's field is package private 349 * So only check it not null 350 */ testGetLineDirections()351 public void testGetLineDirections() { 352 assertNotNull(mDefaultLayout.getLineDirections(0)); 353 assertNotNull(mDefaultLayout.getLineDirections(1)); 354 355 try { 356 mDefaultLayout.getLineDirections(-1); 357 fail("should throw ArrayIndexOutOfBoundsException"); 358 } catch (ArrayIndexOutOfBoundsException e) { 359 } 360 361 try { 362 mDefaultLayout.getLineDirections(LARGER_THAN_LINE_COUNT); 363 fail("should throw ArrayIndexOutOfBoundsException"); 364 } catch (ArrayIndexOutOfBoundsException e) { 365 } 366 } 367 368 /** 369 * Returns the (negative) number of extra pixels of ascent padding 370 * in the top line of the Layout. 371 */ testGetTopPadding()372 public void testGetTopPadding() { 373 assertTrue(mDefaultLayout.getTopPadding() < 0); 374 } 375 376 /** 377 * Returns the number of extra pixels of descent padding in the bottom line of the Layout. 378 */ 379 public void testGetBottomPadding() { 380 assertTrue(mDefaultLayout.getBottomPadding() > 0); 381 } 382 383 /* 384 * Returns the number of characters to be ellipsized away, or 0 if no ellipsis is to take place. 385 * So each line must >= 0 386 */ testGetEllipsisCount()387 public void testGetEllipsisCount() { 388 // Multilines (6 lines) and TruncateAt.START so no ellipsis at all 389 mDefaultLayout = createEllipsizeStaticLayout(LAYOUT_TEXT, 390 TextUtils.TruncateAt.MIDDLE, 391 Integer.MAX_VALUE /* maxLines */); 392 393 assertTrue(mDefaultLayout.getEllipsisCount(0) == 0); 394 assertTrue(mDefaultLayout.getEllipsisCount(1) == 0); 395 assertTrue(mDefaultLayout.getEllipsisCount(2) == 0); 396 assertTrue(mDefaultLayout.getEllipsisCount(3) == 0); 397 assertTrue(mDefaultLayout.getEllipsisCount(4) == 0); 398 assertTrue(mDefaultLayout.getEllipsisCount(5) == 0); 399 400 try { 401 mDefaultLayout.getEllipsisCount(-1); 402 fail("should throw ArrayIndexOutOfBoundsException"); 403 } catch (ArrayIndexOutOfBoundsException e) { 404 } 405 406 try { 407 mDefaultLayout.getEllipsisCount(LARGER_THAN_LINE_COUNT); 408 fail("should throw ArrayIndexOutOfBoundsException"); 409 } catch (ArrayIndexOutOfBoundsException e) { 410 } 411 412 // Multilines (6 lines) and TruncateAt.MIDDLE so no ellipsis at all 413 mDefaultLayout = createEllipsizeStaticLayout(LAYOUT_TEXT, 414 TextUtils.TruncateAt.MIDDLE, 415 Integer.MAX_VALUE /* maxLines */); 416 417 assertTrue(mDefaultLayout.getEllipsisCount(0) == 0); 418 assertTrue(mDefaultLayout.getEllipsisCount(1) == 0); 419 assertTrue(mDefaultLayout.getEllipsisCount(2) == 0); 420 assertTrue(mDefaultLayout.getEllipsisCount(3) == 0); 421 assertTrue(mDefaultLayout.getEllipsisCount(4) == 0); 422 assertTrue(mDefaultLayout.getEllipsisCount(5) == 0); 423 424 // Multilines (6 lines) and TruncateAt.END so ellipsis only on the last line 425 mDefaultLayout = createEllipsizeStaticLayout(LAYOUT_TEXT, 426 TextUtils.TruncateAt.END, 427 Integer.MAX_VALUE /* maxLines */); 428 429 assertTrue(mDefaultLayout.getEllipsisCount(0) == 0); 430 assertTrue(mDefaultLayout.getEllipsisCount(1) == 0); 431 assertTrue(mDefaultLayout.getEllipsisCount(2) == 0); 432 assertTrue(mDefaultLayout.getEllipsisCount(3) == 0); 433 assertTrue(mDefaultLayout.getEllipsisCount(4) == 0); 434 assertTrue(mDefaultLayout.getEllipsisCount(5) > 0); 435 436 // Multilines (6 lines) and TruncateAt.MARQUEE so ellipsis only on the last line 437 mDefaultLayout = createEllipsizeStaticLayout(LAYOUT_TEXT, 438 TextUtils.TruncateAt.END, 439 Integer.MAX_VALUE /* maxLines */); 440 441 assertTrue(mDefaultLayout.getEllipsisCount(0) == 0); 442 assertTrue(mDefaultLayout.getEllipsisCount(1) == 0); 443 assertTrue(mDefaultLayout.getEllipsisCount(2) == 0); 444 assertTrue(mDefaultLayout.getEllipsisCount(3) == 0); 445 assertTrue(mDefaultLayout.getEllipsisCount(4) == 0); 446 assertTrue(mDefaultLayout.getEllipsisCount(5) > 0); 447 } 448 449 /* 450 * Return the offset of the first character to be ellipsized away 451 * relative to the start of the line. 452 * (So 0 if the beginning of the line is ellipsized, not getLineStart().) 453 */ testGetEllipsisStart()454 public void testGetEllipsisStart() { 455 mDefaultLayout = createEllipsizeStaticLayout(); 456 assertTrue(mDefaultLayout.getEllipsisStart(0) >= 0); 457 assertTrue(mDefaultLayout.getEllipsisStart(1) >= 0); 458 459 try { 460 mDefaultLayout.getEllipsisStart(-1); 461 fail("should throw ArrayIndexOutOfBoundsException"); 462 } catch (ArrayIndexOutOfBoundsException e) { 463 } 464 465 try { 466 mDefaultLayout.getEllipsisStart(LARGER_THAN_LINE_COUNT); 467 fail("should throw ArrayIndexOutOfBoundsException"); 468 } catch (ArrayIndexOutOfBoundsException e) { 469 } 470 } 471 472 /* 473 * Return the width to which this Layout is ellipsizing 474 * or getWidth() if it is not doing anything special. 475 * The constructor's Argument TextUtils.TruncateAt defines which EllipsizedWidth to use 476 * ellipsizedWidth if argument is not null 477 * outerWidth if argument is null 478 */ testGetEllipsizedWidth()479 public void testGetEllipsizedWidth() { 480 int ellipsizedWidth = 60; 481 int outerWidth = 100; 482 StaticLayout layout = new StaticLayout(LAYOUT_TEXT, 0, LAYOUT_TEXT.length(), 483 mDefaultPaint, outerWidth, DEFAULT_ALIGN, SPACE_MULTI, 484 SPACE_ADD, false, TextUtils.TruncateAt.END, ellipsizedWidth); 485 assertEquals(ellipsizedWidth, layout.getEllipsizedWidth()); 486 487 layout = new StaticLayout(LAYOUT_TEXT, 0, LAYOUT_TEXT.length(), 488 mDefaultPaint, outerWidth, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, 489 false, null, ellipsizedWidth); 490 assertEquals(outerWidth, layout.getEllipsizedWidth()); 491 } 492 testEllipsis_singleLine()493 public void testEllipsis_singleLine() { 494 { 495 // Single line case and TruncateAt.END so that we have some ellipsis 496 StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE, 497 TextUtils.TruncateAt.END, 1); 498 assertTrue(layout.getEllipsisCount(0) > 0); 499 } 500 { 501 // Single line case and TruncateAt.MIDDLE so that we have some ellipsis 502 StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE, 503 TextUtils.TruncateAt.MIDDLE, 1); 504 assertTrue(layout.getEllipsisCount(0) > 0); 505 } 506 { 507 // Single line case and TruncateAt.END so that we have some ellipsis 508 StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE, 509 TextUtils.TruncateAt.END, 1); 510 assertTrue(layout.getEllipsisCount(0) > 0); 511 } 512 { 513 // Single line case and TruncateAt.MARQUEE so that we have NO ellipsis 514 StaticLayout layout = createEllipsizeStaticLayout(LAYOUT_TEXT_SINGLE_LINE, 515 TextUtils.TruncateAt.MARQUEE, 1); 516 assertTrue(layout.getEllipsisCount(0) == 0); 517 } 518 519 final String text = "\u3042" // HIRAGANA LETTER A 520 + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; 521 final float textWidth = mDefaultPaint.measureText(text); 522 final int halfWidth = (int)(textWidth / 2.0f); 523 { 524 StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint, 525 halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR, 526 SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.END, halfWidth, 1); 527 assertTrue(layout.getEllipsisCount(0) > 0); 528 assertTrue(layout.getEllipsisStart(0) > 0); 529 } 530 { 531 StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint, 532 halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR, 533 SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.START, halfWidth, 1); 534 assertTrue(layout.getEllipsisCount(0) > 0); 535 assertEquals(0, mDefaultLayout.getEllipsisStart(0)); 536 } 537 { 538 StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint, 539 halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR, 540 SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MIDDLE, halfWidth, 1); 541 assertTrue(layout.getEllipsisCount(0) > 0); 542 assertTrue(layout.getEllipsisStart(0) > 0); 543 } 544 { 545 StaticLayout layout = new StaticLayout(text, 0, text.length(), mDefaultPaint, 546 halfWidth, DEFAULT_ALIGN, TextDirectionHeuristics.FIRSTSTRONG_LTR, 547 SPACE_MULTI, SPACE_ADD, false, TextUtils.TruncateAt.MARQUEE, halfWidth, 1); 548 assertEquals(0, layout.getEllipsisCount(0)); 549 } 550 } 551 552 /** 553 * scenario description: 554 * 1. set the text. 555 * 2. change the text 556 * 3. Check the text won't change to the StaticLayout 557 */ testImmutableStaticLayout()558 public void testImmutableStaticLayout() { 559 Editable editable = Editable.Factory.getInstance().newEditable("123\t\n555"); 560 StaticLayout layout = new StaticLayout(editable, mDefaultPaint, 561 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 562 563 assertEquals(2, layout.getLineCount()); 564 assertTrue(mDefaultLayout.getLineContainsTab(0)); 565 566 // change the text 567 editable.delete(0, editable.length() - 1); 568 569 assertEquals(2, layout.getLineCount()); 570 assertTrue(layout.getLineContainsTab(0)); 571 572 } 573 574 // String wrapper for testing not well known implementation of CharSequence. 575 private class FakeCharSequence implements CharSequence { 576 private String mStr; 577 FakeCharSequence(String str)578 public FakeCharSequence(String str) { 579 mStr = str; 580 } 581 582 @Override charAt(int index)583 public char charAt(int index) { 584 return mStr.charAt(index); 585 } 586 587 @Override length()588 public int length() { 589 return mStr.length(); 590 } 591 592 @Override subSequence(int start, int end)593 public CharSequence subSequence(int start, int end) { 594 return mStr.subSequence(start, end); 595 } 596 597 @Override toString()598 public String toString() { 599 return mStr; 600 } 601 }; 602 buildTestCharSequences(String testString, Normalizer.Form[] forms)603 private List<CharSequence> buildTestCharSequences(String testString, Normalizer.Form[] forms) { 604 List<CharSequence> result = new ArrayList<CharSequence>(); 605 606 List<String> normalizedStrings = new ArrayList<String>(); 607 for (Normalizer.Form form: forms) { 608 normalizedStrings.add(Normalizer.normalize(testString, form)); 609 } 610 611 for (String str: normalizedStrings) { 612 result.add(str); 613 result.add(new SpannedString(str)); 614 result.add(new SpannableString(str)); 615 result.add(new SpannableStringBuilder(str)); // as a GraphicsOperations implementation. 616 result.add(new FakeCharSequence(str)); // as a not well known implementation. 617 } 618 return result; 619 } 620 buildTestMessage(CharSequence seq)621 private String buildTestMessage(CharSequence seq) { 622 String normalized; 623 if (Normalizer.isNormalized(seq, Normalizer.Form.NFC)) { 624 normalized = "NFC"; 625 } else if (Normalizer.isNormalized(seq, Normalizer.Form.NFD)) { 626 normalized = "NFD"; 627 } else if (Normalizer.isNormalized(seq, Normalizer.Form.NFKC)) { 628 normalized = "NFKC"; 629 } else if (Normalizer.isNormalized(seq, Normalizer.Form.NFKD)) { 630 normalized = "NFKD"; 631 } else { 632 throw new IllegalStateException("Normalized form is not NFC/NFD/NFKC/NFKD"); 633 } 634 635 StringBuilder builder = new StringBuilder(); 636 for (int i = 0; i < seq.length(); ++i) { 637 builder.append(String.format("0x%04X ", Integer.valueOf(seq.charAt(i)))); 638 } 639 640 return "testString: \"" + seq.toString() + "\"[" + builder.toString() + "]" + 641 ", class: " + seq.getClass().getName() + 642 ", Normalization: " + normalized; 643 } 644 testGetOffset_ASCII()645 public void testGetOffset_ASCII() { 646 String testStrings[] = { "abcde", "ab\ncd", "ab\tcd", "ab\n\nc", "ab\n\tc" }; 647 648 for (String testString: testStrings) { 649 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 650 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 651 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 652 653 String testLabel = buildTestMessage(seq); 654 655 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 656 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 657 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2)); 658 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 659 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4)); 660 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5)); 661 662 assertEquals(testLabel, 1, layout.getOffsetToRightOf(0)); 663 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 664 assertEquals(testLabel, 3, layout.getOffsetToRightOf(2)); 665 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 666 assertEquals(testLabel, 5, layout.getOffsetToRightOf(4)); 667 assertEquals(testLabel, 5, layout.getOffsetToRightOf(5)); 668 } 669 } 670 671 String testString = "ab\r\nde"; 672 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 673 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 674 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 675 676 String testLabel = buildTestMessage(seq); 677 678 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 679 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 680 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2)); 681 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 682 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4)); 683 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5)); 684 assertEquals(testLabel, 5, layout.getOffsetToLeftOf(6)); 685 686 assertEquals(testLabel, 1, layout.getOffsetToRightOf(0)); 687 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 688 assertEquals(testLabel, 4, layout.getOffsetToRightOf(2)); 689 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 690 assertEquals(testLabel, 5, layout.getOffsetToRightOf(4)); 691 assertEquals(testLabel, 6, layout.getOffsetToRightOf(5)); 692 assertEquals(testLabel, 6, layout.getOffsetToRightOf(6)); 693 } 694 } 695 testGetOffset_UNICODE()696 public void testGetOffset_UNICODE() { 697 String testStrings[] = new String[] { 698 // Cyrillic alphabets. 699 "\u0410\u0411\u0412\u0413\u0414", 700 // Japanese Hiragana Characters. 701 "\u3042\u3044\u3046\u3048\u304A", 702 }; 703 704 for (String testString: testStrings) { 705 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 706 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 707 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 708 709 String testLabel = buildTestMessage(seq); 710 711 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 712 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 713 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2)); 714 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 715 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4)); 716 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5)); 717 718 assertEquals(testLabel, 1, layout.getOffsetToRightOf(0)); 719 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 720 assertEquals(testLabel, 3, layout.getOffsetToRightOf(2)); 721 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 722 assertEquals(testLabel, 5, layout.getOffsetToRightOf(4)); 723 assertEquals(testLabel, 5, layout.getOffsetToRightOf(5)); 724 } 725 } 726 } 727 testGetOffset_UNICODE_Normalization()728 public void testGetOffset_UNICODE_Normalization() { 729 // "A" with acute, circumflex, tilde, diaeresis, ring above. 730 String testString = "\u00C1\u00C2\u00C3\u00C4\u00C5"; 731 Normalizer.Form[] oneUnicodeForms = { Normalizer.Form.NFC, Normalizer.Form.NFKC }; 732 for (CharSequence seq: buildTestCharSequences(testString, oneUnicodeForms)) { 733 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 734 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 735 736 String testLabel = buildTestMessage(seq); 737 738 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 739 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 740 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2)); 741 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 742 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4)); 743 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5)); 744 745 assertEquals(testLabel, 1, layout.getOffsetToRightOf(0)); 746 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 747 assertEquals(testLabel, 3, layout.getOffsetToRightOf(2)); 748 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 749 assertEquals(testLabel, 5, layout.getOffsetToRightOf(4)); 750 assertEquals(testLabel, 5, layout.getOffsetToRightOf(5)); 751 } 752 753 Normalizer.Form[] twoUnicodeForms = { Normalizer.Form.NFD, Normalizer.Form.NFKD }; 754 for (CharSequence seq: buildTestCharSequences(testString, twoUnicodeForms)) { 755 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 756 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 757 758 String testLabel = buildTestMessage(seq); 759 760 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 761 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 762 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(2)); 763 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 764 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4)); 765 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5)); 766 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(6)); 767 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(7)); 768 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(8)); 769 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(9)); 770 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(10)); 771 772 assertEquals(testLabel, 2, layout.getOffsetToRightOf(0)); 773 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 774 assertEquals(testLabel, 4, layout.getOffsetToRightOf(2)); 775 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 776 assertEquals(testLabel, 6, layout.getOffsetToRightOf(4)); 777 assertEquals(testLabel, 6, layout.getOffsetToRightOf(5)); 778 assertEquals(testLabel, 8, layout.getOffsetToRightOf(6)); 779 assertEquals(testLabel, 8, layout.getOffsetToRightOf(7)); 780 assertEquals(testLabel, 10, layout.getOffsetToRightOf(8)); 781 assertEquals(testLabel, 10, layout.getOffsetToRightOf(9)); 782 assertEquals(testLabel, 10, layout.getOffsetToRightOf(10)); 783 } 784 } 785 testGetOffset_UNICODE_SurrogatePairs()786 public void testGetOffset_UNICODE_SurrogatePairs() { 787 // Emoticons for surrogate pairs tests. 788 String testString = 789 "\uD83D\uDE00\uD83D\uDE01\uD83D\uDE02\uD83D\uDE03\uD83D\uDE04"; 790 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 791 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 792 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 793 794 String testLabel = buildTestMessage(seq); 795 796 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 797 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 798 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(2)); 799 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 800 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4)); 801 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(5)); 802 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(6)); 803 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(7)); 804 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(8)); 805 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(9)); 806 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(10)); 807 808 assertEquals(testLabel, 2, layout.getOffsetToRightOf(0)); 809 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 810 assertEquals(testLabel, 4, layout.getOffsetToRightOf(2)); 811 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 812 assertEquals(testLabel, 6, layout.getOffsetToRightOf(4)); 813 assertEquals(testLabel, 6, layout.getOffsetToRightOf(5)); 814 assertEquals(testLabel, 8, layout.getOffsetToRightOf(6)); 815 assertEquals(testLabel, 8, layout.getOffsetToRightOf(7)); 816 assertEquals(testLabel, 10, layout.getOffsetToRightOf(8)); 817 assertEquals(testLabel, 10, layout.getOffsetToRightOf(9)); 818 assertEquals(testLabel, 10, layout.getOffsetToRightOf(10)); 819 } 820 } 821 testGetOffset_UNICODE_Thai()822 public void testGetOffset_UNICODE_Thai() { 823 // Thai Characters. The expected cursorable boundary is 824 // | \u0E02 | \u0E2D | \u0E1A | \u0E04\u0E38 | \u0E13 | 825 String testString = "\u0E02\u0E2D\u0E1A\u0E04\u0E38\u0E13"; 826 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 827 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 828 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 829 830 String testLabel = buildTestMessage(seq); 831 832 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 833 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 834 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2)); 835 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(3)); 836 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4)); 837 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(5)); 838 assertEquals(testLabel, 5, layout.getOffsetToLeftOf(6)); 839 840 assertEquals(testLabel, 1, layout.getOffsetToRightOf(0)); 841 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 842 assertEquals(testLabel, 3, layout.getOffsetToRightOf(2)); 843 assertEquals(testLabel, 5, layout.getOffsetToRightOf(3)); 844 assertEquals(testLabel, 5, layout.getOffsetToRightOf(4)); 845 assertEquals(testLabel, 6, layout.getOffsetToRightOf(5)); 846 assertEquals(testLabel, 6, layout.getOffsetToRightOf(6)); 847 } 848 } 849 testGetOffset_UNICODE_Hebrew()850 public void testGetOffset_UNICODE_Hebrew() { 851 String testString = "\u05DE\u05E1\u05E2\u05D3\u05D4"; // Hebrew Characters 852 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 853 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 854 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, 855 TextDirectionHeuristics.RTL, SPACE_MULTI, SPACE_ADD, true); 856 857 String testLabel = buildTestMessage(seq); 858 859 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(0)); 860 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1)); 861 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(2)); 862 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3)); 863 assertEquals(testLabel, 5, layout.getOffsetToLeftOf(4)); 864 assertEquals(testLabel, 5, layout.getOffsetToLeftOf(5)); 865 866 assertEquals(testLabel, 0, layout.getOffsetToRightOf(0)); 867 assertEquals(testLabel, 0, layout.getOffsetToRightOf(1)); 868 assertEquals(testLabel, 1, layout.getOffsetToRightOf(2)); 869 assertEquals(testLabel, 2, layout.getOffsetToRightOf(3)); 870 assertEquals(testLabel, 3, layout.getOffsetToRightOf(4)); 871 assertEquals(testLabel, 4, layout.getOffsetToRightOf(5)); 872 } 873 } 874 testGetOffset_UNICODE_Arabic()875 public void testGetOffset_UNICODE_Arabic() { 876 // Arabic Characters. The expected cursorable boundary is 877 // | \u0623 \u064F | \u0633 \u0652 | \u0631 \u064E | \u0629 \u064C |"; 878 String testString = "\u0623\u064F\u0633\u0652\u0631\u064E\u0629\u064C"; 879 880 Normalizer.Form[] oneUnicodeForms = { Normalizer.Form.NFC, Normalizer.Form.NFKC }; 881 for (CharSequence seq: buildTestCharSequences(testString, oneUnicodeForms)) { 882 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 883 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 884 885 String testLabel = buildTestMessage(seq); 886 887 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(0)); 888 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1)); 889 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(2)); 890 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3)); 891 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(4)); 892 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(5)); 893 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(6)); 894 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(7)); 895 assertEquals(testLabel, 8, layout.getOffsetToLeftOf(8)); 896 897 assertEquals(testLabel, 0, layout.getOffsetToRightOf(0)); 898 assertEquals(testLabel, 0, layout.getOffsetToRightOf(1)); 899 assertEquals(testLabel, 0, layout.getOffsetToRightOf(2)); 900 assertEquals(testLabel, 2, layout.getOffsetToRightOf(3)); 901 assertEquals(testLabel, 2, layout.getOffsetToRightOf(4)); 902 assertEquals(testLabel, 4, layout.getOffsetToRightOf(5)); 903 assertEquals(testLabel, 4, layout.getOffsetToRightOf(6)); 904 assertEquals(testLabel, 6, layout.getOffsetToRightOf(7)); 905 assertEquals(testLabel, 6, layout.getOffsetToRightOf(8)); 906 } 907 } 908 testGetOffset_UNICODE_Bidi()909 public void testGetOffset_UNICODE_Bidi() { 910 // String having RTL characters and LTR characters 911 912 // LTR Context 913 // The first and last two characters are LTR characters. 914 String testString = "\u0061\u0062\u05DE\u05E1\u05E2\u0063\u0064"; 915 // Logical order: [L1] [L2] [R1] [R2] [R3] [L3] [L4] 916 // 0 1 2 3 4 5 6 7 917 // Display order: [L1] [L2] [R3] [R2] [R1] [L3] [L4] 918 // 0 1 2 4 3 5 6 7 919 // [L?] means ?th LTR character and [R?] means ?th RTL character. 920 for (CharSequence seq: buildTestCharSequences(testString, Normalizer.Form.values())) { 921 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 922 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 923 924 String testLabel = buildTestMessage(seq); 925 926 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(0)); 927 assertEquals(testLabel, 0, layout.getOffsetToLeftOf(1)); 928 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(2)); 929 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(3)); 930 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(4)); 931 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(5)); 932 assertEquals(testLabel, 5, layout.getOffsetToLeftOf(6)); 933 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(7)); 934 935 assertEquals(testLabel, 1, layout.getOffsetToRightOf(0)); 936 assertEquals(testLabel, 2, layout.getOffsetToRightOf(1)); 937 assertEquals(testLabel, 4, layout.getOffsetToRightOf(2)); 938 assertEquals(testLabel, 5, layout.getOffsetToRightOf(3)); 939 assertEquals(testLabel, 3, layout.getOffsetToRightOf(4)); 940 assertEquals(testLabel, 6, layout.getOffsetToRightOf(5)); 941 assertEquals(testLabel, 7, layout.getOffsetToRightOf(6)); 942 assertEquals(testLabel, 7, layout.getOffsetToRightOf(7)); 943 } 944 945 // RTL Context 946 // The first and last two characters are RTL characters. 947 String testString2 = "\u05DE\u05E1\u0063\u0064\u0065\u05DE\u05E1"; 948 // Logical order: [R1] [R2] [L1] [L2] [L3] [R3] [R4] 949 // 0 1 2 3 4 5 6 7 950 // Display order: [R4] [R3] [L1] [L2] [L3] [R2] [R1] 951 // 7 6 5 3 4 2 1 0 952 // [L?] means ?th LTR character and [R?] means ?th RTL character. 953 for (CharSequence seq: buildTestCharSequences(testString2, Normalizer.Form.values())) { 954 StaticLayout layout = new StaticLayout(seq, mDefaultPaint, 955 DEFAULT_OUTER_WIDTH, DEFAULT_ALIGN, SPACE_MULTI, SPACE_ADD, true); 956 957 String testLabel = buildTestMessage(seq); 958 959 assertEquals(testLabel, 1, layout.getOffsetToLeftOf(0)); 960 assertEquals(testLabel, 2, layout.getOffsetToLeftOf(1)); 961 assertEquals(testLabel, 4, layout.getOffsetToLeftOf(2)); 962 assertEquals(testLabel, 5, layout.getOffsetToLeftOf(3)); 963 assertEquals(testLabel, 3, layout.getOffsetToLeftOf(4)); 964 assertEquals(testLabel, 6, layout.getOffsetToLeftOf(5)); 965 assertEquals(testLabel, 7, layout.getOffsetToLeftOf(6)); 966 assertEquals(testLabel, 7, layout.getOffsetToLeftOf(7)); 967 968 assertEquals(testLabel, 0, layout.getOffsetToRightOf(0)); 969 assertEquals(testLabel, 0, layout.getOffsetToRightOf(1)); 970 assertEquals(testLabel, 1, layout.getOffsetToRightOf(2)); 971 assertEquals(testLabel, 4, layout.getOffsetToRightOf(3)); 972 assertEquals(testLabel, 2, layout.getOffsetToRightOf(4)); 973 assertEquals(testLabel, 3, layout.getOffsetToRightOf(5)); 974 assertEquals(testLabel, 5, layout.getOffsetToRightOf(6)); 975 assertEquals(testLabel, 6, layout.getOffsetToRightOf(7)); 976 } 977 } 978 } 979