StaticLayout.java revision 2ea5290ffb9efe0a7c187fb1177ef8ecd089803c
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
19531c30c62b14881aab31a5133920a971b1fbb50eRaph Levienimport android.annotation.Nullable;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Paint;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.LeadingMarginSpan;
226611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunneimport android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.LineHeightSpan;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.style.MetricAffectingSpan;
25c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Feltimport android.text.style.TabStopSpan;
268059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglioimport android.util.Log;
2739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levienimport android.util.Pools.SynchronizedPool;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29cb379120456d8065d742021fc5c66748fc8a11a8Doug Feltimport com.android.internal.util.ArrayUtils;
30776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport com.android.internal.util.GrowingArrayUtils;
31cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
32c8f9e6218681640d5f384c12edf06619be56a583Anish Athalyeimport java.util.Arrays;
334c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levienimport java.util.Locale;
34c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * StaticLayout is a Layout for text that will not be edited after it
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is laid out.  Use {@link DynamicLayout} for text that may change.
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>This is used by widgets to control text layout. You should not need
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to use this class directly unless you are implementing your own widget
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or custom display object, or would be tempted to call
414e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int,
424e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * float, float, android.graphics.Paint)
434e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * Canvas.drawText()} directly.</p>
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
45121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Megliopublic class StaticLayout extends Layout {
46121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
478059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio    static final String TAG = "StaticLayout";
488059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio
49d3ab692d28018825578ff05832644cfad60233fbRaph Levien    /**
50531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * Builder for static layouts. The builder is a newer pattern for constructing
51531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * StaticLayout objects and should be preferred over the constructors,
52531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * particularly to access newer features. To build a static layout, first
53531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * call {@link #obtain} with the required arguments (text, paint, and width),
54531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * then call setters for optional parameters, and finally {@link #build}
55531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * to build the StaticLayout object. Parameters not explicitly set will get
56531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien     * default values.
57d3ab692d28018825578ff05832644cfad60233fbRaph Levien     */
58d3ab692d28018825578ff05832644cfad60233fbRaph Levien    public final static class Builder {
594c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        private Builder() {
604c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            mNativePtr = nNewBuilder();
614c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        }
624c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
63531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
64531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Obtain a builder for constructing StaticLayout objects
65531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
66531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param source The text to be laid out, optionally with spans
67531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param start The index of the start of the text
68531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param end The index + 1 of the end of the text
69531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param paint The base paint used for layout
70531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param width The width in pixels
71531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return a builder object used for constructing the StaticLayout
72531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
73ebd66ca600dc2c43edb0830bcf1a92fafec30a5aRaph Levien        public static Builder obtain(CharSequence source, int start, int end, TextPaint paint,
74ebd66ca600dc2c43edb0830bcf1a92fafec30a5aRaph Levien                int width) {
7539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            Builder b = sPool.acquire();
76d3ab692d28018825578ff05832644cfad60233fbRaph Levien            if (b == null) {
77d3ab692d28018825578ff05832644cfad60233fbRaph Levien                b = new Builder();
78d3ab692d28018825578ff05832644cfad60233fbRaph Levien            }
79d3ab692d28018825578ff05832644cfad60233fbRaph Levien
80d3ab692d28018825578ff05832644cfad60233fbRaph Levien            // set default initial values
8139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mText = source;
8239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mStart = start;
8339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mEnd = end;
84ebd66ca600dc2c43edb0830bcf1a92fafec30a5aRaph Levien            b.mPaint = paint;
8539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mWidth = width;
8639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mAlignment = Alignment.ALIGN_NORMAL;
87d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
88d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mSpacingMult = 1.0f;
89d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mSpacingAdd = 0.0f;
90d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mIncludePad = true;
9139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            b.mEllipsizedWidth = width;
92d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mEllipsize = null;
93d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mMaxLines = Integer.MAX_VALUE;
943bd60c7b1125ee42cd7e8746aeaebdb43e8211d8Raph Levien            b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
9595c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader            b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
96d3ab692d28018825578ff05832644cfad60233fbRaph Levien
97d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mMeasuredText = MeasuredText.obtain();
98d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return b;
99d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
100d3ab692d28018825578ff05832644cfad60233fbRaph Levien
10139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        private static void recycle(Builder b) {
102d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mPaint = null;
103d3ab692d28018825578ff05832644cfad60233fbRaph Levien            b.mText = null;
104d3ab692d28018825578ff05832644cfad60233fbRaph Levien            MeasuredText.recycle(b.mMeasuredText);
1053bd60c7b1125ee42cd7e8746aeaebdb43e8211d8Raph Levien            b.mMeasuredText = null;
1062ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            b.mLeftIndents = null;
1072ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            b.mRightIndents = null;
1083bd60c7b1125ee42cd7e8746aeaebdb43e8211d8Raph Levien            nFinishBuilder(b.mNativePtr);
10939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            sPool.release(b);
110d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
111d3ab692d28018825578ff05832644cfad60233fbRaph Levien
112d3ab692d28018825578ff05832644cfad60233fbRaph Levien        // release any expensive state
113d3ab692d28018825578ff05832644cfad60233fbRaph Levien        /* package */ void finish() {
1144c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            nFinishBuilder(mNativePtr);
115d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mMeasuredText.finish();
116d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
117d3ab692d28018825578ff05832644cfad60233fbRaph Levien
118d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setText(CharSequence source) {
119d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return setText(source, 0, source.length());
120d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
121d3ab692d28018825578ff05832644cfad60233fbRaph Levien
122531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
123531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set the text. Only useful when re-using the builder, which is done for
124531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * the internal implementation of {@link DynamicLayout} but not as part
125531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * of normal {@link StaticLayout} usage.
126531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
127531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param source The text to be laid out, optionally with spans
128531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param start The index of the start of the text
129531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param end The index + 1 of the end of the text
130531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
131531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
132531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @hide
133531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
134d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setText(CharSequence source, int start, int end) {
135d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mText = source;
136d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mStart = start;
137d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mEnd = end;
138d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
139d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
140d3ab692d28018825578ff05832644cfad60233fbRaph Levien
141531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
142531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set the paint. Internal for reuse cases only.
143531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
144531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param paint The base paint used for layout
145531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
146531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
147531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @hide
148531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
149d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setPaint(TextPaint paint) {
150d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mPaint = paint;
151d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
152d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
153d3ab692d28018825578ff05832644cfad60233fbRaph Levien
154531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
155531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set the width. Internal for reuse cases only.
156531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
157531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param width The width in pixels
158531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
159531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
160531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @hide
161531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
162d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setWidth(int width) {
163d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mWidth = width;
164d3ab692d28018825578ff05832644cfad60233fbRaph Levien            if (mEllipsize == null) {
165d3ab692d28018825578ff05832644cfad60233fbRaph Levien                mEllipsizedWidth = width;
166d3ab692d28018825578ff05832644cfad60233fbRaph Levien            }
167d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
168d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
169d3ab692d28018825578ff05832644cfad60233fbRaph Levien
170531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
171531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set the alignment. The default is {@link Layout.Alignment#ALIGN_NORMAL}.
172531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
173531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param alignment Alignment for the resulting {@link StaticLayout}
174531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
175531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
17639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        public Builder setAlignment(Alignment alignment) {
17739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mAlignment = alignment;
17839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            return this;
17939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        }
18039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
181531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
182531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set the text direction heuristic. The text direction heuristic is used to
183531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * resolve text direction based per-paragraph based on the input text. The default is
184531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}.
185531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
186531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param textDir text direction heuristic for resolving BiDi behavior.
187531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
188531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
189a6a082862b9e2ea4c9e9a1a945927c4040993f6eRaph Levien        public Builder setTextDirection(TextDirectionHeuristic textDir) {
190d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mTextDir = textDir;
191d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
192d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
193d3ab692d28018825578ff05832644cfad60233fbRaph Levien
194531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
195531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set line spacing parameters. The default is 0.0 for {@code spacingAdd}
196531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * and 1.0 for {@code spacingMult}.
197531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
198531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param spacingAdd line spacing add
199531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param spacingMult line spacing multiplier
200531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
201531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @see android.widget.TextView#setLineSpacing
202531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
203531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        public Builder setLineSpacing(float spacingAdd, float spacingMult) {
204d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mSpacingAdd = spacingAdd;
205531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien            mSpacingMult = spacingMult;
206d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
207d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
208d3ab692d28018825578ff05832644cfad60233fbRaph Levien
209531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
210531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set whether to include extra space beyond font ascent and descent (which is
211531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * needed to avoid clipping in some languages, such as Arabic and Kannada). The
212531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * default is {@code true}.
213531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
214531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param includePad whether to include padding
215531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
216531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @see android.widget.TextView#setIncludeFontPadding
217531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
218d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setIncludePad(boolean includePad) {
219d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mIncludePad = includePad;
220d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
221d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
222d3ab692d28018825578ff05832644cfad60233fbRaph Levien
223531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
224531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set the width as used for ellipsizing purposes, if it differs from the
225531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * normal layout width. The default is the {@code width}
226531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * passed to {@link #obtain}.
227531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
228531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param ellipsizedWidth width used for ellipsizing, in pixels
229531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
230531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @see android.widget.TextView#setEllipsize
231531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
232d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setEllipsizedWidth(int ellipsizedWidth) {
233d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mEllipsizedWidth = ellipsizedWidth;
234d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
235d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
236d3ab692d28018825578ff05832644cfad60233fbRaph Levien
237531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
238531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set ellipsizing on the layout. Causes words that are longer than the view
239531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * is wide, or exceeding the number of lines (see #setMaxLines) in the case
240531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * of {@link android.text.TextUtils.TruncateAt#END} or
241531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * {@link android.text.TextUtils.TruncateAt#MARQUEE}, to be ellipsized instead
242531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * of broken. The default is
243531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * {@code null}, indicating no ellipsis is to be applied.
244531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
245531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param ellipsize type of ellipsis behavior
246531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
247531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @see android.widget.TextView#setEllipsize
248531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
249531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        public Builder setEllipsize(@Nullable TextUtils.TruncateAt ellipsize) {
250d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mEllipsize = ellipsize;
251d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
252d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
253d3ab692d28018825578ff05832644cfad60233fbRaph Levien
254531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
255531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set maximum number of lines. This is particularly useful in the case of
256531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * ellipsizing, where it changes the layout of the last line. The default is
257531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * unlimited.
258531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
259531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param maxLines maximum number of lines in the layout
260531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
261531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @see android.widget.TextView#setMaxLines
262531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
263d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public Builder setMaxLines(int maxLines) {
264d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mMaxLines = maxLines;
265d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return this;
266d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
267d3ab692d28018825578ff05832644cfad60233fbRaph Levien
268531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
269531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set break strategy, useful for selecting high quality or balanced paragraph
270531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * layout options. The default is {@link Layout#BREAK_STRATEGY_SIMPLE}.
271531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
272531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param breakStrategy break strategy for paragraph layout
273531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
274531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @see android.widget.TextView#setBreakStrategy
275531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
27639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
27739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mBreakStrategy = breakStrategy;
27839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            return this;
27939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        }
28039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
281531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
28295c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * Set hyphenation frequency, to control the amount of automatic hyphenation used. The
28395c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * default is {@link Layout#HYPHENATION_FREQUENCY_NONE}.
28495c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         *
28595c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * @param hyphenationFrequency hyphenation frequency for the paragraph
28695c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * @return this builder, useful for chaining
28795c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * @see android.widget.TextView#setHyphenationFrequency
28895c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         */
28995c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader        public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) {
29095c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader            mHyphenationFrequency = hyphenationFrequency;
29195c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader            return this;
29295c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader        }
29395c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader
29495c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader        /**
295531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Set indents. Arguments are arrays holding an indent amount, one per line, measured in
296531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * pixels. For lines past the last element in the array, the last element repeats.
297531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
298531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param leftIndents array of indent values for left margin, in pixels
299531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @param rightIndents array of indent values for right margin, in pixels
300531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return this builder, useful for chaining
301531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
302e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien        public Builder setIndents(int[] leftIndents, int[] rightIndents) {
3032ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            mLeftIndents = leftIndents;
3042ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            mRightIndents = rightIndents;
305e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            int leftLen = leftIndents == null ? 0 : leftIndents.length;
306e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            int rightLen = rightIndents == null ? 0 : rightIndents.length;
307e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            int[] indents = new int[Math.max(leftLen, rightLen)];
308e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            for (int i = 0; i < indents.length; i++) {
309e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien                int leftMargin = i < leftLen ? leftIndents[i] : 0;
310e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien                int rightMargin = i < rightLen ? rightIndents[i] : 0;
311e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien                indents[i] = leftMargin + rightMargin;
312e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            }
313e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            nSetIndents(mNativePtr, indents);
314e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien            return this;
315e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien        }
316e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien
31770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /**
31870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * Measurement and break iteration is done in native code. The protocol for using
31970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * the native code is as follows.
32070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *
32126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien         * For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
32295c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * stops, break strategy, and hyphenation frequency (and possibly other parameters in the
32395c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader         * future).
324c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien         *
325c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien         * Then, for each run within the paragraph:
32670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *  - setLocale (this must be done at least for the first run, optional afterwards)
32770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *  - one of the following, depending on the type of run:
32870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *    + addStyleRun (a text run, to be measured in native code)
32970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *    + addMeasuredRun (a run already measured in Java, passed into native code)
33070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *    + addReplacementRun (a replacement run, width is given)
33170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *
33270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis).
33370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * Run nComputeLineBreaks() to obtain line breaks for the paragraph.
33470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         *
33570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         * After all paragraphs, call finish() to release expensive buffers.
33670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien         */
33770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
33870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        private void setLocale(Locale locale) {
3394c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            if (!locale.equals(mLocale)) {
34026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien                nSetLocale(mNativePtr, locale.toLanguageTag(), Hyphenator.get(locale));
3414c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien                mLocale = locale;
3424c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            }
3434c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        }
3444c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
34570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) {
34670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            return nAddStyleRun(mNativePtr, paint.getNativeInstance(), paint.mNativeTypeface,
34770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    start, end, isRtl);
34870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
34970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
35070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /* package */ void addMeasuredRun(int start, int end, float[] widths) {
35170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            nAddMeasuredRun(mNativePtr, start, end, widths);
35270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
35370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
35470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        /* package */ void addReplacementRun(int start, int end, float width) {
35570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            nAddReplacementRun(mNativePtr, start, end, width);
35670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
35770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
358531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien        /**
359531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * Build the {@link StaticLayout} after options have been set.
360531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
361531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * <p>Note: the builder object must not be reused in any way after calling this
362531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * method. Setting parameters after calling this method, or calling it a second
363531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * time on the same builder object, will likely lead to unexpected results.
364531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         *
365531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         * @return the newly constructed {@link StaticLayout} object
366531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien         */
367d3ab692d28018825578ff05832644cfad60233fbRaph Levien        public StaticLayout build() {
36839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            StaticLayout result = new StaticLayout(this);
36939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            Builder.recycle(this);
370d3ab692d28018825578ff05832644cfad60233fbRaph Levien            return result;
371d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
372d3ab692d28018825578ff05832644cfad60233fbRaph Levien
3734c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        @Override
3744c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        protected void finalize() throws Throwable {
3754c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            try {
3764c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien                nFreeBuilder(mNativePtr);
3774c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            } finally {
3784c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien                super.finalize();
3794c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien            }
3804c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        }
3814c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
3824c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        /* package */ long mNativePtr;
3834c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
384d3ab692d28018825578ff05832644cfad60233fbRaph Levien        CharSequence mText;
385d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mStart;
386d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mEnd;
387d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextPaint mPaint;
388d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mWidth;
38939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        Alignment mAlignment;
390d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextDirectionHeuristic mTextDir;
391d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float mSpacingMult;
392d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float mSpacingAdd;
393d3ab692d28018825578ff05832644cfad60233fbRaph Levien        boolean mIncludePad;
394d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mEllipsizedWidth;
395d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextUtils.TruncateAt mEllipsize;
396d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int mMaxLines;
39739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        int mBreakStrategy;
39895c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader        int mHyphenationFrequency;
3992ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        int[] mLeftIndents;
4002ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        int[] mRightIndents;
401d3ab692d28018825578ff05832644cfad60233fbRaph Levien
402d3ab692d28018825578ff05832644cfad60233fbRaph Levien        Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
403d3ab692d28018825578ff05832644cfad60233fbRaph Levien
404d3ab692d28018825578ff05832644cfad60233fbRaph Levien        // This will go away and be subsumed by native builder code
405d3ab692d28018825578ff05832644cfad60233fbRaph Levien        MeasuredText mMeasuredText;
406d3ab692d28018825578ff05832644cfad60233fbRaph Levien
4074c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        Locale mLocale;
4084c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien
40939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
410d3ab692d28018825578ff05832644cfad60233fbRaph Levien    }
411d3ab692d28018825578ff05832644cfad60233fbRaph Levien
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, TextPaint paint,
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int width,
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align, float spacingmult, float spacingadd,
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(source, 0, source.length(), paint, width, align,
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             spacingmult, spacingadd, includepad);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
420cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
421cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * @hide
422cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
423cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public StaticLayout(CharSequence source, TextPaint paint,
424cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            int width, Alignment align, TextDirectionHeuristic textDir,
425cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            float spacingmult, float spacingadd,
426cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean includepad) {
427cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        this(source, 0, source.length(), paint, width, align, textDir,
428cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                spacingmult, spacingadd, includepad);
429cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
430cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, int bufstart, int bufend,
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextPaint paint, int outerwidth,
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Alignment align,
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(source, bufstart, bufend, paint, outerwidth, align,
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             spacingmult, spacingadd, includepad, null, 0);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
440cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
441cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * @hide
442cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
443cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public StaticLayout(CharSequence source, int bufstart, int bufend,
444cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            TextPaint paint, int outerwidth,
445cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            Alignment align, TextDirectionHeuristic textDir,
446cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            float spacingmult, float spacingadd,
447cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean includepad) {
448cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        this(source, bufstart, bufend, paint, outerwidth, align, textDir,
4498059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                spacingmult, spacingadd, includepad, null, 0, Integer.MAX_VALUE);
450cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt}
451cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
452cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    public StaticLayout(CharSequence source, int bufstart, int bufend,
453cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            TextPaint paint, int outerwidth,
454cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            Alignment align,
455cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            float spacingmult, float spacingadd,
456cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            boolean includepad,
457cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
458cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        this(source, bufstart, bufend, paint, outerwidth, align,
459cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                TextDirectionHeuristics.FIRSTSTRONG_LTR,
4608059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE);
461cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    }
462cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
463cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    /**
464cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     * @hide
465cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt     */
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StaticLayout(CharSequence source, int bufstart, int bufend,
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        TextPaint paint, int outerwidth,
468cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                        Alignment align, TextDirectionHeuristic textDir,
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        float spacingmult, float spacingadd,
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        boolean includepad,
4718059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) {
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super((ellipsize == null)
4734e0c5e55e171532760d5f51e0165563827129d4eDoug Felt                ? source
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                : (source instanceof Spanned)
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? new SpannedEllipsizer(source)
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : new Ellipsizer(source),
477cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt              paint, outerwidth, align, textDir, spacingmult, spacingadd);
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479ebd66ca600dc2c43edb0830bcf1a92fafec30a5aRaph Levien        Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth)
48039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            .setAlignment(align)
481a6a082862b9e2ea4c9e9a1a945927c4040993f6eRaph Levien            .setTextDirection(textDir)
482531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien            .setLineSpacing(spacingadd, spacingmult)
483d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setIncludePad(includepad)
484d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setEllipsizedWidth(ellipsizedWidth)
485d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setEllipsize(ellipsize)
486d3ab692d28018825578ff05832644cfad60233fbRaph Levien            .setMaxLines(maxLines);
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This is annoying, but we can't refer to the layout until
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * superclass construction is finished, and the superclass
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * constructor wants the reference to the display text.
4914e0c5e55e171532760d5f51e0165563827129d4eDoug Felt         *
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This will break if the superclass constructor ever actually
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * cares about the content instead of just holding the reference.
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ellipsize != null) {
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Ellipsizer e = (Ellipsizer) getText();
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mLayout = this;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mWidth = ellipsizedWidth;
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.mMethod = ellipsize;
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEllipsizedWidth = ellipsizedWidth;
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mColumns = COLUMNS_ELLIPSIZE;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mColumns = COLUMNS_NORMAL;
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEllipsizedWidth = outerwidth;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
510776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLines = new int[mLineDirections.length];
5118059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        mMaximumVisibleLineCount = maxLines;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
51370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        generate(b, b.mIncludePad, b.mIncludePad);
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
515d3ab692d28018825578ff05832644cfad60233fbRaph Levien        Builder.recycle(b);
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5188059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio    /* package */ StaticLayout(CharSequence text) {
5198059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        super(text, null, 0, null, 0, 0);
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mColumns = COLUMNS_ELLIPSIZE;
522776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
523776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mLines = new int[mLineDirections.length];
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien    private StaticLayout(Builder b) {
52739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        super((b.mEllipsize == null)
52839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                ? b.mText
52939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                : (b.mText instanceof Spanned)
53039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                    ? new SpannedEllipsizer(b.mText)
53139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                    : new Ellipsizer(b.mText),
53239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien                b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
53339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
53439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        if (b.mEllipsize != null) {
53539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            Ellipsizer e = (Ellipsizer) getText();
53639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
53739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            e.mLayout = this;
53839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            e.mWidth = b.mEllipsizedWidth;
53939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            e.mMethod = b.mEllipsize;
54039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mEllipsizedWidth = b.mEllipsizedWidth;
54139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
54239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mColumns = COLUMNS_ELLIPSIZE;
54339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        } else {
54439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mColumns = COLUMNS_NORMAL;
54539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien            mEllipsizedWidth = b.mWidth;
54639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        }
54739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
54839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
54939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        mLines = new int[mLineDirections.length];
55039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        mMaximumVisibleLineCount = b.mMaxLines;
55139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
5522ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        mLeftIndents = b.mLeftIndents;
5532ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        mRightIndents = b.mRightIndents;
5542ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien
55539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien        generate(b, b.mIncludePad, b.mIncludePad);
55639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien    }
55739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien
558d3ab692d28018825578ff05832644cfad60233fbRaph Levien    /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
559d3ab692d28018825578ff05832644cfad60233fbRaph Levien        CharSequence source = b.mText;
560d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int bufStart = b.mStart;
561d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int bufEnd = b.mEnd;
562d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextPaint paint = b.mPaint;
563d3ab692d28018825578ff05832644cfad60233fbRaph Levien        int outerWidth = b.mWidth;
564d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextDirectionHeuristic textDir = b.mTextDir;
565d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float spacingmult = b.mSpacingMult;
566d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float spacingadd = b.mSpacingAdd;
567d3ab692d28018825578ff05832644cfad60233fbRaph Levien        float ellipsizedWidth = b.mEllipsizedWidth;
568d3ab692d28018825578ff05832644cfad60233fbRaph Levien        TextUtils.TruncateAt ellipsize = b.mEllipsize;
5694c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        LineBreaks lineBreaks = new LineBreaks();  // TODO: move to builder to avoid allocation costs
570c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // store span end locations
571c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        int[] spanEndCache = new int[4];
572c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // store fontMetrics per span range
573c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
574c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        int[] fmCache = new int[4 * 4];
5754c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien        b.setLocale(paint.getTextLocale());  // TODO: also respect LocaleSpan within the text
57688b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineCount = 0;
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int v = 0;
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean needMultiply = (spacingmult != 1 || spacingadd != 0);
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
582d3ab692d28018825578ff05832644cfad60233fbRaph Levien        Paint.FontMetricsInt fm = b.mFontMetricsInt;
583121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        int[] chooseHtv = null;
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
585d3ab692d28018825578ff05832644cfad60233fbRaph Levien        MeasuredText measured = b.mMeasuredText;
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Spanned spanned = null;
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (source instanceof Spanned)
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            spanned = (Spanned) source;
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
591e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int paraEnd;
592121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
593121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd);
594e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (paraEnd < 0)
595121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                paraEnd = bufEnd;
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            else
597e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                paraEnd++;
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int firstWidthLineCount = 1;
600121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int firstWidth = outerWidth;
601121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            int restWidth = outerWidth;
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
603121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            LineHeightSpan[] chooseHt = null;
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanned != null) {
60674d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer                LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd,
607e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        LeadingMarginSpan.class);
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int i = 0; i < sp.length; i++) {
6097b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    LeadingMarginSpan lms = sp[i];
610121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    firstWidth -= sp[i].getLeadingMargin(true);
611121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    restWidth -= sp[i].getLeadingMargin(false);
612cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt
613c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    // LeadingMarginSpan2 is odd.  The count affects all
614ab08c6d38ab2e575f809ca8ce4c7f095e49d258cAnish Athalye                    // leading margin spans, not just this particular one
615c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                    if (lms instanceof LeadingMarginSpan2) {
616c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt                        LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
617c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        firstWidthLineCount = Math.max(firstWidthLineCount,
618c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                                lms2.getLeadingMarginLineCount());
6197b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner                    }
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
622121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class);
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
624121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (chooseHt.length != 0) {
625121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    if (chooseHtv == null ||
626121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHtv.length < chooseHt.length) {
627776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski                        chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
630121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    for (int i = 0; i < chooseHt.length; i++) {
631121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        int o = spanned.getSpanStart(chooseHt[i]);
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
633e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        if (o < paraStart) {
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // starts in this layout, before the
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // current paragraph
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
637121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            chooseHtv[i] = getLineTop(getLineForOffset(o));
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } else {
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            // starts in this paragraph
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
641121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                            chooseHtv[i] = v;
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            measured.setPara(source, paraStart, paraEnd, textDir, b);
648e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            char[] chs = measured.mChars;
649e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            float[] widths = measured.mWidths;
650e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            byte[] chdirs = measured.mLevels;
651e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            int dir = measured.mDir;
652e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            boolean easy = measured.mEasy;
653c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien
654c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            // tab stop locations
655c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            int[] variableTabStops = null;
656c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            if (spanned != null) {
657c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
658c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                        paraEnd, TabStopSpan.class);
659c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                if (spans.length > 0) {
660c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    int[] stops = new int[spans.length];
661c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    for (int i = 0; i < spans.length; i++) {
662c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                        stops[i] = spans[i].getTabStop();
663c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    }
664c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    Arrays.sort(stops, 0, stops.length);
665c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    variableTabStops = stops;
666c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                }
667c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            }
668c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien
669c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
670c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    firstWidth, firstWidthLineCount, restWidth,
67195c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
6722ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            if (mLeftIndents != null || mRightIndents != null) {
6732ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                // TODO(raph) performance: it would be better to do this once per layout rather
6742ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                // than once per paragraph, but that would require a change to the native
6752ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                // interface.
6762ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
6772ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
6782ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount);
6792ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                int[] indents = new int[indentsLen];
6802ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                for (int i = 0; i < indentsLen; i++) {
6812ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                    int leftMargin = mLeftIndents == null ? 0 :
6822ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                            mLeftIndents[Math.min(i + mLineCount, leftLen - 1)];
6832ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                    int rightMargin = mRightIndents == null ? 0 :
6842ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                            mRightIndents[Math.min(i + mLineCount, rightLen - 1)];
6852ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                    indents[i] = leftMargin + rightMargin;
6862ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                }
6872ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                nSetIndents(b.mNativePtr, indents);
6882ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            }
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
690c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // measurement has to be done before performing line breaking
691c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // but we don't want to recompute fontmetrics or span ranges the
692c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // second time, so we cache those and then use those stored values
693c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int fmCacheCount = 0;
694c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int spanEndCacheCount = 0;
695cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne            for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
696c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fmCacheCount * 4 >= fmCache.length) {
697c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    int[] grow = new int[fmCacheCount * 4 * 2];
698c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
699c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmCache = grow;
700c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
701c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
702c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (spanEndCacheCount >= spanEndCache.length) {
703c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    int[] grow = new int[spanEndCacheCount * 2];
704c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
705c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    spanEndCache = grow;
706c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
70723241887515ed77687c23e29a4a3ffff671666bdDoug Felt
708cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                if (spanned == null) {
709cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    spanEnd = paraEnd;
71023241887515ed77687c23e29a4a3ffff671666bdDoug Felt                    int spanLen = spanEnd - spanStart;
711cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    measured.addStyleRun(paint, spanLen, fm);
712cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                } else {
713cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
714cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                            MetricAffectingSpan.class);
715cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    int spanLen = spanEnd - spanStart;
716cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    MetricAffectingSpan[] spans =
71723241887515ed77687c23e29a4a3ffff671666bdDoug Felt                            spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
718cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class);
719cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    measured.addStyleRun(paint, spans, spanLen, fm);
72023241887515ed77687c23e29a4a3ffff671666bdDoug Felt                }
72123241887515ed77687c23e29a4a3ffff671666bdDoug Felt
722c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // the order of storage here (top, bottom, ascent, descent) has to match the code below
723c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // where these values are retrieved
724c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 0] = fm.top;
725c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 1] = fm.bottom;
726c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 2] = fm.ascent;
727c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCache[fmCacheCount * 4 + 3] = fm.descent;
728c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCacheCount++;
729c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
730c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                spanEndCache[spanEndCacheCount] = spanEnd;
731c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                spanEndCacheCount++;
732c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            }
733c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
73470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            nGetWidths(b.mNativePtr, widths);
735c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
736c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien                    lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
73781541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne
738c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int[] breaks = lineBreaks.breaks;
739c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            float[] lineWidths = lineBreaks.widths;
74026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien            int[] flags = lineBreaks.flags;
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
742f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi            final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
743f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi            final boolean ellipsisMayBeApplied = ellipsize != null
744f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                    && (ellipsize == TextUtils.TruncateAt.END
745f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                        || (mMaximumVisibleLineCount == 1
746f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                                && ellipsize != TextUtils.TruncateAt.MARQUEE));
747f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi            if (remainingLineCount < breakCount && ellipsisMayBeApplied) {
748f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                // Treat the last line and overflowed lines as a single line.
749f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                breaks[remainingLineCount - 1] = breaks[breakCount - 1];
750f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                // Calculate width and flag.
751f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                float width = 0;
752f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                int flag = 0;
753f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                for (int i = remainingLineCount - 1; i < breakCount; i++) {
754f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                    width += lineWidths[i];
755f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                    flag |= flags[i] & TAB_MASK;
756f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                }
757f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                lineWidths[remainingLineCount - 1] = width;
758f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                flags[remainingLineCount - 1] = flag;
759f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi
760f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi                breakCount = remainingLineCount;
761f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi            }
762f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi
763c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            // here is the offset of the starting character of the line we are currently measuring
764c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int here = paraStart;
765d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne
766c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
767c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int fmCacheIndex = 0;
768c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int spanEndCacheIndex = 0;
769c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            int breakIndex = 0;
770c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye            for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
771c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // retrieve end of span
772c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                spanEnd = spanEndCache[spanEndCacheIndex++];
773c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
774c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // retrieve cached metrics, order matches above
775c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.top = fmCache[fmCacheIndex * 4 + 0];
776c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.bottom = fmCache[fmCacheIndex * 4 + 1];
777c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.ascent = fmCache[fmCacheIndex * 4 + 2];
778c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fm.descent = fmCache[fmCacheIndex * 4 + 3];
779c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                fmCacheIndex++;
780c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
781c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.top < fmTop) {
782c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmTop = fm.top;
783c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
784c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.ascent < fmAscent) {
785c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmAscent = fm.ascent;
786c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
787c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.descent > fmDescent) {
788c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmDescent = fm.descent;
789c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
790c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                if (fm.bottom > fmBottom) {
791c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    fmBottom = fm.bottom;
792c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
793cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne
794c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                // skip breaks ending before current span range
795c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
796c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    breakIndex++;
797c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                }
79881541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne
799c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
800c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    int endPos = paraStart + breaks[breakIndex];
801c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
802ce4155a204144ae5462f547f7738af24be5a1f77Raph Levien                    boolean moreChars = (endPos < bufEnd);
8034c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien
804c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    v = out(source, here, endPos,
805c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            fmAscent, fmDescent, fmTop, fmBottom,
806c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex],
807c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
808c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                            chs, widths, paraStart, ellipsize, ellipsizedWidth,
8094c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien                            lineWidths[breakIndex], paint, moreChars);
810c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
811c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    if (endPos < spanEnd) {
812c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        // preserve metrics for current span
813c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmTop = fm.top;
814c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmBottom = fm.bottom;
815c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmAscent = fm.ascent;
816c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmDescent = fm.descent;
817c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    } else {
818c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        fmTop = fmBottom = fmAscent = fmDescent = 0;
8198059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
821c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    here = endPos;
822c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    breakIndex++;
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
824c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    if (mLineCount >= mMaximumVisibleLineCount) {
825c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                        return;
826c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye                    }
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
830121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (paraEnd == bufEnd)
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8348059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) &&
835ad0b051b133baf92f199c96a8ac1e81b3393190cFabrice Di Meglio                mLineCount < mMaximumVisibleLineCount) {
836121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            // Log.e("text", "output last " + bufEnd);
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
83870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            measured.setPara(source, bufEnd, bufEnd, textDir, b);
839e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            paint.getFontMetricsInt(fm);
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = out(source,
843121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    bufEnd, bufEnd, fm.ascent, fm.descent,
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fm.top, fm.bottom,
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    v,
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    spacingmult, spacingadd, null,
84726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien                    null, fm, 0,
848e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio                    needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
849d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                    includepad, trackpad, null,
850d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                    null, bufStart, ellipsize,
851d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                    ellipsizedWidth, 0, paint, false);
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int out(CharSequence text, int start, int end,
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      int above, int below, int top, int bottom, int v,
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                      float spacingmult, float spacingadd,
858121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                      LineHeightSpan[] chooseHt, int[] chooseHtv,
85926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien                      Paint.FontMetricsInt fm, int flags,
860d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      boolean needMultiply, byte[] chdirs, int dir,
861d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      boolean easy, int bufEnd, boolean includePad,
862d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      boolean trackPad, char[] chs,
863d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      float[] widths, int widthStart, TextUtils.TruncateAt ellipsize,
864d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      float ellipsisWidth, float textWidth,
865d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne                      TextPaint paint, boolean moreChars) {
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int j = mLineCount;
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int off = j * mColumns;
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int want = off + mColumns + TOP;
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] lines = mLines;
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (want >= lines.length) {
872776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            Directions[] grow2 = ArrayUtils.newUnpaddedArray(
873776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski                    Directions.class, GrowingArrayUtils.growSize(want));
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mLineDirections, 0, grow2, 0,
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                             mLineDirections.length);
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLineDirections = grow2;
877776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski
878776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            int[] grow = new int[grow2.length];
879776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            System.arraycopy(lines, 0, grow, 0, lines.length);
880776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            mLines = grow;
881776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            lines = grow;
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
884121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        if (chooseHt != null) {
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.ascent = above;
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.descent = below;
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.top = top;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fm.bottom = bottom;
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
890121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            for (int i = 0; i < chooseHt.length; i++) {
891121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (chooseHt[i] instanceof LineHeightSpan.WithDensity) {
892121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    ((LineHeightSpan.WithDensity) chooseHt[i]).
893121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                        chooseHeight(text, start, end, chooseHtv[i], v, fm, paint);
894a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer
895a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer                } else {
896121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                    chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm);
897a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer                }
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            above = fm.ascent;
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            below = fm.descent;
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            top = fm.top;
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bottom = fm.bottom;
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
906d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        boolean firstLine = (j == 0);
907d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
908d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd);
909d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien
910d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        if (firstLine) {
911121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (trackPad) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTopPadding = top - above;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
915121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (includePad) {
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                above = top;
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
919d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien
920d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        int extra;
921d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien
922d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        if (lastLine) {
923121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (trackPad) {
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBottomPadding = bottom - below;
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
927121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio            if (includePad) {
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                below = bottom;
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
933d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien        if (needMultiply && !lastLine) {
9341065758a0f8966a8597a61492112f7859a7050a4Doug Felt            double ex = (below - above) * (spacingmult - 1) + spacingadd;
9351065758a0f8966a8597a61492112f7859a7050a4Doug Felt            if (ex >= 0) {
936121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                extra = (int)(ex + EXTRA_ROUNDING);
9371065758a0f8966a8597a61492112f7859a7050a4Doug Felt            } else {
938121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                extra = -(int)(-ex + EXTRA_ROUNDING);
9391065758a0f8966a8597a61492112f7859a7050a4Doug Felt            }
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            extra = 0;
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + START] = start;
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + TOP] = v;
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + DESCENT] = below + extra;
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        v += (below - above) + extra;
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + mColumns + START] = end;
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lines[off + mColumns + TOP] = v;
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
95226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining
95326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        // one bit for start field
95426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        lines[off + TAB] |= flags & TAB_MASK;
95526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        lines[off + HYPHEN] = flags;
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9579f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        lines[off + DIR] |= dir << DIR_SHIFT;
9589f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT;
9599f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        // easy means all chars < the first RTL, so no emoji, no nothing
9604e0c5e55e171532760d5f51e0165563827129d4eDoug Felt        // XXX a run with no text or all spaces is easy but might be an empty
9619f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        // RTL paragraph.  Make sure easy is false if this is the case.
9629f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        if (easy) {
9639f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt            mLineDirections[j] = linedirs;
9649f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt        } else {
965f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne            mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs,
966f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne                    start - widthStart, end - start);
9670a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
969aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio        if (ellipsize != null) {
970aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            // If there is only one line, then do any type of ellipsis except when it is MARQUEE
971aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            // if there are multiple lines, just allow END ellipsis on the last line
9728059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
973aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio
97434a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio            boolean doEllipsis =
97534a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio                        (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) &&
976aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                                ellipsize != TextUtils.TruncateAt.MARQUEE) ||
977aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                        (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) &&
978aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                                ellipsize == TextUtils.TruncateAt.END);
979aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            if (doEllipsis) {
980aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                calculateEllipsis(start, end, widths, widthStart,
981aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                        ellipsisWidth, ellipsize, j,
982aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                        textWidth, paint, forceEllipsis);
983aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            }
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLineCount++;
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
990121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private void calculateEllipsis(int lineStart, int lineEnd,
991121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                                   float[] widths, int widthStart,
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                   float avail, TextUtils.TruncateAt where,
9938059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                                   int line, float textWidth, TextPaint paint,
9948059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                                   boolean forceEllipsis) {
9958059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        if (textWidth <= avail && !forceEllipsis) {
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Everything fits!
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines[mColumns * line + ELLIPSIS_START] = 0;
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLines[mColumns * line + ELLIPSIS_COUNT] = 0;
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1002cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio        float ellipsisWidth = paint.measureText(
10038d44fff7e62f77c3b3072a96712cc1389e63ca64Fabrice Di Meglio                (where == TextUtils.TruncateAt.END_SMALL) ?
1004d29bdb266d54b4551f42776bb790e80147a279d0Neil Fuller                        TextUtils.ELLIPSIS_TWO_DOTS : TextUtils.ELLIPSIS_NORMAL, 0, 1);
10058059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        int ellipsisStart = 0;
10068059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        int ellipsisCount = 0;
1007121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio        int len = lineEnd - lineStart;
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10098059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        // We only support start ellipsis on a single line
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (where == TextUtils.TruncateAt.START) {
10118059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            if (mMaximumVisibleLineCount == 1) {
10128059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float sum = 0;
10138059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                int i;
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1015ed2eea1bfc1fb57d3b34f2c1e6062b541737e73eKeisuke Kuroyanagi                for (i = len; i > 0; i--) {
10168059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    float w = widths[i - 1 + lineStart - widthStart];
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10188059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    if (w + sum + ellipsisWidth > avail) {
10198059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        break;
10208059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
10218059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio
10228059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    sum += w;
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10258059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisStart = 0;
10268059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisCount = i;
10278059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            } else {
10288059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                if (Log.isLoggable(TAG, Log.WARN)) {
10298059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    Log.w(TAG, "Start Ellipsis only supported with one line");
10308059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                }
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1032cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio        } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE ||
1033cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio                where == TextUtils.TruncateAt.END_SMALL) {
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float sum = 0;
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < len; i++) {
1038121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                float w = widths[i + lineStart - widthStart];
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1040121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio                if (w + sum + ellipsisWidth > avail) {
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sum += w;
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisStart = i;
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ellipsisCount = len - i;
1049aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio            if (forceEllipsis && ellipsisCount == 0 && len > 0) {
1050aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio                ellipsisStart = len - 1;
10518059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisCount = 1;
10528059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            }
10538059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio        } else {
10548059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            // where = TextUtils.TruncateAt.MIDDLE We only support middle ellipsis on a single line
10558059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            if (mMaximumVisibleLineCount == 1) {
10568059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float lsum = 0, rsum = 0;
10578059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                int left = 0, right = len;
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10598059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float ravail = (avail - ellipsisWidth) / 2;
10600e3c5e827235911d33312e431975533f046421e7Raph Levien                for (right = len; right > 0; right--) {
10618059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    float w = widths[right - 1 + lineStart - widthStart];
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10638059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    if (w + rsum > ravail) {
10648059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        break;
10658059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
10668059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio
10678059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    rsum += w;
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10708059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                float lavail = avail - ellipsisWidth - rsum;
10718059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                for (left = 0; left < right; left++) {
10728059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    float w = widths[left + lineStart - widthStart];
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10748059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    if (w + lsum > lavail) {
10758059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                        break;
10768059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    }
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10788059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    lsum += w;
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10818059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisStart = left;
10828059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                ellipsisCount = right - left;
10838059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio            } else {
10848059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                if (Log.isLoggable(TAG, Log.WARN)) {
10858059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                    Log.w(TAG, "Middle Ellipsis only supported with one line");
10868059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio                }
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart;
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount;
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1094e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    // Override the base class so we can directly access our members,
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // rather than relying on member functions.
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The logic mirrors that of Layout.getLineForVertical
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // FIXME: It may be faster to do a linear search for layouts without many lines.
10986611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineForVertical(int vertical) {
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int high = mLineCount;
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int low = -1;
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int guess;
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] lines = mLines;
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (high - low > 1) {
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            guess = (high + low) >> 1;
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (lines[mColumns * guess + TOP] > vertical){
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                high = guess;
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                low = guess;
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (low < 0) {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return low;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11196611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineCount() {
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLineCount;
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11246611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineTop(int line) {
11260a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        int top = mLines[mColumns * line + TOP];
11270a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount &&
11280a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                line != mLineCount) {
11290a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne            top += getBottomPadding();
11300a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
11310a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        return top;
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11346611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineDescent(int line) {
11360a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        int descent = mLines[mColumns * line + DESCENT];
1137f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne        if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended
11380a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne                line != mLineCount) {
11390a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne            descent += getBottomPadding();
11400a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        }
11410a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne        return descent;
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11446611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getLineStart(int line) {
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + START] & START_MASK;
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11496611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getParagraphDirection(int line) {
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + DIR] >> DIR_SHIFT;
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11546611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getLineContainsTab(int line) {
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mLines[mColumns * line + TAB] & TAB_MASK) != 0;
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11596611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final Directions getLineDirections(int line) {
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLineDirections[line];
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11646611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getTopPadding() {
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTopPadding;
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11696611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne    @Override
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getBottomPadding() {
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBottomPadding;
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
117426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    /**
117526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien     * @hide
117626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien     */
117726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    @Override
117826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    public int getHyphen(int line) {
117926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        return mLines[mColumns * line + HYPHEN] & 0xff;
118026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    }
118126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien
11822ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien    /**
11832ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien     * @hide
11842ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien     */
11852ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien    @Override
11862ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien    public int getIndentAdjust(int line, Alignment align) {
11872ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        if (align == Alignment.ALIGN_LEFT) {
11882ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            if (mLeftIndents == null) {
11892ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                return 0;
11902ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            } else {
11912ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                return mLeftIndents[Math.min(line, mLeftIndents.length - 1)];
11922ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            }
11932ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        } else if (align == Alignment.ALIGN_RIGHT) {
11942ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            if (mRightIndents == null) {
11952ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                return 0;
11962ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            } else {
11972ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                return -mRightIndents[Math.min(line, mRightIndents.length - 1)];
11982ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            }
11992ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        } else if (align == Alignment.ALIGN_CENTER) {
12002ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            int left = 0;
12012ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            if (mLeftIndents != null) {
12022ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                left = mLeftIndents[Math.min(line, mLeftIndents.length - 1)];
12032ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            }
12042ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            int right = 0;
12052ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            if (mRightIndents != null) {
12062ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien                right = mRightIndents[Math.min(line, mRightIndents.length - 1)];
12072ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            }
12082ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            return (left - right) >> 1;
12092ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        } else {
12102ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien            throw new AssertionError("unhandled alignment " + align);
12112ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien        }
12122ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien    }
12132ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsisCount(int line) {
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mColumns < COLUMNS_ELLIPSIZE) {
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + ELLIPSIS_COUNT];
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsisStart(int line) {
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mColumns < COLUMNS_ELLIPSIZE) {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLines[mColumns * line + ELLIPSIS_START];
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getEllipsizedWidth() {
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mEllipsizedWidth;
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
123770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native long nNewBuilder();
123870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nFreeBuilder(long nativePtr);
123970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nFinishBuilder(long nativePtr);
124026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien
124126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    /* package */ static native long nLoadHyphenator(String patternData);
124226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien
124326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator);
124470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
1245e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien    private static native void nSetIndents(long nativePtr, int[] indents);
1246e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien
1247c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien    // Set up paragraph text and settings; done as one big method to minimize jni crossings
1248c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien    private static native void nSetupParagraph(long nativePtr, char[] text, int length,
1249c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien            float firstWidth, int firstWidthLineCount, float restWidth,
125095c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader            int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency);
125170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
125270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native float nAddStyleRun(long nativePtr, long nativePaint,
125370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            long nativeTypeface, int start, int end, boolean isRtl);
125470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
125570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nAddMeasuredRun(long nativePtr,
125670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            int start, int end, float[] widths);
125770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
125870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nAddReplacementRun(long nativePtr, int start, int end, float width);
125970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
126070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private static native void nGetWidths(long nativePtr, float[] widths);
126170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien
1262c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // populates LineBreaks and returns the number of breaks found
1263c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    //
1264c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // the arrays inside the LineBreaks objects are passed in as well
1265c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // to reduce the number of JNI calls in the common case where the
1266c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // arrays do not have to be resized
1267c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien    private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
126826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien            int[] recycleBreaks, float[] recycleWidths, int[] recycleFlags, int recycleLength);
126988b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mLineCount;
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTopPadding, mBottomPadding;
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mColumns;
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mEllipsizedWidth;
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
127526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int COLUMNS_NORMAL = 4;
127626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int COLUMNS_ELLIPSIZE = 6;
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START = 0;
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DIR = START;
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB = START;
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TOP = 1;
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DESCENT = 2;
128226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int HYPHEN = 3;
128326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int ELLIPSIS_START = 4;
128426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien    private static final int ELLIPSIS_COUNT = 5;
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mLines;
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Directions[] mLineDirections;
12888059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio    private int mMaximumVisibleLineCount = Integer.MAX_VALUE;
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START_MASK = 0x1FFFFFFF;
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DIR_SHIFT  = 30;
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAB_MASK   = 0x20000000;
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1294c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt    private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1296121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final char CHAR_NEW_LINE = '\n';
1297121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio
1298121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio    private static final double EXTRA_ROUNDING = 0.5;
1299cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio
1300c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // This is used to return three arrays from a single JNI call when
1301c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    // performing line breaking
13027053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta    /*package*/ static class LineBreaks {
1303c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        private static final int INITIAL_SIZE = 16;
1304c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        public int[] breaks = new int[INITIAL_SIZE];
1305c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        public float[] widths = new float[INITIAL_SIZE];
130626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien        public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji
1307c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye        // breaks, widths, and flags should all have the same length
1308c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye    }
1309c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye
13102ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien    private int[] mLeftIndents;
13112ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien    private int[] mRightIndents;
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1313