summaryrefslogtreecommitdiffstats
path: root/core/java/android/text/DynamicLayout.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/DynamicLayout.java
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
downloadframeworks_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.java503
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;
-}