summaryrefslogtreecommitdiffstats
path: root/core/java/android/text/BoringLayout.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch)
treed88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/text/BoringLayout.java
parentd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff)
downloadframeworks_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.java388
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;
+ }
+ }
+}