/* * 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.graphics.Typeface; import android.text.style.UpdateLayout; import android.text.style.WrapTogetherSpan; import java.lang.ref.WeakReference; import com.android.internal.util.ArrayUtils; /** * 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; private int mLineCount; private int[] mLines; /** * 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; } mIncludePad = includepad; mLines = new int[ArrayUtils.idealIntArraySize(6)]; mLineCount = 0; int singleHeight = 0; int totalHeight = 0; String fontStyle = "normal"; String fontWeight = "normal"; String fontFamily = "serif"; Typeface tf = paint.getTypeface(); if (tf != null) { switch (tf.getStyle()) { case 0: fontStyle = "normal"; break; case 1: fontWeight = "bold"; break; case 2: fontStyle = "italic"; break; case 3: fontWeight = "bold"; fontStyle = "italic"; break; default: fontWeight = "bold"; fontStyle = "italic"; break; } if (tf.getFamilyName() == "sans-serif" || tf.getFamilyName() == "serif" || tf.getFamilyName() == "monospace") { fontFamily = tf.getFamilyName(); } else if (null != tf.getFamilyName()) { //console.loge("We don't support this font: " + tf.getFamilyName()); } } String value = base.toString(); if (null == value || "".equals(value)) { value = "A"; } /** * @j2sNative * var div = document.createElement("div"); * div.innerHTML = value; * div.id = "measure_div"; * document.body.appendChild(div); * div.style.visibility = "hidden"; * div.style.position = "absolute"; * div.style.overflow = "hidden"; * div.style.border = "none"; * div.style.padding = "0px"; * div.style.margin = "0px"; * div.style.fontSize = paint.getTextSize() + "px"; * div.style.fontStyle = fontStyle; * div.style.fontWeight = fontWeight; * div.style.fontFamily = fontFamily; * div.style.whiteSpace = "nowrap"; * div.style.height = "auto"; * singleHeight = div.offsetHeight; * div.innerText = value; * div.style.width = width + "px"; * div.style.whiteSpace = "normal"; * //div.style.wordWrap = "break-word"; * totalHeight = div.offsetHeight; * this.mLineCount = totalHeight / singleHeight; * div.parentNode.removeChild(div); */{} for (int i = 1; i <= mLineCount; i++) { mLines[i] = singleHeight * i; } if (mLines[mLineCount] != totalHeight) { mLines[mLineCount] = totalHeight; } } public int getLineCount() { //return mInts.size() - 1; return mLineCount; } public int getLineTop(int line) { //return mInts.getValue(line, TOP); return mLines[line]; } 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; } 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; }