1e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt/*
2e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * Copyright (C) 2010 The Android Open Source Project
3e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt *
4e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * Licensed under the Apache License, Version 2.0 (the "License");
5e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * you may not use this file except in compliance with the License.
6e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * You may obtain a copy of the License at
7e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt *
8e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt *      http://www.apache.org/licenses/LICENSE-2.0
9e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt *
10e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * Unless required by applicable law or agreed to in writing, software
11e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * distributed under the License is distributed on an "AS IS" BASIS,
12e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * See the License for the specific language governing permissions and
14e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * limitations under the License.
15e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt */
16e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
17e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltpackage android.text;
18e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
190c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Feltimport android.graphics.Canvas;
20e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.graphics.Paint;
21e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.text.style.MetricAffectingSpan;
22e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.text.style.ReplacementSpan;
23e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.util.Log;
24e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
259a3a8848643faf477335675136efba9a6e58db75Gilles Debunneimport com.android.internal.util.ArrayUtils;
269a3a8848643faf477335675136efba9a6e58db75Gilles Debunne
27e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt/**
28e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * @hide
29e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt */
30e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltclass MeasuredText {
31fbc8630736d12676edc16f3932231713e23dd1dfKenny Root    private static final boolean localLOGV = false;
32e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    CharSequence mText;
33e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    int mTextStart;
34e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    float[] mWidths;
35e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    char[] mChars;
36e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    byte[] mLevels;
37e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    int mDir;
38e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    boolean mEasy;
39e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    int mLen;
40e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy
41e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    private int mPos;
42e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    private TextPaint mWorkPaint;
43e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
44e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    private MeasuredText() {
45e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mWorkPaint = new TextPaint();
46e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
47e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
48e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    private static final Object[] sLock = new Object[0];
49e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    private static MeasuredText[] sCached = new MeasuredText[3];
50e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
51e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    static MeasuredText obtain() {
52e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        MeasuredText mt;
53e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy        synchronized (sLock) {
54e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy            for (int i = sCached.length; --i >= 0;) {
55e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                if (sCached[i] != null) {
56e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                    mt = sCached[i];
57e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                    sCached[i] = null;
58e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    return mt;
59e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
60e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
61e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
62e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mt = new MeasuredText();
63fbc8630736d12676edc16f3932231713e23dd1dfKenny Root        if (localLOGV) {
64fbc8630736d12676edc16f3932231713e23dd1dfKenny Root            Log.v("MEAS", "new: " + mt);
65fbc8630736d12676edc16f3932231713e23dd1dfKenny Root        }
66e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return mt;
67e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
68e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
69e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    static MeasuredText recycle(MeasuredText mt) {
70e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mt.mText = null;
71e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (mt.mLen < 1000) {
72e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy            synchronized(sLock) {
73e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                for (int i = 0; i < sCached.length; ++i) {
74e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                    if (sCached[i] == null) {
75e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                        sCached[i] = mt;
76e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy                        mt.mText = null;
77e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                        break;
78e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    }
79e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
80e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
81e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
82e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return null;
83e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
84e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
85cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne    void setPos(int pos) {
861341ab6f3808d8c11b147f82bc7735116c7d709fRaph Levien        mPos = pos - mTextStart;
87cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne    }
88cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne
89e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    /**
900c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt     * Analyzes text for bidirectional runs.  Allocates working buffers.
91e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt     */
92cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
93e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mText = text;
94e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mTextStart = start;
95e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
96e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int len = end - start;
97e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mLen = len;
98e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mPos = 0;
99e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
100e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (mWidths == null || mWidths.length < len) {
101e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mWidths = new float[ArrayUtils.idealFloatArraySize(len)];
102e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
103e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (mChars == null || mChars.length < len) {
104e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mChars = new char[ArrayUtils.idealCharArraySize(len)];
105e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
106e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        TextUtils.getChars(text, start, end, mChars, 0);
107e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
108e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (text instanceof Spanned) {
109e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            Spanned spanned = (Spanned) text;
110e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            ReplacementSpan[] spans = spanned.getSpans(start, end,
111e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    ReplacementSpan.class);
112e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
113e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            for (int i = 0; i < spans.length; i++) {
114e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                int startInPara = spanned.getSpanStart(spans[i]) - start;
115e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                int endInPara = spanned.getSpanEnd(spans[i]) - start;
116ba3634f35523224d9b4238dbd0b9b5e0cf3b0b9bGilles Debunne                // The span interval may be larger and must be restricted to [start, end[
117ba3634f35523224d9b4238dbd0b9b5e0cf3b0b9bGilles Debunne                if (startInPara < 0) startInPara = 0;
118ba3634f35523224d9b4238dbd0b9b5e0cf3b0b9bGilles Debunne                if (endInPara > len) endInPara = len;
119e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                for (int j = startInPara; j < endInPara; j++) {
120cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    mChars[j] = '\uFFFC'; // object replacement character
121e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
122e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
123e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
124e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
125cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        if ((textDir == TextDirectionHeuristics.LTR ||
126cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
127cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
128cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                TextUtils.doesNotNeedBidi(mChars, 0, len)) {
1290c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            mDir = Layout.DIR_LEFT_TO_RIGHT;
130e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mEasy = true;
131e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        } else {
132e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (mLevels == null || mLevels.length < len) {
133e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                mLevels = new byte[ArrayUtils.idealByteArraySize(len)];
134e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
135cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            int bidiRequest;
136cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            if (textDir == TextDirectionHeuristics.LTR) {
137cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_LTR;
138cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else if (textDir == TextDirectionHeuristics.RTL) {
139cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_RTL;
140cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
141cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
142cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
143cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
144cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else {
145cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                boolean isRtl = textDir.isRtl(mChars, 0, len);
146cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
147cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
148e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false);
149e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mEasy = false;
150e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
151e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
152e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
153e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
1540c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        if (fm != null) {
1550c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            paint.getFontMetricsInt(fm);
1560c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        }
1570c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt
158e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int p = mPos;
1590c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        mPos = p + len;
1600c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt
1610c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        if (mEasy) {
1620c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            int flags = mDir == Layout.DIR_LEFT_TO_RIGHT
1630c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
1640c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p);
1650c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        }
1660c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt
1670c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        float totalAdvance = 0;
1680c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        int level = mLevels[p];
1690c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        for (int q = p, i = p + 1, e = p + len;; ++i) {
1700c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            if (i == e || mLevels[i] != level) {
1710c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL;
1720c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                totalAdvance +=
1730c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                        paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q);
1740c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                if (i == e) {
1750c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                    break;
176e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
1770c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                q = i;
1780c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                level = mLevels[i];
179e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
180e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
1810c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        return totalAdvance;
182e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
183e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
184e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
185e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            Paint.FontMetricsInt fm) {
186e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
187e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        TextPaint workPaint = mWorkPaint;
188e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        workPaint.set(paint);
189e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        // XXX paint should not have a baseline shift, but...
190e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        workPaint.baselineShift = 0;
191e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
192e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        ReplacementSpan replacement = null;
193e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        for (int i = 0; i < spans.length; i++) {
194e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            MetricAffectingSpan span = spans[i];
195e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (span instanceof ReplacementSpan) {
196e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                replacement = (ReplacementSpan)span;
197e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            } else {
198e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                span.updateMeasureState(workPaint);
199e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
200e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
201e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
202e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float wid;
203e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (replacement == null) {
204e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            wid = addStyleRun(workPaint, len, fm);
205e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        } else {
206e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            // Use original text.  Shouldn't matter.
207e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
208e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    mTextStart + mPos + len, fm);
209e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            float[] w = mWidths;
210e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            w[mPos] = wid;
211e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            for (int i = mPos + 1, e = mPos + len; i < e; i++)
212e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                w[i] = 0;
2139a3a8848643faf477335675136efba9a6e58db75Gilles Debunne            mPos += len;
214e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
215e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
216e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (fm != null) {
217e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (workPaint.baselineShift < 0) {
218e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.ascent += workPaint.baselineShift;
219e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.top += workPaint.baselineShift;
220e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            } else {
221e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.descent += workPaint.baselineShift;
222e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.bottom += workPaint.baselineShift;
223e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
224e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
225e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
226e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return wid;
227e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
228e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
229c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne    int breakText(int limit, boolean forwards, float width) {
230e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float[] w = mWidths;
231e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (forwards) {
232c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            int i = 0;
233c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i < limit) {
234c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                width -= w[i];
235c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                if (width < 0.0f) break;
236c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                i++;
237e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
238c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i > 0 && mChars[i - 1] == ' ') i--;
239c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            return i;
240e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        } else {
241c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            int i = limit - 1;
242c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i >= 0) {
243c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                width -= w[i];
244c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                if (width < 0.0f) break;
245c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                i--;
246e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
247c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i < limit - 1 && mChars[i + 1] == ' ') i++;
248c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            return limit - i - 1;
249e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
250e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
251e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
252e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    float measure(int start, int limit) {
253e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float width = 0;
254e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float[] w = mWidths;
255e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        for (int i = start; i < limit; ++i) {
256e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            width += w[i];
257e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
258e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return width;
259e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
260fbc8630736d12676edc16f3932231713e23dd1dfKenny Root}
261