StaticLayout_Delegate.java revision 4ef9b507c2c1b73805533a86d935d637493d5903
1ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptapackage android.text; 2ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta 34ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport com.android.annotations.NonNull; 4ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptaimport com.android.tools.layoutlib.annotations.LayoutlibDelegate; 5ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta 64ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport android.text.StaticLayout.LineBreaks; 74ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport android.text.Primitive.PrimitiveType; 84ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 94ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.ArrayList; 104ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.List; 11ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta 12ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptaimport com.ibm.icu.text.BreakIterator; 13ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptaimport com.ibm.icu.util.ULocale; 14ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptaimport javax.swing.text.Segment; 15ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta 16ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta/** 17ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta * Delegate that provides implementation for native methods in {@link android.text.StaticLayout} 184ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * <p/> 194ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * Through the layoutlib_create tool, selected methods of Handler have been replaced by calls to 204ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * methods of the same name in this delegate class. 21ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta */ 22ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptapublic class StaticLayout_Delegate { 23ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta 244ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static final char CHAR_SPACE = 0x20; 254ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static final char CHAR_TAB = 0x09; 264ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static final char CHAR_NEWLINE = 0x0A; 274ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static final char CHAR_ZWSP = 0x200B; // Zero width space. 284ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 29ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta @LayoutlibDelegate 304ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /*package*/ static int nComputeLineBreaks(String locale, char[] inputText, float[] widths, 314ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int length, float firstWidth, int firstWidthLineCount, float restWidth, 324ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle, 334ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength) { 344ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 354ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // compute all possible breakpoints. 364ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta BreakIterator it = BreakIterator.getLineInstance(new ULocale(locale)); 374ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta it.setText(new Segment(inputText, 0, length)); 384ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // average word length in english is 5. So, initialize the possible breaks with a guess. 394ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d)); 404ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int loc; 414ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta it.first(); 424ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta while ((loc = it.next()) != BreakIterator.DONE) { 434ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breaks.add(loc); 44ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta } 454ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 464ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta LineWidth lineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth); 474ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta TabStops tabStopCalculator = new TabStops(variableTabStops, defaultTabStop); 484ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta List<Primitive> primitives = computePrimitives(inputText, widths, length, breaks); 494ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta LineBreaker lineBreaker; 504ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (optimize) { 514ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineBreaker = new OptimizingLineBreaker(primitives, lineWidth, tabStopCalculator); 524ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else { 534ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineBreaker = new GreedyLineBreaker(primitives, lineWidth, tabStopCalculator); 54ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta } 554ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta lineBreaker.computeBreaks(recycle); 564ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return recycle.breaks.length; 57ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta } 58ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta 594ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta /** 604ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * Compute metadata each character - things which help in deciding if it's possible to break 614ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * at a point or not. 624ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta */ 634ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta @NonNull 644ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths, 654ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int length, @NonNull List<Integer> breaks) { 664ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // Initialize the list with a guess of the number of primitives: 674ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars) 684ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833))); 694ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int breaksSize = breaks.size(); 704ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta int breakIndex = 0; 714ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta for (int i = 0; i < length; i++) { 724ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta char c = text[i]; 734ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (c == CHAR_SPACE || c == CHAR_ZWSP) { 744ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i])); 754ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else if (c == CHAR_TAB) { 764ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i)); 774ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else if (c != CHAR_NEWLINE) { 784ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta while (breakIndex < breaksSize && breaks.get(breakIndex) < i) { 794ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta breakIndex++; 804ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 814ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta Primitive p; 824ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (widths[i] != 0) { 834ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta if (breakIndex < breaksSize && breaks.get(breakIndex) == i) { 844ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0); 854ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } else { 864ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0); 874ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 884ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta primitives.add(p); 894ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 904ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta 914ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i])); 924ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 934ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta } 944ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta // final break at end of everything 954ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta primitives.add( 964ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY)); 974ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta return primitives; 98ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta } 99ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta} 100