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 com.android.internal.util.ArrayUtils;
20776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport com.android.internal.util.GrowingArrayUtils;
21776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski
22776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport libcore.util.EmptyArray;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Array;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* package */ abstract class SpannableStringInternal
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ SpannableStringInternal(CharSequence source,
293483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                                          int start, int end, boolean ignoreNoCopySpan) {
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start == 0 && end == source.length())
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mText = source.toString();
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        else
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mText = source.toString().substring(start, end);
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mSpans = EmptyArray.OBJECT;
36575284af7c1370bd732e3db77ff55f0b57566d91Raph Levien        // Invariant: mSpanData.length = mSpans.length * COLUMNS
37776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski        mSpanData = EmptyArray.INT;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (source instanceof Spanned) {
40fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            if (source instanceof SpannableStringInternal) {
413483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                copySpans((SpannableStringInternal) source, start, end, ignoreNoCopySpan);
42fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            } else {
433483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                copySpans((Spanned) source, start, end, ignoreNoCopySpan);
44fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            }
45fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        }
46fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    }
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
48fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    /**
493483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     * This unused method is left since this is listed in hidden api list.
503483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     *
513483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     * Due to backward compatibility reasons, we copy even NoCopySpan by default
523483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     */
533483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    /* package */ SpannableStringInternal(CharSequence source, int start, int end) {
543483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        this(source, start, end, false /* ignoreNoCopySpan */);
553483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    }
563483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
573483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    /**
58fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * Copies another {@link Spanned} object's spans between [start, end] into this object.
59fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     *
60fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @param src Source object to copy from.
61fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @param start Start index in the source object.
62fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @param end End index in the source object.
633483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     * @param ignoreNoCopySpan whether to copy NoCopySpans in the {@code source}
64fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     */
653483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    private void copySpans(Spanned src, int start, int end, boolean ignoreNoCopySpan) {
66fa4a02c13f29a6d378e02015c2407eba283827c0Siyamed Sinir        Object[] spans = src.getSpans(start, end, Object.class);
67fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir
68fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        for (int i = 0; i < spans.length; i++) {
693483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            if (ignoreNoCopySpan && spans[i] instanceof NoCopySpan) {
703483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                continue;
713483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            }
72fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            int st = src.getSpanStart(spans[i]);
73fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            int en = src.getSpanEnd(spans[i]);
74fa4a02c13f29a6d378e02015c2407eba283827c0Siyamed Sinir            int fl = src.getSpanFlags(spans[i]);
75fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir
76fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            if (st < start)
77fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                st = start;
78fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            if (en > end)
79fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                en = end;
80fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir
81a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir            setSpan(spans[i], st - start, en - start, fl, false/*enforceParagraph*/);
82fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        }
83fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    }
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
85fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    /**
86fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * Copies a {@link SpannableStringInternal} object's spans between [start, end] into this
87fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * object.
88fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     *
89fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @param src Source object to copy from.
90fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @param start Start index in the source object.
91fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @param end End index in the source object.
923483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     * @param ignoreNoCopySpan copy NoCopySpan for backward compatible reasons.
93fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     */
943483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    private void copySpans(SpannableStringInternal src, int start, int end,
953483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            boolean ignoreNoCopySpan) {
963483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        int count = 0;
973483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        final int[] srcData = src.mSpanData;
983483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        final Object[] srcSpans = src.mSpans;
993483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        final int limit = src.mSpanCount;
1003483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        boolean hasNoCopySpan = false;
1013483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
1023483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        for (int i = 0; i < limit; i++) {
1033483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            int spanStart = srcData[i * COLUMNS + START];
1043483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            int spanEnd = srcData[i * COLUMNS + END];
1053483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            if (isOutOfCopyRange(start, end, spanStart, spanEnd)) continue;
1063483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            if (srcSpans[i] instanceof NoCopySpan) {
1073483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                hasNoCopySpan = true;
1083483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                if (ignoreNoCopySpan) {
1093483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                    continue;
1103483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                }
1113483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            }
1123483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka            count++;
1133483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        }
1143483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
1153483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        if (count == 0) return;
1163483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
1173483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        if (!hasNoCopySpan && start == 0 && end == src.length()) {
118fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            mSpans = ArrayUtils.newUnpaddedObjectArray(src.mSpans.length);
119fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            mSpanData = new int[src.mSpanData.length];
120fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            mSpanCount = src.mSpanCount;
121fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            System.arraycopy(src.mSpans, 0, mSpans, 0, src.mSpans.length);
122fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            System.arraycopy(src.mSpanData, 0, mSpanData, 0, mSpanData.length);
123fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        } else {
124fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            mSpanCount = count;
125fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            mSpans = ArrayUtils.newUnpaddedObjectArray(mSpanCount);
126575284af7c1370bd732e3db77ff55f0b57566d91Raph Levien            mSpanData = new int[mSpans.length * COLUMNS];
127fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            for (int i = 0, j = 0; i < limit; i++) {
128fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                int spanStart = srcData[i * COLUMNS + START];
129fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                int spanEnd = srcData[i * COLUMNS + END];
1303483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                if (isOutOfCopyRange(start, end, spanStart, spanEnd)
1313483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                        || (ignoreNoCopySpan && srcSpans[i] instanceof NoCopySpan)) {
1323483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                    continue;
1333483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka                }
134fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                if (spanStart < start) spanStart = start;
135fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                if (spanEnd > end) spanEnd = end;
136fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir
137fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                mSpans[j] = srcSpans[i];
138fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                mSpanData[j * COLUMNS + START] = spanStart - start;
139fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                mSpanData[j * COLUMNS + END] = spanEnd - start;
140fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                mSpanData[j * COLUMNS + FLAGS] = srcData[i * COLUMNS + FLAGS];
141fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir                j++;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
146fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    /**
147fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * Checks if [spanStart, spanEnd] interval is excluded from [start, end].
148fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     *
149fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     * @return True if excluded, false if included.
150fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir     */
151fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    private final boolean isOutOfCopyRange(int start, int end, int spanStart, int spanEnd) {
152fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        if (spanStart > end || spanEnd < start) return true;
153fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        if (spanStart != spanEnd && start != end) {
154fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            if (spanStart == end || spanEnd == start) return true;
155fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        }
156fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir        return false;
157fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir    }
158fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final int length() {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mText.length();
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final char charAt(int i) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mText.charAt(i);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final String toString() {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mText;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* subclasses must do subSequence() to preserve type */
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public final void getChars(int start, int end, char[] dest, int off) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mText.getChars(start, end, dest, off);
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ void setSpan(Object what, int start, int end, int flags) {
178a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir        setSpan(what, start, end, flags, true/*enforceParagraph*/);
179a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir    }
180a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir
181a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir    private boolean isIndexFollowsNextLine(int index) {
182a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir        return index != 0 && index != length() && charAt(index - 1) != '\n';
183a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir    }
184a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir
185a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir    private void setSpan(Object what, int start, int end, int flags, boolean enforceParagraph) {
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int nstart = start;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int nend = end;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkRange("setSpan", start, end);
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & Spannable.SPAN_PARAGRAPH) == Spannable.SPAN_PARAGRAPH) {
192a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir            if (isIndexFollowsNextLine(start)) {
193a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                if (!enforceParagraph) {
194a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                    // do not set the span
195a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                    return;
196a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                }
197a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                throw new RuntimeException("PARAGRAPH span must start at paragraph boundary"
198a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                        + " (" + start + " follows " + charAt(start - 1) + ")");
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
201a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir            if (isIndexFollowsNextLine(end)) {
202a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                if (!enforceParagraph) {
203a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                    // do not set the span
204a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                    return;
205a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                }
206a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                throw new RuntimeException("PARAGRAPH span must end at paragraph boundary"
207a6284a20b590be2be52e207174d3d0a980c77180Siyamed Sinir                        + " (" + end + " follows " + charAt(end - 1) + ")");
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mSpanCount;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spans[i] == what) {
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int ostart = data[i * COLUMNS + START];
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int oend = data[i * COLUMNS + END];
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                data[i * COLUMNS + START] = start;
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                data[i * COLUMNS + END] = end;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                data[i * COLUMNS + FLAGS] = flags;
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sendSpanChanged(what, ostart, oend, nstart, nend);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSpanCount + 1 >= mSpans.length) {
230776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            Object[] newtags = ArrayUtils.newUnpaddedObjectArray(
231776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski                    GrowingArrayUtils.growSize(mSpanCount));
232776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski            int[] newdata = new int[newtags.length * 3];
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mSpans, 0, newtags, 0, mSpanCount);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mSpanData, 0, newdata, 0, mSpanCount * 3);
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSpans = newtags;
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSpanData = newdata;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpans[mSpanCount] = what;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpanData[mSpanCount * COLUMNS + START] = start;
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpanData[mSpanCount * COLUMNS + END] = end;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpanData[mSpanCount * COLUMNS + FLAGS] = flags;
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSpanCount++;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (this instanceof Spannable)
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sendSpanAdded(what, nstart, nend);
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ void removeSpan(Object what) {
2524e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri        removeSpan(what, 0 /* flags */);
2534e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri    }
2544e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri
2554e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri    /**
2564e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri     * @hide
2574e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri     */
2584e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri    public void removeSpan(Object what, int flags) {
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mSpanCount;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = count - 1; i >= 0; i--) {
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spans[i] == what) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int ostart = data[i * COLUMNS + START];
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int oend = data[i * COLUMNS + END];
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int c = count - (i + 1);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.arraycopy(spans, i + 1, spans, i, c);
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.arraycopy(data, (i + 1) * COLUMNS,
2724e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri                        data, i * COLUMNS, c * COLUMNS);
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSpanCount--;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2764e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri                if ((flags & Spanned.SPAN_INTERMEDIATE) == 0) {
2774e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri                    sendSpanRemoved(what, ostart, oend);
2784e51877f5cbdb4a92568dce50c2bdc381cfbe861Clara Bayarri                }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getSpanStart(Object what) {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mSpanCount;
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = count - 1; i >= 0; i--) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spans[i] == what) {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return data[i * COLUMNS + START];
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getSpanEnd(Object what) {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mSpanCount;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = count - 1; i >= 0; i--) {
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spans[i] == what) {
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return data[i * COLUMNS + END];
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return -1;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getSpanFlags(Object what) {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mSpanCount;
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = count - 1; i >= 0; i--) {
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spans[i] == what) {
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return data[i * COLUMNS + FLAGS];
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = 0;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int spanCount = mSpanCount;
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] ret = null;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object ret1 = null;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < spanCount; i++) {
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spanStart = data[i * COLUMNS + START];
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int spanEnd = data[i * COLUMNS + END];
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanStart > queryEnd) {
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanEnd < queryStart) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (spanStart != spanEnd && queryStart != queryEnd) {
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (spanStart == queryEnd) {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (spanEnd == queryStart) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
355fc121c2430cd27c0d9b655105a9ab1c261c10bdcChris Craik            // verify span class as late as possible, since it is expensive
356fa05ba0b0d39fae1d2cb3d98fbee0aef6a9fed88Siyamed Sinir            if (kind != null && kind != Object.class && !kind.isInstance(spans[i])) {
357fc121c2430cd27c0d9b655105a9ab1c261c10bdcChris Craik                continue;
358fc121c2430cd27c0d9b655105a9ab1c261c10bdcChris Craik            }
359fc121c2430cd27c0d9b655105a9ab1c261c10bdcChris Craik
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (count == 0) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ret1 = spans[i];
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count++;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (count == 1) {
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret = (Object[]) Array.newInstance(kind, spanCount - i + 1);
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret[0] = ret1;
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int prio = data[i * COLUMNS + FLAGS] & Spanned.SPAN_PRIORITY;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (prio != 0) {
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int j;
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (j = 0; j < count; j++) {
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int p = getSpanFlags(ret[j]) & Spanned.SPAN_PRIORITY;
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (prio > p) {
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            break;
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    System.arraycopy(ret, j, ret, j + 1, count - j);
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret[j] = spans[i];
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    count++;
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ret[count++] = spans[i];
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count == 0) {
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (T[]) ArrayUtils.emptyArray(kind);
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count == 1) {
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ret = (Object[]) Array.newInstance(kind, 1);
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ret[0] = ret1;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (T[]) ret;
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count == ret.length) {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return (T[]) ret;
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] nret = (Object[]) Array.newInstance(kind, count);
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.arraycopy(ret, 0, nret, 0, count);
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (T[]) nret;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int nextSpanTransition(int start, int limit, Class kind) {
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mSpanCount;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object[] spans = mSpans;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] data = mSpanData;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (kind == null) {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            kind = Object.class;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < count; i++) {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int st = data[i * COLUMNS + START];
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int en = data[i * COLUMNS + END];
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (st > start && st < limit && kind.isInstance(spans[i]))
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                limit = st;
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (en > start && en < limit && kind.isInstance(spans[i]))
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                limit = en;
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return limit;
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendSpanAdded(Object what, int start, int end) {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int n = recip.length;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < n; i++) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            recip[i].onSpanAdded((Spannable) this, what, start, end);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendSpanRemoved(Object what, int start, int end) {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class);
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int n = recip.length;
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < n; i++) {
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            recip[i].onSpanRemoved((Spannable) this, what, start, end);
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void sendSpanChanged(Object what, int s, int e, int st, int en) {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SpanWatcher[] recip = getSpans(Math.min(s, st), Math.max(e, en),
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                       SpanWatcher.class);
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int n = recip.length;
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < n; i++) {
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            recip[i].onSpanChanged((Spannable) this, what, s, e, st, en);
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String region(int start, int end) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return "(" + start + " ... " + end + ")";
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkRange(final String operation, int start, int end) {
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (end < start) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException(operation + " " +
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                region(start, end) +
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                " has end before start");
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = length();
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start > len || end > len) {
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException(operation + " " +
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                region(start, end) +
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                " ends beyond length " + len);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (start < 0 || end < 0) {
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IndexOutOfBoundsException(operation + " " +
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                region(start, end) +
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                " starts before 0");
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    // Same as SpannableStringBuilder
4849b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    @Override
4859b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    public boolean equals(Object o) {
4869b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        if (o instanceof Spanned &&
4879b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                toString().equals(o.toString())) {
4881d3c4b396a393515e738cb72782ef564362420faChet Haase            Spanned other = (Spanned) o;
4899b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            // Check span data
4901d3c4b396a393515e738cb72782ef564362420faChet Haase            Object[] otherSpans = other.getSpans(0, other.length(), Object.class);
4919b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            if (mSpanCount == otherSpans.length) {
4929b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                for (int i = 0; i < mSpanCount; ++i) {
4939b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                    Object thisSpan = mSpans[i];
4949b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                    Object otherSpan = otherSpans[i];
4951d3c4b396a393515e738cb72782ef564362420faChet Haase                    if (thisSpan == this) {
4961d3c4b396a393515e738cb72782ef564362420faChet Haase                        if (other != otherSpan ||
4971d3c4b396a393515e738cb72782ef564362420faChet Haase                                getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
4981d3c4b396a393515e738cb72782ef564362420faChet Haase                                getSpanEnd(thisSpan) != other.getSpanEnd(otherSpan) ||
4991d3c4b396a393515e738cb72782ef564362420faChet Haase                                getSpanFlags(thisSpan) != other.getSpanFlags(otherSpan)) {
5001d3c4b396a393515e738cb72782ef564362420faChet Haase                            return false;
5011d3c4b396a393515e738cb72782ef564362420faChet Haase                        }
5021d3c4b396a393515e738cb72782ef564362420faChet Haase                    } else if (!thisSpan.equals(otherSpan) ||
5031d3c4b396a393515e738cb72782ef564362420faChet Haase                            getSpanStart(thisSpan) != other.getSpanStart(otherSpan) ||
5041d3c4b396a393515e738cb72782ef564362420faChet Haase                            getSpanEnd(thisSpan) != other.getSpanEnd(otherSpan) ||
5051d3c4b396a393515e738cb72782ef564362420faChet Haase                            getSpanFlags(thisSpan) != other.getSpanFlags(otherSpan)) {
5069b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                        return false;
5079b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                    }
5089b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                }
5099b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase                return true;
5109b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            }
5119b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        }
5129b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        return false;
5139b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    }
5149b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase
5159b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    // Same as SpannableStringBuilder
5169b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    @Override
5179b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    public int hashCode() {
5189b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        int hash = toString().hashCode();
5199b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        hash = hash * 31 + mSpanCount;
5209b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        for (int i = 0; i < mSpanCount; ++i) {
5219b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            Object span = mSpans[i];
5221d3c4b396a393515e738cb72782ef564362420faChet Haase            if (span != this) {
5231d3c4b396a393515e738cb72782ef564362420faChet Haase                hash = hash * 31 + span.hashCode();
5241d3c4b396a393515e738cb72782ef564362420faChet Haase            }
5259b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            hash = hash * 31 + getSpanStart(span);
5269b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            hash = hash * 31 + getSpanEnd(span);
5279b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase            hash = hash * 31 + getSpanFlags(span);
5289b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        }
5299b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase        return hash;
5309b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase    }
5319b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase
5323483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    /**
5333483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     * Following two unused methods are left since these are listed in hidden api list.
5343483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     *
5353483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     * Due to backward compatibility reasons, we copy even NoCopySpan by default
5363483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka     */
5373483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    private void copySpans(Spanned src, int start, int end) {
5383483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        copySpans(src, start, end, false);
5393483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    }
5403483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
5413483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    private void copySpans(SpannableStringInternal src, int start, int end) {
5423483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka        copySpans(src, start, end, false);
5433483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka    }
5443483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
5453483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
5463483bc7d648ad96916eb68203103dc9668dd0be7Seigo Nonaka
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mText;
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Object[] mSpans;
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mSpanData;
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mSpanCount;
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static final Object[] EMPTY = new Object[0];
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int START = 0;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int END = 1;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int FLAGS = 2;
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int COLUMNS = 3;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
559