/*
* 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.Bitmap;
import android.graphics.Paint;
import android.graphics.Typeface;
import com.android.internal.util.ArrayUtils;
import android.text.style.LeadingMarginSpan;
import android.text.style.LineHeightSpan;
import android.text.style.MetricAffectingSpan;
import android.text.style.ReplacementSpan;
/**
* StaticLayout is a Layout for text that will not be edited after it
* is laid out. Use {@link DynamicLayout} for text that may change.
* <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 would be tempted to call
* {@link android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
* Canvas.drawText()} directly.</p>
*/
public class StaticLayout extends Layout {
public StaticLayout(CharSequence source, TextPaint paint,
int width,
Alignment align, float spacingmult, float spacingadd,
boolean includepad) {
this(source, 0, source.length(), paint, width, align,
spacingmult, spacingadd, includepad);
}
public StaticLayout(CharSequence source, int bufstart, int bufend,
TextPaint paint, int outerwidth,
Alignment align,
float spacingmult, float spacingadd,
boolean includepad) {
this(source, bufstart, bufend, paint, outerwidth, align,
spacingmult, spacingadd, includepad, null, 0);
}
public StaticLayout(CharSequence source, int bufstart, int bufend,
TextPaint paint, int outerwidth,
Alignment align,
float spacingmult, float spacingadd,
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
super((ellipsize == null) ? source : (source instanceof Spanned) ? new SpannedEllipsizer(source) : new Ellipsizer(source),
paint, outerwidth, align, spacingmult, spacingadd);
/*
* 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;
mEllipsizedWidth = ellipsizedWidth;
mColumns = COLUMNS_ELLIPSIZE;
} else {
mColumns = COLUMNS_NORMAL;
mEllipsizedWidth = outerwidth;
}
mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
mLineDirections = new Directions[
ArrayUtils.idealIntArraySize(2 * mColumns)];
generate(source, bufstart, bufend, paint, outerwidth, align,
spacingmult, spacingadd, includepad, includepad,
ellipsize != null, ellipsizedWidth, ellipsize);
mChdirs = null;
mChs = null;
mWidths = null;
mFontMetricsInt = null;
}
/* package */ StaticLayout(boolean ellipsize) {
super(null, null, 0, null, 0, 0);
mColumns = COLUMNS_ELLIPSIZE;
mLines = new int[ArrayUtils.idealIntArraySize(2 * mColumns)];
mLineDirections = new Directions[
ArrayUtils.idealIntArraySize(2 * mColumns)];
}
/* package */ void generate(CharSequence source, int bufstart, int bufend,
TextPaint paint, int outerwidth,
Alignment align,
float spacingmult, float spacingadd,
boolean includepad, boolean trackpad,
boolean breakOnlyAtSpaces,
float ellipsizedWidth, TextUtils.TruncateAt where) {
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 = source.toString();
/**
* @j2sNative
* var div = document.createElement("div");
* if (value.isHtml) {
* div.innerHTML = value;
* } else {
* div.innerText = 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;
* if (value.isHtml) {
* div.innerHTML = value;
* } else {
* div.innerText = value;
* }
* div.style.width = outerwidth + "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;
}
}
// Override the baseclass so we can directly access our members,
// rather than relying on member functions.
// The logic mirrors that of Layout.getLineForVertical
// FIXME: It may be faster to do a linear search for layouts without many lines.
public int getLineForVertical(int vertical) {
int high = mLineCount;
int low = -1;
int guess;
int[] lines = mLines;
while (high - low > 1) {
guess = (high + low) >> 1;
if (lines[mColumns * guess + TOP] > vertical){
high = guess;
} else {
low = guess;
}
}
if (low < 0) {
return 0;
} else {
return low;
}
}
public int getLineCount() {
return mLineCount;
}
public int getLineTop(int line) {
return mLines[line];
}
public int getLineDescent(int line) {
return mLines[mColumns * line + DESCENT];
}
public int getLineStart(int line) {
return mLines[mColumns * line + START] & START_MASK;
}
public int getParagraphDirection(int line) {
return mLines[mColumns * line + DIR] >> DIR_SHIFT;
}
public boolean getLineContainsTab(int line) {
return (mLines[mColumns * line + TAB] & TAB_MASK) != 0;
}
public final Directions getLineDirections(int line) {
return mLineDirections[line];
}
public int getTopPadding() {
return mTopPadding;
}
public int getBottomPadding() {
return mBottomPadding;
}
@Override
public int getEllipsisCount(int line) {
if (mColumns < COLUMNS_ELLIPSIZE) {
return 0;
}
return mLines[mColumns * line + ELLIPSIS_COUNT];
}
@Override
public int getEllipsisStart(int line) {
if (mColumns < COLUMNS_ELLIPSIZE) {
return 0;
}
return mLines[mColumns * line + ELLIPSIS_START];
}
@Override
public int getEllipsizedWidth() {
return mEllipsizedWidth;
}
private int mLineCount;
private int mTopPadding, mBottomPadding;
private int mColumns;
private int mEllipsizedWidth;
private static final int COLUMNS_NORMAL = 3;
private static final int COLUMNS_ELLIPSIZE = 5;
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 ELLIPSIS_START = 3;
private static final int ELLIPSIS_COUNT = 4;
private int[] mLines;
private Directions[] mLineDirections;
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 char FIRST_RIGHT_TO_LEFT = '\u0590';
/*
* These are reused across calls to generate()
*/
private byte[] mChdirs;
private char[] mChs;
private float[] mWidths;
private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
}