/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package android.text; import android.text.Layout.Directions; import android.text.StaticLayoutTest.LayoutBuilder; import java.util.Arrays; import java.util.Formatter; import junit.framework.TestCase; public class StaticLayoutDirectionsTest extends TestCase { private static final char ALEF = '\u05d0'; private static Directions dirs(int ... dirs) { return new Directions(dirs); } // constants from Layout that are package-protected private static final int RUN_LENGTH_MASK = 0x03ffffff; private static final int RUN_LEVEL_SHIFT = 26; private static final int RUN_LEVEL_MASK = 0x3f; private static final int RUN_RTL_FLAG = 1 << RUN_LEVEL_SHIFT; private static final Directions DIRS_ALL_LEFT_TO_RIGHT = new Directions(new int[] { 0, RUN_LENGTH_MASK }); private static final Directions DIRS_ALL_RIGHT_TO_LEFT = new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG }); private static final int LVL1_1 = 1 | (1 << RUN_LEVEL_SHIFT); private static final int LVL2_1 = 1 | (2 << RUN_LEVEL_SHIFT); private static final int LVL2_2 = 2 | (2 << RUN_LEVEL_SHIFT); private static String[] texts = { "", " ", "a", "a1", "aA", "a1b", "a1A", "aA1", "aAb", "aA1B", "aA1B2", // rtl "A", "A1", "Aa", "A1B", "A1a", "Aa1", "AaB" }; // Expected directions are an array of start/length+level pairs, // in visual order from the leading margin. private static Directions[] expected = { DIRS_ALL_LEFT_TO_RIGHT, DIRS_ALL_LEFT_TO_RIGHT, DIRS_ALL_LEFT_TO_RIGHT, DIRS_ALL_LEFT_TO_RIGHT, dirs(0, 1, 1, LVL1_1), DIRS_ALL_LEFT_TO_RIGHT, dirs(0, 2, 2, LVL1_1), dirs(0, 1, 2, LVL2_1, 1, LVL1_1), dirs(0, 1, 1, LVL1_1, 2, 1), dirs(0, 1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1), dirs(0, 1, 4, LVL2_1, 3, LVL1_1, 2, LVL2_1, 1, LVL1_1), // rtl DIRS_ALL_RIGHT_TO_LEFT, dirs(0, LVL1_1, 1, LVL2_1), dirs(0, LVL1_1, 1, LVL2_1), dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1), dirs(0, LVL1_1, 1, LVL2_2), dirs(0, LVL1_1, 1, LVL2_2), dirs(0, LVL1_1, 1, LVL2_1, 2, LVL1_1), }; private static String pseudoBidiToReal(String src) { char[] chars = src.toCharArray(); for (int j = 0; j < chars.length; ++j) { char c = chars[j]; if (c >= 'A' && c <= 'D') { chars[j] = (char)(ALEF + c - 'A'); } } return new String(chars, 0, chars.length); } // @SmallTest public void testDirections() { StringBuilder buf = new StringBuilder("\n"); Formatter f = new Formatter(buf); LayoutBuilder b = StaticLayoutTest.builder(); for (int i = 0; i < texts.length; ++i) { b.setText(pseudoBidiToReal(texts[i])); checkDirections(b.build(), i, b.text, expected, f); } if (buf.length() > 1) { fail(buf.toString()); } } // @SmallTest public void testTrailingWhitespace() { LayoutBuilder b = StaticLayoutTest.builder(); b.setText(pseudoBidiToReal("Ab c")); float width = b.paint.measureText(b.text, 0, 5); // exclude 'c' b.setWidth(Math.round(width)); Layout l = b.build(); if (l.getLineCount() != 2) { throw new RuntimeException("expected 2 lines, got: " + l.getLineCount()); } Directions result = l.getLineDirections(0); Directions expected = dirs(0, LVL1_1, 1, LVL2_1, 2, 3 | (1 << Layout.RUN_LEVEL_SHIFT)); expectDirections("split line", expected, result); } public void testNextToRightOf() { LayoutBuilder b = StaticLayoutTest.builder(); b.setText(pseudoBidiToReal("aA1B2")); // visual a2B1A positions 04321 // 0: |a2B1A, strong is sol, after -> 0 // 1: a|2B1A, strong is a, after ->, 1 // 2: a2|B1A, strong is B, after -> 4 // 3: a2B|1A, strong is B, before -> 3 // 4: a2B1|A, strong is A, after -> 2 // 5: a2B1A|, strong is eol, before -> 5 int[] expected = { 0, 1, 4, 3, 2, 5 }; Layout l = b.build(); int n = 0; for (int i = 1; i < expected.length; ++i) { int t = l.getOffsetToRightOf(n); if (t != expected[i]) { fail("offset[" + i + "] to right of: " + n + " expected: " + expected[i] + " got: " + t); } n = t; } } public void testNextToLeftOf() { LayoutBuilder b = StaticLayoutTest.builder(); b.setText(pseudoBidiToReal("aA1B2")); int[] expected = { 0, 1, 4, 3, 2, 5 }; Layout l = b.build(); int n = 5; for (int i = expected.length - 1; --i >= 0;) { int t = l.getOffsetToLeftOf(n); if (t != expected[i]) { fail("offset[" + i + "] to left of: " + n + " expected: " + expected[i] + " got: " + t); } n = t; } } // utility, not really a test /* public void testMeasureText1() { LayoutBuilder b = StaticLayoutTest.builder(); String text = "ABC"; // "abAB" b.setText(pseudoBidiToReal(text)); Layout l = b.build(); Directions directions = l.getLineDirections(0); TextPaint workPaint = new TextPaint(); int dir = -1; // LEFT_TO_RIGHT boolean trailing = true; boolean alt = true; do { dir = -dir; do { trailing = !trailing; for (int offset = 0, end = b.text.length(); offset <= end; ++offset) { float width = Layout.measureText(b.paint, workPaint, b.text, 0, offset, end, dir, directions, trailing, false, null); Log.i("BIDI", "dir: " + dir + " trail: " + trailing + " offset: " + offset + " width: " + width); } } while (!trailing); } while (dir > 0); } */ // utility for displaying arrays in hex private static String hexArray(int[] array) { StringBuilder sb = new StringBuilder(); sb.append('{'); for (int i : array) { if (sb.length() > 1) { sb.append(", "); } sb.append(Integer.toHexString(i)); } sb.append('}'); return sb.toString(); } private void checkDirections(Layout l, int i, String text, Directions[] expectedDirs, Formatter f) { Directions expected = expectedDirs[i]; Directions result = l.getLineDirections(0); if (!Arrays.equals(expected.mDirections, result.mDirections)) { f.format("%n[%2d] '%s', %s != %s", i, text, hexArray(expected.mDirections), hexArray(result.mDirections)); } } private void expectDirections(String msg, Directions expected, Directions result) { if (!Arrays.equals(expected.mDirections, result.mDirections)) { fail("expected: " + hexArray(expected.mDirections) + " got: " + hexArray(result.mDirections)); } } }