diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:45 -0800 |
commit | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/text/DynamicLayout.java | |
parent | 076357b8567458d4b6dfdcf839ef751634cd2bfb (diff) | |
download | frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/text/DynamicLayout.java')
-rw-r--r-- | core/java/android/text/DynamicLayout.java | 503 |
1 files changed, 0 insertions, 503 deletions
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java deleted file mode 100644 index 14e5655..0000000 --- a/core/java/android/text/DynamicLayout.java +++ /dev/null @@ -1,503 +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 android.graphics.Paint; -import android.text.style.UpdateLayout; -import android.text.style.WrapTogetherSpan; - -import java.lang.ref.WeakReference; - -/** - * DynamicLayout is a text layout that updates itself as the text is edited. - * <p>This is used by widgets to control text layout. You should not need - * to use this class directly unless you are implementing your own widget - * or custom display object, or need to call - * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) - * Canvas.drawText()} directly.</p> - */ -public class DynamicLayout -extends Layout -{ - private static final int PRIORITY = 128; - - /** - * Make a layout for the specified text that will be updated as - * the text is changed. - */ - public DynamicLayout(CharSequence base, - TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd, - boolean includepad) { - this(base, base, paint, width, align, spacingmult, spacingadd, - includepad); - } - - /** - * Make a layout for the transformed text (password transformation - * being the primary example of a transformation) - * that will be updated as the base text is changed. - */ - public DynamicLayout(CharSequence base, CharSequence display, - TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd, - boolean includepad) { - this(base, display, paint, width, align, spacingmult, spacingadd, - includepad, null, 0); - } - - /** - * Make a layout for the transformed text (password transformation - * being the primary example of a transformation) - * that will be updated as the base text is changed. - * If ellipsize is non-null, the Layout will ellipsize the text - * down to ellipsizedWidth. - */ - public DynamicLayout(CharSequence base, CharSequence display, - TextPaint paint, - int width, Alignment align, - float spacingmult, float spacingadd, - boolean includepad, - TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { - super((ellipsize == null) - ? display - : (display instanceof Spanned) - ? new SpannedEllipsizer(display) - : new Ellipsizer(display), - paint, width, align, spacingmult, spacingadd); - - mBase = base; - mDisplay = display; - - if (ellipsize != null) { - mInts = new PackedIntVector(COLUMNS_ELLIPSIZE); - mEllipsizedWidth = ellipsizedWidth; - mEllipsizeAt = ellipsize; - } else { - mInts = new PackedIntVector(COLUMNS_NORMAL); - mEllipsizedWidth = width; - mEllipsizeAt = ellipsize; - } - - mObjects = new PackedObjectVector<Directions>(1); - - mIncludePad = includepad; - - /* - * This is annoying, but we can't refer to the layout until - * superclass construction is finished, and the superclass - * constructor wants the reference to the display text. - * - * This will break if the superclass constructor ever actually - * cares about the content instead of just holding the reference. - */ - if (ellipsize != null) { - Ellipsizer e = (Ellipsizer) getText(); - - e.mLayout = this; - e.mWidth = ellipsizedWidth; - e.mMethod = ellipsize; - mEllipsize = true; - } - - // Initial state is a single line with 0 characters (0 to 0), - // with top at 0 and bottom at whatever is natural, and - // undefined ellipsis. - - int[] start; - - if (ellipsize != null) { - start = new int[COLUMNS_ELLIPSIZE]; - start[ELLIPSIS_START] = ELLIPSIS_UNDEFINED; - } else { - start = new int[COLUMNS_NORMAL]; - } - - Directions[] dirs = new Directions[] { DIRS_ALL_LEFT_TO_RIGHT }; - - Paint.FontMetricsInt fm = paint.getFontMetricsInt(); - int asc = fm.ascent; - int desc = fm.descent; - - start[DIR] = DIR_LEFT_TO_RIGHT << DIR_SHIFT; - start[TOP] = 0; - start[DESCENT] = desc; - mInts.insertAt(0, start); - - start[TOP] = desc - asc; - mInts.insertAt(1, start); - - mObjects.insertAt(0, dirs); - - // Update from 0 characters to whatever the real text is - - reflow(base, 0, 0, base.length()); - - if (base instanceof Spannable) { - if (mWatcher == null) - mWatcher = new ChangeWatcher(this); - - // Strip out any watchers for other DynamicLayouts. - Spannable sp = (Spannable) base; - ChangeWatcher[] spans = sp.getSpans(0, sp.length(), ChangeWatcher.class); - for (int i = 0; i < spans.length; i++) - sp.removeSpan(spans[i]); - - sp.setSpan(mWatcher, 0, base.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE | - (PRIORITY << Spannable.SPAN_PRIORITY_SHIFT)); - } - } - - private void reflow(CharSequence s, int where, int before, int after) { - if (s != mBase) - return; - - CharSequence text = mDisplay; - int len = text.length(); - - // seek back to the start of the paragraph - - int find = TextUtils.lastIndexOf(text, '\n', where - 1); - if (find < 0) - find = 0; - else - find = find + 1; - - { - int diff = where - find; - before += diff; - after += diff; - where -= diff; - } - - // seek forward to the end of the paragraph - - int look = TextUtils.indexOf(text, '\n', where + after); - if (look < 0) - look = len; - else - look++; // we want the index after the \n - - int change = look - (where + after); - before += change; - after += change; - - // seek further out to cover anything that is forced to wrap together - - if (text instanceof Spanned) { - Spanned sp = (Spanned) text; - boolean again; - - do { - again = false; - - Object[] force = sp.getSpans(where, where + after, - WrapTogetherSpan.class); - - for (int i = 0; i < force.length; i++) { - int st = sp.getSpanStart(force[i]); - int en = sp.getSpanEnd(force[i]); - - if (st < where) { - again = true; - - int diff = where - st; - before += diff; - after += diff; - where -= diff; - } - - if (en > where + after) { - again = true; - - int diff = en - (where + after); - before += diff; - after += diff; - } - } - } while (again); - } - - // find affected region of old layout - - int startline = getLineForOffset(where); - int startv = getLineTop(startline); - - int endline = getLineForOffset(where + before); - if (where + after == len) - endline = getLineCount(); - int endv = getLineTop(endline); - boolean islast = (endline == getLineCount()); - - // generate new layout for affected text - - StaticLayout reflowed; - - synchronized (sLock) { - reflowed = sStaticLayout; - sStaticLayout = null; - } - - if (reflowed == null) - reflowed = new StaticLayout(true); - - reflowed.generate(text, where, where + after, - getPaint(), getWidth(), getAlignment(), - getSpacingMultiplier(), getSpacingAdd(), - false, true, mEllipsize, - mEllipsizedWidth, mEllipsizeAt); - int n = reflowed.getLineCount(); - - // If the new layout has a blank line at the end, but it is not - // the very end of the buffer, then we already have a line that - // starts there, so disregard the blank line. - - if (where + after != len && - reflowed.getLineStart(n - 1) == where + after) - n--; - - // remove affected lines from old layout - - mInts.deleteAt(startline, endline - startline); - mObjects.deleteAt(startline, endline - startline); - - // adjust offsets in layout for new height and offsets - - int ht = reflowed.getLineTop(n); - int toppad = 0, botpad = 0; - - if (mIncludePad && startline == 0) { - toppad = reflowed.getTopPadding(); - mTopPadding = toppad; - ht -= toppad; - } - if (mIncludePad && islast) { - botpad = reflowed.getBottomPadding(); - mBottomPadding = botpad; - ht += botpad; - } - - mInts.adjustValuesBelow(startline, START, after - before); - mInts.adjustValuesBelow(startline, TOP, startv - endv + ht); - - // insert new layout - - int[] ints; - - if (mEllipsize) { - ints = new int[COLUMNS_ELLIPSIZE]; - ints[ELLIPSIS_START] = ELLIPSIS_UNDEFINED; - } else { - ints = new int[COLUMNS_NORMAL]; - } - - Directions[] objects = new Directions[1]; - - - for (int i = 0; i < n; i++) { - ints[START] = reflowed.getLineStart(i) | - (reflowed.getParagraphDirection(i) << DIR_SHIFT) | - (reflowed.getLineContainsTab(i) ? TAB_MASK : 0); - - int top = reflowed.getLineTop(i) + startv; - if (i > 0) - top -= toppad; - ints[TOP] = top; - - int desc = reflowed.getLineDescent(i); - if (i == n - 1) - desc += botpad; - - ints[DESCENT] = desc; - objects[0] = reflowed.getLineDirections(i); - - if (mEllipsize) { - ints[ELLIPSIS_START] = reflowed.getEllipsisStart(i); - ints[ELLIPSIS_COUNT] = reflowed.getEllipsisCount(i); - } - - mInts.insertAt(startline + i, ints); - mObjects.insertAt(startline + i, objects); - } - - synchronized (sLock) { - sStaticLayout = reflowed; - } - } - - private void dump(boolean show) { - int n = getLineCount(); - - for (int i = 0; i < n; i++) { - System.out.print("line " + i + ": " + getLineStart(i) + " to " + getLineEnd(i) + " "); - - if (show) { - System.out.print(getText().subSequence(getLineStart(i), - getLineEnd(i))); - } - - System.out.println(""); - } - - System.out.println(""); - } - - public int getLineCount() { - return mInts.size() - 1; - } - - public int getLineTop(int line) { - return mInts.getValue(line, TOP); - } - - public int getLineDescent(int line) { - return mInts.getValue(line, DESCENT); - } - - public int getLineStart(int line) { - return mInts.getValue(line, START) & START_MASK; - } - - public boolean getLineContainsTab(int line) { - return (mInts.getValue(line, TAB) & TAB_MASK) != 0; - } - - public int getParagraphDirection(int line) { - return mInts.getValue(line, DIR) >> DIR_SHIFT; - } - - public final Directions getLineDirections(int line) { - return mObjects.getValue(line, 0); - } - - public int getTopPadding() { - return mTopPadding; - } - - public int getBottomPadding() { - return mBottomPadding; - } - - @Override - public int getEllipsizedWidth() { - return mEllipsizedWidth; - } - - private static class ChangeWatcher - implements TextWatcher, SpanWatcher - { - public ChangeWatcher(DynamicLayout layout) { - mLayout = new WeakReference(layout); - } - - private void reflow(CharSequence s, int where, int before, int after) { - DynamicLayout ml = (DynamicLayout) mLayout.get(); - - if (ml != null) - ml.reflow(s, where, before, after); - else if (s instanceof Spannable) - ((Spannable) s).removeSpan(this); - } - - public void beforeTextChanged(CharSequence s, - int where, int before, int after) { - ; - } - - public void onTextChanged(CharSequence s, - int where, int before, int after) { - reflow(s, where, before, after); - } - - public void afterTextChanged(Editable s) { - ; - } - - public void onSpanAdded(Spannable s, Object o, int start, int end) { - if (o instanceof UpdateLayout) - reflow(s, start, end - start, end - start); - } - - public void onSpanRemoved(Spannable s, Object o, int start, int end) { - if (o instanceof UpdateLayout) - reflow(s, start, end - start, end - start); - } - - public void onSpanChanged(Spannable s, Object o, int start, int end, - int nstart, int nend) { - if (o instanceof UpdateLayout) { - reflow(s, start, end - start, end - start); - reflow(s, nstart, nend - nstart, nend - nstart); - } - } - - private WeakReference mLayout; - } - - public int getEllipsisStart(int line) { - if (mEllipsizeAt == null) { - return 0; - } - - return mInts.getValue(line, ELLIPSIS_START); - } - - public int getEllipsisCount(int line) { - if (mEllipsizeAt == null) { - return 0; - } - - return mInts.getValue(line, ELLIPSIS_COUNT); - } - - private CharSequence mBase; - private CharSequence mDisplay; - private ChangeWatcher mWatcher; - private boolean mIncludePad; - private boolean mEllipsize; - private int mEllipsizedWidth; - private TextUtils.TruncateAt mEllipsizeAt; - - private PackedIntVector mInts; - private PackedObjectVector<Directions> mObjects; - - private int mTopPadding, mBottomPadding; - - private static StaticLayout sStaticLayout = new StaticLayout(true); - private static Object sLock = new Object(); - - private static final int START = 0; - private static final int DIR = START; - private static final int TAB = START; - private static final int TOP = 1; - private static final int DESCENT = 2; - private static final int COLUMNS_NORMAL = 3; - - private static final int ELLIPSIS_START = 3; - private static final int ELLIPSIS_COUNT = 4; - private static final int COLUMNS_ELLIPSIZE = 5; - - private static final int START_MASK = 0x1FFFFFFF; - private static final int DIR_MASK = 0xC0000000; - private static final int DIR_SHIFT = 30; - private static final int TAB_MASK = 0x20000000; - - private static final int ELLIPSIS_UNDEFINED = 0x80000000; -} |