19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas; 20f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Feltimport android.graphics.Paint; 2134ec2b54da52eeed39d9cf9e5f215650b447edd7Gilles Debunneimport android.util.Log; 226435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 236435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunneimport com.android.internal.util.ArrayUtils; 24776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport com.android.internal.util.GrowingArrayUtils; 25776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski 26776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinskiimport libcore.util.EmptyArray; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.reflect.Array; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is the class for text whose content and markup can both be changed. 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 336435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunnepublic class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable, 346435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne Appendable, GraphicsOperations { 3584a3320507aa2948098c4964cea68b818f76ff88Jean Chalard private final static String TAG = "SpannableStringBuilder"; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a new SpannableStringBuilder with empty contents 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder() { 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(""); 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a new SpannableStringBuilder containing a copy of the 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified text, including its spans if any. 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder(CharSequence text) { 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(text, 0, text.length()); 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a new SpannableStringBuilder containing a copy of the 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified slice of the specified text, including its spans if any. 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder(CharSequence text, int start, int end) { 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int srclen = end - start; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 580249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (srclen < 0) throw new StringIndexOutOfBoundsException(); 590249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne 60776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mText = ArrayUtils.newUnpaddedCharArray(GrowingArrayUtils.growSize(srclen)); 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGapStart = srclen; 62776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mGapLength = mText.length - srclen; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.getChars(text, start, end, mText, 0); 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanCount = 0; 67776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpans = EmptyArray.OBJECT; 68776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpanStarts = EmptyArray.INT; 69776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpanEnds = EmptyArray.INT; 70776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpanFlags = EmptyArray.INT; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (text instanceof Spanned) { 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned sp = (Spanned) text; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = sp.getSpans(start, end, Object.class); 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < spans.length; i++) { 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[i] instanceof NoCopySpan) { 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 80174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int st = sp.getSpanStart(spans[i]) - start; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int en = sp.getSpanEnd(spans[i]) - start; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fl = sp.getSpanFlags(spans[i]); 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (st < 0) 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project st = 0; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (st > end - start) 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project st = end - start; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (en < 0) 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project en = 0; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (en > end - start) 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project en = end - start; 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 950249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne setSpan(false, spans[i], st, en, fl); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static SpannableStringBuilder valueOf(CharSequence source) { 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (source instanceof SpannableStringBuilder) { 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (SpannableStringBuilder) source; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SpannableStringBuilder(source); 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the char at the specified offset within the buffer. 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public char charAt(int where) { 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = length(); 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where < 0) { 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IndexOutOfBoundsException("charAt: " + where + " < 0"); 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (where >= len) { 1166435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne throw new IndexOutOfBoundsException("charAt: " + where + " >= length " + len); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where >= mGapStart) 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText[where + mGapLength]; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText[where]; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the number of chars in the buffer. 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int length() { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mText.length - mGapLength; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resizeFor(int size) { 1337c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne final int oldLength = mText.length; 134776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski if (size + 1 <= oldLength) { 135776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski return; 136776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski } 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 138776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski char[] newText = ArrayUtils.newUnpaddedCharArray(GrowingArrayUtils.growSize(size)); 1397c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne System.arraycopy(mText, 0, newText, 0, mGapStart); 140776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski final int newLength = newText.length; 141776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski final int delta = newLength - oldLength; 14290985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne final int after = oldLength - (mGapStart + mGapLength); 1437c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne System.arraycopy(mText, oldLength - after, newText, newLength - after, after); 1447c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne mText = newText; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1467c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne mGapLength += delta; 1477c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne if (mGapLength < 1) 1487c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne new Exception("mGapLength < 1").printStackTrace(); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mSpanCount; i++) { 1517c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta; 1527c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void moveGapTo(int where) { 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where == mGapStart) 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1600249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne boolean atEnd = (where == length()); 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where < mGapStart) { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int overlap = mGapStart - where; 1647c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne System.arraycopy(mText, where, mText, mGapStart + mGapLength - overlap, overlap); 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else /* where > mGapStart */ { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int overlap = where - mGapStart; 1677c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne System.arraycopy(mText, where + mGapLength - overlap, mText, mGapStart, overlap); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX be more clever 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mSpanCount; i++) { 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start = mSpanStarts[i]; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end = mSpanEnds[i]; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start > mGapStart) 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start -= mGapLength; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start > where) 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start += mGapLength; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (start == where) { 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1820249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flag == POINT || (atEnd && flag == PARAGRAPH)) 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start += mGapLength; 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end > mGapStart) 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end -= mGapLength; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end > where) 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end += mGapLength; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (end == where) { 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int flag = (mSpanFlags[i] & END_MASK); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1930249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flag == POINT || (atEnd && flag == PARAGRAPH)) 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end += mGapLength; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanStarts[i] = start; 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanEnds[i] = end; 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGapStart = where; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) { 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return replace(where, where, tb, start, end); 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder insert(int where, CharSequence tb) { 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return replace(where, where, tb, 0, tb.length()); 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder delete(int start, int end) { 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SpannableStringBuilder ret = replace(start, end, "", 0, 0); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mGapLength > 2 * length()) 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resizeFor(length()); 220174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; // == this 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clear() { 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project replace(0, length(), "", 0, 0); 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 228174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void clearSpans() { 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = mSpanCount - 1; i >= 0; i--) { 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object what = mSpans[i]; 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ostart = mSpanStarts[i]; 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oend = mSpanEnds[i]; 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ostart > mGapStart) 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ostart -= mGapLength; 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oend > mGapStart) 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oend -= mGapLength; 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanCount = i; 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpans[i] = null; 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sendSpanRemoved(what, ostart, oend); 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder append(CharSequence text) { 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = length(); 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return replace(length, length, text, 0, text.length()); 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 254ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts /** 255ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts * Appends the character sequence {@code text} and spans {@code what} over the appended part. 256ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts * See {@link Spanned} for an explanation of what the flags mean. 257ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts * @param text the character sequence to append. 258ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts * @param what the object to be spanned over the appended text. 259ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts * @param flags see {@link Spanned}. 260ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts * @return this {@code SpannableStringBuilder}. 261ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts */ 262ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts public SpannableStringBuilder append(CharSequence text, Object what, int flags) { 263ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts int start = length(); 264ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts append(text); 265ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts setSpan(what, start, length(), flags); 266ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts return this; 267ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts } 268ca7b0277d7721e5d531cb6abe3eb980d42891b7bNiels Egberts 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder append(CharSequence text, int start, int end) { 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = length(); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return replace(length, length, text, start, end); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder append(char text) { 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return append(String.valueOf(text)); 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 280174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private void change(int start, int end, CharSequence cs, int csStart, int csEnd) { 281174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // Can be negative 28226b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne final int replacedLength = end - start; 28326b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne final int replacementLength = csEnd - csStart; 28426b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne final int nbNewChars = replacementLength - replacedLength; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = mSpanCount - 1; i >= 0; i--) { 287174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanStart = mSpanStarts[i]; 288174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart > mGapStart) 289174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanStart -= mGapLength; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 291174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanEnd = mSpanEnds[i]; 292174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd > mGapStart) 293174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanEnd -= mGapLength; 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 295174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) { 296174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int ost = spanStart; 297174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int oen = spanEnd; 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int clen = length(); 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 300174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart > start && spanStart <= end) { 301174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne for (spanStart = end; spanStart < clen; spanStart++) 302174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart > end && charAt(spanStart - 1) == '\n') 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 306174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd > start && spanEnd <= end) { 307174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne for (spanEnd = end; spanEnd < clen; spanEnd++) 308174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd > end && charAt(spanEnd - 1) == '\n') 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 312174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart != ost || spanEnd != oen) 313174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne setSpan(false, mSpans[i], spanStart, spanEnd, mSpanFlags[i]); 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 315174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 316174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int flags = 0; 317174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart == start) flags |= SPAN_START_AT_START; 318174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne else if (spanStart == end + nbNewChars) flags |= SPAN_START_AT_END; 319174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd == start) flags |= SPAN_END_AT_START; 320174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne else if (spanEnd == end + nbNewChars) flags |= SPAN_END_AT_END; 321174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne mSpanFlags[i] |= flags; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project moveGapTo(end); 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 326312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne if (nbNewChars >= mGapLength) { 327312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne resizeFor(mText.length + nbNewChars - mGapLength); 328312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne } 329312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne 330e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne final boolean textIsRemoved = replacementLength == 0; 33190985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // The removal pass needs to be done before the gap is updated in order to broadcast the 33290985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // correct previous positions to the correct intersecting SpanWatchers 33326b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (replacedLength > 0) { // no need for span fixup on pure insertion 33490985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // A for loop will not work because the array is being modified 33590985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // Do not iterate in reverse to keep the SpanWatchers notified in ordering 33690985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // Also, a removed SpanWatcher should not get notified of removed spans located 33790985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // further in the span array. 33890985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne int i = 0; 33990985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne while (i < mSpanCount) { 34090985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) == 34190985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne Spanned.SPAN_EXCLUSIVE_EXCLUSIVE && 342e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength && 343e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength && 344e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne // This condition indicates that the span would become empty 345e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) { 34690985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne removeSpan(i); 347e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne continue; // do not increment i, spans will be shifted left in the array 34890985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne } 349e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne 350e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne i++; 35190985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne } 35290985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne } 35390985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne 354312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne mGapStart += nbNewChars; 355312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne mGapLength -= nbNewChars; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mGapLength < 1) 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Exception("mGapLength < 1").printStackTrace(); 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 360174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne TextUtils.getChars(cs, csStart, csEnd, mText, start); 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 36226b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (replacedLength > 0) { // no need for span fixup on pure insertion 36390985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne final boolean atEnd = (mGapStart + mGapLength == mText.length); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 36590985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne for (int i = 0; i < mSpanCount; i++) { 36626b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne final int startFlag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; 36726b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne mSpanStarts[i] = updatedIntervalBound(mSpanStarts[i], start, nbNewChars, startFlag, 36826b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne atEnd, textIsRemoved); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 37026b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne final int endFlag = (mSpanFlags[i] & END_MASK); 37126b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne mSpanEnds[i] = updatedIntervalBound(mSpanEnds[i], start, nbNewChars, endFlag, 37226b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne atEnd, textIsRemoved); 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3750249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne 376174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne mSpanCountBeforeAdd = mSpanCount; 377174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 378174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (cs instanceof Spanned) { 379174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne Spanned sp = (Spanned) cs; 380174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne Object[] spans = sp.getSpans(csStart, csEnd, Object.class); 3810249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne 3820249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne for (int i = 0; i < spans.length; i++) { 3830249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne int st = sp.getSpanStart(spans[i]); 3840249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne int en = sp.getSpanEnd(spans[i]); 3850249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne 386174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (st < csStart) st = csStart; 387174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (en > csEnd) en = csEnd; 3880249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne 3890249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne // Add span only if this object is not yet used as a span in this string 39090985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne if (getSpanStart(spans[i]) < 0) { 391174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne setSpan(false, spans[i], st - csStart + start, en - csStart + start, 392174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne sp.getSpanFlags(spans[i])); 3930249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne } 3940249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne } 3950249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne } 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 39826b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne private int updatedIntervalBound(int offset, int start, int nbNewChars, int flag, boolean atEnd, 39926b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne boolean textIsRemoved) { 40026b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (offset >= start && offset < mGapStart + mGapLength) { 40126b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (flag == POINT) { 40226b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne // A POINT located inside the replaced range should be moved to the end of the 40326b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne // replaced text. 40426b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne // The exception is when the point is at the start of the range and we are doing a 40526b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne // text replacement (as opposed to a deletion): the point stays there. 40626b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (textIsRemoved || offset > start) { 40726b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne return mGapStart + mGapLength; 40826b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 40926b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } else { 41026b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (flag == PARAGRAPH) { 41126b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (atEnd) { 41226b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne return mGapStart + mGapLength; 41326b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 41426b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } else { // MARK 415e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne // MARKs should be moved to the start, with the exception of a mark located at 416e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne // the end of the range (which will be < mGapStart + mGapLength since mGapLength 417e244868053cfe44742b42e75df3a08d0c5914bcaGilles Debunne // is > 0, which should stay 'unchanged' at the end of the replaced text. 41826b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne if (textIsRemoved || offset < mGapStart - nbNewChars) { 41926b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne return start; 42026b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } else { 42126b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne // Move to the end of replaced text (needed if nbNewChars != 0) 42226b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne return mGapStart; 42326b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 42426b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 42526b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 42626b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 42726b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne return offset; 42826b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne } 42926b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne 43075beb336f4b164c3bed5d4b91f0b9c6ea49a3437Gilles Debunne private void removeSpan(int i) { 4316435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne Object object = mSpans[i]; 4326435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 4336435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne int start = mSpanStarts[i]; 4346435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne int end = mSpanEnds[i]; 4356435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 4366435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne if (start > mGapStart) start -= mGapLength; 4376435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne if (end > mGapStart) end -= mGapLength; 4386435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 4396435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne int count = mSpanCount - (i + 1); 4406435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne System.arraycopy(mSpans, i + 1, mSpans, i, count); 4416435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne System.arraycopy(mSpanStarts, i + 1, mSpanStarts, i, count); 4426435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne System.arraycopy(mSpanEnds, i + 1, mSpanEnds, i, count); 4436435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne System.arraycopy(mSpanFlags, i + 1, mSpanFlags, i, count); 44475beb336f4b164c3bed5d4b91f0b9c6ea49a3437Gilles Debunne 44575beb336f4b164c3bed5d4b91f0b9c6ea49a3437Gilles Debunne mSpanCount--; 4466435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 4476435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne mSpans[mSpanCount] = null; 4486435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 4496435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne sendSpanRemoved(object, start, end); 45075beb336f4b164c3bed5d4b91f0b9c6ea49a3437Gilles Debunne } 45175beb336f4b164c3bed5d4b91f0b9c6ea49a3437Gilles Debunne 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SpannableStringBuilder replace(int start, int end, CharSequence tb) { 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return replace(start, end, tb, 0, tb.length()); 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 4580a993100f98e0cacaf6281214e6b54be9cd1f9fcJean Chalard public SpannableStringBuilder replace(final int start, final int end, 4590249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne CharSequence tb, int tbstart, int tbend) { 460174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne checkRange("replace", start, end); 461174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int filtercount = mFilters.length; 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < filtercount; i++) { 464b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end); 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (repl != null) { 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tb = repl; 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tbstart = 0; 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project tbend = repl.length(); 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 473b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne final int origLen = end - start; 474b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne final int newLen = tbend - tbstart; 475b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne 476d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne if (origLen == 0 && newLen == 0 && !hasNonExclusiveExclusiveSpanAt(tb, tbstart)) { 477d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne // This is a no-op iif there are no spans in tb that would be added (with a 0-length) 478d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne // Early exit so that the text watchers do not get notified 479d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne return this; 480d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne } 481d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne 482b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class); 483b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne sendBeforeTextChanged(textWatchers, start, origLen, newLen); 484b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne 4850249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne // Try to keep the cursor / selection at the same relative position during 4860249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne // a text replacement. If replaced or replacement text length is zero, this 4870249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne // is already taken care of. 4880249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne boolean adjustSelection = origLen != 0 && newLen != 0; 489174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int selectionStart = 0; 490174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int selectionEnd = 0; 4910249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (adjustSelection) { 492174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne selectionStart = Selection.getSelectionStart(this); 493174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne selectionEnd = Selection.getSelectionEnd(this); 4940249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne } 495bc6862300fe5675addfe4ed5d0c7c345aad463aaGilles Debunne 4960249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne change(start, end, tb, tbstart, tbend); 497bc6862300fe5675addfe4ed5d0c7c345aad463aaGilles Debunne 4980249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (adjustSelection) { 499174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (selectionStart > start && selectionStart < end) { 500174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne final int offset = (selectionStart - start) * newLen / origLen; 501174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne selectionStart = start + offset; 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 503174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne setSpan(false, Selection.SELECTION_START, selectionStart, selectionStart, 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Spanned.SPAN_POINT_POINT); 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 506174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (selectionEnd > start && selectionEnd < end) { 507174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne final int offset = (selectionEnd - start) * newLen / origLen; 508174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne selectionEnd = start + offset; 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 510174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd, 511174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne Spanned.SPAN_POINT_POINT); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5146435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 515b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne sendTextChanged(textWatchers, start, origLen, newLen); 516b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne sendAfterTextChanged(textWatchers); 517b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne 518174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // Span watchers need to be called after text watchers, which may update the layout 519174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne sendToSpanWatchers(start, end, newLen - origLen); 520174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 521051910b9f998030dacb8a0722588cc715813fde1Raph Levien return this; 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 524d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne private static boolean hasNonExclusiveExclusiveSpanAt(CharSequence text, int offset) { 525d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne if (text instanceof Spanned) { 526d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne Spanned spanned = (Spanned) text; 527d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne Object[] spans = spanned.getSpans(offset, offset, Object.class); 528d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne final int length = spans.length; 529d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne for (int i = 0; i < length; i++) { 530d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne Object span = spans[i]; 531d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne int flags = spanned.getSpanFlags(span); 532d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne if (flags != Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) return true; 533d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne } 534d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne } 535d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne return false; 536d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne } 537d60da058c6a9a63ef7347685f39a9dedebbc6afaGilles Debunne 538174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private void sendToSpanWatchers(int replaceStart, int replaceEnd, int nbNewChars) { 539174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne for (int i = 0; i < mSpanCountBeforeAdd; i++) { 540174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanStart = mSpanStarts[i]; 541174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanEnd = mSpanEnds[i]; 542174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart > mGapStart) spanStart -= mGapLength; 543174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd > mGapStart) spanEnd -= mGapLength; 544174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanFlags = mSpanFlags[i]; 545174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 546174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int newReplaceEnd = replaceEnd + nbNewChars; 547174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne boolean spanChanged = false; 54890985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne 549174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int previousSpanStart = spanStart; 550174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart > newReplaceEnd) { 551174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (nbNewChars != 0) { 552174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne previousSpanStart -= nbNewChars; 553174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanChanged = true; 554174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 555174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } else if (spanStart >= replaceStart) { 556174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // No change if span start was already at replace interval boundaries before replace 557174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if ((spanStart != replaceStart || 558174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne ((spanFlags & SPAN_START_AT_START) != SPAN_START_AT_START)) && 559174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne (spanStart != newReplaceEnd || 560174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne ((spanFlags & SPAN_START_AT_END) != SPAN_START_AT_END))) { 56190985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // TODO A correct previousSpanStart cannot be computed at this point. 56290985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // It would require to save all the previous spans' positions before the replace 56390985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne // Using an invalid -1 value to convey this would break the broacast range 564174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanChanged = true; 565174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 566174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 56790985286442340b9ad9433d6bf8d51702c8d0fd9Gilles Debunne 568174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int previousSpanEnd = spanEnd; 569174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd > newReplaceEnd) { 570174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (nbNewChars != 0) { 571174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne previousSpanEnd -= nbNewChars; 572174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanChanged = true; 573174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 574174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } else if (spanEnd >= replaceStart) { 575174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // No change if span start was already at replace interval boundaries before replace 576174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if ((spanEnd != replaceStart || 577174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne ((spanFlags & SPAN_END_AT_START) != SPAN_END_AT_START)) && 578174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne (spanEnd != newReplaceEnd || 579174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne ((spanFlags & SPAN_END_AT_END) != SPAN_END_AT_END))) { 580174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // TODO same as above for previousSpanEnd 581174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanChanged = true; 582174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 583174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 584174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 585174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanChanged) { 586174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne sendSpanChanged(mSpans[i], previousSpanStart, previousSpanEnd, spanStart, spanEnd); 587174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 588174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne mSpanFlags[i] &= ~SPAN_START_END_MASK; 589174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 590174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 591174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // The spans starting at mIntermediateSpanCount were added from the replacement text 592174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne for (int i = mSpanCountBeforeAdd; i < mSpanCount; i++) { 593174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanStart = mSpanStarts[i]; 594174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int spanEnd = mSpanEnds[i]; 595174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanStart > mGapStart) spanStart -= mGapLength; 596174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne if (spanEnd > mGapStart) spanEnd -= mGapLength; 597174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne sendSpanAdded(mSpans[i], spanStart, spanEnd); 598174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 599174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne } 600174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Mark the specified range of text with the specified object. 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The flags determine how the span will behave when text is 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * inserted at the start or end of the span's range. 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setSpan(Object what, int start, int end, int flags) { 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSpan(true, what, start, end, flags); 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6106435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne private void setSpan(boolean send, Object what, int start, int end, int flags) { 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange("setSpan", start, end); 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6130249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne int flagsStart = (flags & START_MASK) >> START_SHIFT; 6140249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flagsStart == PARAGRAPH) { 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start != 0 && start != length()) { 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = charAt(start - 1); 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != '\n') 6196435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne throw new RuntimeException("PARAGRAPH span must start at paragraph boundary"); 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6230249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne int flagsEnd = flags & END_MASK; 6240249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flagsEnd == PARAGRAPH) { 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end != 0 && end != length()) { 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char c = charAt(end - 1); 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != '\n') 6296435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne throw new RuntimeException("PARAGRAPH span must end at paragraph boundary"); 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6330249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 6340249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flagsStart == POINT && flagsEnd == MARK && start == end) { 63584a3320507aa2948098c4964cea68b818f76ff88Jean Chalard if (send) { 63684a3320507aa2948098c4964cea68b818f76ff88Jean Chalard Log.e(TAG, "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length"); 63784a3320507aa2948098c4964cea68b818f76ff88Jean Chalard } 63834ec2b54da52eeed39d9cf9e5f215650b447edd7Gilles Debunne // Silently ignore invalid spans when they are created from this class. 63934ec2b54da52eeed39d9cf9e5f215650b447edd7Gilles Debunne // This avoids the duplication of the above test code before all the 64034ec2b54da52eeed39d9cf9e5f215650b447edd7Gilles Debunne // calls to setSpan that are done in this class 64134ec2b54da52eeed39d9cf9e5f215650b447edd7Gilles Debunne return; 6427c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne } 6437c5f670bd698c984dcafea8125f4d3939bc42972Gilles Debunne 6440249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne int nstart = start; 6450249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne int nend = end; 6460249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne 6476435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne if (start > mGapStart) { 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start += mGapLength; 6496435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne } else if (start == mGapStart) { 6500249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flagsStart == POINT || (flagsStart == PARAGRAPH && start == length())) 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project start += mGapLength; 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6546435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne if (end > mGapStart) { 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end += mGapLength; 6566435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne } else if (end == mGapStart) { 6570249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne if (flagsEnd == POINT || (flagsEnd == PARAGRAPH && end == length())) 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end += mGapLength; 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mSpanCount; 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = mSpans; 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[i] == what) { 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ostart = mSpanStarts[i]; 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int oend = mSpanEnds[i]; 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ostart > mGapStart) 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ostart -= mGapLength; 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oend > mGapStart) 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project oend -= mGapLength; 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanStarts[i] = start; 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanEnds[i] = end; 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanFlags[i] = flags; 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 678fc1190b8f143bd00c825d4e52928c577e40e6c49Gilles Debunne if (send) sendSpanChanged(what, ostart, oend, nstart, nend); 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 684776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpans = GrowingArrayUtils.append(mSpans, mSpanCount, what); 685776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start); 686776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end); 687776abc24cdd18610232a50b997cce3cffa74609bAdam Lesinski mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags); 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSpanCount++; 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 690fc1190b8f143bd00c825d4e52928c577e40e6c49Gilles Debunne if (send) sendSpanAdded(what, nstart, nend); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Remove the specified markup object from the buffer. 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void removeSpan(Object what) { 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = mSpanCount - 1; i >= 0; i--) { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpans[i] == what) { 6996435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne removeSpan(i); 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the buffer offset of the beginning of the specified 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * markup object, or -1 if it is not attached to this buffer. 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanStart(Object what) { 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mSpanCount; 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = mSpans; 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = count - 1; i >= 0; i--) { 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[i] == what) { 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int where = mSpanStarts[i]; 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where > mGapStart) 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project where -= mGapLength; 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return where; 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the buffer offset of the end of the specified 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * markup object, or -1 if it is not attached to this buffer. 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanEnd(Object what) { 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mSpanCount; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = mSpans; 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = count - 1; i >= 0; i--) { 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[i] == what) { 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int where = mSpanEnds[i]; 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (where > mGapStart) 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project where -= mGapLength; 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return where; 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the flags of the end of the specified 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * markup object, or 0 if it is not attached to this buffer. 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getSpanFlags(Object what) { 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mSpanCount; 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = mSpans; 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = count - 1; i >= 0; i--) { 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spans[i] == what) { 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mSpanFlags[i]; 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 763051910b9f998030dacb8a0722588cc715813fde1Raph Levien return 0; 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return an array of the spans of the specified type that overlap 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the specified range of the buffer. The kind may be Object.class to get 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a list of all the spans regardless of type. 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 771312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne @SuppressWarnings("unchecked") 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) { 7736435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne if (kind == null) return ArrayUtils.emptyArray(kind); 7746435a56a8c02de98befcc8cd743b2b638cffb327Gilles Debunne 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spanCount = mSpanCount; 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = mSpans; 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] starts = mSpanStarts; 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] ends = mSpanEnds; 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] flags = mSpanFlags; 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int gapstart = mGapStart; 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int gaplen = mGapLength; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = 0; 784312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne T[] ret = null; 785312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne T ret1 = null; 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < spanCount; i++) { 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int spanStart = starts[i]; 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanStart > gapstart) { 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project spanStart -= gaplen; 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanStart > queryEnd) { 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 795b062e81e3a16af43db3619d721aa522c137d1aa9Gilles Debunne 796b062e81e3a16af43db3619d721aa522c137d1aa9Gilles Debunne int spanEnd = ends[i]; 797b062e81e3a16af43db3619d721aa522c137d1aa9Gilles Debunne if (spanEnd > gapstart) { 798b062e81e3a16af43db3619d721aa522c137d1aa9Gilles Debunne spanEnd -= gaplen; 799b062e81e3a16af43db3619d721aa522c137d1aa9Gilles Debunne } 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanEnd < queryStart) { 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanStart != spanEnd && queryStart != queryEnd) { 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanStart == queryEnd) 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (spanEnd == queryStart) 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 811945ee9b1661e60e0074d4f16f61fc147c728c6bfGilles Debunne // Expensive test, should be performed after the previous tests 812945ee9b1661e60e0074d4f16f61fc147c728c6bfGilles Debunne if (!kind.isInstance(spans[i])) continue; 813945ee9b1661e60e0074d4f16f61fc147c728c6bfGilles Debunne 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == 0) { 815312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne // Safe conversion thanks to the isInstance test above 816312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne ret1 = (T) spans[i]; 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count++; 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == 1) { 820312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne // Safe conversion, but requires a suppressWarning 821312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne ret = (T[]) Array.newInstance(kind, spanCount - i + 1); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret[0] = ret1; 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int prio = flags[i] & SPAN_PRIORITY; 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prio != 0) { 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int j; 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (j = 0; j < count; j++) { 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int p = getSpanFlags(ret[j]) & SPAN_PRIORITY; 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (prio > p) { 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(ret, j, ret, j + 1, count - j); 838312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne // Safe conversion thanks to the isInstance test above 839312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne ret[j] = (T) spans[i]; 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count++; 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 842312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne // Safe conversion thanks to the isInstance test above 843312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne ret[count++] = (T) spans[i]; 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == 0) { 849f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt return ArrayUtils.emptyArray(kind); 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == 1) { 852312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne // Safe conversion, but requires a suppressWarning 853312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne ret = (T[]) Array.newInstance(kind, 1); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret[0] = ret1; 855312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne return ret; 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == ret.length) { 858312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne return ret; 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 861312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne // Safe conversion, but requires a suppressWarning 862312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne T[] nret = (T[]) Array.newInstance(kind, count); 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(ret, 0, nret, 0, count); 864312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne return nret; 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return the next offset after <code>start</code> but less than or 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * equal to <code>limit</code> where a span of the specified type 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * begins or ends. 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int nextSpanTransition(int start, int limit, Class kind) { 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mSpanCount; 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object[] spans = mSpans; 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] starts = mSpanStarts; 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] ends = mSpanEnds; 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int gapstart = mGapStart; 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int gaplen = mGapLength; 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (kind == null) { 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project kind = Object.class; 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int st = starts[i]; 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int en = ends[i]; 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (st > gapstart) 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project st -= gaplen; 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (en > gapstart) 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project en -= gaplen; 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (st > start && st < limit && kind.isInstance(spans[i])) 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project limit = st; 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (en > start && en < limit && kind.isInstance(spans[i])) 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project limit = en; 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return limit; 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return a new CharSequence containing a copy of the specified 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * range of this buffer, including the overlapping spans. 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public CharSequence subSequence(int start, int end) { 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new SpannableStringBuilder(this, start, end); 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copy the specified range of chars from this buffer into the 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * specified array, beginning at the specified offset. 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void getChars(int start, int end, char[] dest, int destoff) { 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange("getChars", start, end); 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end <= mGapStart) { 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mText, start, dest, destoff, end - start); 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (start >= mGapStart) { 920174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne System.arraycopy(mText, start + mGapLength, dest, destoff, end - start); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mText, start, dest, destoff, mGapStart - start); 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mText, mGapStart + mGapLength, 924174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne dest, destoff + (mGapStart - start), 925174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne end - mGapStart); 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Return a String containing a copy of the chars in this buffer. 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 932312cd580391d70140eeb4080a4e195039172a6a6Gilles Debunne @Override 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = length(); 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] buf = new char[len]; 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(0, len, buf, 0); 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new String(buf); 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 941653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne /** 942653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne * Return a String containing a copy of the chars in this buffer, limited to the 943653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne * [start, end[ range. 944653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne * @hide 945653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne */ 946653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne public String substring(int start, int end) { 947653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne char[] buf = new char[end - start]; 948653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne getChars(start, end, buf, 0); 949653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne return new String(buf); 950653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne } 951653d3a27878d5358b4a91518a756f6b9b3407b07Gilles Debunne 952b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne private void sendBeforeTextChanged(TextWatcher[] watchers, int start, int before, int after) { 953b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne int n = watchers.length; 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 956b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne watchers[i].beforeTextChanged(this, start, before, after); 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 960b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne private void sendTextChanged(TextWatcher[] watchers, int start, int before, int after) { 961b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne int n = watchers.length; 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 964b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne watchers[i].onTextChanged(this, start, before, after); 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 968b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne private void sendAfterTextChanged(TextWatcher[] watchers) { 969b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne int n = watchers.length; 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 972b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne watchers[i].afterTextChanged(this); 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void sendSpanAdded(Object what, int start, int end) { 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int n = recip.length; 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recip[i].onSpanAdded(this, what, start, end); 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void sendSpanRemoved(Object what, int start, int end) { 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class); 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int n = recip.length; 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project recip[i].onSpanRemoved(this, what, start, end); 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 994174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private void sendSpanChanged(Object what, int oldStart, int oldEnd, int start, int end) { 995174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // The bounds of a possible SpanWatcher are guaranteed to be set before this method is 996174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // called, so that the order of the span does not affect this broadcast. 997174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne SpanWatcher[] spanWatchers = getSpans(Math.min(oldStart, start), 998174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne Math.min(Math.max(oldEnd, end), length()), SpanWatcher.class); 999174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne int n = spanWatchers.length; 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < n; i++) { 1001174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne spanWatchers[i].onSpanChanged(this, what, oldStart, oldEnd, start, end); 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static String region(int start, int end) { 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return "(" + start + " ... " + end + ")"; 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void checkRange(final String operation, int start, int end) { 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end < start) { 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IndexOutOfBoundsException(operation + " " + 1012174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne region(start, end) + " has end before start"); 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = length(); 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start > len || end > len) { 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IndexOutOfBoundsException(operation + " " + 1019174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne region(start, end) + " ends beyond length " + len); 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start < 0 || end < 0) { 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IndexOutOfBoundsException(operation + " " + 1024174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne region(start, end) + " starts before 0"); 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1028174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne /* 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean isprint(char c) { // XXX 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c >= ' ' && c <= '~') 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int startFlag(int flag) { 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (flag >> 4) & 0x0F; 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int endFlag(int flag) { 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return flag & 0x0F; 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void dump() { // XXX 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mGapStart; i++) { 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print('|'); 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(' '); 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(isprint(mText[i]) ? mText[i] : '.'); 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(' '); 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = mGapStart; i < mGapStart + mGapLength; i++) { 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print('|'); 10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print('('); 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(isprint(mText[i]) ? mText[i] : '.'); 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(')'); 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = mGapStart + mGapLength; i < mText.length; i++) { 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print('|'); 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(' '); 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(isprint(mText[i]) ? mText[i] : '.'); 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(' '); 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print('\n'); 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < mText.length + 1; i++) { 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int found = 0; 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int wfound = 0; 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int j = 0; j < mSpanCount; j++) { 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpanStarts[j] == i) { 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project found = 1; 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project wfound = j; 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSpanEnds[j] == i) { 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project found = 2; 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project wfound = j; 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (found == 1) { 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startFlag(mSpanFlags[wfound]) == MARK) 10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print("( "); 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (startFlag(mSpanFlags[wfound]) == PARAGRAPH) 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print("< "); 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print("[ "); 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (found == 2) { 10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (endFlag(mSpanFlags[wfound]) == POINT) 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(") "); 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (endFlag(mSpanFlags[wfound]) == PARAGRAPH) 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print("> "); 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print("] "); 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print(" "); 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.out.print("\n"); 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 110726b62d432101084c832f5587798cfd24a4ed9c59Gilles Debunne */ 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Don't call this yourself -- exists for Canvas to use internally. 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1113b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne public void drawText(Canvas c, int start, int end, float x, float y, Paint p) { 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange("drawText", start, end); 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end <= mGapStart) { 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.drawText(mText, start, end - start, x, y, p); 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (start >= mGapStart) { 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.drawText(mText, start + mGapLength, end - start, x, y, p); 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] buf = TextUtils.obtain(end - start); 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, buf, 0); 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.drawText(buf, 0, end - start, x, y, p); 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.recycle(buf); 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11290c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1131f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt * Don't call this yourself -- exists for Canvas to use internally. 1132f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt * {@hide} 1133f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt */ 1134b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd, 1135051910b9f998030dacb8a0722588cc715813fde1Raph Levien float x, float y, boolean isRtl, Paint p) { 1136f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt checkRange("drawTextRun", start, end); 1137f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt 11380c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int contextLen = contextEnd - contextStart; 11390c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int len = end - start; 11400c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt if (contextEnd <= mGapStart) { 1141051910b9f998030dacb8a0722588cc715813fde1Raph Levien c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, isRtl, p); 11420c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } else if (contextStart >= mGapStart) { 11430c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength, 1144051910b9f998030dacb8a0722588cc715813fde1Raph Levien contextLen, x, y, isRtl, p); 1145f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt } else { 11460c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt char[] buf = TextUtils.obtain(contextLen); 11470c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt getChars(contextStart, contextEnd, buf, 0); 1148051910b9f998030dacb8a0722588cc715813fde1Raph Levien c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, isRtl, p); 1149f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt TextUtils.recycle(buf); 1150f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt } 1151f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt } 1152f47d7405bbcb25d7cdf89ebb059f41520fe9ab87Doug Felt 1153174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne /** 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Don't call this yourself -- exists for Paint to use internally. 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public float measureText(int start, int end, Paint p) { 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange("measureText", start, end); 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float ret; 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end <= mGapStart) { 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = p.measureText(mText, start, end - start); 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (start >= mGapStart) { 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = p.measureText(mText, start + mGapLength, end - start); 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] buf = TextUtils.obtain(end - start); 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, buf, 0); 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = p.measureText(buf, 0, end - start); 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.recycle(buf); 11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Don't call this yourself -- exists for Paint to use internally. 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getTextWidths(int start, int end, float[] widths, Paint p) { 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkRange("getTextWidths", start, end); 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ret; 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end <= mGapStart) { 11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = p.getTextWidths(mText, start, end - start, widths); 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (start >= mGapStart) { 1189174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne ret = p.getTextWidths(mText, start + mGapLength, end - start, widths); 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] buf = TextUtils.obtain(end - start); 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getChars(start, end, buf, 0); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = p.getTextWidths(buf, 0, end - start, widths); 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TextUtils.recycle(buf); 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12010c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt /** 12020c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt * Don't call this yourself -- exists for Paint to use internally. 12030c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt * {@hide} 12040c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt */ 1205051910b9f998030dacb8a0722588cc715813fde1Raph Levien public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, boolean isRtl, 12060c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt float[] advances, int advancesPos, Paint p) { 12070c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12080c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt float ret; 12090c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12100c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int contextLen = contextEnd - contextStart; 12110c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int len = end - start; 12120c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12130c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt if (end <= mGapStart) { 12140c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen, 1215051910b9f998030dacb8a0722588cc715813fde1Raph Levien isRtl, advances, advancesPos); 12160c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } else if (start >= mGapStart) { 12170c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt ret = p.getTextRunAdvances(mText, start + mGapLength, len, 1218051910b9f998030dacb8a0722588cc715813fde1Raph Levien contextStart + mGapLength, contextLen, isRtl, advances, advancesPos); 12190c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } else { 12200c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt char[] buf = TextUtils.obtain(contextLen); 12210c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt getChars(contextStart, contextEnd, buf, 0); 12220c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt ret = p.getTextRunAdvances(buf, start - contextStart, len, 1223051910b9f998030dacb8a0722588cc715813fde1Raph Levien 0, contextLen, isRtl, advances, advancesPos); 1224da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio TextUtils.recycle(buf); 1225da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio } 1226da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio 1227da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio return ret; 1228da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio } 1229da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio 1230da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio /** 1231f09d510cd18854f41632433503ca46cc41362febGilles Debunne * Returns the next cursor position in the run. This avoids placing the cursor between 1232f09d510cd18854f41632433503ca46cc41362febGilles Debunne * surrogates, between characters that form conjuncts, between base characters and combining 1233f09d510cd18854f41632433503ca46cc41362febGilles Debunne * marks, or within a reordering cluster. 1234f09d510cd18854f41632433503ca46cc41362febGilles Debunne * 1235f09d510cd18854f41632433503ca46cc41362febGilles Debunne * <p>The context is the shaping context for cursor movement, generally the bounds of the metric 1236f09d510cd18854f41632433503ca46cc41362febGilles Debunne * span enclosing the cursor in the direction of movement. 1237f09d510cd18854f41632433503ca46cc41362febGilles Debunne * <code>contextStart</code>, <code>contextEnd</code> and <code>offset</code> are relative to 1238f09d510cd18854f41632433503ca46cc41362febGilles Debunne * the start of the string.</p> 1239f09d510cd18854f41632433503ca46cc41362febGilles Debunne * 1240616f3835a0a67328b378cb1cbc126f17478ab4a0Gilles Debunne * <p>If cursorOpt is CURSOR_AT and the offset is not a valid cursor position, 1241f09d510cd18854f41632433503ca46cc41362febGilles Debunne * this returns -1. Otherwise this will never return a value before contextStart or after 1242f09d510cd18854f41632433503ca46cc41362febGilles Debunne * contextEnd.</p> 1243f09d510cd18854f41632433503ca46cc41362febGilles Debunne * 1244f09d510cd18854f41632433503ca46cc41362febGilles Debunne * @param contextStart the start index of the context 1245f09d510cd18854f41632433503ca46cc41362febGilles Debunne * @param contextEnd the (non-inclusive) end index of the context 1246051910b9f998030dacb8a0722588cc715813fde1Raph Levien * @param dir either DIRECTION_RTL or DIRECTION_LTR 1247f09d510cd18854f41632433503ca46cc41362febGilles Debunne * @param offset the cursor position to move from 1248616f3835a0a67328b378cb1cbc126f17478ab4a0Gilles Debunne * @param cursorOpt how to move the cursor, one of CURSOR_AFTER, 1249616f3835a0a67328b378cb1cbc126f17478ab4a0Gilles Debunne * CURSOR_AT_OR_AFTER, CURSOR_BEFORE, 1250616f3835a0a67328b378cb1cbc126f17478ab4a0Gilles Debunne * CURSOR_AT_OR_BEFORE, or CURSOR_AT 1251f09d510cd18854f41632433503ca46cc41362febGilles Debunne * @param p the Paint object that is requesting this information 1252f09d510cd18854f41632433503ca46cc41362febGilles Debunne * @return the offset of the next position, or -1 1253b0b225602cc84e0602450a417a562e8f53f29c6bGilles Debunne * @deprecated This is an internal method, refrain from using it in your code 1254f09d510cd18854f41632433503ca46cc41362febGilles Debunne */ 1255b0b225602cc84e0602450a417a562e8f53f29c6bGilles Debunne @Deprecated 1256051910b9f998030dacb8a0722588cc715813fde1Raph Levien public int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset, 1257da12f389eb4be0c08ca3fa9ca7663f4977858df5Fabrice Di Meglio int cursorOpt, Paint p) { 12580c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12590c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int ret; 12600c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12610c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt int contextLen = contextEnd - contextStart; 12620c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt if (contextEnd <= mGapStart) { 12630c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt ret = p.getTextRunCursor(mText, contextStart, contextLen, 1264051910b9f998030dacb8a0722588cc715813fde1Raph Levien dir, offset, cursorOpt); 12650c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } else if (contextStart >= mGapStart) { 12660c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen, 1267051910b9f998030dacb8a0722588cc715813fde1Raph Levien dir, offset + mGapLength, cursorOpt) - mGapLength; 12680c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } else { 12690c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt char[] buf = TextUtils.obtain(contextLen); 12700c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt getChars(contextStart, contextEnd, buf, 0); 12710c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt ret = p.getTextRunCursor(buf, 0, contextLen, 1272051910b9f998030dacb8a0722588cc715813fde1Raph Levien dir, offset - contextStart, cursorOpt) + contextStart; 12730c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt TextUtils.recycle(buf); 12740c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } 12750c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12760c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt return ret; 12770c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt } 12780c702b88c5d0d4380930b920f5be6e66dd95a0d8Doug Felt 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFilters(InputFilter[] filters) { 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (filters == null) { 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException(); 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFilters = filters; 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Documentation from interface 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public InputFilter[] getFilters() { 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mFilters; 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12939b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase // Same as SpannableStringInternal 12949b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase @Override 12959b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase public boolean equals(Object o) { 12969b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase if (o instanceof Spanned && 12979b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase toString().equals(o.toString())) { 12981d3c4b396a393515e738cb72782ef564362420faChet Haase Spanned other = (Spanned) o; 12999b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase // Check span data 13001d3c4b396a393515e738cb72782ef564362420faChet Haase Object[] otherSpans = other.getSpans(0, other.length(), Object.class); 13019b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase if (mSpanCount == otherSpans.length) { 13029b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase for (int i = 0; i < mSpanCount; ++i) { 13039b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase Object thisSpan = mSpans[i]; 13049b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase Object otherSpan = otherSpans[i]; 13051d3c4b396a393515e738cb72782ef564362420faChet Haase if (thisSpan == this) { 13061d3c4b396a393515e738cb72782ef564362420faChet Haase if (other != otherSpan || 13071d3c4b396a393515e738cb72782ef564362420faChet Haase getSpanStart(thisSpan) != other.getSpanStart(otherSpan) || 13081d3c4b396a393515e738cb72782ef564362420faChet Haase getSpanEnd(thisSpan) != other.getSpanEnd(otherSpan) || 13091d3c4b396a393515e738cb72782ef564362420faChet Haase getSpanFlags(thisSpan) != other.getSpanFlags(otherSpan)) { 13101d3c4b396a393515e738cb72782ef564362420faChet Haase return false; 13111d3c4b396a393515e738cb72782ef564362420faChet Haase } 13121d3c4b396a393515e738cb72782ef564362420faChet Haase } else if (!thisSpan.equals(otherSpan) || 13131d3c4b396a393515e738cb72782ef564362420faChet Haase getSpanStart(thisSpan) != other.getSpanStart(otherSpan) || 13141d3c4b396a393515e738cb72782ef564362420faChet Haase getSpanEnd(thisSpan) != other.getSpanEnd(otherSpan) || 13151d3c4b396a393515e738cb72782ef564362420faChet Haase getSpanFlags(thisSpan) != other.getSpanFlags(otherSpan)) { 13169b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase return false; 13179b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13189b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13199b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase return true; 13209b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13219b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13229b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase return false; 13239b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13249b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase 13259b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase // Same as SpannableStringInternal 13269b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase @Override 13279b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase public int hashCode() { 13289b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase int hash = toString().hashCode(); 13299b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase hash = hash * 31 + mSpanCount; 13309b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase for (int i = 0; i < mSpanCount; ++i) { 13319b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase Object span = mSpans[i]; 13321d3c4b396a393515e738cb72782ef564362420faChet Haase if (span != this) { 13331d3c4b396a393515e738cb72782ef564362420faChet Haase hash = hash * 31 + span.hashCode(); 13341d3c4b396a393515e738cb72782ef564362420faChet Haase } 13359b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase hash = hash * 31 + getSpanStart(span); 13369b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase hash = hash * 31 + getSpanEnd(span); 13379b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase hash = hash * 31 + getSpanFlags(span); 13389b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13399b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase return hash; 13409b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase } 13419b985721dafaa28d1aa34499d23a83afc6d0a2faChet Haase 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final InputFilter[] NO_FILTERS = new InputFilter[0]; 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private InputFilter[] mFilters = NO_FILTERS; 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private char[] mText; 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mGapStart; 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mGapLength; 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Object[] mSpans; 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mSpanStarts; 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mSpanEnds; 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int[] mSpanFlags; 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mSpanCount; 1354174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private int mSpanCountBeforeAdd; 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1356b51036f72aa69e56133fefbf2b56724768423512Gilles Debunne // TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned} 13570249b43f6ce59bfec104f0fe606d9059244f8797Gilles Debunne private static final int MARK = 1; 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int POINT = 2; 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int PARAGRAPH = 3; 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int START_MASK = 0xF0; 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int END_MASK = 0x0F; 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int START_SHIFT = 4; 1364174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne 1365174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne // These bits are not (currently) used by SPANNED flags 1366174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private static final int SPAN_START_AT_START = 0x1000; 1367174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private static final int SPAN_START_AT_END = 0x2000; 1368174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private static final int SPAN_END_AT_START = 0x4000; 1369174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private static final int SPAN_END_AT_END = 0x8000; 1370174c44c6cfeead714bb180d21332e712e8b0bbd8Gilles Debunne private static final int SPAN_START_END_MASK = 0xF000; 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1372