StaticLayout.java revision 4c02e831728daf9374b52e2fe3fdbf7ce982bfc4
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 19105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.graphics.Bitmap; 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; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28cb379120456d8065d742021fc5c66748fc8a11a8Doug Feltimport com.android.internal.util.ArrayUtils; 29776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport com.android.internal.util.GrowingArrayUtils; 30cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 31c8f9e6218681640d5f384c12edf06619be56a583Anish Athalyeimport java.util.Arrays; 32c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * StaticLayout is a Layout for text that will not be edited after it 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is laid out. Use {@link DynamicLayout} for text that may change. 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>This is used by widgets to control text layout. You should not need 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to use this class directly unless you are implementing your own widget 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or custom display object, or would be tempted to call 394e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, 404e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * float, float, android.graphics.Paint) 414e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * Canvas.drawText()} directly.</p> 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 43121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Megliopublic class StaticLayout extends Layout { 44121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio 458059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio static final String TAG = "StaticLayout"; 468059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StaticLayout(CharSequence source, TextPaint paint, 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int width, 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align, float spacingmult, float spacingadd, 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean includepad) { 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(source, 0, source.length(), paint, width, align, 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spacingmult, spacingadd, includepad); 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 55cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt /** 56cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt * @hide 57cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */ 58cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt public StaticLayout(CharSequence source, TextPaint paint, 59cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt int width, Alignment align, TextDirectionHeuristic textDir, 60cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt float spacingmult, float spacingadd, 61cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt boolean includepad) { 62cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt this(source, 0, source.length(), paint, width, align, textDir, 63cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt spacingmult, spacingadd, includepad); 64cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt } 65cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StaticLayout(CharSequence source, int bufstart, int bufend, 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint, int outerwidth, 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Alignment align, 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd, 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean includepad) { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(source, bufstart, bufend, paint, outerwidth, align, 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spacingmult, spacingadd, includepad, null, 0); 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 75cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt /** 76cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt * @hide 77cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */ 78cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt public StaticLayout(CharSequence source, int bufstart, int bufend, 79cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextPaint paint, int outerwidth, 80cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt Alignment align, TextDirectionHeuristic textDir, 81cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt float spacingmult, float spacingadd, 82cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt boolean includepad) { 83cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt this(source, bufstart, bufend, paint, outerwidth, align, textDir, 848059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio spacingmult, spacingadd, includepad, null, 0, Integer.MAX_VALUE); 85cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt} 86cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 87cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt public StaticLayout(CharSequence source, int bufstart, int bufend, 88cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextPaint paint, int outerwidth, 89cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt Alignment align, 90cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt float spacingmult, float spacingadd, 91cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt boolean includepad, 92cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { 93cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt this(source, bufstart, bufend, paint, outerwidth, align, 94cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt TextDirectionHeuristics.FIRSTSTRONG_LTR, 958059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth, Integer.MAX_VALUE); 96cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt } 97cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 98cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt /** 99cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt * @hide 100cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt */ 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StaticLayout(CharSequence source, int bufstart, int bufend, 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextPaint paint, int outerwidth, 103cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt Alignment align, TextDirectionHeuristic textDir, 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd, 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean includepad, 1068059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio TextUtils.TruncateAt ellipsize, int ellipsizedWidth, int maxLines) { 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super((ellipsize == null) 1084e0c5e55e171532760d5f51e0165563827129d4eDoug Felt ? source 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : (source instanceof Spanned) 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? new SpannedEllipsizer(source) 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : new Ellipsizer(source), 112cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt paint, outerwidth, align, textDir, spacingmult, spacingadd); 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is annoying, but we can't refer to the layout until 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * superclass construction is finished, and the superclass 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * constructor wants the reference to the display text. 1184e0c5e55e171532760d5f51e0165563827129d4eDoug Felt * 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will break if the superclass constructor ever actually 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cares about the content instead of just holding the reference. 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ellipsize != null) { 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Ellipsizer e = (Ellipsizer) getText(); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.mLayout = this; 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.mWidth = ellipsizedWidth; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.mMethod = ellipsize; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEllipsizedWidth = ellipsizedWidth; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mColumns = COLUMNS_ELLIPSIZE; 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mColumns = COLUMNS_NORMAL; 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mEllipsizedWidth = outerwidth; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 136776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns); 137776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLines = new int[mLineDirections.length]; 1388059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio mMaximumVisibleLineCount = maxLines; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 140e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt mMeasured = MeasuredText.obtain(); 141e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt 142d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne generate(source, bufstart, bufend, paint, outerwidth, textDir, spacingmult, 143d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne spacingadd, includepad, includepad, ellipsizedWidth, 144d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne ellipsize); 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 146e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt mMeasured = MeasuredText.recycle(mMeasured); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFontMetricsInt = null; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1508059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio /* package */ StaticLayout(CharSequence text) { 1518059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio super(text, null, 0, null, 0, 0); 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mColumns = COLUMNS_ELLIPSIZE; 154776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns); 155776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLines = new int[mLineDirections.length]; 15681541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne // FIXME This is never recycled 157e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt mMeasured = MeasuredText.obtain(); 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 160121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio /* package */ void generate(CharSequence source, int bufStart, int bufEnd, 161121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio TextPaint paint, int outerWidth, 162d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne TextDirectionHeuristic textDir, float spacingmult, 163d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne float spacingadd, boolean includepad, 164d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean trackpad, float ellipsizedWidth, 165d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne TextUtils.TruncateAt ellipsize) { 166c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye LineBreaks lineBreaks = new LineBreaks(); 167c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // store span end locations 168c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] spanEndCache = new int[4]; 169c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // store fontMetrics per span range 170c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range) 171c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] fmCache = new int[4 * 4]; 17288b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye final String localeLanguageTag = paint.getTextLocale().toLanguageTag(); 17388b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineCount = 0; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int v = 0; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean needMultiply = (spacingmult != 1 || spacingadd != 0); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Paint.FontMetricsInt fm = mFontMetricsInt; 180121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int[] chooseHtv = null; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 182e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt MeasuredText measured = mMeasured; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned spanned = null; 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (source instanceof Spanned) 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spanned = (Spanned) source; 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 188e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int paraEnd; 189121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) { 190121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio paraEnd = TextUtils.indexOf(source, CHAR_NEW_LINE, paraStart, bufEnd); 191e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (paraEnd < 0) 192121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio paraEnd = bufEnd; 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 194e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt paraEnd++; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 196c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int firstWidthLineCount = 1; 197121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int firstWidth = outerWidth; 198121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int restWidth = outerWidth; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 200121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio LineHeightSpan[] chooseHt = null; 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanned != null) { 20374d31ef2b2c42b54fa1f7cf94ea955ea67ab69a0Eric Fischer LeadingMarginSpan[] sp = getParagraphSpans(spanned, paraStart, paraEnd, 204e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt LeadingMarginSpan.class); 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < sp.length; i++) { 2067b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner LeadingMarginSpan lms = sp[i]; 207121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio firstWidth -= sp[i].getLeadingMargin(true); 208121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio restWidth -= sp[i].getLeadingMargin(false); 209cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt 210c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt // LeadingMarginSpan2 is odd. The count affects all 211ab08c6d38ab2e575f809ca8ce4c7f095e49d258cAnish Athalye // leading margin spans, not just this particular one 212c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (lms instanceof LeadingMarginSpan2) { 213c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms; 214c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye firstWidthLineCount = Math.max(firstWidthLineCount, 215c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye lms2.getLeadingMarginLineCount()); 2167b5676e4d40a09ccdbc8b6f691a3d8be23e480d3Mark Wagner } 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHt = getParagraphSpans(spanned, paraStart, paraEnd, LineHeightSpan.class); 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 221121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHt.length != 0) { 222121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHtv == null || 223121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHtv.length < chooseHt.length) { 224776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski chooseHtv = ArrayUtils.newUnpaddedIntArray(chooseHt.length); 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 227121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio for (int i = 0; i < chooseHt.length; i++) { 228121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int o = spanned.getSpanStart(chooseHt[i]); 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 230e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt if (o < paraStart) { 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // starts in this layout, before the 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // current paragraph 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 234121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHtv[i] = getLineTop(getLineForOffset(o)); 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // starts in this paragraph 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 238121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHtv[i] = v; 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 244cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt measured.setPara(source, paraStart, paraEnd, textDir); 245e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt char[] chs = measured.mChars; 246e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt float[] widths = measured.mWidths; 247e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt byte[] chdirs = measured.mLevels; 248e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt int dir = measured.mDir; 249e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt boolean easy = measured.mEasy; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 251c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // measurement has to be done before performing line breaking 252c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // but we don't want to recompute fontmetrics or span ranges the 253c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // second time, so we cache those and then use those stored values 254c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int fmCacheCount = 0; 255c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int spanEndCacheCount = 0; 256cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) { 257c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fmCacheCount * 4 >= fmCache.length) { 258c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] grow = new int[fmCacheCount * 4 * 2]; 259c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4); 260c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache = grow; 261c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 262c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 263c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (spanEndCacheCount >= spanEndCache.length) { 264c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] grow = new int[spanEndCacheCount * 2]; 265c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount); 266c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEndCache = grow; 267c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 26823241887515ed77687c23e29a4a3ffff671666bdDoug Felt 269cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne if (spanned == null) { 270cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne spanEnd = paraEnd; 27123241887515ed77687c23e29a4a3ffff671666bdDoug Felt int spanLen = spanEnd - spanStart; 272cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne measured.addStyleRun(paint, spanLen, fm); 273cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne } else { 274cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne spanEnd = spanned.nextSpanTransition(spanStart, paraEnd, 275cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne MetricAffectingSpan.class); 276cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne int spanLen = spanEnd - spanStart; 277cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne MetricAffectingSpan[] spans = 27823241887515ed77687c23e29a4a3ffff671666bdDoug Felt spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class); 279cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne spans = TextUtils.removeEmptySpans(spans, spanned, MetricAffectingSpan.class); 280cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne measured.addStyleRun(paint, spans, spanLen, fm); 28123241887515ed77687c23e29a4a3ffff671666bdDoug Felt } 28223241887515ed77687c23e29a4a3ffff671666bdDoug Felt 283c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // the order of storage here (top, bottom, ascent, descent) has to match the code below 284c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // where these values are retrieved 285c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 0] = fm.top; 286c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 1] = fm.bottom; 287c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 2] = fm.ascent; 288c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCache[fmCacheCount * 4 + 3] = fm.descent; 289c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCacheCount++; 290c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 291c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEndCache[spanEndCacheCount] = spanEnd; 292c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEndCacheCount++; 293c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 294c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 295c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // tab stop locations 296c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] variableTabStops = null; 297c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (spanned != null) { 298c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye TabStopSpan[] spans = getParagraphSpans(spanned, paraStart, 299c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye paraEnd, TabStopSpan.class); 300c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (spans.length > 0) { 301c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] stops = new int[spans.length]; 302c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye for (int i = 0; i < spans.length; i++) { 303c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye stops[i] = spans[i].getTabStop(); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 305c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye Arrays.sort(stops, 0, stops.length); 306c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye variableTabStops = stops; 307c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 308c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 310c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int breakCount = nComputeLineBreaks(localeLanguageTag, chs, widths, paraEnd - paraStart, firstWidth, 311969e7b949633baebd3f6090a60d622ee475a5b22Anish Athalye firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks, 312c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length); 31381541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne 314c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] breaks = lineBreaks.breaks; 315c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye float[] lineWidths = lineBreaks.widths; 316c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye boolean[] flags = lineBreaks.flags; 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 318c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // here is the offset of the starting character of the line we are currently measuring 319c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int here = paraStart; 320d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne 321c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0; 322c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int fmCacheIndex = 0; 323c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int spanEndCacheIndex = 0; 324c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int breakIndex = 0; 325c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) { 326c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // retrieve end of span 327c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye spanEnd = spanEndCache[spanEndCacheIndex++]; 328c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 329c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // retrieve cached metrics, order matches above 330c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.top = fmCache[fmCacheIndex * 4 + 0]; 331c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.bottom = fmCache[fmCacheIndex * 4 + 1]; 332c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.ascent = fmCache[fmCacheIndex * 4 + 2]; 333c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fm.descent = fmCache[fmCacheIndex * 4 + 3]; 334c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmCacheIndex++; 335c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 336c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.top < fmTop) { 337c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmTop = fm.top; 338c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 339c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.ascent < fmAscent) { 340c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmAscent = fm.ascent; 341c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 342c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.descent > fmDescent) { 343c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmDescent = fm.descent; 344c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 345c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (fm.bottom > fmBottom) { 346c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmBottom = fm.bottom; 347c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 348cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne 349c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // skip breaks ending before current span range 350c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) { 351c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye breakIndex++; 352c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 35381541491946bfc4f2e26c171b4ebff4249dca51cGilles Debunne 354c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) { 355c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int endPos = paraStart + breaks[breakIndex]; 356c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 3574c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien boolean moreChars = (endPos < paraEnd); // XXX is this the right way to calculate this? 3584c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien 359c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye v = out(source, here, endPos, 360c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmAscent, fmDescent, fmTop, fmBottom, 361c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex], 362c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad, 363c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye chs, widths, paraStart, ellipsize, ellipsizedWidth, 3644c02e831728daf9374b52e2fe3fdbf7ce982bfc4Raph Levien lineWidths[breakIndex], paint, moreChars); 365c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 366c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (endPos < spanEnd) { 367c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // preserve metrics for current span 368c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmTop = fm.top; 369c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmBottom = fm.bottom; 370c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmAscent = fm.ascent; 371c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmDescent = fm.descent; 372c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } else { 373c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye fmTop = fmBottom = fmAscent = fmDescent = 0; 3748059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 376c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye here = endPos; 377c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye breakIndex++; 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 379c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye if (mLineCount >= mMaximumVisibleLineCount) { 380c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye return; 381c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 385121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (paraEnd == bufEnd) 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3898059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) && 390ad0b051b133baf92f199c96a8ac1e81b3393190cFabrice Di Meglio mLineCount < mMaximumVisibleLineCount) { 391121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio // Log.e("text", "output last " + bufEnd); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 39346514a75e33e87d3461a502a5a0821c46b2783ebAnish Athalye measured.setPara(source, bufEnd, bufEnd, textDir); 394e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project paint.getFontMetricsInt(fm); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v = out(source, 398121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio bufEnd, bufEnd, fm.ascent, fm.descent, 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.top, fm.bottom, 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v, 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spacingmult, spacingadd, null, 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, fm, false, 403e631889e1ae7edc6a2fae495ba504f85820b6a4bFabrice Di Meglio needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd, 404d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne includepad, trackpad, null, 405d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne null, bufStart, ellipsize, 406d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne ellipsizedWidth, 0, paint, false); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int out(CharSequence text, int start, int end, 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int above, int below, int top, int bottom, int v, 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float spacingmult, float spacingadd, 413121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio LineHeightSpan[] chooseHt, int[] chooseHtv, 414c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt Paint.FontMetricsInt fm, boolean hasTabOrEmoji, 415d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean needMultiply, byte[] chdirs, int dir, 416d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean easy, int bufEnd, boolean includePad, 417d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne boolean trackPad, char[] chs, 418d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne float[] widths, int widthStart, TextUtils.TruncateAt ellipsize, 419d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne float ellipsisWidth, float textWidth, 420d300e75eff0d5e54390400cbd3f80dc4cea8b617Gilles Debunne TextPaint paint, boolean moreChars) { 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int j = mLineCount; 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int off = j * mColumns; 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int want = off + mColumns + TOP; 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] lines = mLines; 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (want >= lines.length) { 427776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski Directions[] grow2 = ArrayUtils.newUnpaddedArray( 428776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski Directions.class, GrowingArrayUtils.growSize(want)); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mLineDirections, 0, grow2, 0, 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineDirections.length); 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineDirections = grow2; 432776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 433776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski int[] grow = new int[grow2.length]; 434776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski System.arraycopy(lines, 0, grow, 0, lines.length); 435776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mLines = grow; 436776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski lines = grow; 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 439121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHt != null) { 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.ascent = above; 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.descent = below; 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.top = top; 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fm.bottom = bottom; 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 445121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio for (int i = 0; i < chooseHt.length; i++) { 446121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (chooseHt[i] instanceof LineHeightSpan.WithDensity) { 447121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio ((LineHeightSpan.WithDensity) chooseHt[i]). 448121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHeight(text, start, end, chooseHtv[i], v, fm, paint); 449a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer 450a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer } else { 451121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio chooseHt[i].chooseHeight(text, start, end, chooseHtv[i], v, fm); 452a9f1dd021f8f6ee777bc4d27913bd40c42e753afEric Fischer } 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project above = fm.ascent; 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project below = fm.descent; 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project top = fm.top; 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bottom = fm.bottom; 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 461d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien boolean firstLine = (j == 0); 462d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount); 463d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd); 464d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien 465d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien if (firstLine) { 466121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (trackPad) { 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTopPadding = top - above; 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 470121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (includePad) { 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project above = top; 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 474d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien 475d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien int extra; 476d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien 477d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien if (lastLine) { 478121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (trackPad) { 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBottomPadding = bottom - below; 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 482121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (includePad) { 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project below = bottom; 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 488d97b097a5b7a906e8d30c6d3b0f41c55650ce7a9Raph Levien if (needMultiply && !lastLine) { 4891065758a0f8966a8597a61492112f7859a7050a4Doug Felt double ex = (below - above) * (spacingmult - 1) + spacingadd; 4901065758a0f8966a8597a61492112f7859a7050a4Doug Felt if (ex >= 0) { 491121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio extra = (int)(ex + EXTRA_ROUNDING); 4921065758a0f8966a8597a61492112f7859a7050a4Doug Felt } else { 493121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio extra = -(int)(-ex + EXTRA_ROUNDING); 4941065758a0f8966a8597a61492112f7859a7050a4Doug Felt } 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project extra = 0; 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + START] = start; 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + TOP] = v; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + DESCENT] = below + extra; 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project v += (below - above) + extra; 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + mColumns + START] = end; 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + mColumns + TOP] = v; 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 507c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt if (hasTabOrEmoji) 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lines[off + TAB] |= TAB_MASK; 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5109f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt lines[off + DIR] |= dir << DIR_SHIFT; 5119f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt Directions linedirs = DIRS_ALL_LEFT_TO_RIGHT; 5129f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // easy means all chars < the first RTL, so no emoji, no nothing 5134e0c5e55e171532760d5f51e0165563827129d4eDoug Felt // XXX a run with no text or all spaces is easy but might be an empty 5149f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt // RTL paragraph. Make sure easy is false if this is the case. 5159f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt if (easy) { 5169f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt mLineDirections[j] = linedirs; 5179f7a4442b89cc06cb8cae6992484e7ae795323abDoug Felt } else { 518f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs, 519f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne start - widthStart, end - start); 5200a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 522aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio if (ellipsize != null) { 523aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio // If there is only one line, then do any type of ellipsis except when it is MARQUEE 524aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio // if there are multiple lines, just allow END ellipsis on the last line 5258059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); 526aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio 52734a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio boolean doEllipsis = 52834a126e51aaf22e32c7af808ec6b5a0c41ae3311Fabrice Di Meglio (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && 529aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsize != TextUtils.TruncateAt.MARQUEE) || 530aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && 531aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsize == TextUtils.TruncateAt.END); 532aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio if (doEllipsis) { 533aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio calculateEllipsis(start, end, widths, widthStart, 534aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsisWidth, ellipsize, j, 535aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio textWidth, paint, forceEllipsis); 536aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio } 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLineCount++; 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return v; 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 543121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio private void calculateEllipsis(int lineStart, int lineEnd, 544121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio float[] widths, int widthStart, 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float avail, TextUtils.TruncateAt where, 5468059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int line, float textWidth, TextPaint paint, 5478059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio boolean forceEllipsis) { 5488059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (textWidth <= avail && !forceEllipsis) { 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Everything fits! 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_START] = 0; 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_COUNT] = 0; 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 555cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio float ellipsisWidth = paint.measureText( 5568d44fff7e62f77c3b3072a96712cc1389e63ca64Fabrice Di Meglio (where == TextUtils.TruncateAt.END_SMALL) ? 5578d44fff7e62f77c3b3072a96712cc1389e63ca64Fabrice Di Meglio ELLIPSIS_TWO_DOTS : ELLIPSIS_NORMAL, 0, 1); 5588059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int ellipsisStart = 0; 5598059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int ellipsisCount = 0; 560121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio int len = lineEnd - lineStart; 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5628059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio // We only support start ellipsis on a single line 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where == TextUtils.TruncateAt.START) { 5648059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (mMaximumVisibleLineCount == 1) { 5658059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float sum = 0; 5668059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int i; 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5688059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio for (i = len; i >= 0; i--) { 5698059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float w = widths[i - 1 + lineStart - widthStart]; 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5718059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (w + sum + ellipsisWidth > avail) { 5728059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio break; 5738059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 5748059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio 5758059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio sum += w; 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5788059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisStart = 0; 5798059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisCount = i; 5808059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } else { 5818059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (Log.isLoggable(TAG, Log.WARN)) { 5828059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio Log.w(TAG, "Start Ellipsis only supported with one line"); 5838059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 585cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio } else if (where == TextUtils.TruncateAt.END || where == TextUtils.TruncateAt.MARQUEE || 586cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio where == TextUtils.TruncateAt.END_SMALL) { 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float sum = 0; 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int i; 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (i = 0; i < len; i++) { 591121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio float w = widths[i + lineStart - widthStart]; 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 593121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio if (w + sum + ellipsisWidth > avail) { 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sum += w; 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ellipsisStart = i; 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ellipsisCount = len - i; 602aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio if (forceEllipsis && ellipsisCount == 0 && len > 0) { 603aef455fd5b4c667267deb050bc7997e737b7507eFabrice Di Meglio ellipsisStart = len - 1; 6048059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisCount = 1; 6058059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 6068059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } else { 6078059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio // where = TextUtils.TruncateAt.MIDDLE We only support middle ellipsis on a single line 6088059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (mMaximumVisibleLineCount == 1) { 6098059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float lsum = 0, rsum = 0; 6108059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio int left = 0, right = len; 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6128059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float ravail = (avail - ellipsisWidth) / 2; 6130e3c5e827235911d33312e431975533f046421e7Raph Levien for (right = len; right > 0; right--) { 6148059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float w = widths[right - 1 + lineStart - widthStart]; 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6168059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (w + rsum > ravail) { 6178059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio break; 6188059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 6198059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio 6208059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio rsum += w; 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6238059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float lavail = avail - ellipsisWidth - rsum; 6248059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio for (left = 0; left < right; left++) { 6258059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio float w = widths[left + lineStart - widthStart]; 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6278059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (w + lsum > lavail) { 6288059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio break; 6298059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6318059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio lsum += w; 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6348059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisStart = left; 6358059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio ellipsisCount = right - left; 6368059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } else { 6378059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio if (Log.isLoggable(TAG, Log.WARN)) { 6388059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio Log.w(TAG, "Middle Ellipsis only supported with one line"); 6398059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio } 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_START] = ellipsisStart; 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLines[mColumns * line + ELLIPSIS_COUNT] = ellipsisCount; 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 647e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt // Override the base class so we can directly access our members, 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // rather than relying on member functions. 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The logic mirrors that of Layout.getLineForVertical 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME: It may be faster to do a linear search for layouts without many lines. 6516611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineForVertical(int vertical) { 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int high = mLineCount; 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int low = -1; 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int guess; 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] lines = mLines; 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (high - low > 1) { 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project guess = (high + low) >> 1; 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lines[mColumns * guess + TOP] > vertical){ 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project high = guess; 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project low = guess; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (low < 0) { 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return low; 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6726611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineCount() { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLineCount; 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6776611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineTop(int line) { 6790a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne int top = mLines[mColumns * line + TOP]; 6800a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount && 6810a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne line != mLineCount) { 6820a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne top += getBottomPadding(); 6830a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne } 6840a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne return top; 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6876611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineDescent(int line) { 6890a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne int descent = mLines[mColumns * line + DESCENT]; 690f3fa0cdbaea109b114f7facbb5d42de3fc12bbc8Gilles Debunne if (mMaximumVisibleLineCount > 0 && line >= mMaximumVisibleLineCount - 1 && // -1 intended 6910a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne line != mLineCount) { 6920a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne descent += getBottomPadding(); 6930a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne } 6940a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne return descent; 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6976611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getLineStart(int line) { 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + START] & START_MASK; 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7026611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getParagraphDirection(int line) { 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + DIR] >> DIR_SHIFT; 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7076611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean getLineContainsTab(int line) { 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mLines[mColumns * line + TAB] & TAB_MASK) != 0; 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7126611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final Directions getLineDirections(int line) { 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLineDirections[line]; 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7176611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getTopPadding() { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mTopPadding; 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7226611147383118cd91cc29b31bff9aaf4c853f39dGilles Debunne @Override 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getBottomPadding() { 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBottomPadding; 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsisCount(int line) { 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mColumns < COLUMNS_ELLIPSIZE) { 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + ELLIPSIS_COUNT]; 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsisStart(int line) { 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mColumns < COLUMNS_ELLIPSIZE) { 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mLines[mColumns * line + ELLIPSIS_START]; 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getEllipsizedWidth() { 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mEllipsizedWidth; 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 750e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy void prepare() { 751e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy mMeasured = MeasuredText.obtain(); 752e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy } 753e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy 754e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy void finish() { 755e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy mMeasured = MeasuredText.recycle(mMeasured); 756e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy } 7570a4db3c5270440eeb7e4e44a7029926e239ec3bdGilles Debunne 758c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // populates LineBreaks and returns the number of breaks found 759c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // 760c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // the arrays inside the LineBreaks objects are passed in as well 761c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // to reduce the number of JNI calls in the common case where the 762c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // arrays do not have to be resized 763c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye private static native int nComputeLineBreaks(String locale, char[] text, float[] widths, 764c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int length, float firstWidth, int firstWidthLineCount, float restWidth, 765969e7b949633baebd3f6090a60d622ee475a5b22Anish Athalye int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle, 766c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength); 76788b5b0be887fc5dc3b0b879b4179dde200d2e4d6Anish Athalye 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mLineCount; 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTopPadding, mBottomPadding; 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mColumns; 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mEllipsizedWidth; 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int COLUMNS_NORMAL = 3; 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int COLUMNS_ELLIPSIZE = 5; 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int START = 0; 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DIR = START; 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TAB = START; 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TOP = 1; 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DESCENT = 2; 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int ELLIPSIS_START = 3; 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int ELLIPSIS_COUNT = 4; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mLines; 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Directions[] mLineDirections; 7858059e0903e36cbb5cf8b5c5d5d653acc9bbc8402Fabrice Di Meglio private int mMaximumVisibleLineCount = Integer.MAX_VALUE; 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int START_MASK = 0x1FFFFFFF; 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DIR_SHIFT = 30; 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TAB_MASK = 0x20000000; 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 791c982f60e982c1d2df9f115ed9a5c3ef3643d0892Doug Felt private static final int TAB_INCREMENT = 20; // same as Layout, but that's private 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 793121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio private static final char CHAR_NEW_LINE = '\n'; 794121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio 795121c82c8130c2658f73fb19f3a62eb88c8679968Fabrice Di Meglio private static final double EXTRA_ROUNDING = 0.5; 796cb332649e44db86ff8b4e7f006db4bbfd82fed55Fabrice Di Meglio 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 798e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * This is reused across calls to generate() 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 800e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt private MeasuredText mMeasured; 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt(); 802c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 803c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // This is used to return three arrays from a single JNI call when 804c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // performing line breaking 8057053919a3a55ad1b58e6db701afda18850037732Deepanshu Gupta /*package*/ static class LineBreaks { 806c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye private static final int INITIAL_SIZE = 16; 807c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye public int[] breaks = new int[INITIAL_SIZE]; 808c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye public float[] widths = new float[INITIAL_SIZE]; 809c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye public boolean[] flags = new boolean[INITIAL_SIZE]; // hasTabOrEmoji 810c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye // breaks, widths, and flags should all have the same length 811c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye } 812c8f9e6218681640d5f384c12edf06619be56a583Anish Athalye 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 814