diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/text/BoringLayout.java | |
parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
download | frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/text/BoringLayout.java')
-rw-r--r-- | core/java/android/text/BoringLayout.java | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java new file mode 100644 index 0000000..843754b --- /dev/null +++ b/core/java/android/text/BoringLayout.java @@ -0,0 +1,388 @@ +/* + * 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.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.FloatMath; + +/** + * A BoringLayout is a very simple Layout implementation for text that + * fits on a single line and is all left-to-right characters. + * You will probably never want to make one of these yourself; + * if you do, be sure to call {@link #isBoring} first to make sure + * the text meets the criteria. + * <p>This class 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, in which case + * you are encouraged to use a Layout instead of calling + * {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint) + * Canvas.drawText()} directly.</p> + */ +public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback { + public static BoringLayout make(CharSequence source, + TextPaint paint, int outerwidth, + Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, boolean includepad) { + return new BoringLayout(source, paint, outerwidth, align, + spacingmult, spacingadd, metrics, + includepad); + } + + public static BoringLayout make(CharSequence source, + TextPaint paint, int outerwidth, + Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, boolean includepad, + TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { + return new BoringLayout(source, paint, outerwidth, align, + spacingmult, spacingadd, metrics, + includepad, ellipsize, ellipsizedWidth); + } + + /** + * Returns a BoringLayout for the specified text, potentially reusing + * this one if it is already suitable. The caller must make sure that + * no one is still using this Layout. + */ + public BoringLayout replaceOrMake(CharSequence source, TextPaint paint, + int outerwidth, Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, + boolean includepad) { + replaceWith(source, paint, outerwidth, align, spacingmult, + spacingadd); + + mEllipsizedWidth = outerwidth; + mEllipsizedStart = 0; + mEllipsizedCount = 0; + + init(source, paint, outerwidth, align, spacingmult, spacingadd, + metrics, includepad, true); + return this; + } + + /** + * Returns a BoringLayout for the specified text, potentially reusing + * this one if it is already suitable. The caller must make sure that + * no one is still using this Layout. + */ + public BoringLayout replaceOrMake(CharSequence source, TextPaint paint, + int outerwidth, Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, + boolean includepad, + TextUtils.TruncateAt ellipsize, + int ellipsizedWidth) { + boolean trust; + + if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) { + replaceWith(source, paint, outerwidth, align, spacingmult, + spacingadd); + + mEllipsizedWidth = outerwidth; + mEllipsizedStart = 0; + mEllipsizedCount = 0; + trust = true; + } else { + replaceWith(TextUtils.ellipsize(source, paint, ellipsizedWidth, + ellipsize, true, this), + paint, outerwidth, align, spacingmult, + spacingadd); + + mEllipsizedWidth = ellipsizedWidth; + trust = false; + } + + init(getText(), paint, outerwidth, align, spacingmult, spacingadd, + metrics, includepad, trust); + return this; + } + + public BoringLayout(CharSequence source, + TextPaint paint, int outerwidth, + Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, boolean includepad) { + super(source, paint, outerwidth, align, spacingmult, spacingadd); + + mEllipsizedWidth = outerwidth; + mEllipsizedStart = 0; + mEllipsizedCount = 0; + + init(source, paint, outerwidth, align, spacingmult, spacingadd, + metrics, includepad, true); + } + + public BoringLayout(CharSequence source, + TextPaint paint, int outerwidth, + Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, boolean includepad, + TextUtils.TruncateAt ellipsize, int ellipsizedWidth) { + /* + * It is silly to have to call super() and then replaceWith(), + * but we can't use "this" for the callback until the call to + * super() finishes. + */ + super(source, paint, outerwidth, align, spacingmult, spacingadd); + + boolean trust; + + if (ellipsize == null || ellipsize == TextUtils.TruncateAt.MARQUEE) { + mEllipsizedWidth = outerwidth; + mEllipsizedStart = 0; + mEllipsizedCount = 0; + trust = true; + } else { + replaceWith(TextUtils.ellipsize(source, paint, ellipsizedWidth, + ellipsize, true, this), + paint, outerwidth, align, spacingmult, + spacingadd); + + + mEllipsizedWidth = ellipsizedWidth; + trust = false; + } + + init(getText(), paint, outerwidth, align, spacingmult, spacingadd, + metrics, includepad, trust); + } + + /* package */ void init(CharSequence source, + TextPaint paint, int outerwidth, + Alignment align, + float spacingmult, float spacingadd, + BoringLayout.Metrics metrics, boolean includepad, + boolean trustWidth) { + int spacing; + + if (source instanceof String && align == Layout.Alignment.ALIGN_NORMAL) { + mDirect = source.toString(); + } else { + mDirect = null; + } + + mPaint = paint; + + if (includepad) { + spacing = metrics.bottom - metrics.top; + } else { + spacing = metrics.descent - metrics.ascent; + } + + if (spacingmult != 1 || spacingadd != 0) { + spacing = (int)(spacing * spacingmult + spacingadd + 0.5f); + } + + mBottom = spacing; + + if (includepad) { + mDesc = spacing + metrics.top; + } else { + mDesc = spacing + metrics.ascent; + } + + if (trustWidth) { + mMax = metrics.width; + } else { + /* + * If we have ellipsized, we have to actually calculate the + * width because the width that was passed in was for the + * full text, not the ellipsized form. + */ + synchronized (sTemp) { + mMax = (int) (FloatMath.ceil(Styled.measureText(paint, sTemp, + source, 0, source.length(), + null))); + } + } + + if (includepad) { + mTopPadding = metrics.top - metrics.ascent; + mBottomPadding = metrics.bottom - metrics.descent; + } + } + + /** + * Returns null if not boring; the width, ascent, and descent if boring. + */ + public static Metrics isBoring(CharSequence text, + TextPaint paint) { + return isBoring(text, paint, null); + } + + /** + * Returns null if not boring; the width, ascent, and descent in the + * provided Metrics object (or a new one if the provided one was null) + * if boring. + */ + public static Metrics isBoring(CharSequence text, TextPaint paint, + Metrics metrics) { + char[] temp = TextUtils.obtain(500); + int len = text.length(); + boolean boring = true; + + outer: + for (int i = 0; i < len; i += 500) { + int j = i + 500; + + if (j > len) + j = len; + + TextUtils.getChars(text, i, j, temp, 0); + + int n = j - i; + + for (int a = 0; a < n; a++) { + char c = temp[a]; + + if (c == '\n' || c == '\t' || c >= FIRST_RIGHT_TO_LEFT) { + boring = false; + break outer; + } + } + } + + TextUtils.recycle(temp); + + if (boring) { + Metrics fm = metrics; + if (fm == null) { + fm = new Metrics(); + } + + int wid; + + synchronized (sTemp) { + wid = (int) (FloatMath.ceil(Styled.measureText(paint, sTemp, + text, 0, text.length(), fm))); + } + fm.width = wid; + return fm; + } else { + return null; + } + } + + @Override public int getHeight() { + return mBottom; + } + + @Override public int getLineCount() { + return 1; + } + + @Override public int getLineTop(int line) { + if (line == 0) + return 0; + else + return mBottom; + } + + @Override public int getLineDescent(int line) { + return mDesc; + } + + @Override public int getLineStart(int line) { + if (line == 0) + return 0; + else + return getText().length(); + } + + @Override public int getParagraphDirection(int line) { + return DIR_LEFT_TO_RIGHT; + } + + @Override public boolean getLineContainsTab(int line) { + return false; + } + + @Override public float getLineMax(int line) { + return mMax; + } + + @Override public final Directions getLineDirections(int line) { + return Layout.DIRS_ALL_LEFT_TO_RIGHT; + } + + public int getTopPadding() { + return mTopPadding; + } + + public int getBottomPadding() { + return mBottomPadding; + } + + @Override + public int getEllipsisCount(int line) { + return mEllipsizedCount; + } + + @Override + public int getEllipsisStart(int line) { + return mEllipsizedStart; + } + + @Override + public int getEllipsizedWidth() { + return mEllipsizedWidth; + } + + // Override draw so it will be faster. + @Override + public void draw(Canvas c, Path highlight, Paint highlightpaint, + int cursorOffset) { + if (mDirect != null && highlight == null) { + c.drawText(mDirect, 0, mBottom - mDesc, mPaint); + } else { + super.draw(c, highlight, highlightpaint, cursorOffset); + } + } + + /** + * Callback for the ellipsizer to report what region it ellipsized. + */ + public void ellipsized(int start, int end) { + mEllipsizedStart = start; + mEllipsizedCount = end - start; + } + + private static final char FIRST_RIGHT_TO_LEFT = '\u0590'; + + private String mDirect; + private Paint mPaint; + + /* package */ int mBottom, mDesc; // for Direct + private int mTopPadding, mBottomPadding; + private float mMax; + private int mEllipsizedWidth, mEllipsizedStart, mEllipsizedCount; + + private static final TextPaint sTemp = + new TextPaint(); + + public static class Metrics extends Paint.FontMetricsInt { + public int width; + + @Override public String toString() { + return super.toString() + " width=" + width; + } + } +} |