StaticLayout_Delegate.java revision 7053919a3a55ad1b58e6db701afda18850037732
1package android.text; 2 3import com.android.annotations.NonNull; 4import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 5 6import android.text.StaticLayout.LineBreaks; 7import android.text.Primitive.PrimitiveType; 8 9import java.util.ArrayList; 10import java.util.List; 11 12import com.ibm.icu.text.BreakIterator; 13import com.ibm.icu.util.ULocale; 14import javax.swing.text.Segment; 15 16/** 17 * Delegate that provides implementation for native methods in {@link android.text.StaticLayout} 18 * <p/> 19 * Through the layoutlib_create tool, selected methods of Handler have been replaced by calls to 20 * methods of the same name in this delegate class. 21 */ 22public class StaticLayout_Delegate { 23 24 private static final char CHAR_SPACE = 0x20; 25 private static final char CHAR_TAB = 0x09; 26 private static final char CHAR_NEWLINE = 0x0A; 27 private static final char CHAR_ZWSP = 0x200B; // Zero width space. 28 29 @LayoutlibDelegate 30 /*package*/ static int nComputeLineBreaks(String locale, char[] inputText, float[] widths, 31 int length, float firstWidth, int firstWidthLineCount, float restWidth, 32 int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle, 33 int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) { 34 35 // compute all possible breakpoints. 36 BreakIterator it = BreakIterator.getLineInstance(new ULocale(locale)); 37 it.setText(new Segment(inputText, 0, length)); 38 // average word length in english is 5. So, initialize the possible breaks with a guess. 39 List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d)); 40 int loc; 41 it.first(); 42 while ((loc = it.next()) != BreakIterator.DONE) { 43 breaks.add(loc); 44 } 45 46 LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth); 47 TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop); 48 List<Primitive> primitives = computePrimitives(inputText, widths, length, breaks); 49 LineBreaker lineBreaker; 50 if (optimize) { 51 lineBreaker = new OptimizingLineBreaker(primitives, lineWidth, tabStopCalculator); 52 } else { 53 lineBreaker = new GreedyLineBreaker(primitives, lineWidth, tabStopCalculator); 54 } 55 lineBreaker.computeBreaks(recycle); 56 return recycle.breaks.length; 57 } 58 59 /** 60 * Compute metadata each character - things which help in deciding if it's possible to break 61 * at a point or not. 62 */ 63 @NonNull 64 private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths, 65 int length, @NonNull List<Integer> breaks) { 66 // Initialize the list with a guess of the number of primitives: 67 // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars) 68 List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833))); 69 int breaksSize = breaks.size(); 70 int breakIndex = 0; 71 for (int i = 0; i < length; i++) { 72 char c = text[i]; 73 if (c == CHAR_SPACE || c == CHAR_ZWSP) { 74 primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i])); 75 } else if (c == CHAR_TAB) { 76 primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i)); 77 } else if (c != CHAR_NEWLINE) { 78 while (breakIndex < breaksSize && breaks.get(breakIndex) < i) { 79 breakIndex++; 80 } 81 Primitive p; 82 if (widths[i] != 0) { 83 if (breakIndex < breaksSize && breaks.get(breakIndex) == i) { 84 p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0); 85 } else { 86 p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0); 87 } 88 primitives.add(p); 89 } 90 91 primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i])); 92 } 93 } 94 // final break at end of everything 95 primitives.add( 96 PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY)); 97 return primitives; 98 } 99} 100