summaryrefslogtreecommitdiff
path: root/core/java/android/text/SpannableStringBuilder.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
commitd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/text/SpannableStringBuilder.java
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/text/SpannableStringBuilder.java')
-rw-r--r--core/java/android/text/SpannableStringBuilder.java1140
1 files changed, 0 insertions, 1140 deletions
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
deleted file mode 100644
index caaafa147397..000000000000
--- a/core/java/android/text/SpannableStringBuilder.java
+++ /dev/null
@@ -1,1140 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text;
-
-import com.android.internal.util.ArrayUtils;
-import android.graphics.Paint;
-import android.graphics.Canvas;
-
-import java.lang.reflect.Array;
-
-/**
- * This is the class for text whose content and markup can both be changed.
- */
-public class SpannableStringBuilder
-implements CharSequence, GetChars, Spannable, Editable, Appendable,
- GraphicsOperations
-{
- /**
- * Create a new SpannableStringBuilder with empty contents
- */
- public SpannableStringBuilder() {
- this("");
- }
-
- /**
- * Create a new SpannableStringBuilder containing a copy of the
- * specified text, including its spans if any.
- */
- public SpannableStringBuilder(CharSequence text) {
- this(text, 0, text.length());
- }
-
- /**
- * Create a new SpannableStringBuilder containing a copy of the
- * specified slice of the specified text, including its spans if any.
- */
- public SpannableStringBuilder(CharSequence text, int start, int end) {
- int srclen = end - start;
-
- int len = ArrayUtils.idealCharArraySize(srclen + 1);
- mText = new char[len];
- mGapStart = srclen;
- mGapLength = len - srclen;
-
- TextUtils.getChars(text, start, end, mText, 0);
-
- mSpanCount = 0;
- int alloc = ArrayUtils.idealIntArraySize(0);
- mSpans = new Object[alloc];
- mSpanStarts = new int[alloc];
- mSpanEnds = new int[alloc];
- mSpanFlags = new int[alloc];
-
- if (text instanceof Spanned) {
- Spanned sp = (Spanned) text;
- Object[] spans = sp.getSpans(start, end, Object.class);
-
- for (int i = 0; i < spans.length; i++) {
- if (spans[i] instanceof NoCopySpan) {
- continue;
- }
-
- int st = sp.getSpanStart(spans[i]) - start;
- int en = sp.getSpanEnd(spans[i]) - start;
- int fl = sp.getSpanFlags(spans[i]);
-
- if (st < 0)
- st = 0;
- if (st > end - start)
- st = end - start;
-
- if (en < 0)
- en = 0;
- if (en > end - start)
- en = end - start;
-
- setSpan(spans[i], st, en, fl);
- }
- }
- }
-
- public static SpannableStringBuilder valueOf(CharSequence source) {
- if (source instanceof SpannableStringBuilder) {
- return (SpannableStringBuilder) source;
- } else {
- return new SpannableStringBuilder(source);
- }
- }
-
- /**
- * Return the char at the specified offset within the buffer.
- */
- public char charAt(int where) {
- int len = length();
- if (where < 0) {
- throw new IndexOutOfBoundsException("charAt: " + where + " < 0");
- } else if (where >= len) {
- throw new IndexOutOfBoundsException("charAt: " + where +
- " >= length " + len);
- }
-
- if (where >= mGapStart)
- return mText[where + mGapLength];
- else
- return mText[where];
- }
-
- /**
- * Return the number of chars in the buffer.
- */
- public int length() {
- return mText.length - mGapLength;
- }
-
- private void resizeFor(int size) {
- int newlen = ArrayUtils.idealCharArraySize(size + 1);
- char[] newtext = new char[newlen];
-
- int after = mText.length - (mGapStart + mGapLength);
-
- System.arraycopy(mText, 0, newtext, 0, mGapStart);
- System.arraycopy(mText, mText.length - after,
- newtext, newlen - after, after);
-
- for (int i = 0; i < mSpanCount; i++) {
- if (mSpanStarts[i] > mGapStart)
- mSpanStarts[i] += newlen - mText.length;
- if (mSpanEnds[i] > mGapStart)
- mSpanEnds[i] += newlen - mText.length;
- }
-
- int oldlen = mText.length;
- mText = newtext;
- mGapLength += mText.length - oldlen;
-
- if (mGapLength < 1)
- new Exception("mGapLength < 1").printStackTrace();
- }
-
- private void moveGapTo(int where) {
- if (where == mGapStart)
- return;
-
- boolean atend = (where == length());
-
- if (where < mGapStart) {
- int overlap = mGapStart - where;
-
- System.arraycopy(mText, where,
- mText, mGapStart + mGapLength - overlap, overlap);
- } else /* where > mGapStart */ {
- int overlap = where - mGapStart;
-
- System.arraycopy(mText, where + mGapLength - overlap,
- mText, mGapStart, overlap);
- }
-
- // XXX be more clever
- for (int i = 0; i < mSpanCount; i++) {
- int start = mSpanStarts[i];
- int end = mSpanEnds[i];
-
- if (start > mGapStart)
- start -= mGapLength;
- if (start > where)
- start += mGapLength;
- else if (start == where) {
- int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
-
- if (flag == POINT || (atend && flag == PARAGRAPH))
- start += mGapLength;
- }
-
- if (end > mGapStart)
- end -= mGapLength;
- if (end > where)
- end += mGapLength;
- else if (end == where) {
- int flag = (mSpanFlags[i] & END_MASK);
-
- if (flag == POINT || (atend && flag == PARAGRAPH))
- end += mGapLength;
- }
-
- mSpanStarts[i] = start;
- mSpanEnds[i] = end;
- }
-
- mGapStart = where;
- }
-
- // Documentation from interface
- public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) {
- return replace(where, where, tb, start, end);
- }
-
- // Documentation from interface
- public SpannableStringBuilder insert(int where, CharSequence tb) {
- return replace(where, where, tb, 0, tb.length());
- }
-
- // Documentation from interface
- public SpannableStringBuilder delete(int start, int end) {
- SpannableStringBuilder ret = replace(start, end, "", 0, 0);
-
- if (mGapLength > 2 * length())
- resizeFor(length());
-
- return ret; // == this
- }
-
- // Documentation from interface
- public void clear() {
- replace(0, length(), "", 0, 0);
- }
-
- // Documentation from interface
- public void clearSpans() {
- for (int i = mSpanCount - 1; i >= 0; i--) {
- Object what = mSpans[i];
- int ostart = mSpanStarts[i];
- int oend = mSpanEnds[i];
-
- if (ostart > mGapStart)
- ostart -= mGapLength;
- if (oend > mGapStart)
- oend -= mGapLength;
-
- mSpanCount = i;
- mSpans[i] = null;
-
- sendSpanRemoved(what, ostart, oend);
- }
- }
-
- // Documentation from interface
- public SpannableStringBuilder append(CharSequence text) {
- int length = length();
- return replace(length, length, text, 0, text.length());
- }
-
- // Documentation from interface
- public SpannableStringBuilder append(CharSequence text, int start, int end) {
- int length = length();
- return replace(length, length, text, start, end);
- }
-
- // Documentation from interface
- public SpannableStringBuilder append(char text) {
- return append(String.valueOf(text));
- }
-
- private int change(int start, int end,
- CharSequence tb, int tbstart, int tbend) {
- return change(true, start, end, tb, tbstart, tbend);
- }
-
- private int change(boolean notify, int start, int end,
- CharSequence tb, int tbstart, int tbend) {
- checkRange("replace", start, end);
- int ret = tbend - tbstart;
- TextWatcher[] recipients = null;
-
- if (notify)
- recipients = sendTextWillChange(start, end - start,
- tbend - tbstart);
-
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if ((mSpanFlags[i] & SPAN_PARAGRAPH) == SPAN_PARAGRAPH) {
- int st = mSpanStarts[i];
- if (st > mGapStart)
- st -= mGapLength;
-
- int en = mSpanEnds[i];
- if (en > mGapStart)
- en -= mGapLength;
-
- int ost = st;
- int oen = en;
- int clen = length();
-
- if (st > start && st <= end) {
- for (st = end; st < clen; st++)
- if (st > end && charAt(st - 1) == '\n')
- break;
- }
-
- if (en > start && en <= end) {
- for (en = end; en < clen; en++)
- if (en > end && charAt(en - 1) == '\n')
- break;
- }
-
- if (st != ost || en != oen)
- setSpan(mSpans[i], st, en, mSpanFlags[i]);
- }
- }
-
- moveGapTo(end);
-
- if (tbend - tbstart >= mGapLength + (end - start))
- resizeFor(mText.length - mGapLength +
- tbend - tbstart - (end - start));
-
- mGapStart += tbend - tbstart - (end - start);
- mGapLength -= tbend - tbstart - (end - start);
-
- if (mGapLength < 1)
- new Exception("mGapLength < 1").printStackTrace();
-
- TextUtils.getChars(tb, tbstart, tbend, mText, start);
-
- if (tb instanceof Spanned) {
- Spanned sp = (Spanned) tb;
- Object[] spans = sp.getSpans(tbstart, tbend, Object.class);
-
- for (int i = 0; i < spans.length; i++) {
- int st = sp.getSpanStart(spans[i]);
- int en = sp.getSpanEnd(spans[i]);
-
- if (st < tbstart)
- st = tbstart;
- if (en > tbend)
- en = tbend;
-
- if (getSpanStart(spans[i]) < 0) {
- setSpan(false, spans[i],
- st - tbstart + start,
- en - tbstart + start,
- sp.getSpanFlags(spans[i]));
- }
- }
- }
-
- // no need for span fixup on pure insertion
- if (tbend > tbstart && end - start == 0) {
- if (notify) {
- sendTextChange(recipients, start, end - start, tbend - tbstart);
- sendTextHasChanged(recipients);
- }
-
- return ret;
- }
-
- boolean atend = (mGapStart + mGapLength == mText.length);
-
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpanStarts[i] >= start &&
- mSpanStarts[i] < mGapStart + mGapLength) {
- int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
-
- if (flag == POINT || (flag == PARAGRAPH && atend))
- mSpanStarts[i] = mGapStart + mGapLength;
- else
- mSpanStarts[i] = start;
- }
-
- if (mSpanEnds[i] >= start &&
- mSpanEnds[i] < mGapStart + mGapLength) {
- int flag = (mSpanFlags[i] & END_MASK);
-
- if (flag == POINT || (flag == PARAGRAPH && atend))
- mSpanEnds[i] = mGapStart + mGapLength;
- else
- mSpanEnds[i] = start;
- }
-
- // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
- // XXX send notification on removal
-
- if (mSpanEnds[i] < mSpanStarts[i]) {
- System.arraycopy(mSpans, i + 1,
- mSpans, i, mSpanCount - (i + 1));
- System.arraycopy(mSpanStarts, i + 1,
- mSpanStarts, i, mSpanCount - (i + 1));
- System.arraycopy(mSpanEnds, i + 1,
- mSpanEnds, i, mSpanCount - (i + 1));
- System.arraycopy(mSpanFlags, i + 1,
- mSpanFlags, i, mSpanCount - (i + 1));
-
- mSpanCount--;
- }
- }
-
- if (notify) {
- sendTextChange(recipients, start, end - start, tbend - tbstart);
- sendTextHasChanged(recipients);
- }
-
- return ret;
- }
-
- // Documentation from interface
- public SpannableStringBuilder replace(int start, int end, CharSequence tb) {
- return replace(start, end, tb, 0, tb.length());
- }
-
- // Documentation from interface
- public SpannableStringBuilder replace(final int start, final int end,
- CharSequence tb, int tbstart, int tbend) {
- int filtercount = mFilters.length;
- for (int i = 0; i < filtercount; i++) {
- CharSequence repl = mFilters[i].filter(tb, tbstart, tbend,
- this, start, end);
-
- if (repl != null) {
- tb = repl;
- tbstart = 0;
- tbend = repl.length();
- }
- }
-
- if (end == start && tbstart == tbend) {
- return this;
- }
-
- if (end == start || tbstart == tbend) {
- change(start, end, tb, tbstart, tbend);
- } else {
- int selstart = Selection.getSelectionStart(this);
- int selend = Selection.getSelectionEnd(this);
-
- // XXX just make the span fixups in change() do the right thing
- // instead of this madness!
-
- checkRange("replace", start, end);
- moveGapTo(end);
- TextWatcher[] recipients;
-
- recipients = sendTextWillChange(start, end - start,
- tbend - tbstart);
-
- int origlen = end - start;
-
- if (mGapLength < 2)
- resizeFor(length() + 1);
-
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpanStarts[i] == mGapStart)
- mSpanStarts[i]++;
-
- if (mSpanEnds[i] == mGapStart)
- mSpanEnds[i]++;
- }
-
- mText[mGapStart] = ' ';
- mGapStart++;
- mGapLength--;
-
- if (mGapLength < 1)
- new Exception("mGapLength < 1").printStackTrace();
-
- int oldlen = (end + 1) - start;
-
- int inserted = change(false, start + 1, start + 1,
- tb, tbstart, tbend);
- change(false, start, start + 1, "", 0, 0);
- change(false, start + inserted, start + inserted + oldlen - 1,
- "", 0, 0);
-
- /*
- * Special case to keep the cursor in the same position
- * if it was somewhere in the middle of the replaced region.
- * If it was at the start or the end or crossing the whole
- * replacement, it should already be where it belongs.
- * TODO: Is there some more general mechanism that could
- * accomplish this?
- */
- if (selstart > start && selstart < end) {
- long off = selstart - start;
-
- off = off * inserted / (end - start);
- selstart = (int) off + start;
-
- setSpan(false, Selection.SELECTION_START, selstart, selstart,
- Spanned.SPAN_POINT_POINT);
- }
- if (selend > start && selend < end) {
- long off = selend - start;
-
- off = off * inserted / (end - start);
- selend = (int) off + start;
-
- setSpan(false, Selection.SELECTION_END, selend, selend,
- Spanned.SPAN_POINT_POINT);
- }
-
- sendTextChange(recipients, start, origlen, inserted);
- sendTextHasChanged(recipients);
- }
- return this;
- }
-
- /**
- * Mark the specified range of text with the specified object.
- * The flags determine how the span will behave when text is
- * inserted at the start or end of the span's range.
- */
- public void setSpan(Object what, int start, int end, int flags) {
- setSpan(true, what, start, end, flags);
- }
-
- private void setSpan(boolean send,
- Object what, int start, int end, int flags) {
- int nstart = start;
- int nend = end;
-
- checkRange("setSpan", start, end);
-
- if ((flags & START_MASK) == (PARAGRAPH << START_SHIFT)) {
- if (start != 0 && start != length()) {
- char c = charAt(start - 1);
-
- if (c != '\n')
- throw new RuntimeException(
- "PARAGRAPH span must start at paragraph boundary");
- }
- }
-
- if ((flags & END_MASK) == PARAGRAPH) {
- if (end != 0 && end != length()) {
- char c = charAt(end - 1);
-
- if (c != '\n')
- throw new RuntimeException(
- "PARAGRAPH span must end at paragraph boundary");
- }
- }
-
- if (start > mGapStart)
- start += mGapLength;
- else if (start == mGapStart) {
- int flag = (flags & START_MASK) >> START_SHIFT;
-
- if (flag == POINT || (flag == PARAGRAPH && start == length()))
- start += mGapLength;
- }
-
- if (end > mGapStart)
- end += mGapLength;
- else if (end == mGapStart) {
- int flag = (flags & END_MASK);
-
- if (flag == POINT || (flag == PARAGRAPH && end == length()))
- end += mGapLength;
- }
-
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = 0; i < count; i++) {
- if (spans[i] == what) {
- int ostart = mSpanStarts[i];
- int oend = mSpanEnds[i];
-
- if (ostart > mGapStart)
- ostart -= mGapLength;
- if (oend > mGapStart)
- oend -= mGapLength;
-
- mSpanStarts[i] = start;
- mSpanEnds[i] = end;
- mSpanFlags[i] = flags;
-
- if (send)
- sendSpanChanged(what, ostart, oend, nstart, nend);
-
- return;
- }
- }
-
- if (mSpanCount + 1 >= mSpans.length) {
- int newsize = ArrayUtils.idealIntArraySize(mSpanCount + 1);
- Object[] newspans = new Object[newsize];
- int[] newspanstarts = new int[newsize];
- int[] newspanends = new int[newsize];
- int[] newspanflags = new int[newsize];
-
- System.arraycopy(mSpans, 0, newspans, 0, mSpanCount);
- System.arraycopy(mSpanStarts, 0, newspanstarts, 0, mSpanCount);
- System.arraycopy(mSpanEnds, 0, newspanends, 0, mSpanCount);
- System.arraycopy(mSpanFlags, 0, newspanflags, 0, mSpanCount);
-
- mSpans = newspans;
- mSpanStarts = newspanstarts;
- mSpanEnds = newspanends;
- mSpanFlags = newspanflags;
- }
-
- mSpans[mSpanCount] = what;
- mSpanStarts[mSpanCount] = start;
- mSpanEnds[mSpanCount] = end;
- mSpanFlags[mSpanCount] = flags;
- mSpanCount++;
-
- if (send)
- sendSpanAdded(what, nstart, nend);
- }
-
- /**
- * Remove the specified markup object from the buffer.
- */
- public void removeSpan(Object what) {
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpans[i] == what) {
- int ostart = mSpanStarts[i];
- int oend = mSpanEnds[i];
-
- if (ostart > mGapStart)
- ostart -= mGapLength;
- if (oend > mGapStart)
- oend -= mGapLength;
-
- int count = mSpanCount - (i + 1);
-
- System.arraycopy(mSpans, i + 1, mSpans, i, count);
- System.arraycopy(mSpanStarts, i + 1, mSpanStarts, i, count);
- System.arraycopy(mSpanEnds, i + 1, mSpanEnds, i, count);
- System.arraycopy(mSpanFlags, i + 1, mSpanFlags, i, count);
-
- mSpanCount--;
- mSpans[mSpanCount] = null;
-
- sendSpanRemoved(what, ostart, oend);
- return;
- }
- }
- }
-
- /**
- * Return the buffer offset of the beginning of the specified
- * markup object, or -1 if it is not attached to this buffer.
- */
- public int getSpanStart(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- int where = mSpanStarts[i];
-
- if (where > mGapStart)
- where -= mGapLength;
-
- return where;
- }
- }
-
- return -1;
- }
-
- /**
- * Return the buffer offset of the end of the specified
- * markup object, or -1 if it is not attached to this buffer.
- */
- public int getSpanEnd(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- int where = mSpanEnds[i];
-
- if (where > mGapStart)
- where -= mGapLength;
-
- return where;
- }
- }
-
- return -1;
- }
-
- /**
- * Return the flags of the end of the specified
- * markup object, or 0 if it is not attached to this buffer.
- */
- public int getSpanFlags(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- return mSpanFlags[i];
- }
- }
-
- return 0;
- }
-
- /**
- * Return an array of the spans of the specified type that overlap
- * the specified range of the buffer. The kind may be Object.class to get
- * a list of all the spans regardless of type.
- */
- public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
- int spanCount = mSpanCount;
- Object[] spans = mSpans;
- int[] starts = mSpanStarts;
- int[] ends = mSpanEnds;
- int[] flags = mSpanFlags;
- int gapstart = mGapStart;
- int gaplen = mGapLength;
-
- int count = 0;
- Object[] ret = null;
- Object ret1 = null;
-
- for (int i = 0; i < spanCount; i++) {
- int spanStart = starts[i];
- int spanEnd = ends[i];
-
- if (spanStart > gapstart) {
- spanStart -= gaplen;
- }
- if (spanEnd > gapstart) {
- spanEnd -= gaplen;
- }
-
- if (spanStart > queryEnd) {
- continue;
- }
- if (spanEnd < queryStart) {
- continue;
- }
-
- if (spanStart != spanEnd && queryStart != queryEnd) {
- if (spanStart == queryEnd)
- continue;
- if (spanEnd == queryStart)
- continue;
- }
-
- if (kind != null && !kind.isInstance(spans[i])) {
- continue;
- }
-
- if (count == 0) {
- ret1 = spans[i];
- count++;
- } else {
- if (count == 1) {
- ret = (Object[]) Array.newInstance(kind, spanCount - i + 1);
- ret[0] = ret1;
- }
-
- int prio = flags[i] & SPAN_PRIORITY;
- if (prio != 0) {
- int j;
-
- for (j = 0; j < count; j++) {
- int p = getSpanFlags(ret[j]) & SPAN_PRIORITY;
-
- if (prio > p) {
- break;
- }
- }
-
- System.arraycopy(ret, j, ret, j + 1, count - j);
- ret[j] = spans[i];
- count++;
- } else {
- ret[count++] = spans[i];
- }
- }
- }
-
- if (count == 0) {
- return (T[]) ArrayUtils.emptyArray(kind);
- }
- if (count == 1) {
- ret = (Object[]) Array.newInstance(kind, 1);
- ret[0] = ret1;
- return (T[]) ret;
- }
- if (count == ret.length) {
- return (T[]) ret;
- }
-
- Object[] nret = (Object[]) Array.newInstance(kind, count);
- System.arraycopy(ret, 0, nret, 0, count);
- return (T[]) nret;
- }
-
- /**
- * Return the next offset after <code>start</code> but less than or
- * equal to <code>limit</code> where a span of the specified type
- * begins or ends.
- */
- public int nextSpanTransition(int start, int limit, Class kind) {
- int count = mSpanCount;
- Object[] spans = mSpans;
- int[] starts = mSpanStarts;
- int[] ends = mSpanEnds;
- int gapstart = mGapStart;
- int gaplen = mGapLength;
-
- if (kind == null) {
- kind = Object.class;
- }
-
- for (int i = 0; i < count; i++) {
- int st = starts[i];
- int en = ends[i];
-
- if (st > gapstart)
- st -= gaplen;
- if (en > gapstart)
- en -= gaplen;
-
- if (st > start && st < limit && kind.isInstance(spans[i]))
- limit = st;
- if (en > start && en < limit && kind.isInstance(spans[i]))
- limit = en;
- }
-
- return limit;
- }
-
- /**
- * Return a new CharSequence containing a copy of the specified
- * range of this buffer, including the overlapping spans.
- */
- public CharSequence subSequence(int start, int end) {
- return new SpannableStringBuilder(this, start, end);
- }
-
- /**
- * Copy the specified range of chars from this buffer into the
- * specified array, beginning at the specified offset.
- */
- public void getChars(int start, int end, char[] dest, int destoff) {
- checkRange("getChars", start, end);
-
- if (end <= mGapStart) {
- System.arraycopy(mText, start, dest, destoff, end - start);
- } else if (start >= mGapStart) {
- System.arraycopy(mText, start + mGapLength,
- dest, destoff, end - start);
- } else {
- System.arraycopy(mText, start, dest, destoff, mGapStart - start);
- System.arraycopy(mText, mGapStart + mGapLength,
- dest, destoff + (mGapStart - start),
- end - mGapStart);
- }
- }
-
- /**
- * Return a String containing a copy of the chars in this buffer.
- */
- public String toString() {
- int len = length();
- char[] buf = new char[len];
-
- getChars(0, len, buf, 0);
- return new String(buf);
- }
-
- private TextWatcher[] sendTextWillChange(int start, int before, int after) {
- TextWatcher[] recip = getSpans(start, start + before, TextWatcher.class);
- int n = recip.length;
-
- for (int i = 0; i < n; i++) {
- recip[i].beforeTextChanged(this, start, before, after);
- }
-
- return recip;
- }
-
- private void sendTextChange(TextWatcher[] recip, int start, int before,
- int after) {
- int n = recip.length;
-
- for (int i = 0; i < n; i++) {
- recip[i].onTextChanged(this, start, before, after);
- }
- }
-
- private void sendTextHasChanged(TextWatcher[] recip) {
- int n = recip.length;
-
- for (int i = 0; i < n; i++) {
- recip[i].afterTextChanged(this);
- }
- }
-
- private void sendSpanAdded(Object what, int start, int end) {
- SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class);
- int n = recip.length;
-
- for (int i = 0; i < n; i++) {
- recip[i].onSpanAdded(this, what, start, end);
- }
- }
-
- private void sendSpanRemoved(Object what, int start, int end) {
- SpanWatcher[] recip = getSpans(start, end, SpanWatcher.class);
- int n = recip.length;
-
- for (int i = 0; i < n; i++) {
- recip[i].onSpanRemoved(this, what, start, end);
- }
- }
-
- private void sendSpanChanged(Object what, int s, int e, int st, int en) {
- SpanWatcher[] recip = getSpans(Math.min(s, st), Math.max(e, en),
- SpanWatcher.class);
- int n = recip.length;
-
- for (int i = 0; i < n; i++) {
- recip[i].onSpanChanged(this, what, s, e, st, en);
- }
- }
-
- private static String region(int start, int end) {
- return "(" + start + " ... " + end + ")";
- }
-
- private void checkRange(final String operation, int start, int end) {
- if (end < start) {
- throw new IndexOutOfBoundsException(operation + " " +
- region(start, end) +
- " has end before start");
- }
-
- int len = length();
-
- if (start > len || end > len) {
- throw new IndexOutOfBoundsException(operation + " " +
- region(start, end) +
- " ends beyond length " + len);
- }
-
- if (start < 0 || end < 0) {
- throw new IndexOutOfBoundsException(operation + " " +
- region(start, end) +
- " starts before 0");
- }
- }
-
- private boolean isprint(char c) { // XXX
- if (c >= ' ' && c <= '~')
- return true;
- else
- return false;
- }
-
-/*
- private static final int startFlag(int flag) {
- return (flag >> 4) & 0x0F;
- }
-
- private static final int endFlag(int flag) {
- return flag & 0x0F;
- }
-
- public void dump() { // XXX
- for (int i = 0; i < mGapStart; i++) {
- System.out.print('|');
- System.out.print(' ');
- System.out.print(isprint(mText[i]) ? mText[i] : '.');
- System.out.print(' ');
- }
-
- for (int i = mGapStart; i < mGapStart + mGapLength; i++) {
- System.out.print('|');
- System.out.print('(');
- System.out.print(isprint(mText[i]) ? mText[i] : '.');
- System.out.print(')');
- }
-
- for (int i = mGapStart + mGapLength; i < mText.length; i++) {
- System.out.print('|');
- System.out.print(' ');
- System.out.print(isprint(mText[i]) ? mText[i] : '.');
- System.out.print(' ');
- }
-
- System.out.print('\n');
-
- for (int i = 0; i < mText.length + 1; i++) {
- int found = 0;
- int wfound = 0;
-
- for (int j = 0; j < mSpanCount; j++) {
- if (mSpanStarts[j] == i) {
- found = 1;
- wfound = j;
- break;
- }
-
- if (mSpanEnds[j] == i) {
- found = 2;
- wfound = j;
- break;
- }
- }
-
- if (found == 1) {
- if (startFlag(mSpanFlags[wfound]) == MARK)
- System.out.print("( ");
- if (startFlag(mSpanFlags[wfound]) == PARAGRAPH)
- System.out.print("< ");
- else
- System.out.print("[ ");
- } else if (found == 2) {
- if (endFlag(mSpanFlags[wfound]) == POINT)
- System.out.print(") ");
- if (endFlag(mSpanFlags[wfound]) == PARAGRAPH)
- System.out.print("> ");
- else
- System.out.print("] ");
- } else {
- System.out.print(" ");
- }
- }
-
- System.out.print("\n");
- }
-*/
-
- /**
- * Don't call this yourself -- exists for Canvas to use internally.
- * {@hide}
- */
- public void drawText(Canvas c, int start, int end,
- float x, float y, Paint p) {
- checkRange("drawText", start, end);
-
- if (end <= mGapStart) {
- c.drawText(mText, start, end - start, x, y, p);
- } else if (start >= mGapStart) {
- c.drawText(mText, start + mGapLength, end - start, x, y, p);
- } else {
- char[] buf = TextUtils.obtain(end - start);
-
- getChars(start, end, buf, 0);
- c.drawText(buf, 0, end - start, x, y, p);
- TextUtils.recycle(buf);
- }
- }
-
- /**
- * Don't call this yourself -- exists for Paint to use internally.
- * {@hide}
- */
- public float measureText(int start, int end, Paint p) {
- checkRange("measureText", start, end);
-
- float ret;
-
- if (end <= mGapStart) {
- ret = p.measureText(mText, start, end - start);
- } else if (start >= mGapStart) {
- ret = p.measureText(mText, start + mGapLength, end - start);
- } else {
- char[] buf = TextUtils.obtain(end - start);
-
- getChars(start, end, buf, 0);
- ret = p.measureText(buf, 0, end - start);
- TextUtils.recycle(buf);
- }
-
- return ret;
- }
-
- /**
- * Don't call this yourself -- exists for Paint to use internally.
- * {@hide}
- */
- public int getTextWidths(int start, int end, float[] widths, Paint p) {
- checkRange("getTextWidths", start, end);
-
- int ret;
-
- if (end <= mGapStart) {
- ret = p.getTextWidths(mText, start, end - start, widths);
- } else if (start >= mGapStart) {
- ret = p.getTextWidths(mText, start + mGapLength, end - start,
- widths);
- } else {
- char[] buf = TextUtils.obtain(end - start);
-
- getChars(start, end, buf, 0);
- ret = p.getTextWidths(buf, 0, end - start, widths);
- TextUtils.recycle(buf);
- }
-
- return ret;
- }
-
- // Documentation from interface
- public void setFilters(InputFilter[] filters) {
- if (filters == null) {
- throw new IllegalArgumentException();
- }
-
- mFilters = filters;
- }
-
- // Documentation from interface
- public InputFilter[] getFilters() {
- return mFilters;
- }
-
- private static final InputFilter[] NO_FILTERS = new InputFilter[0];
- private InputFilter[] mFilters = NO_FILTERS;
-
- private char[] mText;
- private int mGapStart;
- private int mGapLength;
-
- private Object[] mSpans;
- private int[] mSpanStarts;
- private int[] mSpanEnds;
- private int[] mSpanFlags;
- private int mSpanCount;
-
- private static final int MARK = 1;
- private static final int POINT = 2;
- private static final int PARAGRAPH = 3;
-
- private static final int START_MASK = 0xF0;
- private static final int END_MASK = 0x0F;
- private static final int START_SHIFT = 4;
-}