summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src/android
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge/src/android')
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap.java4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java90
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java534
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface.java48
-rw-r--r--tools/layoutlib/bridge/src/android/webkit/WebView.java7
5 files changed, 540 insertions, 143 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
index 7dde634..ff1b295 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
@@ -28,13 +28,13 @@ public final class Bitmap extends _Original_Bitmap {
private BufferedImage mImage;
public Bitmap(File input) throws IOException {
- super(1, true, null);
+ super(1, true, null, -1);
mImage = ImageIO.read(input);
}
Bitmap(BufferedImage image) {
- super(1, true, null);
+ super(1, true, null, -1);
mImage = image;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
index 3fa1d1d..4986c77 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
@@ -26,6 +26,7 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Xfermode;
import android.graphics.Paint.Align;
+import android.graphics.Paint.FontInfo;
import android.graphics.Paint.Style;
import android.graphics.Region.Op;
@@ -37,6 +38,7 @@ import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
+import java.util.List;
import java.util.Stack;
import javax.microedition.khronos.opengles.GL;
@@ -620,19 +622,21 @@ public class Canvas extends _Original_Canvas {
*/
@Override
public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
+ // WARNING: the logic in this method is similar to Paint.measureText.
+ // Any change to this method should be reflected in Paint.measureText
Graphics2D g = getGraphics2d();
g = (Graphics2D)g.create();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setFont(paint.getFont());
-
- // set the color. because this only handles RGB we have to handle the alpha separately
+ // set the color. because this only handles RGB, the alpha channel is handled
+ // as a composite.
g.setColor(new Color(paint.getColor()));
int alpha = paint.getAlpha();
float falpha = alpha / 255.f;
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
+
// Paint.TextAlign indicates how the text is positioned relative to X.
// LEFT is the default and there's nothing to do.
if (paint.getTextAlign() != Align.LEFT) {
@@ -644,9 +648,83 @@ public class Canvas extends _Original_Canvas {
}
}
- g.drawChars(text, index, count, (int)x, (int)y);
-
- g.dispose();
+ List<FontInfo> fonts = paint.getFonts();
+ try {
+ if (fonts.size() > 0) {
+ FontInfo mainFont = fonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // draw all the rest and exit.
+ g.setFont(mainFont.mFont);
+ g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
+ return;
+ } else if (upTo > 0) {
+ // draw what's possible
+ g.setFont(mainFont.mFont);
+ g.drawChars(text, i, upTo - i, (int)x, (int)y);
+
+ // compute the width that was drawn to increase x
+ x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+
+ // move index to the first non displayed char.
+ i = upTo;
+
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < fonts.size() ; f++) {
+ FontInfo fontInfo = fonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ // draw that char
+ g.setFont(fontInfo.mFont);
+ g.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // update x
+ x += fontInfo.mMetrics.charsWidth(text, i, charCount);
+
+ // update the index in the text, and move on
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, display it with the main font.
+ // (it'll put a square probably)
+ if (foundFont == false) {
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+
+ g.setFont(mainFont.mFont);
+ g.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // measure it to advance x
+ x += mainFont.mMetrics.charsWidth(text, i, charCount);
+
+ // and move to the next chars.
+ i += charCount;
+ }
+ }
+ }
+ } finally {
+ g.dispose();
+ }
}
/* (non-Javadoc)
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
index ade07d6..86de56b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint.java
@@ -26,6 +26,9 @@ import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
* A paint implementation overridden by the LayoutLib bridge.
@@ -33,17 +36,28 @@ import java.awt.geom.Rectangle2D;
public class Paint extends _Original_Paint {
private int mColor = 0xFFFFFFFF;
+ private float mStrokeWidth = 1.f;
private float mTextSize = 20;
private float mScaleX = 1;
private float mSkewX = 0;
private Align mAlign = Align.LEFT;
private Style mStyle = Style.FILL;
+ private float mStrokeMiter = 4.0f;
+ private Cap mCap = Cap.BUTT;
+ private Join mJoin = Join.MITER;
private int mFlags = 0;
-
- private Font mFont;
+
+ /**
+ * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+ */
+ public static final class FontInfo {
+ Font mFont;
+ java.awt.FontMetrics mMetrics;
+ }
+
+ private List<FontInfo> mFonts;
private final FontRenderContext mFontContext = new FontRenderContext(
new AffineTransform(), true, true);
- private java.awt.FontMetrics mMetrics;
@SuppressWarnings("hiding")
public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
@@ -65,11 +79,11 @@ public class Paint extends _Original_Paint {
public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
public static class FontMetrics extends _Original_Paint.FontMetrics {
- }
+ }
public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
}
-
+
/**
* The Style specifies if the primitive being drawn is filled,
* stroked, or both (in the same color). The default is FILL.
@@ -91,7 +105,7 @@ public class Paint extends _Original_Paint {
* the paint.
*/
FILL_AND_STROKE (2);
-
+
Style(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -117,7 +131,7 @@ public class Paint extends _Original_Paint {
* end of the path.
*/
SQUARE (2);
-
+
private Cap(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -141,7 +155,7 @@ public class Paint extends _Original_Paint {
* The outer edges of a join meet with a straight line
*/
BEVEL (2);
-
+
private Join(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -165,7 +179,7 @@ public class Paint extends _Original_Paint {
* The text is drawn to the left of the x,y origin
*/
RIGHT (2);
-
+
private Align(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -185,43 +199,61 @@ public class Paint extends _Original_Paint {
set(paint);
initFont();
}
-
+
@Override
public void finalize() throws Throwable {
// pass
}
-
+
+ @Override
+ public void reset() {
+ super.reset();
+ }
+
/**
- * Returns the {@link Font} object.
+ * Returns the list of {@link Font} objects. The first item is the main font, the rest
+ * are fall backs for characters not present in the main font.
*/
- public Font getFont() {
- return mFont;
+ public List<FontInfo> getFonts() {
+ return mFonts;
}
-
+
private void initFont() {
mTypeface = Typeface.DEFAULT;
updateFontObject();
}
-
+
/**
* Update the {@link Font} object from the typeface, text size and scaling
*/
+ @SuppressWarnings("deprecation")
private void updateFontObject() {
if (mTypeface != null) {
- // get the typeface font object, and get our font object from it, based on the current size
- mFont = mTypeface.getFont().deriveFont(mTextSize);
- if (mScaleX != 1.0 || mSkewX != 0) {
- // TODO: support skew
- mFont = mFont.deriveFont(new AffineTransform(
- mScaleX, mSkewX, 0, 0, 1, 0));
+ // Get the fonts from the TypeFace object.
+ List<Font> fonts = mTypeface.getFonts();
+
+ // create new font objects as well as FontMetrics, based on the current text size
+ // and skew info.
+ ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
+ for (Font font : fonts) {
+ FontInfo info = new FontInfo();
+ info.mFont = font.deriveFont(mTextSize);
+ if (mScaleX != 1.0 || mSkewX != 0) {
+ // TODO: support skew
+ info.mFont = info.mFont.deriveFont(new AffineTransform(
+ mScaleX, mSkewX, 0, 0, 1, 0));
+ }
+ info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
+
+ infoList.add(info);
}
-
- mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(mFont);
+
+ mFonts = Collections.unmodifiableList(infoList);
}
}
-
+
//----------------------------------------
-
+
public void set(Paint src) {
if (this != src) {
mColor = src.mColor;
@@ -237,6 +269,11 @@ public class Paint extends _Original_Paint {
}
@Override
+ public void setCompatibilityScaling(float factor) {
+ super.setCompatibilityScaling(factor);
+ }
+
+ @Override
public int getFlags() {
return mFlags;
}
@@ -245,7 +282,47 @@ public class Paint extends _Original_Paint {
public void setFlags(int flags) {
mFlags = flags;
}
-
+
+ @Override
+ public boolean isAntiAlias() {
+ return super.isAntiAlias();
+ }
+
+ @Override
+ public boolean isDither() {
+ return super.isDither();
+ }
+
+ @Override
+ public boolean isLinearText() {
+ return super.isLinearText();
+ }
+
+ @Override
+ public boolean isStrikeThruText() {
+ return super.isStrikeThruText();
+ }
+
+ @Override
+ public boolean isUnderlineText() {
+ return super.isUnderlineText();
+ }
+
+ @Override
+ public boolean isFakeBoldText() {
+ return super.isFakeBoldText();
+ }
+
+ @Override
+ public boolean isSubpixelText() {
+ return super.isSubpixelText();
+ }
+
+ @Override
+ public boolean isFilterBitmap() {
+ return super.isFilterBitmap();
+ }
+
/**
* Return the font's recommended interline spacing, given the Paint's
* settings for typeface, textSize, etc. If metrics is not null, return the
@@ -256,39 +333,41 @@ public class Paint extends _Original_Paint {
* @return the font's recommended interline spacing.
*/
public float getFontMetrics(FontMetrics metrics) {
- if (mMetrics != null) {
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
if (metrics != null) {
- // ascent stuff should be negatif, but awt returns them as positive.
- metrics.top = - mMetrics.getMaxAscent();
- metrics.ascent = - mMetrics.getAscent();
- metrics.descent = mMetrics.getDescent();
- metrics.bottom = mMetrics.getMaxDescent();
- metrics.leading = mMetrics.getLeading();
+ // Android expects negative ascent so we invert the value from Java.
+ metrics.top = - javaMetrics.getMaxAscent();
+ metrics.ascent = - javaMetrics.getAscent();
+ metrics.descent = javaMetrics.getDescent();
+ metrics.bottom = javaMetrics.getMaxDescent();
+ metrics.leading = javaMetrics.getLeading();
}
-
- return mMetrics.getHeight();
+
+ return javaMetrics.getHeight();
}
-
+
return 0;
}
public int getFontMetricsInt(FontMetricsInt metrics) {
- if (mMetrics != null) {
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
if (metrics != null) {
- // ascent stuff should be negatif, but awt returns them as positive.
- metrics.top = - mMetrics.getMaxAscent();
- metrics.ascent = - mMetrics.getAscent();
- metrics.descent = mMetrics.getDescent();
- metrics.bottom = mMetrics.getMaxDescent();
- metrics.leading = mMetrics.getLeading();
+ // Android expects negative ascent so we invert the value from Java.
+ metrics.top = - javaMetrics.getMaxAscent();
+ metrics.ascent = - javaMetrics.getAscent();
+ metrics.descent = javaMetrics.getDescent();
+ metrics.bottom = javaMetrics.getMaxDescent();
+ metrics.leading = javaMetrics.getLeading();
}
-
- return mMetrics.getHeight();
+
+ return javaMetrics.getHeight();
}
-
+
return 0;
}
-
+
/**
* Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
*/
@@ -297,7 +376,7 @@ public class Paint extends _Original_Paint {
getFontMetrics(fm);
return fm;
}
-
+
/**
* Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
*/
@@ -311,16 +390,14 @@ public class Paint extends _Original_Paint {
@Override
public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
@Override
public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
-
+
@Override
public Typeface setTypeface(Typeface typeface) {
if (typeface != null) {
@@ -328,12 +405,17 @@ public class Paint extends _Original_Paint {
} else {
mTypeface = Typeface.DEFAULT;
}
-
+
updateFontObject();
return typeface;
}
-
+
+ @Override
+ public Typeface getTypeface() {
+ return super.getTypeface();
+ }
+
@Override
public int getColor() {
return mColor;
@@ -344,17 +426,21 @@ public class Paint extends _Original_Paint {
mColor = color;
}
+ @Override
+ public void setARGB(int a, int r, int g, int b) {
+ super.setARGB(a, r, g, b);
+ }
@Override
public void setAlpha(int alpha) {
mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
}
-
+
@Override
public int getAlpha() {
return mColor >>> 24;
}
-
+
/**
* Set or clear the shader object.
* <p />
@@ -369,6 +455,11 @@ public class Paint extends _Original_Paint {
return mShader = shader;
}
+ @Override
+ public Shader getShader() {
+ return super.getShader();
+ }
+
/**
* Set or clear the paint's colorfilter, returning the parameter.
*
@@ -377,13 +468,15 @@ public class Paint extends _Original_Paint {
*/
@Override
public ColorFilter setColorFilter(ColorFilter filter) {
- int filterNative = 0;
- if (filter != null)
- filterNative = filter.native_instance;
mColorFilter = filter;
return filter;
}
+ @Override
+ public ColorFilter getColorFilter() {
+ return super.getColorFilter();
+ }
+
/**
* Set or clear the xfermode object.
* <p />
@@ -397,50 +490,172 @@ public class Paint extends _Original_Paint {
public Xfermode setXfermode(Xfermode xfermode) {
return mXfermode = xfermode;
}
-
+
+ @Override
+ public Xfermode getXfermode() {
+ return super.getXfermode();
+ }
+
+ @Override
+ public Rasterizer setRasterizer(Rasterizer rasterizer) {
+ mRasterizer = rasterizer;
+ return rasterizer;
+ }
+
+ @Override
+ public Rasterizer getRasterizer() {
+ return super.getRasterizer();
+ }
+
+ @Override
+ public void setShadowLayer(float radius, float dx, float dy, int color) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void clearShadowLayer() {
+ super.clearShadowLayer();
+ }
+
public void setTextAlign(Align align) {
mAlign = align;
}
-
+
@Override
public void setTextAlign(android.graphics._Original_Paint.Align align) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
-
+
public Align getTextAlign() {
return mAlign;
}
-
+
public void setStyle(Style style) {
mStyle = style;
}
@Override
public void setStyle(android.graphics._Original_Paint.Style style) {
- // TODO implement if needed
throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
}
public Style getStyle() {
return mStyle;
}
-
+
@Override
public void setDither(boolean dither) {
mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
}
-
+
@Override
public void setAntiAlias(boolean aa) {
mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
}
-
+
@Override
public void setFakeBoldText(boolean flag) {
mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
}
+ @Override
+ public void setLinearText(boolean flag) {
+ mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
+ }
+
+ @Override
+ public void setSubpixelText(boolean flag) {
+ mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
+ }
+
+ @Override
+ public void setUnderlineText(boolean flag) {
+ mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
+ }
+
+ @Override
+ public void setStrikeThruText(boolean flag) {
+ mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
+ }
+
+ @Override
+ public void setFilterBitmap(boolean flag) {
+ mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
+ }
+
+ @Override
+ public float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ @Override
+ public void setStrokeWidth(float width) {
+ mStrokeWidth = width;
+ }
+
+ @Override
+ public float getStrokeMiter() {
+ return mStrokeMiter;
+ }
+
+ @Override
+ public void setStrokeMiter(float miter) {
+ mStrokeMiter = miter;
+ }
+
+ @Override
+ public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
+ public void setStrokeCap(Cap cap) {
+ mCap = cap;
+ }
+
+ public Cap getStrokeCap() {
+ return mCap;
+ }
+
+ @Override
+ public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
+ throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
+ }
+
+ public void setStrokeJoin(Join join) {
+ mJoin = join;
+ }
+
+ public Join getStrokeJoin() {
+ return mJoin;
+ }
+
+ @Override
+ public boolean getFillPath(Path src, Path dst) {
+ return super.getFillPath(src, dst);
+ }
+
+ @Override
+ public PathEffect setPathEffect(PathEffect effect) {
+ mPathEffect = effect;
+ return effect;
+ }
+
+ @Override
+ public PathEffect getPathEffect() {
+ return super.getPathEffect();
+ }
+
+ @Override
+ public MaskFilter setMaskFilter(MaskFilter maskfilter) {
+ mMaskFilter = maskfilter;
+ return maskfilter;
+ }
+
+ @Override
+ public MaskFilter getMaskFilter() {
+ return super.getMaskFilter();
+ }
+
/**
* Return the paint's text size.
*
@@ -459,7 +674,7 @@ public class Paint extends _Original_Paint {
@Override
public void setTextSize(float textSize) {
mTextSize = textSize;
-
+
updateFontObject();
}
@@ -484,7 +699,7 @@ public class Paint extends _Original_Paint {
@Override
public void setTextScaleX(float scaleX) {
mScaleX = scaleX;
-
+
updateFontObject();
}
@@ -508,10 +723,15 @@ public class Paint extends _Original_Paint {
@Override
public void setTextSkewX(float skewX) {
mSkewX = skewX;
-
+
updateFontObject();
}
+ @Override
+ public float getFontSpacing() {
+ return super.getFontSpacing();
+ }
+
/**
* Return the distance above (negative) the baseline (ascent) based on the
* current typeface and text size.
@@ -521,11 +741,12 @@ public class Paint extends _Original_Paint {
*/
@Override
public float ascent() {
- if (mMetrics != null) {
- // ascent stuff should be negatif, but awt returns them as positive.
- return - mMetrics.getAscent();
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
+ // Android expects negative ascent so we invert the value from Java.
+ return - javaMetrics.getAscent();
}
-
+
return 0;
}
@@ -538,13 +759,14 @@ public class Paint extends _Original_Paint {
*/
@Override
public float descent() {
- if (mMetrics != null) {
- return mMetrics.getDescent();
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
+ return javaMetrics.getDescent();
}
-
+
return 0;
}
-
+
/**
* Return the width of the text.
*
@@ -555,12 +777,57 @@ public class Paint extends _Original_Paint {
*/
@Override
public float measureText(char[] text, int index, int count) {
- if (mFont != null && text != null && text.length > 0) {
- Rectangle2D bounds = mFont.getStringBounds(text, index, index + count, mFontContext);
-
- return (float)bounds.getWidth();
+ // WARNING: the logic in this method is similar to Canvas.drawText.
+ // Any change to this method should be reflected in Canvas.drawText
+ if (mFonts.size() > 0) {
+ FontInfo mainFont = mFonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ float total = 0f;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // shortcut to exit
+ return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
+ } else if (upTo > 0) {
+ total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+ i = upTo;
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < mFonts.size() ; f++) {
+ FontInfo fontInfo = mFonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ total += fontInfo.mMetrics.charsWidth(text, i, charCount);
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, measure it with the main font.
+ if (foundFont == false) {
+ int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ total += mainFont.mMetrics.charsWidth(text, i, size);
+ i += size;
+ }
+ }
}
-
+
return 0;
}
@@ -587,7 +854,7 @@ public class Paint extends _Original_Paint {
public float measureText(String text) {
return measureText(text.toCharArray(), 0, text.length());
}
-
+
/*
* re-implement to call SpannableStringBuilder.measureText with a Paint object
* instead of an _Original_Paint
@@ -611,7 +878,7 @@ public class Paint extends _Original_Paint {
TemporaryBuffer.recycle(buf);
return result;
}
-
+
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
* Return the number of chars that were measured, and if measuredWidth is
@@ -633,7 +900,7 @@ public class Paint extends _Original_Paint {
public int breakText(char[] text, int index, int count,
float maxWidth, float[] measuredWidth) {
int inc = count > 0 ? 1 : -1;
-
+
int measureIndex = 0;
float measureAcc = 0;
for (int i = index ; i != index + count ; i += inc, measureIndex++) {
@@ -645,23 +912,23 @@ public class Paint extends _Original_Paint {
start = index;
end = i;
}
-
+
// measure from start to end
float res = measureText(text, start, end - start + 1);
-
+
if (measuredWidth != null) {
measuredWidth[measureIndex] = res;
}
-
+
measureAcc += res;
if (res > maxWidth) {
// we should not return this char index, but since it's 0-based and we need
// to return a count, we simply return measureIndex;
return measureIndex;
}
-
+
}
-
+
return measureIndex;
}
@@ -690,6 +957,28 @@ public class Paint extends _Original_Paint {
}
/**
+ * Measure the text, stopping early if the measured width exceeds maxWidth.
+ * Return the number of chars that were measured, and if measuredWidth is
+ * not null, return in it the actual width measured.
+ *
+ * @param text The text to measure
+ * @param start The offset into text to begin measuring at
+ * @param end The end of the text slice to measure.
+ * @param measureForwards If true, measure forwards, starting at start.
+ * Otherwise, measure backwards, starting with end.
+ * @param maxWidth The maximum width to accumulate.
+ * @param measuredWidth Optional. If not null, returns the actual width
+ * measured.
+ * @return The number of chars that were measured. Will always be <=
+ * abs(end - start).
+ */
+ @Override
+ public int breakText(CharSequence text, int start, int end, boolean measureForwards,
+ float maxWidth, float[] measuredWidth) {
+ return super.breakText(text, start, end, measureForwards, maxWidth, measuredWidth);
+ }
+
+ /**
* Return the advance widths for the characters in the string.
*
* @param text The text to measure
@@ -702,19 +991,35 @@ public class Paint extends _Original_Paint {
@Override
public int getTextWidths(char[] text, int index, int count,
float[] widths) {
- if (mMetrics != null) {
+ if (mFonts.size() > 0) {
if ((index | count) < 0 || index + count > text.length
|| count > widths.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
+ // FIXME: handle multi-char characters.
+ // Need to figure out if the lengths of the width array takes into account
+ // multi-char characters.
for (int i = 0; i < count; i++) {
- widths[i] = mMetrics.charWidth(text[i + index]);
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ widths[i] = info.mMetrics.charWidth(c);
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // we stop there.
+ return i;
+ }
}
-
+
return count;
}
-
+
return 0;
}
@@ -736,10 +1041,10 @@ public class Paint extends _Original_Paint {
if (end - start > widths.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
return getTextWidths(text.toCharArray(), start, end - start, widths);
}
-
+
/*
* re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
* instead of an _Original_Paint
@@ -763,6 +1068,10 @@ public class Paint extends _Original_Paint {
return result;
}
+ @Override
+ public int getTextWidths(String text, float[] widths) {
+ return super.getTextWidths(text, widths);
+ }
/**
* Return the path (outline) for the specified text.
@@ -782,13 +1091,13 @@ public class Paint extends _Original_Paint {
float x, float y, Path path) {
// TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
-
+
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
// TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
-
+
throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
}
@@ -811,10 +1120,10 @@ public class Paint extends _Original_Paint {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
-
+
getTextPath(text.toCharArray(), start, end - start, x, y, path);
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -833,10 +1142,10 @@ public class Paint extends _Original_Paint {
if (bounds == null) {
throw new NullPointerException("need bounds Rect");
}
-
+
getTextBounds(text.toCharArray(), start, end - start, bounds);
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -849,16 +1158,23 @@ public class Paint extends _Original_Paint {
*/
@Override
public void getTextBounds(char[] text, int index, int count, Rect bounds) {
- if (mFont != null) {
+ // FIXME
+ if (mFonts.size() > 0) {
if ((index | count) < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
if (bounds == null) {
throw new NullPointerException("need bounds Rect");
}
-
- Rectangle2D rect = mFont.getStringBounds(text, index, index + count, mFontContext);
+
+ FontInfo mainInfo = mFonts.get(0);
+
+ Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
}
}
+
+ public static void finalizer(int foo) {
+ // pass
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface.java b/tools/layoutlib/bridge/src/android/graphics/Typeface.java
index e878b04..af3adb5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface.java
@@ -21,9 +21,12 @@ import com.android.layoutlib.bridge.FontLoader;
import android.content.res.AssetManager;
import java.awt.Font;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
- * Re-implementation of Typeface over java.awt
+ * Re-implementation of Typeface over java.awt
*/
public class Typeface {
private static final String DEFAULT_FAMILY = "sans-serif";
@@ -46,11 +49,11 @@ public class Typeface {
private static Typeface[] sDefaults;
private static FontLoader mFontLoader;
-
+
private final int mStyle;
- private final Font mFont;
+ private final List<Font> mFonts;
private final String mFamily;
-
+
// Style
public static final int NORMAL = _Original_Typeface.NORMAL;
public static final int BOLD = _Original_Typeface.BOLD;
@@ -58,12 +61,13 @@ public class Typeface {
public static final int BOLD_ITALIC = _Original_Typeface.BOLD_ITALIC;
/**
- * Returns the underlying {@link Font} object.
+ * Returns the underlying {@link Font} objects. The first item in the list is the real
+ * font. Any other items are fallback fonts for characters not found in the first one.
*/
- public Font getFont() {
- return mFont;
+ public List<Font> getFonts() {
+ return mFonts;
}
-
+
/** Returns the typeface's intrinsic style attributes */
public int getStyle() {
return mStyle;
@@ -94,9 +98,12 @@ public class Typeface {
styleBuffer[0] = style;
Font font = mFontLoader.getFont(familyName, styleBuffer);
if (font != null) {
- return new Typeface(familyName, styleBuffer[0], font);
+ ArrayList<Font> list = new ArrayList<Font>();
+ list.add(font);
+ list.addAll(mFontLoader.getFallBackFonts());
+ return new Typeface(familyName, styleBuffer[0], list);
}
-
+
return null;
}
@@ -115,7 +122,10 @@ public class Typeface {
styleBuffer[0] = style;
Font font = mFontLoader.getFont(family.mFamily, styleBuffer);
if (font != null) {
- return new Typeface(family.mFamily, styleBuffer[0], font);
+ ArrayList<Font> list = new ArrayList<Font>();
+ list.add(font);
+ list.addAll(mFontLoader.getFallBackFonts());
+ return new Typeface(family.mFamily, styleBuffer[0], list);
}
return null;
@@ -129,7 +139,7 @@ public class Typeface {
public static Typeface defaultFromStyle(int style) {
return sDefaults[style];
}
-
+
/**
* Create a new typeface from the specified font data.
* @param mgr The application's asset manager
@@ -140,17 +150,17 @@ public class Typeface {
return null;
//return new Typeface(nativeCreateFromAsset(mgr, path));
}
-
+
// don't allow clients to call this directly
- private Typeface(String family, int style, Font f) {
+ private Typeface(String family, int style, List<Font> fonts) {
mFamily = family;
- mFont = f;
+ mFonts = Collections.unmodifiableList(fonts);
mStyle = style;
}
-
+
public static void init(FontLoader fontLoader) {
mFontLoader = fontLoader;
-
+
DEFAULT = create(DEFAULT_FAMILY, NORMAL);
DEFAULT_BOLD = create(DEFAULT_FAMILY, BOLD);
SANS_SERIF = create("sans-serif", NORMAL);
@@ -162,14 +172,14 @@ public class Typeface {
create(DEFAULT_FAMILY, ITALIC),
create(DEFAULT_FAMILY, BOLD_ITALIC),
};
-
+
/*
DEFAULT = create((String)null, 0);
DEFAULT_BOLD = create((String)null, Typeface.BOLD);
SANS_SERIF = create("sans-serif", 0);
SERIF = create("serif", 0);
MONOSPACE = create("monospace", 0);
-
+
sDefaults = new Typeface[] {
DEFAULT,
DEFAULT_BOLD,
diff --git a/tools/layoutlib/bridge/src/android/webkit/WebView.java b/tools/layoutlib/bridge/src/android/webkit/WebView.java
index 42e4dfa..3b66188 100644
--- a/tools/layoutlib/bridge/src/android/webkit/WebView.java
+++ b/tools/layoutlib/bridge/src/android/webkit/WebView.java
@@ -240,13 +240,6 @@ public class WebView extends MockView {
return null;
}
- public static synchronized PluginList getPluginList() {
- return null;
- }
-
- public void refreshPlugins(boolean reloadOpenPages) {
- }
-
public View getZoomControls() {
return null;
}