StaticLayout.java revision 121c82c8130c2658f73fb19f3a62eb88c8679968
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
194e0c5e55e171532760d5f51e0165563827129d4eDoug Feltimport com.android.internal.util.ArrayUtils;
204e0c5e55e171532760d5f51e0165563827129d4eDoug Felt
21105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.graphics.Bitmap;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.LeadingMarginSpan;
246611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunneimport android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.LineHeightSpan;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.MetricAffectingSpan;
27c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Feltimport android.text.style.TabStopSpan;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * StaticLayout is a Layout for text that will not be edited after it
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is laid out.  Use {@link DynamicLayout} for text that may change.
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>This is used by widgets to control text layout. You should not need
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to use this class directly unless you are implementing your own widget
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or custom display object, or would be tempted to call
354e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int,
364e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * float, float, android.graphics.Paint)
374e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * Canvas.drawText()} directly.</p>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
39121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Megliopublic class StaticLayout extends Layout {
40121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, TextPaint paint,
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int width,
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align, float spacingmult, float spacingadd,
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad) {
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(source, 0, source.length(), paint, width, align,
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             spacingmult, spacingadd, includepad);
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, int bufstart, int bufend,
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextPaint paint, int outerwidth,
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align,
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad) {
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(source, bufstart, bufend, paint, outerwidth, align,
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             spacingmult, spacingadd, includepad, null, 0);
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, int bufstart, int bufend,
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextPaint paint, int outerwidth,
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align,
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad,
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super((ellipsize == null)
654e0c5e55e171532760d5f51e0165563827129d4eDoug Felt                ? source
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                : (source instanceof Spanned)
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? new SpannedEllipsizer(source)
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : new Ellipsizer(source),
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project              paint, outerwidth, align, spacingmult, spacingadd);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This is annoying, but we can't refer to the layout until
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * superclass construction is finished, and the superclass
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * constructor wants the reference to the display text.
754e0c5e55e171532760d5f51e0165563827129d4eDoug Felt         *
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This will break if the superclass constructor ever actually
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * cares about the content instead of just holding the reference.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ellipsize != null) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Ellipsizer e = (Ellipsizer) getText();
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mLayout = this;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mWidth = ellipsizedWidth;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mMethod = ellipsize;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEllipsizedWidth = ellipsizedWidth;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mColumns = COLUMNS_ELLIPSIZE;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mColumns = COLUMNS_NORMAL;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEllipsizedWidth = outerwidth;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineDirections = new Directions[
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             ArrayUtils.idealIntArraySize(2 * mColumns)];
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
97e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mMeasured = MeasuredText.obtain();
98e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        generate(source, bufstart, bufend, paint, outerwidth, align,
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 spacingmult, spacingadd, includepad, includepad,
1010a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                 ellipsizedWidth, ellipsize);
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
103e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mMeasured = MeasuredText.recycle(mMeasured);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFontMetricsInt = null;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ StaticLayout(boolean ellipsize) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(null, null, 0, null, 0, 0);
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mColumns = COLUMNS_ELLIPSIZE;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineDirections = new Directions[
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             ArrayUtils.idealIntArraySize(2 * mColumns)];
114e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mMeasured = MeasuredText.obtain();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
117121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    /* package */ void generate(CharSequence source, int bufStart, int bufEnd,
118121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        TextPaint paint, int outerWidth,
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align,
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad, boolean trackpad,
1220a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                        float ellipsizedWidth, TextUtils.TruncateAt ellipsize) {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineCount = 0;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int v = 0;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Paint.FontMetricsInt fm = mFontMetricsInt;
129121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        int[] chooseHtv = null;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
131e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        MeasuredText measured = mMeasured;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Spanned spanned = null;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (source instanceof Spanned)
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            spanned = (Spanned) source;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int DEFAULT_DIR = DIR_LEFT_TO_RIGHT; // XXX
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
139e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int paraEnd;
140121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
141121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
142e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (paraEnd < 0)
143121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                paraEnd = bufEnd;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
145e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                paraEnd++;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
147c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt            int firstWidthLineLimit = mLineCount + 1;
148121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int firstWidth = outerWidth;
149121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int restWidth = outerWidth;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
151121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            LineHeightSpan[] chooseHt = null;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanned != null) {
15474d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer                LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
155e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        LeadingMarginSpan.class);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < sp.length; i++) {
1577b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    LeadingMarginSpan lms = sp[i];
158121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    firstWidth -= sp[i].getLeadingMargin(true);
159121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    restWidth -= sp[i].getLeadingMargin(false);
160c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt
161c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    // LeadingMarginSpan2 is odd.  The count affects all
162c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    // leading margin spans, not just this particular one,
163c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    // and start from the top of the span, not the top of the
164c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    // paragraph.
165c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    if (lms instanceof LeadingMarginSpan2) {
166c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
167c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        int lmsFirstLine = getLineForOffset(spanned.getSpanStart(lms2));
168121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        firstWidthLineLimit = lmsFirstLine + lms2.getLeadingMarginLineCount();
1697b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
172121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
174121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (chooseHt.length != 0) {
175121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    if (chooseHtv == null ||
176121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHtv.length < chooseHt.length) {
177121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHtv = new int[ArrayUtils.idealIntArraySize(
178121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                            chooseHt.length)];
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
181121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    for (int i = 0; i < chooseHt.length; i++) {
182121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        int o = spanned.getSpanStart(chooseHt[i]);
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
184e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        if (o < paraStart) {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // starts in this layout, before the
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // current paragraph
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
188121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            chooseHtv[i] = getLineTop(getLineForOffset(o));
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // starts in this paragraph
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
192121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            chooseHtv[i] = v;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
198e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            measured.setPara(source, paraStart, paraEnd, DIR_REQUEST_DEFAULT_LTR);
199e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            char[] chs = measured.mChars;
200e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            float[] widths = measured.mWidths;
201e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            byte[] chdirs = measured.mLevels;
202e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            int dir = measured.mDir;
203e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            boolean easy = measured.mEasy;
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
205121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int width = firstWidth;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float w = 0;
208e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            int here = paraStart;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
210e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            int ok = paraStart;
211121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            float okWidth = w;
212121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int okAscent = 0, okDescent = 0, okTop = 0, okBottom = 0;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
214e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            int fit = paraStart;
215121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            float fitWidth = w;
216121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int fitAscent = 0, fitDescent = 0, fitTop = 0, fitBottom = 0;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
218c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt            boolean hasTabOrEmoji = false;
219c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt            boolean hasTab = false;
220c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt            TabStops tabStops = null;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22223241887515ed77687c23e29a4a3ffff671666bdDoug Felt            for (int spanStart = paraStart, spanEnd = spanStart, nextSpanStart;
22323241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    spanStart < paraEnd; spanStart = nextSpanStart) {
22423241887515ed77687c23e29a4a3ffff671666bdDoug Felt
22523241887515ed77687c23e29a4a3ffff671666bdDoug Felt                if (spanStart == spanEnd) {
22623241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    if (spanned == null)
22723241887515ed77687c23e29a4a3ffff671666bdDoug Felt                        spanEnd = paraEnd;
22823241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    else
22923241887515ed77687c23e29a4a3ffff671666bdDoug Felt                        spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
23023241887515ed77687c23e29a4a3ffff671666bdDoug Felt                                MetricAffectingSpan.class);
23123241887515ed77687c23e29a4a3ffff671666bdDoug Felt
23223241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    int spanLen = spanEnd - spanStart;
23323241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    if (spanned == null) {
23423241887515ed77687c23e29a4a3ffff671666bdDoug Felt                        measured.addStyleRun(paint, spanLen, fm);
23523241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    } else {
23623241887515ed77687c23e29a4a3ffff671666bdDoug Felt                        MetricAffectingSpan[] spans =
23723241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
23823241887515ed77687c23e29a4a3ffff671666bdDoug Felt                        measured.addStyleRun(paint, spans, spanLen, fm);
23923241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    }
24023241887515ed77687c23e29a4a3ffff671666bdDoug Felt                }
24123241887515ed77687c23e29a4a3ffff671666bdDoug Felt
24223241887515ed77687c23e29a4a3ffff671666bdDoug Felt                nextSpanStart = spanEnd;
2434e0c5e55e171532760d5f51e0165563827129d4eDoug Felt
244121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                int fmTop = fm.top;
245121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                int fmBottom = fm.bottom;
246121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                int fmAscent = fm.ascent;
247121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                int fmDescent = fm.descent;
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                for (int j = spanStart; j < spanEnd; j++) {
250e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    char c = chs[j - paraStart];
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
252121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    if (c == CHAR_NEW_LINE) {
2536611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne                        // intentionally left empty
254121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    } else if (c == CHAR_TAB) {
255c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        if (hasTab == false) {
256c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                            hasTab = true;
257c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                            hasTabOrEmoji = true;
25824ca4545f3fa9ffaf0a84af11f1ab74cd14d232eKenny Root                            if (spanned != null) {
25924ca4545f3fa9ffaf0a84af11f1ab74cd14d232eKenny Root                                // First tab this para, check for tabstops
26074d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer                                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
26124ca4545f3fa9ffaf0a84af11f1ab74cd14d232eKenny Root                                        paraEnd, TabStopSpan.class);
26224ca4545f3fa9ffaf0a84af11f1ab74cd14d232eKenny Root                                if (spans.length > 0) {
26324ca4545f3fa9ffaf0a84af11f1ab74cd14d232eKenny Root                                    tabStops = new TabStops(TAB_INCREMENT, spans);
26424ca4545f3fa9ffaf0a84af11f1ab74cd14d232eKenny Root                                }
265c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                            }
266c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        }
267c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        if (tabStops != null) {
268c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                            w = tabStops.nextTab(w);
269c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        } else {
270c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                            w = TabStops.nextDefaultStop(w, TAB_INCREMENT);
271c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        }
272121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    } else if (c >= CHAR_FIRST_HIGH_SURROGATE && c <= CHAR_LAST_LOW_SURROGATE
273121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            && j + 1 < spanEnd) {
274e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        int emoji = Character.codePointAt(chs, j - paraStart);
275105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
276105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
2770a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                            Bitmap bm = EMOJI_FACTORY.getBitmapFromAndroidPua(emoji);
278105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
279105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            if (bm != null) {
280423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                Paint whichPaint;
281423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer
282423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                if (spanned == null) {
283423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                    whichPaint = paint;
284423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                } else {
285423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                    whichPaint = mWorkPaint;
286423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                }
287423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer
2884e0c5e55e171532760d5f51e0165563827129d4eDoug Felt                                float wid = bm.getWidth() *
289423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                            -whichPaint.ascent() /
290423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                            bm.getHeight();
291423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer
292423f0e4205e3c49c6a87b389fa6025772aa7010cEric Fischer                                w += wid;
293c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                                hasTabOrEmoji = true;
294105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                j++;
295105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            } else {
296e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                                w += widths[j - paraStart];
297105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            }
298105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        } else {
299e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                            w += widths[j - paraStart];
300105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        }
301105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    } else {
302e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        w += widths[j - paraStart];
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Log.e("text", "was " + before + " now " + w + " after " + c + " within " + width);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (w <= width) {
308121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        fitWidth = w;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        fit = j + 1;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
311121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        if (fmTop < fitTop)
312121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            fitTop = fmTop;
313121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        if (fmAscent < fitAscent)
314121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            fitAscent = fmAscent;
315121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        if (fmDescent > fitDescent)
316121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            fitDescent = fmDescent;
317121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        if (fmBottom > fitBottom)
318121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            fitBottom = fmBottom;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        /*
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         * From the Unicode Line Breaking Algorithm:
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         * (at least approximately)
3234e0c5e55e171532760d5f51e0165563827129d4eDoug Felt                         *
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         * .,:; are class IS: breakpoints
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         *      except when adjacent to digits
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         * /    is class SY: a breakpoint
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         *      except when followed by a digit.
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         * -    is class HY: a breakpoint
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         *      except when followed by a digit.
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         *
331549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                         * Ideographs are class ID: breakpoints when adjacent,
332549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                         * except for NS (non-starters), which can be broken
333549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                         * after but not before.
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         */
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
336121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        if (c == CHAR_SPACE || c == CHAR_TAB ||
337121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            ((c == CHAR_DOT || c == CHAR_COMMA ||
338121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                    c == CHAR_COLON || c == CHAR_SEMICOLON) &&
339e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                             (j - 1 < here || !Character.isDigit(chs[j - 1 - paraStart])) &&
340e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                             (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
341121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            ((c == CHAR_SLASH || c == CHAR_HYPHEN) &&
342e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                             (j + 1 >= spanEnd || !Character.isDigit(chs[j + 1 - paraStart]))) ||
343121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            (c >= CHAR_FIRST_CJK && isIdeographic(c, true) &&
344e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                             j + 1 < spanEnd && isIdeographic(chs[j + 1 - paraStart], false))) {
345121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            okWidth = w;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ok = j + 1;
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
348121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            if (fitTop < okTop)
349121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                okTop = fitTop;
350121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            if (fitAscent < okAscent)
351121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                okAscent = fitAscent;
352121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            if (fitDescent > okDescent)
353121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                okDescent = fitDescent;
354121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            if (fitBottom > okBottom)
355121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                okBottom = fitBottom;
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
357d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                    } else {
3580a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                        if (ellipsize != null) {
3590a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                            // Break only at spaces using ok indexes.
360d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            if (ok != here) {
361d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // Log.e("text", "output ok " + here + " to " +ok);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
363121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                while (ok < spanEnd && chs[ok - paraStart] == CHAR_SPACE) {
364d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                    ok++;
365d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
367d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                v = out(source,
368d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        here, ok,
369121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        okAscent, okDescent, okTop, okBottom,
370d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        v,
371121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        spacingmult, spacingadd, chooseHt,
372121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        chooseHtv, fm, hasTabOrEmoji,
373d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        needMultiply, paraStart, chdirs, dir, easy,
374121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        ok == bufEnd, includepad, trackpad,
375d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        chs, widths, here - paraStart,
376121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        ellipsize, ellipsizedWidth, okWidth,
377d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        paint);
378d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
379d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                here = ok;
380d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            } else {
381d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // Act like it fit even though it didn't.
382d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
383121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                fitWidth = w;
384d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                here = fit = j + 1;
385d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
386121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                if (fmTop < fitTop)
387121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                    fitTop = fmTop;
388121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                if (fmAscent < fitAscent)
389121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                    fitAscent = fmAscent;
390121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                if (fmDescent > fitDescent)
391121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                    fitDescent = fmDescent;
392121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                if (fmBottom > fitBottom)
393121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                    fitBottom = fmBottom;
394d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            }
3954cf435df2e485e405f085982ac8fd9c82fb57d47Gilles Debunne                        } else {
396d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            if (ok != here) {
397d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // Log.e("text", "output ok " + here + " to " +ok);
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                while (ok < spanEnd && chs[ok - paraStart] == CHAR_SPACE) {
400d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                    ok++;
401d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                }
4024cf435df2e485e405f085982ac8fd9c82fb57d47Gilles Debunne
403d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                v = out(source,
404d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        here, ok,
405121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        okAscent, okDescent, okTop, okBottom,
406d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        v,
407121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        spacingmult, spacingadd, chooseHt,
408121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        chooseHtv, fm, hasTabOrEmoji,
409d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        needMultiply, paraStart, chdirs, dir, easy,
410121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        ok == bufEnd, includepad, trackpad,
411d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        chs, widths, here - paraStart,
412121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        ellipsize, ellipsizedWidth, okWidth,
413d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        paint);
414d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
415d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                here = ok;
416d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            } else if (fit != here) {
417d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // Log.e("text", "output fit " + here + " to " +fit);
418d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                v = out(source,
419d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        here, fit,
420121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        fitAscent, fitDescent,
421121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        fitTop, fitBottom,
422d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        v,
423121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        spacingmult, spacingadd, chooseHt,
424121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        chooseHtv, fm, hasTabOrEmoji,
425d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        needMultiply, paraStart, chdirs, dir, easy,
426121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        fit == bufEnd, includepad, trackpad,
427d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        chs, widths, here - paraStart,
428121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        ellipsize, ellipsizedWidth, fitWidth,
429d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        paint);
430d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
431d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                here = fit;
432d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            } else {
433d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // Log.e("text", "output one " + here + " to " +(here + 1));
434d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // XXX not sure why the existing fm wasn't ok.
435d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                // measureText(paint, mWorkPaint,
436d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                //             source, here, here + 1, fm, tab,
437d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                //             null);
438d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
439d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                v = out(source,
440d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        here, here+1,
441d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        fm.ascent, fm.descent,
442d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        fm.top, fm.bottom,
443d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        v,
444121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        spacingmult, spacingadd, chooseHt,
445121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        chooseHtv, fm, hasTabOrEmoji,
446d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        needMultiply, paraStart, chdirs, dir, easy,
447121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                        here + 1 == bufEnd, includepad,
448d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        trackpad,
449d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        chs, widths, here - paraStart,
4500a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                                        ellipsize, ellipsizedWidth,
451d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                        widths[here - paraStart], paint);
452d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne
453d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                                here = here + 1;
454d434d2334d2362f77d3a3fb0b1f788f667039bbfGilles Debunne                            }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
457e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        if (here < spanStart) {
45823241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            // didn't output all the text for this span
45923241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            // we've measured the raw widths, though, so
46023241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            // just reset the start point
46123241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            j = nextSpanStart = here;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            j = here - 1;    // continue looping
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ok = fit = here;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        w = 0;
468121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        fitAscent = fitDescent = fitTop = fitBottom = 0;
469121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        okAscent = okDescent = okTop = okBottom = 0;
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
471c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        if (--firstWidthLineLimit <= 0) {
472121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            width = restWidth;
4737b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                        }
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
478e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (paraEnd != here) {
479121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if ((fitTop | fitBottom | fitDescent | fitAscent) == 0) {
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    paint.getFontMetricsInt(fm);
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
482121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    fitTop = fm.top;
483121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    fitBottom = fm.bottom;
484121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    fitAscent = fm.ascent;
485121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    fitDescent = fm.descent;
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Log.e("text", "output rest " + here + " to " + end);
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                v = out(source,
491121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        here, paraEnd, fitAscent, fitDescent,
492121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        fitTop, fitBottom,
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        v,
494121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        spacingmult, spacingadd, chooseHt,
495121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHtv, fm, hasTabOrEmoji,
496e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        needMultiply, paraStart, chdirs, dir, easy,
497121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        paraEnd == bufEnd, includepad, trackpad,
498be46d1456beb7e2f3e8b82bda2d0a5023db3debdPaul Eastham                        chs, widths, here - paraStart,
4990a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                        ellipsize, ellipsizedWidth, w, paint);
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
502e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            paraStart = paraEnd;
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
504121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (paraEnd == bufEnd)
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
508121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        if (bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) {
509121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            // Log.e("text", "output last " + bufEnd);
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            paint.getFontMetricsInt(fm);
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = out(source,
514121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    bufEnd, bufEnd, fm.ascent, fm.descent,
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fm.top, fm.bottom,
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v,
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    spacingmult, spacingadd, null,
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    null, fm, false,
519121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    needMultiply, bufEnd, null, DEFAULT_DIR, true,
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    true, includepad, trackpad,
521121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    null, null, bufStart,
5220a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                    ellipsize, ellipsizedWidth, 0, paint);
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if the specified character is one of those specified
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as being Ideographic (class ID) by the Unicode Line Breaking Algorithm
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (http://www.unicode.org/unicode/reports/tr14/), and is therefore OK
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to break between a pair of.
531549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer     *
532549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer     * @param includeNonStarters also return true for category NS
533549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer     *                           (non-starters), which can be broken
534549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer     *                           after but not before.
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
536549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer    private static final boolean isIdeographic(char c, boolean includeNonStarters) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\u2E80' && c <= '\u2FFF') {
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // CJK, KANGXI RADICALS, DESCRIPTION SYMBOLS
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c == '\u3000') {
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // IDEOGRAPHIC SPACE
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\u3040' && c <= '\u309F') {
544549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer            if (!includeNonStarters) {
545549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                switch (c) {
546549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3041': //  # HIRAGANA LETTER SMALL A
547549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3043': //  # HIRAGANA LETTER SMALL I
548549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3045': //  # HIRAGANA LETTER SMALL U
549549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3047': //  # HIRAGANA LETTER SMALL E
550549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3049': //  # HIRAGANA LETTER SMALL O
551549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3063': //  # HIRAGANA LETTER SMALL TU
552549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3083': //  # HIRAGANA LETTER SMALL YA
553549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3085': //  # HIRAGANA LETTER SMALL YU
554549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3087': //  # HIRAGANA LETTER SMALL YO
555549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u308E': //  # HIRAGANA LETTER SMALL WA
556549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3095': //  # HIRAGANA LETTER SMALL KA
557549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u3096': //  # HIRAGANA LETTER SMALL KE
558549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u309B': //  # KATAKANA-HIRAGANA VOICED SOUND MARK
559549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u309C': //  # KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
560549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u309D': //  # HIRAGANA ITERATION MARK
561549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u309E': //  # HIRAGANA VOICED ITERATION MARK
562549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                    return false;
563549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                }
564549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer            }
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // Hiragana (except small characters)
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\u30A0' && c <= '\u30FF') {
568549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer            if (!includeNonStarters) {
569549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                switch (c) {
570549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30A0': //  # KATAKANA-HIRAGANA DOUBLE HYPHEN
571549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30A1': //  # KATAKANA LETTER SMALL A
572549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30A3': //  # KATAKANA LETTER SMALL I
573549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30A5': //  # KATAKANA LETTER SMALL U
574549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30A7': //  # KATAKANA LETTER SMALL E
575549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30A9': //  # KATAKANA LETTER SMALL O
576549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30C3': //  # KATAKANA LETTER SMALL TU
577549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30E3': //  # KATAKANA LETTER SMALL YA
578549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30E5': //  # KATAKANA LETTER SMALL YU
579549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30E7': //  # KATAKANA LETTER SMALL YO
580549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30EE': //  # KATAKANA LETTER SMALL WA
581549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30F5': //  # KATAKANA LETTER SMALL KA
582549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30F6': //  # KATAKANA LETTER SMALL KE
583549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30FB': //  # KATAKANA MIDDLE DOT
584549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30FC': //  # KATAKANA-HIRAGANA PROLONGED SOUND MARK
585549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30FD': //  # KATAKANA ITERATION MARK
586549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                case '\u30FE': //  # KATAKANA VOICED ITERATION MARK
587549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                    return false;
588549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer                }
589549d7243ff9cf638a63a0d5cc82c792b39484e8eEric Fischer            }
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // Katakana (except small characters)
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\u3400' && c <= '\u4DB5') {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // CJK UNIFIED IDEOGRAPHS EXTENSION A
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\u4E00' && c <= '\u9FBB') {
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // CJK UNIFIED IDEOGRAPHS
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\uF900' && c <= '\uFAD9') {
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // CJK COMPATIBILITY IDEOGRAPHS
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\uA000' && c <= '\uA48F') {
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // YI SYLLABLES
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\uA490' && c <= '\uA4CF') {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // YI RADICALS
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\uFE62' && c <= '\uFE66') {
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // SMALL PLUS SIGN to SMALL EQUALS SIGN
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (c >= '\uFF10' && c <= '\uFF19') {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true; // WIDE DIGITS
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void dump(byte[] data, int count, String label) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (false) {
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.out.print(label);
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; i++)
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.out.print(" " + data[i]);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.out.println();
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int out(CharSequence text, int start, int end,
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      int above, int below, int top, int bottom, int v,
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      float spacingmult, float spacingadd,
633121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      LineHeightSpan[] chooseHt, int[] chooseHtv,
634c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                      Paint.FontMetricsInt fm, boolean hasTabOrEmoji,
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      boolean needMultiply, int pstart, byte[] chdirs,
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      int dir, boolean easy, boolean last,
637121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      boolean includePad, boolean trackPad,
638121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      char[] chs, float[] widths, int widthStart,
639121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      TextUtils.TruncateAt ellipsize, float ellipsisWidth,
640121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      float textWidth, TextPaint paint) {
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int j = mLineCount;
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int off = j * mColumns;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int want = off + mColumns + TOP;
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] lines = mLines;
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (want >= lines.length) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int nlen = ArrayUtils.idealIntArraySize(want + 1);
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] grow = new int[nlen];
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(lines, 0, grow, 0, lines.length);
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines = grow;
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lines = grow;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Directions[] grow2 = new Directions[nlen];
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mLineDirections, 0, grow2, 0,
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             mLineDirections.length);
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLineDirections = grow2;
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        if (chooseHt != null) {
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.ascent = above;
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.descent = below;
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.top = top;
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.bottom = bottom;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
665121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            for (int i = 0; i < chooseHt.length; i++) {
666121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (chooseHt[i] instanceof LineHeightSpan.WithDensity) {
667121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    ((LineHeightSpan.WithDensity) chooseHt[i]).
668121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHeight(text, start, end, chooseHtv[i], v, fm, paint);
669a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer
670a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer                } else {
671121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm);
672a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer                }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fm.ascent;
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fm.descent;
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            top = fm.top;
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottom = fm.bottom;
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (j == 0) {
682121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (trackPad) {
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTopPadding = top - above;
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
686121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (includePad) {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                above = top;
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (last) {
691121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (trackPad) {
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBottomPadding = bottom - below;
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
695121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (includePad) {
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                below = bottom;
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int extra;
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (needMultiply) {
7031065758a0f8966a8597a61492112f7859a7050a4Doug Felt            double ex = (below - above) * (spacingmult - 1) + spacingadd;
7041065758a0f8966a8597a61492112f7859a7050a4Doug Felt            if (ex >= 0) {
705121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                extra = (int)(ex + EXTRA_ROUNDING);
7061065758a0f8966a8597a61492112f7859a7050a4Doug Felt            } else {
707121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                extra = -(int)(-ex + EXTRA_ROUNDING);
7081065758a0f8966a8597a61492112f7859a7050a4Doug Felt            }
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extra = 0;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + START] = start;
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + TOP] = v;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + DESCENT] = below + extra;
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v += (below - above) + extra;
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + mColumns + START] = end;
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + mColumns + TOP] = v;
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
721c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt        if (hasTabOrEmoji)
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lines[off + TAB] |= TAB_MASK;
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7249f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        lines[off + DIR] |= dir << DIR_SHIFT;
7259f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
7269f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        // easy means all chars < the first RTL, so no emoji, no nothing
7274e0c5e55e171532760d5f51e0165563827129d4eDoug Felt        // XXX a run with no text or all spaces is easy but might be an empty
7289f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        // RTL paragraph.  Make sure easy is false if this is the case.
7299f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        if (easy) {
7309f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt            mLineDirections[j] = linedirs;
7319f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        } else {
732121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            mLineDirections[j] = AndroidBidi.directions(dir, chdirs, widthStart, chs,
733121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    widthStart, end - start);
7340a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7360a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        // If ellipsize is in marquee mode, do not apply ellipsis on the first line
7370a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        if (ellipsize != null && (ellipsize != TextUtils.TruncateAt.MARQUEE || j != 0)) {
738121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            calculateEllipsis(start, end, widths, widthStart,
739121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    ellipsisWidth, ellipsize, j,
740121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    textWidth, paint);
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineCount++;
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
747121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private void calculateEllipsis(int lineStart, int lineEnd,
748121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                   float[] widths, int widthStart,
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   float avail, TextUtils.TruncateAt where,
750121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                   int line, float textWidth, TextPaint paint) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
752121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        if (textWidth <= avail) {
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Everything fits!
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines[mColumns * line + ELLIPSIS_START] = 0;
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines[mColumns * line + ELLIPSIS_COUNT] = 0;
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        float ellipsisWidth = paint.measureText(HORIZONTAL_ELLIPSIS);
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int ellipsisStart, ellipsisCount;
761121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        int len = lineEnd - lineStart;
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where == TextUtils.TruncateAt.START) {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float sum = 0;
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = len; i >= 0; i--) {
768121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                float w = widths[i - 1 + lineStart - widthStart];
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
770121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (w + sum + ellipsisWidth > avail) {
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sum += w;
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisStart = 0;
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisCount = i;
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE) {
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float sum = 0;
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < len; i++) {
784121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                float w = widths[i + lineStart - widthStart];
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
786121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (w + sum + ellipsisWidth > avail) {
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sum += w;
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisStart = i;
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisCount = len - i;
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else /* where = TextUtils.TruncateAt.MIDDLE */ {
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float lsum = 0, rsum = 0;
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int left = 0, right = len;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            float ravail = (avail - ellipsisWidth) / 2;
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (right = len; right >= 0; right--) {
801121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                float w = widths[right - 1 + lineStart - widthStart];
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (w + rsum > ravail) {
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                rsum += w;
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
810121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            float lavail = avail - ellipsisWidth - rsum;
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (left = 0; left < right; left++) {
812121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                float w = widths[left + lineStart - widthStart];
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (w + lsum > lavail) {
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                lsum += w;
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisStart = left;
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisCount = right - left;
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart;
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    // Override the base class so we can directly access our members,
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // rather than relying on member functions.
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The logic mirrors that of Layout.getLineForVertical
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // FIXME: It may be faster to do a linear search for layouts without many lines.
8336611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineForVertical(int vertical) {
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int high = mLineCount;
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int low = -1;
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int guess;
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] lines = mLines;
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (high - low > 1) {
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            guess = (high + low) >> 1;
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lines[mColumns * guess + TOP] > vertical){
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                high = guess;
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = guess;
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (low < 0) {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return low;
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8546611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineCount() {
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLineCount;
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8596611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineTop(int line) {
8610a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        int top = mLines[mColumns * line + TOP];
8620a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount &&
8630a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                line != mLineCount) {
8640a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne            top += getBottomPadding();
8650a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
8660a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        return top;
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8696611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineDescent(int line) {
8710a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        int descent = mLines[mColumns * line + DESCENT];
8720a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 &&
8730a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                line != mLineCount) {
8740a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne            descent += getBottomPadding();
8750a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
8760a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        return descent;
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8796611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineStart(int line) {
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + START] & START_MASK;
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8846611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getParagraphDirection(int line) {
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + DIR] >> DIR_SHIFT;
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8896611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getLineContainsTab(int line) {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mLines[mColumns * line + TAB] & TAB_MASK) != 0;
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8946611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Directions getLineDirections(int line) {
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLineDirections[line];
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8996611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getTopPadding() {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTopPadding;
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9046611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getBottomPadding() {
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBottomPadding;
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsisCount(int line) {
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mColumns < COLUMNS_ELLIPSIZE) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + ELLIPSIS_COUNT];
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsisStart(int line) {
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mColumns < COLUMNS_ELLIPSIZE) {
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + ELLIPSIS_START];
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsizedWidth() {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEllipsizedWidth;
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9320a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne    /**
9330a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne     * @hide
9340a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne     */
9350a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne    @Override
9360a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne    public void setMaximumVisibleLineCount(int line) {
9370a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        mMaximumVisibleLineCount = line;
9380a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne    }
9390a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mLineCount;
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTopPadding, mBottomPadding;
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mColumns;
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mEllipsizedWidth;
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int COLUMNS_NORMAL = 3;
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int COLUMNS_ELLIPSIZE = 5;
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START = 0;
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DIR = START;
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB = START;
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TOP = 1;
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DESCENT = 2;
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int ELLIPSIS_START = 3;
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int ELLIPSIS_COUNT = 4;
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mLines;
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Directions[] mLineDirections;
9570a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne    private int mMaximumVisibleLineCount = 0;
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START_MASK = 0x1FFFFFFF;
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DIR_SHIFT  = 30;
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB_MASK   = 0x20000000;
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
963c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt    private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
965121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_FIRST_CJK = '\u2E80';
966121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
967121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_NEW_LINE = '\n';
968121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_TAB = '\t';
969121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_SPACE = ' ';
970121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_DOT = '.';
971121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_COMMA = ',';
972121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_COLON = ':';
973121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_SEMICOLON = ';';
974121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_SLASH = '/';
975121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_HYPHEN = '-';
976121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
977121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final double EXTRA_ROUNDING = 0.5;
978121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final String HORIZONTAL_ELLIPSIS = "\u2026"; // this is "..."
979121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
980121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final int CHAR_FIRST_HIGH_SURROGATE = 0xD800;
981121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final int CHAR_LAST_LOW_SURROGATE = 0xDFFF;
982121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
984e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt     * This is reused across calls to generate()
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
986e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    private MeasuredText mMeasured;
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
989