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
19e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.graphics.Paint;
20e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.text.style.MetricAffectingSpan;
21e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.text.style.ReplacementSpan;
22e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltimport android.util.Log;
23e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
249a3a8848643faf477335675136efba9a6e58db75Gilles Debunneimport com.android.internal.util.ArrayUtils;
259a3a8848643faf477335675136efba9a6e58db75Gilles Debunne
26e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt/**
27e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt * @hide
28e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt */
29e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Feltclass MeasuredText {
30fbc8630736d12676edc16f3932231713e23dd1dfKenny Root    private static final boolean localLOGV = false;
31e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    CharSequence mText;
32e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    int mTextStart;
33e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    float[] mWidths;
34e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    char[] mChars;
35e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    byte[] mLevels;
36e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    int mDir;
37e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    boolean mEasy;
38e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy    int mLen;
39e5ea4403ce58982522554b7ff23f41e6551923c1Romain Guy
40e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    private int mPos;
41e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    private TextPaint mWorkPaint;
4270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    private StaticLayout.Builder mBuilder;
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];
49d4f4526cb4bfa343714dbb63b82c82798db5a4e0Brian Carlstrom    private static final 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) {
70d3ab692d28018825578ff05832644cfad60233fbRaph Levien        mt.finish();
71d3ab692d28018825578ff05832644cfad60233fbRaph Levien        synchronized(sLock) {
72d3ab692d28018825578ff05832644cfad60233fbRaph Levien            for (int i = 0; i < sCached.length; ++i) {
73d3ab692d28018825578ff05832644cfad60233fbRaph Levien                if (sCached[i] == null) {
74d3ab692d28018825578ff05832644cfad60233fbRaph Levien                    sCached[i] = mt;
75d3ab692d28018825578ff05832644cfad60233fbRaph Levien                    mt.mText = null;
76d3ab692d28018825578ff05832644cfad60233fbRaph Levien                    break;
77e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
78e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
79e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
80e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return null;
81e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
82e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
83d3ab692d28018825578ff05832644cfad60233fbRaph Levien    void finish() {
84d3ab692d28018825578ff05832644cfad60233fbRaph Levien        mText = null;
8570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        mBuilder = null;
86d3ab692d28018825578ff05832644cfad60233fbRaph Levien        if (mLen > 1000) {
87d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mWidths = null;
88d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mChars = null;
89d3ab692d28018825578ff05832644cfad60233fbRaph Levien            mLevels = null;
90d3ab692d28018825578ff05832644cfad60233fbRaph Levien        }
91d3ab692d28018825578ff05832644cfad60233fbRaph Levien    }
92d3ab692d28018825578ff05832644cfad60233fbRaph Levien
93cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne    void setPos(int pos) {
941341ab6f3808d8c11b147f82bc7735116c7d709fRaph Levien        mPos = pos - mTextStart;
95cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne    }
96cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne
97e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    /**
980c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt     * Analyzes text for bidirectional runs.  Allocates working buffers.
99e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt     */
10070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien    void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir,
10170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            StaticLayout.Builder builder) {
10270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        mBuilder = builder;
103e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mText = text;
104e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mTextStart = start;
105e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
106e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int len = end - start;
107e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mLen = len;
108e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        mPos = 0;
109e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
110e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (mWidths == null || mWidths.length < len) {
111776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            mWidths = ArrayUtils.newUnpaddedFloatArray(len);
112e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
113e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (mChars == null || mChars.length < len) {
114776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            mChars = ArrayUtils.newUnpaddedCharArray(len);
115e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
116e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        TextUtils.getChars(text, start, end, mChars, 0);
117e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
118e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (text instanceof Spanned) {
119e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            Spanned spanned = (Spanned) text;
120e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            ReplacementSpan[] spans = spanned.getSpans(start, end,
121e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    ReplacementSpan.class);
122e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
123e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            for (int i = 0; i < spans.length; i++) {
124e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                int startInPara = spanned.getSpanStart(spans[i]) - start;
125e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                int endInPara = spanned.getSpanEnd(spans[i]) - start;
126ba3634f35523224d9b4238dbd0b9b5e0cf3b0b9bGilles Debunne                // The span interval may be larger and must be restricted to [start, end[
127ba3634f35523224d9b4238dbd0b9b5e0cf3b0b9bGilles Debunne                if (startInPara < 0) startInPara = 0;
128ba3634f35523224d9b4238dbd0b9b5e0cf3b0b9bGilles Debunne                if (endInPara > len) endInPara = len;
129e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                for (int j = startInPara; j < endInPara; j++) {
130cd943a7a013952af9b7286fd506fd63bf0993ac1Gilles Debunne                    mChars[j] = '\uFFFC'; // object replacement character
131e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
132e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
133e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
134e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
135cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt        if ((textDir == TextDirectionHeuristics.LTR ||
136cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
137cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
138cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                TextUtils.doesNotNeedBidi(mChars, 0, len)) {
1390c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            mDir = Layout.DIR_LEFT_TO_RIGHT;
140e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mEasy = true;
141e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        } else {
142e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (mLevels == null || mLevels.length < len) {
143776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski                mLevels = ArrayUtils.newUnpaddedByteArray(len);
144e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
145cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            int bidiRequest;
146cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            if (textDir == TextDirectionHeuristics.LTR) {
147cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_LTR;
148cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else if (textDir == TextDirectionHeuristics.RTL) {
149cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_RTL;
150cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
151cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
152cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
153cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
154cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            } else {
155cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                boolean isRtl = textDir.isRtl(mChars, 0, len);
156cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt                bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
157cb379120456d8065d742021fc5c66748fc8a11a8Doug Felt            }
158e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false);
159e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            mEasy = false;
160e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
161e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
162e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
163e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
1640c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        if (fm != null) {
1650c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            paint.getFontMetricsInt(fm);
1660c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        }
1670c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt
168e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        int p = mPos;
1690c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        mPos = p + len;
1700c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt
17170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        // try to do widths measurement in native code, but use Java if paint has been subclassed
17270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        // FIXME: may want to eliminate special case for subclass
17370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        float[] widths = null;
17470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        if (mBuilder == null || paint.getClass() != TextPaint.class) {
17570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            widths = mWidths;
17670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien        }
1770c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        if (mEasy) {
178051910b9f998030dacb8a0722588cc715813fde1Raph Levien            boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
17970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            float width = 0;
18070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            if (widths != null) {
18170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                width = paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, widths, p);
18270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                if (mBuilder != null) {
18370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    mBuilder.addMeasuredRun(p, p + len, widths);
18470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                }
18570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            } else {
18670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                width = mBuilder.addStyleRun(paint, p, p + len, isRtl);
18770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            }
18870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            return width;
1890c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        }
1900c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt
1910c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        float totalAdvance = 0;
1920c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        int level = mLevels[p];
1930c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        for (int q = p, i = p + 1, e = p + len;; ++i) {
1940c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt            if (i == e || mLevels[i] != level) {
195051910b9f998030dacb8a0722588cc715813fde1Raph Levien                boolean isRtl = (level & 0x1) != 0;
19670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                if (widths != null) {
19770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    totalAdvance +=
19870616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                            paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, widths, q);
19970616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    if (mBuilder != null) {
20070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                        mBuilder.addMeasuredRun(q, i, widths);
20170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    }
20270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                } else {
20370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    totalAdvance += mBuilder.addStyleRun(paint, q, i, isRtl);
20470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                }
2050c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                if (i == e) {
2060c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                    break;
207e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                }
2080c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                q = i;
2090c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt                level = mLevels[i];
210e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
211e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
2120c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt        return totalAdvance;
213e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
214e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
215e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
216e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            Paint.FontMetricsInt fm) {
217e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
218e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        TextPaint workPaint = mWorkPaint;
219e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        workPaint.set(paint);
220e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        // XXX paint should not have a baseline shift, but...
221e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        workPaint.baselineShift = 0;
222e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
223e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        ReplacementSpan replacement = null;
224e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        for (int i = 0; i < spans.length; i++) {
225e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            MetricAffectingSpan span = spans[i];
226e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (span instanceof ReplacementSpan) {
227e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                replacement = (ReplacementSpan)span;
228e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            } else {
229e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                span.updateMeasureState(workPaint);
230e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
231e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
232e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
233e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float wid;
234e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (replacement == null) {
235e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            wid = addStyleRun(workPaint, len, fm);
236e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        } else {
237e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            // Use original text.  Shouldn't matter.
238e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
239e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                    mTextStart + mPos + len, fm);
24070616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            if (mBuilder == null) {
24170616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                float[] w = mWidths;
24270616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                w[mPos] = wid;
24370616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                for (int i = mPos + 1, e = mPos + len; i < e; i++)
24470616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                    w[i] = 0;
24570616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            } else {
24670616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien                mBuilder.addReplacementRun(mPos, mPos + len, wid);
24770616ecd22fafccf2fab7565ccfbb3b5f91c5580Raph Levien            }
2489a3a8848643faf477335675136efba9a6e58db75Gilles Debunne            mPos += len;
249e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
250e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
251e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (fm != null) {
252e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            if (workPaint.baselineShift < 0) {
253e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.ascent += workPaint.baselineShift;
254e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.top += workPaint.baselineShift;
255e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            } else {
256e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.descent += workPaint.baselineShift;
257e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt                fm.bottom += workPaint.baselineShift;
258e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
259e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
260e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
261e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return wid;
262e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
263e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
264c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne    int breakText(int limit, boolean forwards, float width) {
265e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float[] w = mWidths;
266e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        if (forwards) {
267c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            int i = 0;
268c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i < limit) {
269c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                width -= w[i];
270c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                if (width < 0.0f) break;
271c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                i++;
272e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
273c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i > 0 && mChars[i - 1] == ' ') i--;
274c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            return i;
275e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        } else {
276c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            int i = limit - 1;
277c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            while (i >= 0) {
278c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                width -= w[i];
279c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                if (width < 0.0f) break;
280c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne                i--;
281e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            }
28282d1c443330785ae9561393880b92cbc44de7db2Keisuke Kuroyanagi            while (i < limit - 1 && (mChars[i + 1] == ' ' || w[i + 1] == 0.0f)) {
28382d1c443330785ae9561393880b92cbc44de7db2Keisuke Kuroyanagi                i++;
28482d1c443330785ae9561393880b92cbc44de7db2Keisuke Kuroyanagi            }
285c70e7a0b8add16d2e6cec4d58c3cc74d08cc20b4Gilles Debunne            return limit - i - 1;
286e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
287e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
288e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt
289e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    float measure(int start, int limit) {
290e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float width = 0;
291e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        float[] w = mWidths;
292e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        for (int i = start; i < limit; ++i) {
293e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt            width += w[i];
294e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        }
295e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt        return width;
296e8e45f2c05cb3b6d23f30c8f96d8e0b3699cea7aDoug Felt    }
297fbc8630736d12676edc16f3932231713e23dd1dfKenny Root}
298