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