StaticLayout.java revision e319d5a3627aa3cd73c6ec0c76f8593ddefbab9d
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
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.LeadingMarginSpan;
216611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunneimport android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.LineHeightSpan;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.MetricAffectingSpan;
24c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Feltimport android.text.style.TabStopSpan;
258059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglioimport android.util.Log;
2639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levienimport android.util.Pools.SynchronizedPool;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28cb379120456d8065d742021fc5c66748fc8a11a8Doug Feltimport com.android.internal.util.ArrayUtils;
29776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport com.android.internal.util.GrowingArrayUtils;
30cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
31c8f9e6218681640d5f384c12edf06619be56a583Anish Athalyeimport java.util.Arrays;
324c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levienimport java.util.Locale;
33c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * StaticLayout is a Layout for text that will not be edited after it
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is laid out.  Use {@link DynamicLayout} for text that may change.
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>This is used by widgets to control text layout. You should not need
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to use this class directly unless you are implementing your own widget
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or custom display object, or would be tempted to call
404e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int,
414e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * float, float, android.graphics.Paint)
424e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * Canvas.drawText()} directly.</p>
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
44121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Megliopublic class StaticLayout extends Layout {
45121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
468059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio    static final String TAG = "StaticLayout";
478059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio
48d3ab692d28018825578ff05832644cfad60233fbRaph Levien    /**
49d3ab692d28018825578ff05832644cfad60233fbRaph Levien     * Builder for static layouts. It would be better if this were a public
50d3ab692d28018825578ff05832644cfad60233fbRaph Levien     * API (as it would offer much greater flexibility for adding new options)
51d3ab692d28018825578ff05832644cfad60233fbRaph Levien     * but for the time being it's just internal.
52d3ab692d28018825578ff05832644cfad60233fbRaph Levien     *
53d3ab692d28018825578ff05832644cfad60233fbRaph Levien     * @hide
54d3ab692d28018825578ff05832644cfad60233fbRaph Levien     */
55d3ab692d28018825578ff05832644cfad60233fbRaph Levien    public final static class Builder {
564c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        private Builder() {
574c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            mNativePtr = nNewBuilder();
584c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        }
594c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
6039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        public static Builder obtain(CharSequence source, int start, int end, int width) {
6139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            Builder b = sPool.acquire();
62d3ab692d28018825578ff05832644cfad60233fbRaph Levien            if (b == null) {
63d3ab692d28018825578ff05832644cfad60233fbRaph Levien                b = new Builder();
64d3ab692d28018825578ff05832644cfad60233fbRaph Levien            }
65d3ab692d28018825578ff05832644cfad60233fbRaph Levien
66d3ab692d28018825578ff05832644cfad60233fbRaph Levien            // set default initial values
6739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mText = source;
6839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mStart = start;
6939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mEnd = end;
7039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mWidth = width;
7139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mAlignment = Alignment.ALIGN_NORMAL;
72d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
73d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mSpacingMult = 1.0f;
74d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mSpacingAdd = 0.0f;
75d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mIncludePad = true;
7639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mEllipsizedWidth = width;
77d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mEllipsize = null;
78d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mMaxLines = Integer.MAX_VALUE;
79d3ab692d28018825578ff05832644cfad60233fbRaph Levien
80d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mMeasuredText = MeasuredText.obtain();
81d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return b;
82d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
83d3ab692d28018825578ff05832644cfad60233fbRaph Levien
8439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        private static void recycle(Builder b) {
85d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mPaint = null;
86d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mText = null;
87d3ab692d28018825578ff05832644cfad60233fbRaph Levien            MeasuredText.recycle(b.mMeasuredText);
8839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            sPool.release(b);
89d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
90d3ab692d28018825578ff05832644cfad60233fbRaph Levien
91d3ab692d28018825578ff05832644cfad60233fbRaph Levien        // release any expensive state
92d3ab692d28018825578ff05832644cfad60233fbRaph Levien        /* package */ void finish() {
934c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            nFinishBuilder(mNativePtr);
94d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mMeasuredText.finish();
95d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
96d3ab692d28018825578ff05832644cfad60233fbRaph Levien
97d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setText(CharSequence source) {
98d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return setText(source, 0, source.length());
99d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
100d3ab692d28018825578ff05832644cfad60233fbRaph Levien
101d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setText(CharSequence source, int start, int end) {
102d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mText = source;
103d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mStart = start;
104d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mEnd = end;
105d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
106d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
107d3ab692d28018825578ff05832644cfad60233fbRaph Levien
108d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setPaint(TextPaint paint) {
109d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mPaint = paint;
110d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
111d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
112d3ab692d28018825578ff05832644cfad60233fbRaph Levien
113d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setWidth(int width) {
114d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mWidth = width;
115d3ab692d28018825578ff05832644cfad60233fbRaph Levien            if (mEllipsize == null) {
116d3ab692d28018825578ff05832644cfad60233fbRaph Levien                mEllipsizedWidth = width;
117d3ab692d28018825578ff05832644cfad60233fbRaph Levien            }
118d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
119d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
120d3ab692d28018825578ff05832644cfad60233fbRaph Levien
12139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        public Builder setAlignment(Alignment alignment) {
12239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mAlignment = alignment;
12339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            return this;
12439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        }
12539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
126d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setTextDir(TextDirectionHeuristic textDir) {
127d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mTextDir = textDir;
128d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
129d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
130d3ab692d28018825578ff05832644cfad60233fbRaph Levien
131d3ab692d28018825578ff05832644cfad60233fbRaph Levien        // TODO: combine the following, as they're almost always set together?
132d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setSpacingMult(float spacingMult) {
133d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mSpacingMult = spacingMult;
134d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
135d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
136d3ab692d28018825578ff05832644cfad60233fbRaph Levien
137d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setSpacingAdd(float spacingAdd) {
138d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mSpacingAdd = spacingAdd;
139d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
140d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
141d3ab692d28018825578ff05832644cfad60233fbRaph Levien
142d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setIncludePad(boolean includePad) {
143d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mIncludePad = includePad;
144d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
145d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
146d3ab692d28018825578ff05832644cfad60233fbRaph Levien
147d3ab692d28018825578ff05832644cfad60233fbRaph Levien        // TODO: combine the following?
148d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setEllipsizedWidth(int ellipsizedWidth) {
149d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mEllipsizedWidth = ellipsizedWidth;
150d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
151d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
152d3ab692d28018825578ff05832644cfad60233fbRaph Levien
153d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setEllipsize(TextUtils.TruncateAt ellipsize) {
154d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mEllipsize = ellipsize;
155d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
156d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
157d3ab692d28018825578ff05832644cfad60233fbRaph Levien
158d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setMaxLines(int maxLines) {
159d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mMaxLines = maxLines;
160d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
161d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
162d3ab692d28018825578ff05832644cfad60233fbRaph Levien
16339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
16439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mBreakStrategy = breakStrategy;
16539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            return this;
16639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        }
16739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
168e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien        public Builder setIndents(int[] leftIndents, int[] rightIndents) {
169e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            int leftLen = leftIndents == null ? 0 : leftIndents.length;
170e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            int rightLen = rightIndents == null ? 0 : rightIndents.length;
171e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            int[] indents = new int[Math.max(leftLen, rightLen)];
172e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            for (int i = 0; i < indents.length; i++) {
173e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien                int leftMargin = i < leftLen ? leftIndents[i] : 0;
174e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien                int rightMargin = i < rightLen ? rightIndents[i] : 0;
175e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien                indents[i] = leftMargin + rightMargin;
176e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            }
177e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            nSetIndents(mNativePtr, indents);
178e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            return this;
179e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien        }
180e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien
18170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /**
18270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * Measurement and break iteration is done in native code. The protocol for using
18370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * the native code is as follows.
18470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *
18526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien         * For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
18626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien         * stops, break strategy (and possibly other parameters in the future).
187c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien         *
188c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien         * Then, for each run within the paragraph:
18970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *  - setLocale (this must be done at least for the first run, optional afterwards)
19070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *  - one of the following, depending on the type of run:
19170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *    + addStyleRun (a text run, to be measured in native code)
19270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *    + addMeasuredRun (a run already measured in Java, passed into native code)
19370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *    + addReplacementRun (a replacement run, width is given)
19470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *
19570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis).
19670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * Run nComputeLineBreaks() to obtain line breaks for the paragraph.
19770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *
19870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * After all paragraphs, call finish() to release expensive buffers.
19970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         */
20070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
20170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        private void setLocale(Locale locale) {
2024c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            if (!locale.equals(mLocale)) {
20326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien                nSetLocale(mNativePtr, locale.toLanguageTag(), Hyphenator.get(locale));
2044c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien                mLocale = locale;
2054c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            }
2064c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        }
2074c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
20870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
20970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            return nAddStyleRun(mNativePtr, paint.getNativeInstance(), paint.mNativeTypeface,
21070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    start, end, isRtl);
21170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
21270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
21370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /* package */ void addMeasuredRun(int start, int end, float[] widths) {
21470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            nAddMeasuredRun(mNativePtr, start, end, widths);
21570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
21670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
21770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /* package */ void addReplacementRun(int start, int end, float width) {
21870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            nAddReplacementRun(mNativePtr, start, end, width);
21970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
22070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
221d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public StaticLayout build() {
22239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            StaticLayout result = new StaticLayout(this);
22339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            Builder.recycle(this);
224d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return result;
225d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
226d3ab692d28018825578ff05832644cfad60233fbRaph Levien
2274c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        @Override
2284c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        protected void finalize() throws Throwable {
2294c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            try {
2304c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien                nFreeBuilder(mNativePtr);
2314c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            } finally {
2324c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien                super.finalize();
2334c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            }
2344c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        }
2354c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
2364c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        /* package */ long mNativePtr;
2374c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
238d3ab692d28018825578ff05832644cfad60233fbRaph Levien        CharSequence mText;
239d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mStart;
240d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mEnd;
241d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextPaint mPaint;
242d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mWidth;
24339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        Alignment mAlignment;
244d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextDirectionHeuristic mTextDir;
245d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float mSpacingMult;
246d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float mSpacingAdd;
247d3ab692d28018825578ff05832644cfad60233fbRaph Levien        boolean mIncludePad;
248d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mEllipsizedWidth;
249d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextUtils.TruncateAt mEllipsize;
250d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mMaxLines;
25139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        int mBreakStrategy;
252d3ab692d28018825578ff05832644cfad60233fbRaph Levien
253d3ab692d28018825578ff05832644cfad60233fbRaph Levien        Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
254d3ab692d28018825578ff05832644cfad60233fbRaph Levien
255d3ab692d28018825578ff05832644cfad60233fbRaph Levien        // This will go away and be subsumed by native builder code
256d3ab692d28018825578ff05832644cfad60233fbRaph Levien        MeasuredText mMeasuredText;
257d3ab692d28018825578ff05832644cfad60233fbRaph Levien
2584c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        Locale mLocale;
2594c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
26039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
261d3ab692d28018825578ff05832644cfad60233fbRaph Levien    }
262d3ab692d28018825578ff05832644cfad60233fbRaph Levien
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, TextPaint paint,
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int width,
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align, float spacingmult, float spacingadd,
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad) {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(source, 0, source.length(), paint, width, align,
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             spacingmult, spacingadd, includepad);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
271cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
272cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * @hide
273cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
274cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public StaticLayout(CharSequence source, TextPaint paint,
275cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            int width, Alignment align, TextDirectionHeuristic textDir,
276cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            float spacingmult, float spacingadd,
277cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean includepad) {
278cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        this(source, 0, source.length(), paint, width, align, textDir,
279cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                spacingmult, spacingadd, includepad);
280cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
281cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, int bufstart, int bufend,
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextPaint paint, int outerwidth,
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align,
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad) {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(source, bufstart, bufend, paint, outerwidth, align,
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             spacingmult, spacingadd, includepad, null, 0);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
291cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
292cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * @hide
293cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
294cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public StaticLayout(CharSequence source, int bufstart, int bufend,
295cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            TextPaint paint, int outerwidth,
296cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            Alignment align, TextDirectionHeuristic textDir,
297cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            float spacingmult, float spacingadd,
298cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean includepad) {
299cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        this(source, bufstart, bufend, paint, outerwidth, align, textDir,
3008059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                spacingmult, spacingadd, includepad, null, 0, Integer.MAX_VALUE);
301cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt}
302cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
303cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public StaticLayout(CharSequence source, int bufstart, int bufend,
304cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            TextPaint paint, int outerwidth,
305cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            Alignment align,
306cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            float spacingmult, float spacingadd,
307cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean includepad,
308cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
309cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        this(source, bufstart, bufend, paint, outerwidth, align,
310cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                TextDirectionHeuristics.FIRSTSTRONG_LTR,
3118059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE);
312cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
313cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
314cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
315cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * @hide
316cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, int bufstart, int bufend,
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextPaint paint, int outerwidth,
319cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        Alignment align, TextDirectionHeuristic textDir,
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad,
3228059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) {
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super((ellipsize == null)
3244e0c5e55e171532760d5f51e0165563827129d4eDoug Felt                ? source
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                : (source instanceof Spanned)
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? new SpannedEllipsizer(source)
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : new Ellipsizer(source),
328cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt              paint, outerwidth, align, textDir, spacingmult, spacingadd);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        Builder b = Builder.obtain(source, bufstart, bufend, outerwidth)
331d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setPaint(paint)
33239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            .setAlignment(align)
333d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setTextDir(textDir)
334d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setSpacingMult(spacingmult)
335d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setSpacingAdd(spacingadd)
336d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setIncludePad(includepad)
337d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setEllipsizedWidth(ellipsizedWidth)
338d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setEllipsize(ellipsize)
339d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setMaxLines(maxLines);
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This is annoying, but we can't refer to the layout until
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * superclass construction is finished, and the superclass
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * constructor wants the reference to the display text.
3444e0c5e55e171532760d5f51e0165563827129d4eDoug Felt         *
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This will break if the superclass constructor ever actually
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * cares about the content instead of just holding the reference.
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ellipsize != null) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Ellipsizer e = (Ellipsizer) getText();
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mLayout = this;
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mWidth = ellipsizedWidth;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mMethod = ellipsize;
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEllipsizedWidth = ellipsizedWidth;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mColumns = COLUMNS_ELLIPSIZE;
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mColumns = COLUMNS_NORMAL;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEllipsizedWidth = outerwidth;
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
362776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
363776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLines = new int[mLineDirections.length];
3648059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        mMaximumVisibleLineCount = maxLines;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        generate(b, b.mIncludePad, b.mIncludePad);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
368d3ab692d28018825578ff05832644cfad60233fbRaph Levien        Builder.recycle(b);
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3718059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio    /* package */ StaticLayout(CharSequence text) {
3728059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        super(text, null, 0, null, 0, 0);
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mColumns = COLUMNS_ELLIPSIZE;
375776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
376776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLines = new int[mLineDirections.length];
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien    private StaticLayout(Builder b) {
38039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        super((b.mEllipsize == null)
38139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                ? b.mText
38239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                : (b.mText instanceof Spanned)
38339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                    ? new SpannedEllipsizer(b.mText)
38439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                    : new Ellipsizer(b.mText),
38539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
38639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
38739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        if (b.mEllipsize != null) {
38839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            Ellipsizer e = (Ellipsizer) getText();
38939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
39039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            e.mLayout = this;
39139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            e.mWidth = b.mEllipsizedWidth;
39239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            e.mMethod = b.mEllipsize;
39339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mEllipsizedWidth = b.mEllipsizedWidth;
39439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
39539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mColumns = COLUMNS_ELLIPSIZE;
39639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        } else {
39739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mColumns = COLUMNS_NORMAL;
39839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mEllipsizedWidth = b.mWidth;
39939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        }
40039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
40139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
40239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        mLines = new int[mLineDirections.length];
40339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        mMaximumVisibleLineCount = b.mMaxLines;
40439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
40539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        generate(b, b.mIncludePad, b.mIncludePad);
40639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien    }
40739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
408d3ab692d28018825578ff05832644cfad60233fbRaph Levien    /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
409d3ab692d28018825578ff05832644cfad60233fbRaph Levien        CharSequence source = b.mText;
410d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int bufStart = b.mStart;
411d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int bufEnd = b.mEnd;
412d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextPaint paint = b.mPaint;
413d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int outerWidth = b.mWidth;
414d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextDirectionHeuristic textDir = b.mTextDir;
415d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float spacingmult = b.mSpacingMult;
416d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float spacingadd = b.mSpacingAdd;
417d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float ellipsizedWidth = b.mEllipsizedWidth;
418d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextUtils.TruncateAt ellipsize = b.mEllipsize;
4194c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        LineBreaks lineBreaks = new LineBreaks();  // TODO: move to builder to avoid allocation costs
420c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // store span end locations
421c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        int[] spanEndCache = new int[4];
422c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // store fontMetrics per span range
423c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
424c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        int[] fmCache = new int[4 * 4];
4254c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        b.setLocale(paint.getTextLocale());  // TODO: also respect LocaleSpan within the text
42688b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineCount = 0;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int v = 0;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
432d3ab692d28018825578ff05832644cfad60233fbRaph Levien        Paint.FontMetricsInt fm = b.mFontMetricsInt;
433121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        int[] chooseHtv = null;
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
435d3ab692d28018825578ff05832644cfad60233fbRaph Levien        MeasuredText measured = b.mMeasuredText;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Spanned spanned = null;
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (source instanceof Spanned)
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            spanned = (Spanned) source;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
441e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int paraEnd;
442121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
443121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
444e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (paraEnd < 0)
445121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                paraEnd = bufEnd;
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
447e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                paraEnd++;
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
449c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int firstWidthLineCount = 1;
450121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int firstWidth = outerWidth;
451121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int restWidth = outerWidth;
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
453121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            LineHeightSpan[] chooseHt = null;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanned != null) {
45674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer                LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
457e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        LeadingMarginSpan.class);
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < sp.length; i++) {
4597b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    LeadingMarginSpan lms = sp[i];
460121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    firstWidth -= sp[i].getLeadingMargin(true);
461121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    restWidth -= sp[i].getLeadingMargin(false);
462cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
463c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    // LeadingMarginSpan2 is odd.  The count affects all
464ab08c6d38ab2e575f809ca8ce4c7f095e49d258cAnish Athalye                    // leading margin spans, not just this particular one
465c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    if (lms instanceof LeadingMarginSpan2) {
466c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
467c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        firstWidthLineCount = Math.max(firstWidthLineCount,
468c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                                lms2.getLeadingMarginLineCount());
4697b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    }
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
472121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
474121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (chooseHt.length != 0) {
475121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    if (chooseHtv == null ||
476121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHtv.length < chooseHt.length) {
477776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski                        chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
480121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    for (int i = 0; i < chooseHt.length; i++) {
481121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        int o = spanned.getSpanStart(chooseHt[i]);
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
483e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        if (o < paraStart) {
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // starts in this layout, before the
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // current paragraph
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
487121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            chooseHtv[i] = getLineTop(getLineForOffset(o));
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // starts in this paragraph
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
491121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            chooseHtv[i] = v;
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
49770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            measured.setPara(source, paraStart, paraEnd, textDir, b);
498e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            char[] chs = measured.mChars;
499e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            float[] widths = measured.mWidths;
500e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            byte[] chdirs = measured.mLevels;
501e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            int dir = measured.mDir;
502e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            boolean easy = measured.mEasy;
503c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien
504c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            // tab stop locations
505c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            int[] variableTabStops = null;
506c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            if (spanned != null) {
507c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
508c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                        paraEnd, TabStopSpan.class);
509c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                if (spans.length > 0) {
510c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    int[] stops = new int[spans.length];
511c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    for (int i = 0; i < spans.length; i++) {
512c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                        stops[i] = spans[i].getTabStop();
513c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    }
514c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    Arrays.sort(stops, 0, stops.length);
515c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    variableTabStops = stops;
516c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                }
517c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            }
518c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien
519c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
520c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    firstWidth, firstWidthLineCount, restWidth,
52139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
523c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // measurement has to be done before performing line breaking
524c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // but we don't want to recompute fontmetrics or span ranges the
525c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // second time, so we cache those and then use those stored values
526c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int fmCacheCount = 0;
527c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int spanEndCacheCount = 0;
528cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne            for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
529c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fmCacheCount * 4 >= fmCache.length) {
530c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    int[] grow = new int[fmCacheCount * 4 * 2];
531c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
532c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmCache = grow;
533c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
534c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
535c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (spanEndCacheCount >= spanEndCache.length) {
536c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    int[] grow = new int[spanEndCacheCount * 2];
537c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
538c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    spanEndCache = grow;
539c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
54023241887515ed77687c23e29a4a3ffff671666bdDoug Felt
541cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                if (spanned == null) {
542cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    spanEnd = paraEnd;
54323241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    int spanLen = spanEnd - spanStart;
544cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    measured.addStyleRun(paint, spanLen, fm);
545cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                } else {
546cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
547cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                            MetricAffectingSpan.class);
548cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    int spanLen = spanEnd - spanStart;
549cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    MetricAffectingSpan[] spans =
55023241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
551cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class);
552cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    measured.addStyleRun(paint, spans, spanLen, fm);
55323241887515ed77687c23e29a4a3ffff671666bdDoug Felt                }
55423241887515ed77687c23e29a4a3ffff671666bdDoug Felt
555c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // the order of storage here (top, bottom, ascent, descent) has to match the code below
556c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // where these values are retrieved
557c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 0] = fm.top;
558c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 1] = fm.bottom;
559c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 2] = fm.ascent;
560c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 3] = fm.descent;
561c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCacheCount++;
562c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
563c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                spanEndCache[spanEndCacheCount] = spanEnd;
564c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                spanEndCacheCount++;
565c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            }
566c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
56770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            nGetWidths(b.mNativePtr, widths);
568c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
569c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
57081541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne
571c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int[] breaks = lineBreaks.breaks;
572c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            float[] lineWidths = lineBreaks.widths;
57326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien            int[] flags = lineBreaks.flags;
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
575c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // here is the offset of the starting character of the line we are currently measuring
576c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int here = paraStart;
577d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne
578c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
579c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int fmCacheIndex = 0;
580c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int spanEndCacheIndex = 0;
581c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int breakIndex = 0;
582c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
583c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // retrieve end of span
584c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                spanEnd = spanEndCache[spanEndCacheIndex++];
585c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
586c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // retrieve cached metrics, order matches above
587c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.top = fmCache[fmCacheIndex * 4 + 0];
588c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.bottom = fmCache[fmCacheIndex * 4 + 1];
589c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.ascent = fmCache[fmCacheIndex * 4 + 2];
590c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.descent = fmCache[fmCacheIndex * 4 + 3];
591c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCacheIndex++;
592c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
593c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.top < fmTop) {
594c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmTop = fm.top;
595c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
596c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.ascent < fmAscent) {
597c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmAscent = fm.ascent;
598c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
599c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.descent > fmDescent) {
600c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmDescent = fm.descent;
601c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
602c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.bottom > fmBottom) {
603c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmBottom = fm.bottom;
604c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
605cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne
606c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // skip breaks ending before current span range
607c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
608c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    breakIndex++;
609c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
61081541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne
611c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
612c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    int endPos = paraStart + breaks[breakIndex];
613c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
614ce4155a204144ae5462f547f7738af24be5a1f77Raph Levien                    boolean moreChars = (endPos < bufEnd);
6154c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien
616c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    v = out(source, here, endPos,
617c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            fmAscent, fmDescent, fmTop, fmBottom,
618c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex],
619c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
620c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            chs, widths, paraStart, ellipsize, ellipsizedWidth,
6214c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien                            lineWidths[breakIndex], paint, moreChars);
622c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
623c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    if (endPos < spanEnd) {
624c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        // preserve metrics for current span
625c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmTop = fm.top;
626c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmBottom = fm.bottom;
627c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmAscent = fm.ascent;
628c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmDescent = fm.descent;
629c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    } else {
630c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmTop = fmBottom = fmAscent = fmDescent = 0;
6318059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
633c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    here = endPos;
634c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    breakIndex++;
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
636c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    if (mLineCount >= mMaximumVisibleLineCount) {
637c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        return;
638c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    }
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
642121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (paraEnd == bufEnd)
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6468059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) &&
647ad0b051b133baf92f199c96a8ac1e81b3393190cFabrice Di Meglio                mLineCount < mMaximumVisibleLineCount) {
648121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            // Log.e("text", "output last " + bufEnd);
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
65070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            measured.setPara(source, bufEnd, bufEnd, textDir, b);
651e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            paint.getFontMetricsInt(fm);
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = out(source,
655121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    bufEnd, bufEnd, fm.ascent, fm.descent,
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fm.top, fm.bottom,
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v,
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    spacingmult, spacingadd, null,
65926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien                    null, fm, 0,
660e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio                    needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
661d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                    includepad, trackpad, null,
662d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                    null, bufStart, ellipsize,
663d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                    ellipsizedWidth, 0, paint, false);
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int out(CharSequence text, int start, int end,
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      int above, int below, int top, int bottom, int v,
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      float spacingmult, float spacingadd,
670121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      LineHeightSpan[] chooseHt, int[] chooseHtv,
67126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien                      Paint.FontMetricsInt fm, int flags,
672d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      boolean needMultiply, byte[] chdirs, int dir,
673d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      boolean easy, int bufEnd, boolean includePad,
674d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      boolean trackPad, char[] chs,
675d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      float[] widths, int widthStart, TextUtils.TruncateAt ellipsize,
676d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      float ellipsisWidth, float textWidth,
677d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      TextPaint paint, boolean moreChars) {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int j = mLineCount;
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int off = j * mColumns;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int want = off + mColumns + TOP;
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] lines = mLines;
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (want >= lines.length) {
684776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            Directions[] grow2 = ArrayUtils.newUnpaddedArray(
685776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski                    Directions.class, GrowingArrayUtils.growSize(want));
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mLineDirections, 0, grow2, 0,
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             mLineDirections.length);
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLineDirections = grow2;
689776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski
690776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            int[] grow = new int[grow2.length];
691776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            System.arraycopy(lines, 0, grow, 0, lines.length);
692776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            mLines = grow;
693776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            lines = grow;
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
696121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        if (chooseHt != null) {
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.ascent = above;
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.descent = below;
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.top = top;
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.bottom = bottom;
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
702121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            for (int i = 0; i < chooseHt.length; i++) {
703121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (chooseHt[i] instanceof LineHeightSpan.WithDensity) {
704121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    ((LineHeightSpan.WithDensity) chooseHt[i]).
705121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHeight(text, start, end, chooseHtv[i], v, fm, paint);
706a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer
707a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer                } else {
708121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm);
709a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer                }
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fm.ascent;
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fm.descent;
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            top = fm.top;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottom = fm.bottom;
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
718d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        boolean firstLine = (j == 0);
719d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
720d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd);
721d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien
722d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        if (firstLine) {
723121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (trackPad) {
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTopPadding = top - above;
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
727121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (includePad) {
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                above = top;
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
731d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien
732d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        int extra;
733d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien
734d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        if (lastLine) {
735121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (trackPad) {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBottomPadding = bottom - below;
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
739121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (includePad) {
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                below = bottom;
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
745d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        if (needMultiply && !lastLine) {
7461065758a0f8966a8597a61492112f7859a7050a4Doug Felt            double ex = (below - above) * (spacingmult - 1) + spacingadd;
7471065758a0f8966a8597a61492112f7859a7050a4Doug Felt            if (ex >= 0) {
748121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                extra = (int)(ex + EXTRA_ROUNDING);
7491065758a0f8966a8597a61492112f7859a7050a4Doug Felt            } else {
750121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                extra = -(int)(-ex + EXTRA_ROUNDING);
7511065758a0f8966a8597a61492112f7859a7050a4Doug Felt            }
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extra = 0;
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + START] = start;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + TOP] = v;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + DESCENT] = below + extra;
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v += (below - above) + extra;
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + mColumns + START] = end;
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + mColumns + TOP] = v;
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
76426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
76526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        // one bit for start field
76626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        lines[off + TAB] |= flags & TAB_MASK;
76726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        lines[off + HYPHEN] = flags;
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7699f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        lines[off + DIR] |= dir << DIR_SHIFT;
7709f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
7719f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        // easy means all chars < the first RTL, so no emoji, no nothing
7724e0c5e55e171532760d5f51e0165563827129d4eDoug Felt        // XXX a run with no text or all spaces is easy but might be an empty
7739f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        // RTL paragraph.  Make sure easy is false if this is the case.
7749f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        if (easy) {
7759f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt            mLineDirections[j] = linedirs;
7769f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        } else {
777f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne            mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs,
778f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne                    start - widthStart, end - start);
7790a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
781aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio        if (ellipsize != null) {
782aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            // If there is only one line, then do any type of ellipsis except when it is MARQUEE
783aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            // if there are multiple lines, just allow END ellipsis on the last line
7848059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
785aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio
78634a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio            boolean doEllipsis =
78734a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio                        (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) &&
788aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                                ellipsize != TextUtils.TruncateAt.MARQUEE) ||
789aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                        (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
790aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                                ellipsize == TextUtils.TruncateAt.END);
791aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            if (doEllipsis) {
792aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                calculateEllipsis(start, end, widths, widthStart,
793aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                        ellipsisWidth, ellipsize, j,
794aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                        textWidth, paint, forceEllipsis);
795aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            }
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineCount++;
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
802121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private void calculateEllipsis(int lineStart, int lineEnd,
803121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                   float[] widths, int widthStart,
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   float avail, TextUtils.TruncateAt where,
8058059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                                   int line, float textWidth, TextPaint paint,
8068059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                                   boolean forceEllipsis) {
8078059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        if (textWidth <= avail && !forceEllipsis) {
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Everything fits!
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines[mColumns * line + ELLIPSIS_START] = 0;
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines[mColumns * line + ELLIPSIS_COUNT] = 0;
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
814cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio        float ellipsisWidth = paint.measureText(
8158d44fff7e62f77c3b3072a96712cc1389e63ca64Fabrice Di Meglio                (where == TextUtils.TruncateAt.END_SMALL) ?
816d29bdb266d54b4551f42776bb790e80147a279d0Neil Fuller                        TextUtils.ELLIPSIS_TWO_DOTS : TextUtils.ELLIPSIS_NORMAL, 0, 1);
8178059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        int ellipsisStart = 0;
8188059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        int ellipsisCount = 0;
819121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        int len = lineEnd - lineStart;
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8218059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        // We only support start ellipsis on a single line
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where == TextUtils.TruncateAt.START) {
8238059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            if (mMaximumVisibleLineCount == 1) {
8248059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float sum = 0;
8258059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                int i;
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
827ed2eea1bfc1fb57d3b34f2c1e6062b541737e73eKeisuke Kuroyanagi                for (i = len; i > 0; i--) {
8288059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    float w = widths[i - 1 + lineStart - widthStart];
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8308059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    if (w + sum + ellipsisWidth > avail) {
8318059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        break;
8328059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
8338059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio
8348059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    sum += w;
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8378059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisStart = 0;
8388059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisCount = i;
8398059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            } else {
8408059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                if (Log.isLoggable(TAG, Log.WARN)) {
8418059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    Log.w(TAG, "Start Ellipsis only supported with one line");
8428059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                }
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
844cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio        } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE ||
845cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio                where == TextUtils.TruncateAt.END_SMALL) {
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float sum = 0;
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < len; i++) {
850121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                float w = widths[i + lineStart - widthStart];
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
852121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (w + sum + ellipsisWidth > avail) {
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sum += w;
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisStart = i;
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisCount = len - i;
861aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            if (forceEllipsis && ellipsisCount == 0 && len > 0) {
862aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                ellipsisStart = len - 1;
8638059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisCount = 1;
8648059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            }
8658059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        } else {
8668059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            // where = TextUtils.TruncateAt.MIDDLE We only support middle ellipsis on a single line
8678059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            if (mMaximumVisibleLineCount == 1) {
8688059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float lsum = 0, rsum = 0;
8698059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                int left = 0, right = len;
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8718059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float ravail = (avail - ellipsisWidth) / 2;
8720e3c5e827235911d33312e431975533f046421e7Raph Levien                for (right = len; right > 0; right--) {
8738059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    float w = widths[right - 1 + lineStart - widthStart];
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8758059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    if (w + rsum > ravail) {
8768059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        break;
8778059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
8788059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio
8798059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    rsum += w;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8828059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float lavail = avail - ellipsisWidth - rsum;
8838059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                for (left = 0; left < right; left++) {
8848059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    float w = widths[left + lineStart - widthStart];
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8868059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    if (w + lsum > lavail) {
8878059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        break;
8888059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8908059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    lsum += w;
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8938059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisStart = left;
8948059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisCount = right - left;
8958059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            } else {
8968059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                if (Log.isLoggable(TAG, Log.WARN)) {
8978059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    Log.w(TAG, "Middle Ellipsis only supported with one line");
8988059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart;
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
906e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    // Override the base class so we can directly access our members,
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // rather than relying on member functions.
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The logic mirrors that of Layout.getLineForVertical
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // FIXME: It may be faster to do a linear search for layouts without many lines.
9106611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineForVertical(int vertical) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int high = mLineCount;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int low = -1;
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int guess;
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] lines = mLines;
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (high - low > 1) {
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            guess = (high + low) >> 1;
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lines[mColumns * guess + TOP] > vertical){
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                high = guess;
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = guess;
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (low < 0) {
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return low;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9316611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineCount() {
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLineCount;
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9366611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineTop(int line) {
9380a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        int top = mLines[mColumns * line + TOP];
9390a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount &&
9400a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                line != mLineCount) {
9410a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne            top += getBottomPadding();
9420a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
9430a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        return top;
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9466611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineDescent(int line) {
9480a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        int descent = mLines[mColumns * line + DESCENT];
949f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended
9500a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                line != mLineCount) {
9510a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne            descent += getBottomPadding();
9520a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
9530a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        return descent;
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9566611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineStart(int line) {
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + START] & START_MASK;
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9616611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getParagraphDirection(int line) {
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + DIR] >> DIR_SHIFT;
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9666611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getLineContainsTab(int line) {
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mLines[mColumns * line + TAB] & TAB_MASK) != 0;
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9716611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Directions getLineDirections(int line) {
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLineDirections[line];
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9766611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getTopPadding() {
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTopPadding;
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9816611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getBottomPadding() {
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBottomPadding;
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
98626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    /**
98726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien     * @hide
98826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien     */
98926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    @Override
99026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    public int getHyphen(int line) {
99126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        return mLines[mColumns * line + HYPHEN] & 0xff;
99226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    }
99326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsisCount(int line) {
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mColumns < COLUMNS_ELLIPSIZE) {
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + ELLIPSIS_COUNT];
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsisStart(int line) {
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mColumns < COLUMNS_ELLIPSIZE) {
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + ELLIPSIS_START];
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsizedWidth() {
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEllipsizedWidth;
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
101770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native long nNewBuilder();
101870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nFreeBuilder(long nativePtr);
101970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nFinishBuilder(long nativePtr);
102026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien
102126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    /* package */ static native long nLoadHyphenator(String patternData);
102226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien
102326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
102470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
1025e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien    private static native void nSetIndents(long nativePtr, int[] indents);
1026e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien
1027c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien    // Set up paragraph text and settings; done as one big method to minimize jni crossings
1028c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien    private static native void nSetupParagraph(long nativePtr, char[] text, int length,
1029c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            float firstWidth, int firstWidthLineCount, float restWidth,
1030c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            int[] variableTabStops, int defaultTabStop, int breakStrategy);
103170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
103270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native float nAddStyleRun(long nativePtr, long nativePaint,
103370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            long nativeTypeface, int start, int end, boolean isRtl);
103470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
103570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nAddMeasuredRun(long nativePtr,
103670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            int start, int end, float[] widths);
103770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
103870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nAddReplacementRun(long nativePtr, int start, int end, float width);
103970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
104070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nGetWidths(long nativePtr, float[] widths);
104170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
1042c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // populates LineBreaks and returns the number of breaks found
1043c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    //
1044c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // the arrays inside the LineBreaks objects are passed in as well
1045c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // to reduce the number of JNI calls in the common case where the
1046c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // arrays do not have to be resized
1047c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien    private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
104826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien            int[] recycleBreaks, float[] recycleWidths, int[] recycleFlags, int recycleLength);
104988b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mLineCount;
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTopPadding, mBottomPadding;
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mColumns;
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mEllipsizedWidth;
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
105526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int COLUMNS_NORMAL = 4;
105626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int COLUMNS_ELLIPSIZE = 6;
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START = 0;
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DIR = START;
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB = START;
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TOP = 1;
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DESCENT = 2;
106226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int HYPHEN = 3;
106326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int ELLIPSIS_START = 4;
106426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int ELLIPSIS_COUNT = 5;
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mLines;
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Directions[] mLineDirections;
10688059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio    private int mMaximumVisibleLineCount = Integer.MAX_VALUE;
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START_MASK = 0x1FFFFFFF;
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DIR_SHIFT  = 30;
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB_MASK   = 0x20000000;
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1074c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt    private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1076121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_NEW_LINE = '\n';
1077121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
1078121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final double EXTRA_ROUNDING = 0.5;
1079cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio
1080c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // This is used to return three arrays from a single JNI call when
1081c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // performing line breaking
10827053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta    /*package*/ static class LineBreaks {
1083c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        private static final int INITIAL_SIZE = 16;
1084c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        public int[] breaks = new int[INITIAL_SIZE];
1085c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        public float[] widths = new float[INITIAL_SIZE];
108626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji
1087c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // breaks, widths, and flags should all have the same length
1088c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    }
1089c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1091