StaticLayout_Delegate.java revision 345d3cef8e40f59abeaba5402f51d3068b229bbc
1ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptapackage android.text;
2ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta
3e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perezimport com.android.layoutlib.bridge.impl.DelegateManager;
4ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptaimport com.android.tools.layoutlib.annotations.LayoutlibDelegate;
5ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta
6442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull;
7345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillardimport android.annotation.Nullable;
8f3284cbd38989279a116e0082b7ab5b987c13388Diego Perezimport android.graphics.BidiRenderer;
9f3284cbd38989279a116e0082b7ab5b987c13388Diego Perezimport android.graphics.Paint;
10f3284cbd38989279a116e0082b7ab5b987c13388Diego Perezimport android.graphics.Paint_Delegate;
11f3284cbd38989279a116e0082b7ab5b987c13388Diego Perezimport android.graphics.RectF;
129fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Guptaimport android.icu.text.BreakIterator;
13345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillardimport android.text.Layout.BreakStrategy;
14345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillardimport android.text.Layout.HyphenationFrequency;
154ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport android.text.Primitive.PrimitiveType;
169fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Guptaimport android.text.StaticLayout.LineBreaks;
174ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta
184ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.ArrayList;
19f3284cbd38989279a116e0082b7ab5b987c13388Diego Perezimport java.util.Arrays;
204ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Guptaimport java.util.List;
21ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta
22ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptaimport javax.swing.text.Segment;
23ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta
24ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta/**
25ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta * Delegate that provides implementation for native methods in {@link android.text.StaticLayout}
264ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta * <p/>
278a16d5d203a48e7b13761f329333b3dcb8f8210bDeepanshu Gupta * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
28ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta * by calls to methods of the same name in this delegate class.
29ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta *
30ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta */
31ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Guptapublic class StaticLayout_Delegate {
32ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta
334ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    private static final char CHAR_SPACE     = 0x20;
344ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    private static final char CHAR_TAB       = 0x09;
354ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    private static final char CHAR_NEWLINE   = 0x0A;
364ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    private static final char CHAR_ZWSP      = 0x200B;  // Zero width space.
374ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta
38e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez    // ---- Builder delegate manager ----
39e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez    private static final DelegateManager<Builder> sBuilderManager =
40e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez        new DelegateManager<Builder>(Builder.class);
41e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez
42ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta    @LayoutlibDelegate
43345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    /*package*/ static long nInit(
44345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @BreakStrategy int breakStrategy,
45345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @HyphenationFrequency int hyphenationFrequency,
46345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            boolean isJustified,
47345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @Nullable int[] indents,
48345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @Nullable int[] leftPaddings,
49345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @Nullable int[] rightPaddings) {
50345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        Builder builder = new Builder();
51345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mBreakStrategy = breakStrategy;
52345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        return sBuilderManager.addNewDelegate(builder);
539fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    }
549fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta
559fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    @LayoutlibDelegate
56345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    /*package*/ static void nFinish(long nativePtr) {
57345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        sBuilderManager.removeJavaReferenceFor(nativePtr);
589fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    }
599fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta
609fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    @LayoutlibDelegate
611d98a835ecb5d85ab9045fe9bee4af8fe5a5cca7Jerome Gaillard    /*package*/ static void nAddStyleRun(long nativeBuilder, long nativePaint, int start,
62009184dd1182a3bcd25a18302ad34a07c3e6be42Jerome Gaillard            int end, boolean isRtl) {
639fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
644e51324759676e6f66edd7e34a2c0ec7c997d8eeJerome Gaillard        if (builder == null) {
651d98a835ecb5d85ab9045fe9bee4af8fe5a5cca7Jerome Gaillard            return;
664e51324759676e6f66edd7e34a2c0ec7c997d8eeJerome Gaillard        }
67345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mRuns.add(new StyleRun(nativePaint, start, end, isRtl));
689fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    }
699fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta
709fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    @LayoutlibDelegate
71009184dd1182a3bcd25a18302ad34a07c3e6be42Jerome Gaillard    /*package*/ static void nAddReplacementRun(long nativeBuilder, long nativePaint, int start,
72009184dd1182a3bcd25a18302ad34a07c3e6be42Jerome Gaillard            int end, float width) {
739fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        Builder builder = sBuilderManager.getDelegate(nativeBuilder);
749fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        if (builder == null) {
759fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta            return;
769fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        }
77345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mRuns.add(new ReplacementRun(start, end, width));
789fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    }
799fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta
809fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    @LayoutlibDelegate
81345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    /*package*/ static int nComputeLineBreaks(
82345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            /* non zero */ long nativePtr,
839fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta
84345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            // Inputs
85345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull char[] text,
86345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            int length,
87345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            float firstWidth,
88345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            int firstWidthLineCount,
89345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            float restWidth,
90345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @Nullable int[] variableTabStops,
91345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            int defaultTabStop,
92345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            int indentsOffset,
93345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
94345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            // Outputs
95345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull LineBreaks recycle,
96345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            int recycleLength,
97345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull int[] recycleBreaks,
98345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull float[] recycleWidths,
99345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull float[] recycleAscents,
100345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull float[] recycleDescents,
101345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull int[] recycleFlags,
102345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            @NonNull float[] charWidths) {
103345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        Builder builder = sBuilderManager.getDelegate(nativePtr);
1049fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        if (builder == null) {
1059fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta            return 0;
1069fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        }
1077169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta
108345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mText = text;
109345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mWidths = new float[length];
110345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mLineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
111345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        builder.mTabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
112345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
113345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        for (Run run: builder.mRuns) {
114345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            run.addTo(builder);
115345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        }
116345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
1177169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        // compute all possible breakpoints.
118009184dd1182a3bcd25a18302ad34a07c3e6be42Jerome Gaillard        BreakIterator it = BreakIterator.getLineInstance();
1197169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        it.setText(new Segment(builder.mText, 0, length));
1207169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta
1217169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        // average word length in english is 5. So, initialize the possible breaks with a guess.
1227169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
1237169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        int loc;
1247169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        it.first();
1257169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        while ((loc = it.next()) != BreakIterator.DONE) {
1267169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta            breaks.add(loc);
1277169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        }
1287169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta
1297169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        List<Primitive> primitives =
1307169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                computePrimitives(builder.mText, builder.mWidths, length, breaks);
1317169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        switch (builder.mBreakStrategy) {
1327169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta            case Layout.BREAK_STRATEGY_SIMPLE:
1337169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth,
1347169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                        builder.mTabStopCalculator);
1357169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                break;
1367169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta            case Layout.BREAK_STRATEGY_HIGH_QUALITY:
1377169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                // TODO
1387169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta//                break;
1397169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta            case Layout.BREAK_STRATEGY_BALANCED:
1407169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                builder.mLineBreaker = new OptimizingLineBreaker(primitives, builder.mLineWidth,
1417169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                        builder.mTabStopCalculator);
1427169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta                break;
1437169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta            default:
1440609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez                assert false : "Unknown break strategy: " + builder.mBreakStrategy;
1450609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez                builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth,
1460609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez                        builder.mTabStopCalculator);
1477169c14107fc4291342b6211fff01723996fd351Deepanshu Gupta        }
1489fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta        builder.mLineBreaker.computeBreaks(recycle);
149b28e813fd8bd9a9e330ea1803f5b153b6fc7d4e0Jerome Gaillard        System.arraycopy(builder.mWidths, 0, charWidths, 0, builder.mWidths.length);
1504ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        return recycle.breaks.length;
151ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta    }
152ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta
1534ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    /**
1544ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta     * Compute metadata each character - things which help in deciding if it's possible to break
1554ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta     * at a point or not.
1564ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta     */
1574ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    @NonNull
1584ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta    private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths,
1594ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta            int length, @NonNull List<Integer> breaks) {
1604ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        // Initialize the list with a guess of the number of primitives:
1614ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars)
1624ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833)));
1634ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        int breaksSize = breaks.size();
1644ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        int breakIndex = 0;
1654ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        for (int i = 0; i < length; i++) {
1664ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta            char c = text[i];
1674ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta            if (c == CHAR_SPACE || c == CHAR_ZWSP) {
1684ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i]));
1694ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta            } else if (c == CHAR_TAB) {
1704ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i));
1714ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta            } else if (c != CHAR_NEWLINE) {
1724ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                while (breakIndex < breaksSize && breaks.get(breakIndex) < i) {
1734ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                    breakIndex++;
1744ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                }
1754ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                Primitive p;
1764ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                if (widths[i] != 0) {
1774ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                    if (breakIndex < breaksSize && breaks.get(breakIndex) == i) {
1784ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                        p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0);
1794ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                    } else {
1804ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                        p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0);
1814ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                    }
1824ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                    primitives.add(p);
1834ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                }
1844ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta
1854ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i]));
1864ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta            }
1874ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        }
1884ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        // final break at end of everything
1894ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        primitives.add(
1904ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta                PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
1914ef9b507c2c1b73805533a86d935d637493d5903Deepanshu Gupta        return primitives;
192ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta    }
193e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez
194f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez    private static float measureText(long nativePaint, char []text, int index, int count,
195f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez            float[] widths, int bidiFlags) {
196f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez        Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
197f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez        RectF bounds = new BidiRenderer(null, paint, text)
198f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez            .renderText(index, index + count, bidiFlags, widths, 0, false);
199f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez        return bounds.right - bounds.left;
200f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez    }
201f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez
2029fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    // TODO: Rename to LineBreakerRef and move everything other than LineBreaker to LineBreaker.
203e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez    /**
204f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez     * Java representation of the native Builder class.
205e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez     */
2069fe7fca9bcdceade9c654c6a8dcf0c48be16d78dDeepanshu Gupta    private static class Builder {
207f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez        char[] mText;
208f3284cbd38989279a116e0082b7ab5b987c13388Diego Perez        float[] mWidths;
209345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private LineBreaker mLineBreaker;
210345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private int mBreakStrategy;
211345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private LineWidth mLineWidth;
212345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private TabStops mTabStopCalculator;
213345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private ArrayList<Run> mRuns = new ArrayList<>();
214345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    }
215345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
216345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    private abstract static class Run {
217345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        int mStart;
218345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        int mEnd;
219345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
220345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        Run(int start, int end) {
221345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            mStart = start;
222345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            mEnd = end;
223345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        }
224345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
225345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        abstract void addTo(Builder builder);
226345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    }
227345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
228345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    private static class StyleRun extends Run {
229345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private long mNativePaint;
230345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private boolean mIsRtl;
231345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
232345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private StyleRun(long nativePaint, int start, int end, boolean isRtl) {
233345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            super(start, end);
234345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            mNativePaint = nativePaint;
235345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            mIsRtl = isRtl;
236345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        }
237345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
238345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        @Override
239345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        void addTo(Builder builder) {
240345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            int bidiFlags = mIsRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
241345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            measureText(mNativePaint, builder.mText, mStart, mEnd - mStart, builder.mWidths,
242345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard                    bidiFlags);
243345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        }
244345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    }
245345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
246345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard    private static class ReplacementRun extends Run {
247345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private final float mWidth;
248345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
249345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        private ReplacementRun(int start, int end, float width) {
250345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            super(start, end);
251345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            mWidth = width;
252345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        }
253345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard
254345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        @Override
255345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        void addTo(Builder builder) {
256345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            builder.mWidths[mStart] = mWidth;
257345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard            Arrays.fill(builder.mWidths, mStart + 1, mEnd, 0.0f);
258345d3cef8e40f59abeaba5402f51d3068b229bbcJerome Gaillard        }
259e8685f6153d281f24d1d2cbfa5942f40a5b461b1Diego Perez    }
260ae0b1a2ebde9984c2e75650b7dcfa7449d1a8833Deepanshu Gupta}
261