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); 11522ba7869f6e211f5a692235f52687a6acdd71afcRaph Levien mText = null; 11622ba7869f6e211f5a692235f52687a6acdd71afcRaph Levien mPaint = null; 11722ba7869f6e211f5a692235f52687a6acdd71afcRaph Levien mLeftIndents = null; 11822ba7869f6e211f5a692235f52687a6acdd71afcRaph Levien mRightIndents = null; 119d3ab692d28018825578ff05832644cfad60233fbRaph Levien mMeasuredText.finish(); 120d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 121d3ab692d28018825578ff05832644cfad60233fbRaph Levien 122d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setText(CharSequence source) { 123d3ab692d28018825578ff05832644cfad60233fbRaph Levien return setText(source, 0, source.length()); 124d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 125d3ab692d28018825578ff05832644cfad60233fbRaph Levien 126531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 127531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set the text. Only useful when re-using the builder, which is done for 128531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * the internal implementation of {@link DynamicLayout} but not as part 129531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * of normal {@link StaticLayout} usage. 130531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 131531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param source The text to be laid out, optionally with spans 132531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param start The index of the start of the text 133531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param end The index + 1 of the end of the text 134531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 135531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 136531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @hide 137531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 138d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setText(CharSequence source, int start, int end) { 139d3ab692d28018825578ff05832644cfad60233fbRaph Levien mText = source; 140d3ab692d28018825578ff05832644cfad60233fbRaph Levien mStart = start; 141d3ab692d28018825578ff05832644cfad60233fbRaph Levien mEnd = end; 142d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 143d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 144d3ab692d28018825578ff05832644cfad60233fbRaph Levien 145531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 146531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set the paint. Internal for reuse cases only. 147531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 148531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param paint The base paint used for layout 149531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 150531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 151531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @hide 152531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 153d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setPaint(TextPaint paint) { 154d3ab692d28018825578ff05832644cfad60233fbRaph Levien mPaint = paint; 155d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 156d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 157d3ab692d28018825578ff05832644cfad60233fbRaph Levien 158531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 159531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set the width. Internal for reuse cases only. 160531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 161531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param width The width in pixels 162531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 163531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 164531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @hide 165531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 166d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setWidth(int width) { 167d3ab692d28018825578ff05832644cfad60233fbRaph Levien mWidth = width; 168d3ab692d28018825578ff05832644cfad60233fbRaph Levien if (mEllipsize == null) { 169d3ab692d28018825578ff05832644cfad60233fbRaph Levien mEllipsizedWidth = width; 170d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 171d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 172d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 173d3ab692d28018825578ff05832644cfad60233fbRaph Levien 174531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 175531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set the alignment. The default is {@link Layout.Alignment#ALIGN_NORMAL}. 176531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 177531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param alignment Alignment for the resulting {@link StaticLayout} 178531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 179531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 18039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien public Builder setAlignment(Alignment alignment) { 18139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mAlignment = alignment; 18239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien return this; 18339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien } 18439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 185531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 186531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set the text direction heuristic. The text direction heuristic is used to 187531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * resolve text direction based per-paragraph based on the input text. The default is 188531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * {@link TextDirectionHeuristics#FIRSTSTRONG_LTR}. 189531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 190531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param textDir text direction heuristic for resolving BiDi behavior. 191531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 192531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 193a6a082862b9e2ea4c9e9a1a945927c4040993f6eRaph Levien public Builder setTextDirection(TextDirectionHeuristic textDir) { 194d3ab692d28018825578ff05832644cfad60233fbRaph Levien mTextDir = textDir; 195d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 196d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 197d3ab692d28018825578ff05832644cfad60233fbRaph Levien 198531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 199531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set line spacing parameters. The default is 0.0 for {@code spacingAdd} 200531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * and 1.0 for {@code spacingMult}. 201531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 202531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param spacingAdd line spacing add 203531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param spacingMult line spacing multiplier 204531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 205531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @see android.widget.TextView#setLineSpacing 206531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 207531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien public Builder setLineSpacing(float spacingAdd, float spacingMult) { 208d3ab692d28018825578ff05832644cfad60233fbRaph Levien mSpacingAdd = spacingAdd; 209531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien mSpacingMult = spacingMult; 210d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 211d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 212d3ab692d28018825578ff05832644cfad60233fbRaph Levien 213531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 214531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set whether to include extra space beyond font ascent and descent (which is 215531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * needed to avoid clipping in some languages, such as Arabic and Kannada). The 216531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * default is {@code true}. 217531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 218531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param includePad whether to include padding 219531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 220531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @see android.widget.TextView#setIncludeFontPadding 221531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 222d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setIncludePad(boolean includePad) { 223d3ab692d28018825578ff05832644cfad60233fbRaph Levien mIncludePad = includePad; 224d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 225d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 226d3ab692d28018825578ff05832644cfad60233fbRaph Levien 227531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 228531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set the width as used for ellipsizing purposes, if it differs from the 229531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * normal layout width. The default is the {@code width} 230531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * passed to {@link #obtain}. 231531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 232531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param ellipsizedWidth width used for ellipsizing, in pixels 233531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 234531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @see android.widget.TextView#setEllipsize 235531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 236d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setEllipsizedWidth(int ellipsizedWidth) { 237d3ab692d28018825578ff05832644cfad60233fbRaph Levien mEllipsizedWidth = ellipsizedWidth; 238d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 239d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 240d3ab692d28018825578ff05832644cfad60233fbRaph Levien 241531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 242531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set ellipsizing on the layout. Causes words that are longer than the view 243531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * is wide, or exceeding the number of lines (see #setMaxLines) in the case 244531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * of {@link android.text.TextUtils.TruncateAt#END} or 245531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * {@link android.text.TextUtils.TruncateAt#MARQUEE}, to be ellipsized instead 246531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * of broken. The default is 247531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * {@code null}, indicating no ellipsis is to be applied. 248531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 249531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param ellipsize type of ellipsis behavior 250531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 251531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @see android.widget.TextView#setEllipsize 252531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 253531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien public Builder setEllipsize(@Nullable TextUtils.TruncateAt ellipsize) { 254d3ab692d28018825578ff05832644cfad60233fbRaph Levien mEllipsize = ellipsize; 255d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 256d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 257d3ab692d28018825578ff05832644cfad60233fbRaph Levien 258531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 259531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set maximum number of lines. This is particularly useful in the case of 260531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * ellipsizing, where it changes the layout of the last line. The default is 261531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * unlimited. 262531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 263531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param maxLines maximum number of lines in the layout 264531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 265531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @see android.widget.TextView#setMaxLines 266531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 267d3ab692d28018825578ff05832644cfad60233fbRaph Levien public Builder setMaxLines(int maxLines) { 268d3ab692d28018825578ff05832644cfad60233fbRaph Levien mMaxLines = maxLines; 269d3ab692d28018825578ff05832644cfad60233fbRaph Levien return this; 270d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 271d3ab692d28018825578ff05832644cfad60233fbRaph Levien 272531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 273531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set break strategy, useful for selecting high quality or balanced paragraph 274531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * layout options. The default is {@link Layout#BREAK_STRATEGY_SIMPLE}. 275531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 276531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param breakStrategy break strategy for paragraph layout 277531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 278531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @see android.widget.TextView#setBreakStrategy 279531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 28039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien public Builder setBreakStrategy(@BreakStrategy int breakStrategy) { 28139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mBreakStrategy = breakStrategy; 28239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien return this; 28339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien } 28439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 285531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 28695c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * Set hyphenation frequency, to control the amount of automatic hyphenation used. The 28795c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * default is {@link Layout#HYPHENATION_FREQUENCY_NONE}. 28895c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * 28995c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * @param hyphenationFrequency hyphenation frequency for the paragraph 29095c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * @return this builder, useful for chaining 29195c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * @see android.widget.TextView#setHyphenationFrequency 29295c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader */ 29395c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) { 29495c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader mHyphenationFrequency = hyphenationFrequency; 29595c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader return this; 29695c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader } 29795c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader 29895c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader /** 299531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Set indents. Arguments are arrays holding an indent amount, one per line, measured in 300531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * pixels. For lines past the last element in the array, the last element repeats. 301531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 302531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param leftIndents array of indent values for left margin, in pixels 303531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @param rightIndents array of indent values for right margin, in pixels 304531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return this builder, useful for chaining 305531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 306e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien public Builder setIndents(int[] leftIndents, int[] rightIndents) { 3072ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien mLeftIndents = leftIndents; 3082ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien mRightIndents = rightIndents; 309e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien int leftLen = leftIndents == null ? 0 : leftIndents.length; 310e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien int rightLen = rightIndents == null ? 0 : rightIndents.length; 311e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien int[] indents = new int[Math.max(leftLen, rightLen)]; 312e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien for (int i = 0; i < indents.length; i++) { 313e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien int leftMargin = i < leftLen ? leftIndents[i] : 0; 314e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien int rightMargin = i < rightLen ? rightIndents[i] : 0; 315e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien indents[i] = leftMargin + rightMargin; 316e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien } 317e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien nSetIndents(mNativePtr, indents); 318e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien return this; 319e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien } 320e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien 32170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien /** 32270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * Measurement and break iteration is done in native code. The protocol for using 32370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * the native code is as follows. 32470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * 32526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien * For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab 32695c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * stops, break strategy, and hyphenation frequency (and possibly other parameters in the 32795c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader * future). 328c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien * 329c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien * Then, for each run within the paragraph: 33070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * - setLocale (this must be done at least for the first run, optional afterwards) 33170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * - one of the following, depending on the type of run: 33270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * + addStyleRun (a text run, to be measured in native code) 33370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * + addMeasuredRun (a run already measured in Java, passed into native code) 33470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * + addReplacementRun (a replacement run, width is given) 33570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * 33670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * After measurement, nGetWidths() is valid if the widths are needed (eg for ellipsis). 33770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * Run nComputeLineBreaks() to obtain line breaks for the paragraph. 33870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * 33970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien * After all paragraphs, call finish() to release expensive buffers. 34070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien */ 34170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 34270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private void setLocale(Locale locale) { 3434c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien if (!locale.equals(mLocale)) { 34426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien nSetLocale(mNativePtr, locale.toLanguageTag(), Hyphenator.get(locale)); 3454c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien mLocale = locale; 3464c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien } 3474c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien } 3484c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien 34970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien /* package */ float addStyleRun(TextPaint paint, int start, int end, boolean isRtl) { 35070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien return nAddStyleRun(mNativePtr, paint.getNativeInstance(), paint.mNativeTypeface, 35170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien start, end, isRtl); 35270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien } 35370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 35470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien /* package */ void addMeasuredRun(int start, int end, float[] widths) { 35570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien nAddMeasuredRun(mNativePtr, start, end, widths); 35670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien } 35770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 35870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien /* package */ void addReplacementRun(int start, int end, float width) { 35970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien nAddReplacementRun(mNativePtr, start, end, width); 36070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien } 36170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 362531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien /** 363531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * Build the {@link StaticLayout} after options have been set. 364531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 365531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * <p>Note: the builder object must not be reused in any way after calling this 366531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * method. Setting parameters after calling this method, or calling it a second 367531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * time on the same builder object, will likely lead to unexpected results. 368531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * 369531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien * @return the newly constructed {@link StaticLayout} object 370531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien */ 371d3ab692d28018825578ff05832644cfad60233fbRaph Levien public StaticLayout build() { 37239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien StaticLayout result = new StaticLayout(this); 37339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien Builder.recycle(this); 374d3ab692d28018825578ff05832644cfad60233fbRaph Levien return result; 375d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 376d3ab692d28018825578ff05832644cfad60233fbRaph Levien 3774c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien @Override 3784c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien protected void finalize() throws Throwable { 3794c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien try { 3804c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien nFreeBuilder(mNativePtr); 3814c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien } finally { 3824c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien super.finalize(); 3834c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien } 3844c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien } 3854c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien 3864c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien /* package */ long mNativePtr; 3874c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien 388d3ab692d28018825578ff05832644cfad60233fbRaph Levien CharSequence mText; 389d3ab692d28018825578ff05832644cfad60233fbRaph Levien int mStart; 390d3ab692d28018825578ff05832644cfad60233fbRaph Levien int mEnd; 391d3ab692d28018825578ff05832644cfad60233fbRaph Levien TextPaint mPaint; 392d3ab692d28018825578ff05832644cfad60233fbRaph Levien int mWidth; 39339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien Alignment mAlignment; 394d3ab692d28018825578ff05832644cfad60233fbRaph Levien TextDirectionHeuristic mTextDir; 395d3ab692d28018825578ff05832644cfad60233fbRaph Levien float mSpacingMult; 396d3ab692d28018825578ff05832644cfad60233fbRaph Levien float mSpacingAdd; 397d3ab692d28018825578ff05832644cfad60233fbRaph Levien boolean mIncludePad; 398d3ab692d28018825578ff05832644cfad60233fbRaph Levien int mEllipsizedWidth; 399d3ab692d28018825578ff05832644cfad60233fbRaph Levien TextUtils.TruncateAt mEllipsize; 400d3ab692d28018825578ff05832644cfad60233fbRaph Levien int mMaxLines; 40139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien int mBreakStrategy; 40295c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader int mHyphenationFrequency; 4032ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int[] mLeftIndents; 4042ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int[] mRightIndents; 405d3ab692d28018825578ff05832644cfad60233fbRaph Levien 406d3ab692d28018825578ff05832644cfad60233fbRaph Levien Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); 407d3ab692d28018825578ff05832644cfad60233fbRaph Levien 408d3ab692d28018825578ff05832644cfad60233fbRaph Levien // This will go away and be subsumed by native builder code 409d3ab692d28018825578ff05832644cfad60233fbRaph Levien MeasuredText mMeasuredText; 410d3ab692d28018825578ff05832644cfad60233fbRaph Levien 4114c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien Locale mLocale; 4124c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien 41339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3); 414d3ab692d28018825578ff05832644cfad60233fbRaph Levien } 415d3ab692d28018825578ff05832644cfad60233fbRaph Levien 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StaticLayout(CharSequence source, TextPaint paint, 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width, 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align, float spacingmult, float spacingadd, 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean includepad) { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(source, 0, source.length(), paint, width, align, 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spacingmult, spacingadd, includepad); 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 424cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt /** 425cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt * @hide 426cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */ 427cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt public StaticLayout(CharSequence source, TextPaint paint, 428cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt int width, Alignment align, TextDirectionHeuristic textDir, 429cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt float spacingmult, float spacingadd, 430cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt boolean includepad) { 431cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt this(source, 0, source.length(), paint, width, align, textDir, 432cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt spacingmult, spacingadd, includepad); 433cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt } 434cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StaticLayout(CharSequence source, int bufstart, int bufend, 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint, int outerwidth, 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align, 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd, 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean includepad) { 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(source, bufstart, bufend, paint, outerwidth, align, 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spacingmult, spacingadd, includepad, null, 0); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 444cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt /** 445cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt * @hide 446cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */ 447cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt public StaticLayout(CharSequence source, int bufstart, int bufend, 448cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextPaint paint, int outerwidth, 449cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt Alignment align, TextDirectionHeuristic textDir, 450cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt float spacingmult, float spacingadd, 451cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt boolean includepad) { 452cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt this(source, bufstart, bufend, paint, outerwidth, align, textDir, 4538059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio spacingmult, spacingadd, includepad, null, 0, Integer.MAX_VALUE); 454cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt} 455cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 456cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt public StaticLayout(CharSequence source, int bufstart, int bufend, 457cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextPaint paint, int outerwidth, 458cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt Alignment align, 459cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt float spacingmult, float spacingadd, 460cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt boolean includepad, 461cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { 462cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt this(source, bufstart, bufend, paint, outerwidth, align, 463cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextDirectionHeuristics.FIRSTSTRONG_LTR, 4648059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE); 465cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt } 466cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 467cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt /** 468cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt * @hide 469cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */ 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StaticLayout(CharSequence source, int bufstart, int bufend, 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint, int outerwidth, 472cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt Alignment align, TextDirectionHeuristic textDir, 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd, 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean includepad, 4758059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) { 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super((ellipsize == null) 4774e0c5e55e171532760d5f51e0165563827129d4eDoug Felt ? source 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : (source instanceof Spanned) 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? new SpannedEllipsizer(source) 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : new Ellipsizer(source), 481cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt paint, outerwidth, align, textDir, spacingmult, spacingadd); 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 483ebd66ca600dc2c43edb0830bcf1a92fafec30a5aRaph Levien Builder b = Builder.obtain(source, bufstart, bufend, paint, outerwidth) 48439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien .setAlignment(align) 485a6a082862b9e2ea4c9e9a1a945927c4040993f6eRaph Levien .setTextDirection(textDir) 486531c30c62b14881aab31a5133920a971b1fbb50eRaph Levien .setLineSpacing(spacingadd, spacingmult) 487d3ab692d28018825578ff05832644cfad60233fbRaph Levien .setIncludePad(includepad) 488d3ab692d28018825578ff05832644cfad60233fbRaph Levien .setEllipsizedWidth(ellipsizedWidth) 489d3ab692d28018825578ff05832644cfad60233fbRaph Levien .setEllipsize(ellipsize) 490d3ab692d28018825578ff05832644cfad60233fbRaph Levien .setMaxLines(maxLines); 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is annoying, but we can't refer to the layout until 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * superclass construction is finished, and the superclass 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * constructor wants the reference to the display text. 4954e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will break if the superclass constructor ever actually 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cares about the content instead of just holding the reference. 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ellipsize != null) { 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Ellipsizer e = (Ellipsizer) getText(); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.mLayout = this; 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.mWidth = ellipsizedWidth; 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.mMethod = ellipsize; 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEllipsizedWidth = ellipsizedWidth; 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mColumns = COLUMNS_ELLIPSIZE; 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mColumns = COLUMNS_NORMAL; 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEllipsizedWidth = outerwidth; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 513776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns); 514776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLines = new int[mLineDirections.length]; 5158059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio mMaximumVisibleLineCount = maxLines; 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 51770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien generate(b, b.mIncludePad, b.mIncludePad); 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519d3ab692d28018825578ff05832644cfad60233fbRaph Levien Builder.recycle(b); 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5228059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio /* package */ StaticLayout(CharSequence text) { 5238059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio super(text, null, 0, null, 0, 0); 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mColumns = COLUMNS_ELLIPSIZE; 526776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns); 527776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLines = new int[mLineDirections.length]; 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 53039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien private StaticLayout(Builder b) { 53139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien super((b.mEllipsize == null) 53239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien ? b.mText 53339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien : (b.mText instanceof Spanned) 53439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien ? new SpannedEllipsizer(b.mText) 53539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien : new Ellipsizer(b.mText), 53639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd); 53739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 53839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien if (b.mEllipsize != null) { 53939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien Ellipsizer e = (Ellipsizer) getText(); 54039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 54139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien e.mLayout = this; 54239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien e.mWidth = b.mEllipsizedWidth; 54339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien e.mMethod = b.mEllipsize; 54439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mEllipsizedWidth = b.mEllipsizedWidth; 54539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 54639b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mColumns = COLUMNS_ELLIPSIZE; 54739b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien } else { 54839b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mColumns = COLUMNS_NORMAL; 54939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mEllipsizedWidth = b.mWidth; 55039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien } 55139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 55239b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns); 55339b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mLines = new int[mLineDirections.length]; 55439b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien mMaximumVisibleLineCount = b.mMaxLines; 55539b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 5562ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien mLeftIndents = b.mLeftIndents; 5572ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien mRightIndents = b.mRightIndents; 5582ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien 55939b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien generate(b, b.mIncludePad, b.mIncludePad); 56039b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien } 56139b4db73c3340ff955f67e4e5318159d19d1ab3aRaph Levien 562d3ab692d28018825578ff05832644cfad60233fbRaph Levien /* package */ void generate(Builder b, boolean includepad, boolean trackpad) { 563d3ab692d28018825578ff05832644cfad60233fbRaph Levien CharSequence source = b.mText; 564d3ab692d28018825578ff05832644cfad60233fbRaph Levien int bufStart = b.mStart; 565d3ab692d28018825578ff05832644cfad60233fbRaph Levien int bufEnd = b.mEnd; 566d3ab692d28018825578ff05832644cfad60233fbRaph Levien TextPaint paint = b.mPaint; 567d3ab692d28018825578ff05832644cfad60233fbRaph Levien int outerWidth = b.mWidth; 568d3ab692d28018825578ff05832644cfad60233fbRaph Levien TextDirectionHeuristic textDir = b.mTextDir; 569d3ab692d28018825578ff05832644cfad60233fbRaph Levien float spacingmult = b.mSpacingMult; 570d3ab692d28018825578ff05832644cfad60233fbRaph Levien float spacingadd = b.mSpacingAdd; 571d3ab692d28018825578ff05832644cfad60233fbRaph Levien float ellipsizedWidth = b.mEllipsizedWidth; 572d3ab692d28018825578ff05832644cfad60233fbRaph Levien TextUtils.TruncateAt ellipsize = b.mEllipsize; 5734c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs 574c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // store span end locations 575c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] spanEndCache = new int[4]; 576c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // store fontMetrics per span range 577c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range) 578c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] fmCache = new int[4 * 4]; 5794c1f12efcf24e404df40f19075eb95a148a9d6a1Raph Levien b.setLocale(paint.getTextLocale()); // TODO: also respect LocaleSpan within the text 58088b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineCount = 0; 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int v = 0; 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean needMultiply = (spacingmult != 1 || spacingadd != 0); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 586d3ab692d28018825578ff05832644cfad60233fbRaph Levien Paint.FontMetricsInt fm = b.mFontMetricsInt; 587121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int[] chooseHtv = null; 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589d3ab692d28018825578ff05832644cfad60233fbRaph Levien MeasuredText measured = b.mMeasuredText; 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned spanned = null; 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (source instanceof Spanned) 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spanned = (Spanned) source; 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 595e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int paraEnd; 596121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) { 597121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd); 598e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (paraEnd < 0) 599121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio paraEnd = bufEnd; 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 601e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt paraEnd++; 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 603c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int firstWidthLineCount = 1; 604121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int firstWidth = outerWidth; 605121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int restWidth = outerWidth; 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 607121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio LineHeightSpan[] chooseHt = null; 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanned != null) { 61074d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd, 611e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt LeadingMarginSpan.class); 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < sp.length; i++) { 6137b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner LeadingMarginSpan lms = sp[i]; 614121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio firstWidth -= sp[i].getLeadingMargin(true); 615121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio restWidth -= sp[i].getLeadingMargin(false); 616cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 617c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // LeadingMarginSpan2 is odd. The count affects all 618ab08c6d38ab2e575f809ca8ce4c7f095e49d258cAnish Athalye // leading margin spans, not just this particular one 619c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (lms instanceof LeadingMarginSpan2) { 620c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms; 621c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye firstWidthLineCount = Math.max(firstWidthLineCount, 622c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye lms2.getLeadingMarginLineCount()); 6237b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner } 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 626121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class); 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 628121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHt.length != 0) { 629121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHtv == null || 630121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHtv.length < chooseHt.length) { 631776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length); 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 634121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio for (int i = 0; i < chooseHt.length; i++) { 635121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int o = spanned.getSpanStart(chooseHt[i]); 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 637e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (o < paraStart) { 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // starts in this layout, before the 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // current paragraph 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 641121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHtv[i] = getLineTop(getLineForOffset(o)); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // starts in this paragraph 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 645121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHtv[i] = v; 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 65170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien measured.setPara(source, paraStart, paraEnd, textDir, b); 652e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt char[] chs = measured.mChars; 653e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float[] widths = measured.mWidths; 654e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt byte[] chdirs = measured.mLevels; 655e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int dir = measured.mDir; 656e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt boolean easy = measured.mEasy; 657c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien 658c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien // tab stop locations 659c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien int[] variableTabStops = null; 660c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien if (spanned != null) { 661c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, 662c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien paraEnd, TabStopSpan.class); 663c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien if (spans.length > 0) { 664c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien int[] stops = new int[spans.length]; 665c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien for (int i = 0; i < spans.length; i++) { 666c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien stops[i] = spans[i].getTabStop(); 667c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien } 668c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien Arrays.sort(stops, 0, stops.length); 669c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien variableTabStops = stops; 670c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien } 671c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien } 672c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien 673c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart, 674c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien firstWidth, firstWidthLineCount, restWidth, 67595c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency); 6762ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien if (mLeftIndents != null || mRightIndents != null) { 6772ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien // TODO(raph) performance: it would be better to do this once per layout rather 6782ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien // than once per paragraph, but that would require a change to the native 6792ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien // interface. 6802ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length; 6812ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int rightLen = mRightIndents == null ? 0 : mRightIndents.length; 6822ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount); 6832ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int[] indents = new int[indentsLen]; 6842ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien for (int i = 0; i < indentsLen; i++) { 6852ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int leftMargin = mLeftIndents == null ? 0 : 6862ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien mLeftIndents[Math.min(i + mLineCount, leftLen - 1)]; 6872ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int rightMargin = mRightIndents == null ? 0 : 6882ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien mRightIndents[Math.min(i + mLineCount, rightLen - 1)]; 6892ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien indents[i] = leftMargin + rightMargin; 6902ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 6912ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien nSetIndents(b.mNativePtr, indents); 6922ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 694c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // measurement has to be done before performing line breaking 695c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // but we don't want to recompute fontmetrics or span ranges the 696c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // second time, so we cache those and then use those stored values 697c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int fmCacheCount = 0; 698c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int spanEndCacheCount = 0; 699cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) { 700c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fmCacheCount * 4 >= fmCache.length) { 701c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] grow = new int[fmCacheCount * 4 * 2]; 702c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4); 703c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache = grow; 704c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 705c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 706c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (spanEndCacheCount >= spanEndCache.length) { 707c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] grow = new int[spanEndCacheCount * 2]; 708c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount); 709c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEndCache = grow; 710c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 71123241887515ed77687c23e29a4a3ffff671666bdDoug Felt 712cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne if (spanned == null) { 713cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne spanEnd = paraEnd; 71423241887515ed77687c23e29a4a3ffff671666bdDoug Felt int spanLen = spanEnd - spanStart; 715cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne measured.addStyleRun(paint, spanLen, fm); 716cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne } else { 717cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne spanEnd = spanned.nextSpanTransition(spanStart, paraEnd, 718cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne MetricAffectingSpan.class); 719cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne int spanLen = spanEnd - spanStart; 720cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne MetricAffectingSpan[] spans = 72123241887515ed77687c23e29a4a3ffff671666bdDoug Felt spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class); 722cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class); 723cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne measured.addStyleRun(paint, spans, spanLen, fm); 72423241887515ed77687c23e29a4a3ffff671666bdDoug Felt } 72523241887515ed77687c23e29a4a3ffff671666bdDoug Felt 726c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // the order of storage here (top, bottom, ascent, descent) has to match the code below 727c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // where these values are retrieved 728c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 0] = fm.top; 729c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 1] = fm.bottom; 730c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 2] = fm.ascent; 731c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 3] = fm.descent; 732c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCacheCount++; 733c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 734c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEndCache[spanEndCacheCount] = spanEnd; 735c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEndCacheCount++; 736c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 737c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 73870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien nGetWidths(b.mNativePtr, widths); 739c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks, 740c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length); 74181541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne 742c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] breaks = lineBreaks.breaks; 743c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye float[] lineWidths = lineBreaks.widths; 74426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien int[] flags = lineBreaks.flags; 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 746f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi final int remainingLineCount = mMaximumVisibleLineCount - mLineCount; 747f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi final boolean ellipsisMayBeApplied = ellipsize != null 748f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi && (ellipsize == TextUtils.TruncateAt.END 749f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi || (mMaximumVisibleLineCount == 1 750f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi && ellipsize != TextUtils.TruncateAt.MARQUEE)); 75104a84559fd11b36196872b1ac0cb82e5f7367806Raph Levien if (remainingLineCount > 0 && remainingLineCount < breakCount && 75204a84559fd11b36196872b1ac0cb82e5f7367806Raph Levien ellipsisMayBeApplied) { 753f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi // Treat the last line and overflowed lines as a single line. 754f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi breaks[remainingLineCount - 1] = breaks[breakCount - 1]; 755f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi // Calculate width and flag. 756f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi float width = 0; 757f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi int flag = 0; 758f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi for (int i = remainingLineCount - 1; i < breakCount; i++) { 759f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi width += lineWidths[i]; 760f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi flag |= flags[i] & TAB_MASK; 761f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi } 762f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi lineWidths[remainingLineCount - 1] = width; 763f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi flags[remainingLineCount - 1] = flag; 764f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi 765f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi breakCount = remainingLineCount; 766f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi } 767f4a3f3a03c72b6a38dc2f3f965531dc2a12460dfKeisuke Kuroyanagi 768c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // here is the offset of the starting character of the line we are currently measuring 769c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int here = paraStart; 770d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne 771c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0; 772c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int fmCacheIndex = 0; 773c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int spanEndCacheIndex = 0; 774c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int breakIndex = 0; 775c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) { 776c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // retrieve end of span 777c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEnd = spanEndCache[spanEndCacheIndex++]; 778c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 779c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // retrieve cached metrics, order matches above 780c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.top = fmCache[fmCacheIndex * 4 + 0]; 781c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.bottom = fmCache[fmCacheIndex * 4 + 1]; 782c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.ascent = fmCache[fmCacheIndex * 4 + 2]; 783c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.descent = fmCache[fmCacheIndex * 4 + 3]; 784c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCacheIndex++; 785c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 786c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.top < fmTop) { 787c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmTop = fm.top; 788c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 789c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.ascent < fmAscent) { 790c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmAscent = fm.ascent; 791c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 792c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.descent > fmDescent) { 793c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmDescent = fm.descent; 794c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 795c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.bottom > fmBottom) { 796c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmBottom = fm.bottom; 797c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 798cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne 799c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // skip breaks ending before current span range 800c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) { 801c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye breakIndex++; 802c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 80381541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne 804c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) { 805c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int endPos = paraStart + breaks[breakIndex]; 806c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 807ce4155a204144ae5462f547f7738af24be5a1f77Raph Levien boolean moreChars = (endPos < bufEnd); 8084c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien 809c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye v = out(source, here, endPos, 810c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmAscent, fmDescent, fmTop, fmBottom, 811c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex], 812c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad, 813c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye chs, widths, paraStart, ellipsize, ellipsizedWidth, 8144c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien lineWidths[breakIndex], paint, moreChars); 815c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 816c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (endPos < spanEnd) { 817c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // preserve metrics for current span 818c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmTop = fm.top; 819c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmBottom = fm.bottom; 820c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmAscent = fm.ascent; 821c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmDescent = fm.descent; 822c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } else { 823c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmTop = fmBottom = fmAscent = fmDescent = 0; 8248059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 826c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye here = endPos; 827c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye breakIndex++; 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 829c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (mLineCount >= mMaximumVisibleLineCount) { 830c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye return; 831c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 835121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (paraEnd == bufEnd) 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8398059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && 840ad0b051b133baf92f199c96a8ac1e81b3393190cFabrice Di Meglio mLineCount < mMaximumVisibleLineCount) { 841121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio // Log.e("text", "output last " + bufEnd); 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 84370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien measured.setPara(source, bufEnd, bufEnd, textDir, b); 844e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.getFontMetricsInt(fm); 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = out(source, 848121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio bufEnd, bufEnd, fm.ascent, fm.descent, 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.top, fm.bottom, 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v, 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spacingmult, spacingadd, null, 85226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien null, fm, 0, 853e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd, 854d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne includepad, trackpad, null, 855d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne null, bufStart, ellipsize, 856d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne ellipsizedWidth, 0, paint, false); 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int out(CharSequence text, int start, int end, 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int above, int below, int top, int bottom, int v, 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd, 863121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio LineHeightSpan[] chooseHt, int[] chooseHtv, 86426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien Paint.FontMetricsInt fm, int flags, 865d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean needMultiply, byte[] chdirs, int dir, 866d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean easy, int bufEnd, boolean includePad, 867d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean trackPad, char[] chs, 868d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne float[] widths, int widthStart, TextUtils.TruncateAt ellipsize, 869d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne float ellipsisWidth, float textWidth, 870d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne TextPaint paint, boolean moreChars) { 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int j = mLineCount; 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int off = j * mColumns; 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int want = off + mColumns + TOP; 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] lines = mLines; 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (want >= lines.length) { 877776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski Directions[] grow2 = ArrayUtils.newUnpaddedArray( 878776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski Directions.class, GrowingArrayUtils.growSize(want)); 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mLineDirections, 0, grow2, 0, 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineDirections.length); 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineDirections = grow2; 882776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 883776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski int[] grow = new int[grow2.length]; 884776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski System.arraycopy(lines, 0, grow, 0, lines.length); 885776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLines = grow; 886776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski lines = grow; 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHt != null) { 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.ascent = above; 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.descent = below; 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.top = top; 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.bottom = bottom; 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 895121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio for (int i = 0; i < chooseHt.length; i++) { 896121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHt[i] instanceof LineHeightSpan.WithDensity) { 897121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio ((LineHeightSpan.WithDensity) chooseHt[i]). 898121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHeight(text, start, end, chooseHtv[i], v, fm, paint); 899a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer 900a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer } else { 901121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm); 902a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer } 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project above = fm.ascent; 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project below = fm.descent; 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = fm.top; 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = fm.bottom; 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 911d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien boolean firstLine = (j == 0); 912d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount); 913d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd); 914d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien 915d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien if (firstLine) { 916121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (trackPad) { 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTopPadding = top - above; 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 920121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (includePad) { 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project above = top; 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 924d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien 925d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien int extra; 926d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien 927d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien if (lastLine) { 928121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (trackPad) { 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBottomPadding = bottom - below; 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 932121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (includePad) { 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project below = bottom; 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 938d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien if (needMultiply && !lastLine) { 9391065758a0f8966a8597a61492112f7859a7050a4Doug Felt double ex = (below - above) * (spacingmult - 1) + spacingadd; 9401065758a0f8966a8597a61492112f7859a7050a4Doug Felt if (ex >= 0) { 941121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio extra = (int)(ex + EXTRA_ROUNDING); 9421065758a0f8966a8597a61492112f7859a7050a4Doug Felt } else { 943121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio extra = -(int)(-ex + EXTRA_ROUNDING); 9441065758a0f8966a8597a61492112f7859a7050a4Doug Felt } 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project extra = 0; 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + START] = start; 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + TOP] = v; 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + DESCENT] = below + extra; 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v += (below - above) + extra; 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + mColumns + START] = end; 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + mColumns + TOP] = v; 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 95726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien // TODO: could move TAB to share same column as HYPHEN, simplifying this code and gaining 95826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien // one bit for start field 95926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien lines[off + TAB] |= flags & TAB_MASK; 96026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien lines[off + HYPHEN] = flags; 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9629f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt lines[off + DIR] |= dir << DIR_SHIFT; 9639f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT; 9649f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // easy means all chars < the first RTL, so no emoji, no nothing 9654e0c5e55e171532760d5f51e0165563827129d4eDoug Felt // XXX a run with no text or all spaces is easy but might be an empty 9669f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // RTL paragraph. Make sure easy is false if this is the case. 9679f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (easy) { 9689f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt mLineDirections[j] = linedirs; 9699f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } else { 970f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs, 971f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne start - widthStart, end - start); 9720a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne } 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 974aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio if (ellipsize != null) { 975aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio // If there is only one line, then do any type of ellipsis except when it is MARQUEE 976aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio // if there are multiple lines, just allow END ellipsis on the last line 9778059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); 978aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio 97934a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio boolean doEllipsis = 98034a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && 981aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsize != TextUtils.TruncateAt.MARQUEE) || 982aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && 983aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsize == TextUtils.TruncateAt.END); 984aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio if (doEllipsis) { 985aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio calculateEllipsis(start, end, widths, widthStart, 986aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsisWidth, ellipsize, j, 987aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio textWidth, paint, forceEllipsis); 988aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio } 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineCount++; 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 995121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio private void calculateEllipsis(int lineStart, int lineEnd, 996121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio float[] widths, int widthStart, 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float avail, TextUtils.TruncateAt where, 9988059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int line, float textWidth, TextPaint paint, 9998059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio boolean forceEllipsis) { 10008059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (textWidth <= avail && !forceEllipsis) { 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Everything fits! 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_START] = 0; 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_COUNT] = 0; 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1007cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio float ellipsisWidth = paint.measureText( 10088d44fff7e62f77c3b3072a96712cc1389e63ca64Fabrice Di Meglio (where == TextUtils.TruncateAt.END_SMALL) ? 1009d29bdb266d54b4551f42776bb790e80147a279d0Neil Fuller TextUtils.ELLIPSIS_TWO_DOTS : TextUtils.ELLIPSIS_NORMAL, 0, 1); 10108059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int ellipsisStart = 0; 10118059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int ellipsisCount = 0; 1012121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int len = lineEnd - lineStart; 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10148059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio // We only support start ellipsis on a single line 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where == TextUtils.TruncateAt.START) { 10168059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (mMaximumVisibleLineCount == 1) { 10178059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float sum = 0; 10188059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int i; 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1020ed2eea1bfc1fb57d3b34f2c1e6062b541737e73eKeisuke Kuroyanagi for (i = len; i > 0; i--) { 10218059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float w = widths[i - 1 + lineStart - widthStart]; 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10238059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (w + sum + ellipsisWidth > avail) { 10248059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio break; 10258059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 10268059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio 10278059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio sum += w; 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10308059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisStart = 0; 10318059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisCount = i; 10328059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } else { 10338059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (Log.isLoggable(TAG, Log.WARN)) { 10348059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio Log.w(TAG, "Start Ellipsis only supported with one line"); 10358059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1037cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE || 1038cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio where == TextUtils.TruncateAt.END_SMALL) { 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float sum = 0; 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i; 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < len; i++) { 1043121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio float w = widths[i + lineStart - widthStart]; 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1045121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (w + sum + ellipsisWidth > avail) { 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sum += w; 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ellipsisStart = i; 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ellipsisCount = len - i; 1054aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio if (forceEllipsis && ellipsisCount == 0 && len > 0) { 1055aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsisStart = len - 1; 10568059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisCount = 1; 10578059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 10588059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } else { 10598059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio // where = TextUtils.TruncateAt.MIDDLE We only support middle ellipsis on a single line 10608059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (mMaximumVisibleLineCount == 1) { 10618059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float lsum = 0, rsum = 0; 10628059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int left = 0, right = len; 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10648059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float ravail = (avail - ellipsisWidth) / 2; 10650e3c5e827235911d33312e431975533f046421e7Raph Levien for (right = len; right > 0; right--) { 10668059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float w = widths[right - 1 + lineStart - widthStart]; 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10688059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (w + rsum > ravail) { 10698059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio break; 10708059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 10718059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio 10728059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio rsum += w; 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10758059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float lavail = avail - ellipsisWidth - rsum; 10768059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio for (left = 0; left < right; left++) { 10778059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float w = widths[left + lineStart - widthStart]; 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10798059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (w + lsum > lavail) { 10808059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio break; 10818059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10838059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio lsum += w; 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10868059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisStart = left; 10878059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisCount = right - left; 10888059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } else { 10898059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (Log.isLoggable(TAG, Log.WARN)) { 10908059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio Log.w(TAG, "Middle Ellipsis only supported with one line"); 10918059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart; 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount; 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1099e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // Override the base class so we can directly access our members, 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // rather than relying on member functions. 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The logic mirrors that of Layout.getLineForVertical 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME: It may be faster to do a linear search for layouts without many lines. 11036611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineForVertical(int vertical) { 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = mLineCount; 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int low = -1; 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int guess; 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] lines = mLines; 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) >> 1; 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lines[mColumns * guess + TOP] > vertical){ 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < 0) { 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return low; 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11246611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineCount() { 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLineCount; 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11296611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineTop(int line) { 11310a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne int top = mLines[mColumns * line + TOP]; 11320a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount && 11330a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne line != mLineCount) { 11340a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne top += getBottomPadding(); 11350a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne } 11360a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne return top; 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11396611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineDescent(int line) { 11410a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne int descent = mLines[mColumns * line + DESCENT]; 1142f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended 11430a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne line != mLineCount) { 11440a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne descent += getBottomPadding(); 11450a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne } 11460a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne return descent; 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11496611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineStart(int line) { 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + START] & START_MASK; 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11546611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getParagraphDirection(int line) { 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + DIR] >> DIR_SHIFT; 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11596611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean getLineContainsTab(int line) { 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mLines[mColumns * line + TAB] & TAB_MASK) != 0; 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11646611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final Directions getLineDirections(int line) { 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLineDirections[line]; 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11696611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getTopPadding() { 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mTopPadding; 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11746611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getBottomPadding() { 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBottomPadding; 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 117926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien /** 118026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien * @hide 118126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien */ 118226d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien @Override 118326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien public int getHyphen(int line) { 118426d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien return mLines[mColumns * line + HYPHEN] & 0xff; 118526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien } 118626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien 11872ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien /** 11882ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien * @hide 11892ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien */ 11902ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien @Override 11912ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien public int getIndentAdjust(int line, Alignment align) { 11922ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien if (align == Alignment.ALIGN_LEFT) { 11932ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien if (mLeftIndents == null) { 11942ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien return 0; 11952ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } else { 11962ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien return mLeftIndents[Math.min(line, mLeftIndents.length - 1)]; 11972ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 11982ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } else if (align == Alignment.ALIGN_RIGHT) { 11992ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien if (mRightIndents == null) { 12002ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien return 0; 12012ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } else { 12022ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien return -mRightIndents[Math.min(line, mRightIndents.length - 1)]; 12032ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 12042ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } else if (align == Alignment.ALIGN_CENTER) { 12052ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int left = 0; 12062ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien if (mLeftIndents != null) { 12072ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien left = mLeftIndents[Math.min(line, mLeftIndents.length - 1)]; 12082ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 12092ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien int right = 0; 12102ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien if (mRightIndents != null) { 12112ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien right = mRightIndents[Math.min(line, mRightIndents.length - 1)]; 12122ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 12132ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien return (left - right) >> 1; 12142ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } else { 12152ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien throw new AssertionError("unhandled alignment " + align); 12162ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 12172ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien } 12182ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsisCount(int line) { 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mColumns < COLUMNS_ELLIPSIZE) { 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + ELLIPSIS_COUNT]; 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsisStart(int line) { 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mColumns < COLUMNS_ELLIPSIZE) { 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + ELLIPSIS_START]; 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsizedWidth() { 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mEllipsizedWidth; 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 124270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native long nNewBuilder(); 124370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native void nFreeBuilder(long nativePtr); 124470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native void nFinishBuilder(long nativePtr); 124526d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien 124626d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien /* package */ static native long nLoadHyphenator(String patternData); 124726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien 124826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien private static native void nSetLocale(long nativePtr, String locale, long nativeHyphenator); 124970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 1250e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien private static native void nSetIndents(long nativePtr, int[] indents); 1251e319d5a3627aa3cd73c6ec0c76f8593ddefbab9dRaph Levien 1252c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien // Set up paragraph text and settings; done as one big method to minimize jni crossings 1253c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien private static native void nSetupParagraph(long nativePtr, char[] text, int length, 1254c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien float firstWidth, int firstWidthLineCount, float restWidth, 125595c7a13f2ac4f31ed3aaec9b47b9a29a3dbca978Roozbeh Pournader int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency); 125670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 125770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native float nAddStyleRun(long nativePtr, long nativePaint, 125870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien long nativeTypeface, int start, int end, boolean isRtl); 125970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 126070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native void nAddMeasuredRun(long nativePtr, 126170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien int start, int end, float[] widths); 126270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 126370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native void nAddReplacementRun(long nativePtr, int start, int end, float width); 126470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 126570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien private static native void nGetWidths(long nativePtr, float[] widths); 126670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien 1267c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // populates LineBreaks and returns the number of breaks found 1268c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // 1269c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // the arrays inside the LineBreaks objects are passed in as well 1270c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // to reduce the number of JNI calls in the common case where the 1271c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // arrays do not have to be resized 1272c94f742f7e07a3b86c8f603836c19638472b3e83Raph Levien private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle, 127326d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien int[] recycleBreaks, float[] recycleWidths, int[] recycleFlags, int recycleLength); 127488b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye 12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLineCount; 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTopPadding, mBottomPadding; 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mColumns; 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mEllipsizedWidth; 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 128026d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien private static final int COLUMNS_NORMAL = 4; 128126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien private static final int COLUMNS_ELLIPSIZE = 6; 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int START = 0; 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DIR = START; 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TAB = START; 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TOP = 1; 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DESCENT = 2; 128726d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien private static final int HYPHEN = 3; 128826d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien private static final int ELLIPSIS_START = 4; 128926d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien private static final int ELLIPSIS_COUNT = 5; 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mLines; 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Directions[] mLineDirections; 12938059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio private int mMaximumVisibleLineCount = Integer.MAX_VALUE; 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int START_MASK = 0x1FFFFFFF; 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DIR_SHIFT = 30; 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TAB_MASK = 0x20000000; 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1299c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private static final int TAB_INCREMENT = 20; // same as Layout, but that's private 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1301121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio private static final char CHAR_NEW_LINE = '\n'; 1302121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio 1303121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio private static final double EXTRA_ROUNDING = 0.5; 1304cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio 1305c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // This is used to return three arrays from a single JNI call when 1306c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // performing line breaking 13077053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /*package*/ static class LineBreaks { 1308c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye private static final int INITIAL_SIZE = 16; 1309c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye public int[] breaks = new int[INITIAL_SIZE]; 1310c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye public float[] widths = new float[INITIAL_SIZE]; 131126d443aee4ee5a8791417b4ca09e8c78ba8dc78bRaph Levien public int[] flags = new int[INITIAL_SIZE]; // hasTabOrEmoji 1312c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // breaks, widths, and flags should all have the same length 1313c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 1314c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 13152ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien private int[] mLeftIndents; 13162ea5290ffb9efe0a7c187fb1177ef8ecd089803cRaph Levien private int[] mRightIndents; 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1318