summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2010-11-01 16:17:18 -0700
committerXavier Ducrohet <xav@android.com>2010-11-01 17:52:42 -0700
commit5802deabf06a0754c36e990ce2af7b5c8727e543 (patch)
tree1d824bd2fda259b9eaed46aab4742bc9e82359ba
parent1d8479fa95d61d5e49a8b054f5a8aad62432af1e (diff)
downloadframeworks_base-5802deabf06a0754c36e990ce2af7b5c8727e543.zip
frameworks_base-5802deabf06a0754c36e990ce2af7b5c8727e543.tar.gz
frameworks_base-5802deabf06a0754c36e990ce2af7b5c8727e543.tar.bz2
More implementation of the layoutlib Paint/Canvas delegates.
Change-Id: I0c0029b9a679af4ae0178488f70b2a90292ea42d
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java536
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java32
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java279
3 files changed, 720 insertions, 127 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 6627d37..2b54711 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -19,10 +19,22 @@ package android.graphics;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.bridge.DelegateManager;
+import android.graphics.Paint_Delegate.FontInfo;
+import android.text.TextUtils;
+
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Composite;
import java.awt.Graphics2D;
+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;
+
/**
* Delegate implementing the native methods of android.graphics.Canvas
*
@@ -95,80 +107,177 @@ public class Canvas_Delegate {
}
/*package*/ static int getWidth(Canvas thisCanvas) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return canvasDelegate.mBufferedImage.getWidth();
}
/*package*/ static int getHeight(Canvas thisCanvas) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return canvasDelegate.mBufferedImage.getHeight();
}
/*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ canvasDelegate.getGraphics2d().translate(dx, dy);
}
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ canvasDelegate.getGraphics2d().rotate(Math.toRadians(degrees));
}
/*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ canvasDelegate.getGraphics2d().scale(sx, sy);
}
- /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) {
- // FIXME
- throw new UnsupportedOperationException();
+ /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the current top graphics2D object.
+ Graphics2D g = canvasDelegate.getGraphics2d();
+
+ // get its current matrix
+ AffineTransform currentTx = g.getTransform();
+ // get the AffineTransform for the given skew.
+ float[] mtx = Matrix_Delegate.getSkew(kx, ky);
+ AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ g.setTransform(currentTx);
}
/*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
- // FIXME
- throw new UnsupportedOperationException();
+ return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
}
/*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
- // FIXME
- throw new UnsupportedOperationException();
+ return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
}
/*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
float bottom) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return false;
+ }
+
+ canvasDelegate.getGraphics2d().clipRect((int)left, (int)top, (int)(right-left),
+ (int)(bottom-top));
+ return true;
}
/*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
int bottom) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return false;
+ }
+
+ canvasDelegate.getGraphics2d().clipRect(left, top, right - left, bottom - top);
+ return true;
}
/*package*/ static int save(Canvas thisCanvas) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return 0;
+ }
+
+ // get the current save count
+ int count = canvasDelegate.mGraphicsStack.size();
+
+ // create a new graphics and add it to the stack
+ Graphics2D g = (Graphics2D)canvasDelegate.getGraphics2d().create();
+ canvasDelegate.mGraphicsStack.push(g);
+
+ // return the old save count
+ return count;
+
}
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
- // FIXME
- throw new UnsupportedOperationException();
+ // FIXME implement save(flags)
+ return save(thisCanvas);
}
/*package*/ static void restore(Canvas thisCanvas) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ canvasDelegate.mGraphicsStack.pop();
}
/*package*/ static int getSaveCount(Canvas thisCanvas) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return canvasDelegate.mGraphicsStack.size();
}
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ while (canvasDelegate.mGraphicsStack.size() > saveCount) {
+ canvasDelegate.mGraphicsStack.pop();
+ }
}
/*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
@@ -296,8 +405,22 @@ public class Canvas_Delegate {
/*package*/ static boolean native_getClipBounds(int nativeCanvas,
Rect bounds) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return false;
+ }
+
+ Rectangle rect = canvasDelegate.getGraphics2d().getClipBounds();
+ if (rect != null) {
+ bounds.left = rect.x;
+ bounds.top = rect.y;
+ bounds.right = rect.x + rect.width;
+ bounds.bottom = rect.y + rect.height;
+ return true;
+ }
+ return false;
}
/*package*/ static void native_getCTM(int canvas, int matrix) {
@@ -309,14 +432,14 @@ public class Canvas_Delegate {
RectF rect,
int native_edgeType) {
// FIXME
- throw new UnsupportedOperationException();
+ return false;
}
/*package*/ static boolean native_quickReject(int nativeCanvas,
int path,
int native_edgeType) {
// FIXME
- throw new UnsupportedOperationException();
+ return false;
}
/*package*/ static boolean native_quickReject(int nativeCanvas,
@@ -324,7 +447,7 @@ public class Canvas_Delegate {
float right, float bottom,
int native_edgeType) {
// FIXME
- throw new UnsupportedOperationException();
+ return false;
}
/*package*/ static void native_drawRGB(int nativeCanvas, int r, int g,
@@ -371,8 +494,41 @@ public class Canvas_Delegate {
/*package*/ static void native_drawRect(int nativeCanvas, float left,
float top, float right,
float bottom, int paint) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+ if (paintDelegate == null) {
+ assert false;
+ return;
+ }
+
+ if (right > left && bottom > top) {
+ // get a Graphics2D object configured with the drawing parameters.
+ Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate);
+
+ int style = paintDelegate.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
+ }
+
+ // dispose Graphics2D object
+ g.dispose();
+ }
+
}
/*package*/ static void native_drawOval(int nativeCanvas, RectF oval,
@@ -423,8 +579,24 @@ public class Canvas_Delegate {
int nativePaintOrZero,
int screenDensity,
int bitmapDensity) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ assert false;
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+
+ if (src == null) {
+ drawBitmap(nativeCanvas, image, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
+ } else {
+ drawBitmap(nativeCanvas, image, nativePaintOrZero,
+ src.left, src.top, src.width(), src.height(),
+ (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
+ }
}
/*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
@@ -432,8 +604,24 @@ public class Canvas_Delegate {
int nativePaintOrZero,
int screenDensity,
int bitmapDensity) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ assert false;
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+
+ if (src == null) {
+ drawBitmap(nativeCanvas, image, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ dst.left, dst.top, dst.right, dst.bottom);
+ } else {
+ drawBitmap(nativeCanvas, image, nativePaintOrZero,
+ src.left, src.top, src.width(), src.height(),
+ dst.left, dst.top, dst.right, dst.bottom);
+ }
}
/*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
@@ -471,15 +659,134 @@ public class Canvas_Delegate {
/*package*/ static void native_drawText(int nativeCanvas, char[] text,
int index, int count, float x,
float y, int flags, int paint) {
- // FIXME
- throw new UnsupportedOperationException();
+ // WARNING: the logic in this method is similar to Paint.measureText.
+ // Any change to this method should be reflected in Paint.measureText
+
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+ if (paintDelegate == null) {
+ assert false;
+ return;
+ }
+
+ Graphics2D g = canvasDelegate.getGraphics2d();
+
+ g = (Graphics2D)g.create();
+ g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ // set the color. because this only handles RGB, the alpha channel is handled
+ // as a composite.
+ g.setColor(new Color(paintDelegate.getColor()));
+ int alpha = paintDelegate.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 (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+ float m = paintDelegate.measureText(text, index, count);
+ if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+ x -= m / 2;
+ } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+ x -= m;
+ }
+ }
+
+ List<FontInfo> fonts = paintDelegate.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();
+ }
}
/*package*/ static void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int flags, int paint) {
- // FIXME
- throw new UnsupportedOperationException();
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
}
@@ -556,4 +863,141 @@ public class Canvas_Delegate {
mBufferedImage = image;
mGraphicsStack.push(mBufferedImage.createGraphics());
}
+
+ /**
+ * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
+ * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
+ */
+ private Graphics2D getCustomGraphics(Paint_Delegate paint) {
+ // make new one
+ Graphics2D g = getGraphics2d();
+ g = (Graphics2D)g.create();
+
+ // configure it
+ g.setColor(new Color(paint.getColor()));
+ int alpha = paint.getAlpha();
+ float falpha = alpha / 255.f;
+
+ int style = paint.getStyle();
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ /* FIXME
+ PathEffect e = paint.getPathEffect();
+ if (e instanceof DashPathEffect) {
+ DashPathEffect dpe = (DashPathEffect)e;
+ g.setStroke(new BasicStroke(
+ paint.getStrokeWidth(),
+ paint.getStrokeCap().getJavaCap(),
+ paint.getStrokeJoin().getJavaJoin(),
+ paint.getStrokeMiter(),
+ dpe.getIntervals(),
+ dpe.getPhase()));
+ } else {*/
+ g.setStroke(new BasicStroke(
+ paint.getStrokeWidth(),
+ paint.getJavaCap(),
+ paint.getJavaJoin(),
+ paint.getStrokeMiter()));
+ /* }*/
+ }
+/*
+ Xfermode xfermode = paint.getXfermode();
+ if (xfermode instanceof PorterDuffXfermode) {
+ PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
+
+ setModeInGraphics(mode, g, falpha);
+ } else {
+ if (mLogger != null && xfermode != null) {
+ mLogger.warning(String.format(
+ "Xfermode '%1$s' is not supported in the Layout Editor.",
+ xfermode.getClass().getCanonicalName()));
+ }
+ g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
+ }
+
+ Shader shader = paint.getShader();
+ if (shader != null) {
+ java.awt.Paint shaderPaint = shader.getJavaPaint();
+ if (shaderPaint != null) {
+ g.setPaint(shaderPaint);
+ } else {
+ if (mLogger != null) {
+ mLogger.warning(String.format(
+ "Shader '%1$s' is not supported in the Layout Editor.",
+ shader.getClass().getCanonicalName()));
+ }
+ }
+ }
+*/
+ return g;
+ }
+
+
+ private static void drawBitmap(
+ int nativeCanvas,
+ BufferedImage image,
+ int nativePaintOrZero,
+ int sleft, int stop, int sright, int sbottom,
+ int dleft, int dtop, int dright, int dbottom) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate paintDelegate = null;
+ if (nativePaintOrZero > 0) {
+ paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
+ if (paintDelegate == null) {
+ assert false;
+ return;
+ }
+ }
+
+ drawBitmap(canvasDelegate, image, paintDelegate,
+ sleft, stop, sright, sbottom,
+ dleft, dtop, dright, dbottom);
+ }
+
+ private static void drawBitmap(
+ Canvas_Delegate canvasDelegate,
+ BufferedImage image,
+ Paint_Delegate paintDelegate,
+ int sleft, int stop, int sright, int sbottom,
+ int dleft, int dtop, int dright, int dbottom) {
+
+ Graphics2D g = canvasDelegate.getGraphics2d();
+
+ Composite c = null;
+
+ if (paintDelegate != null) {
+ if (paintDelegate.isFilterBitmap()) {
+ g = (Graphics2D)g.create();
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ if (paintDelegate.getAlpha() != 0xFF) {
+ c = g.getComposite();
+ g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
+ paintDelegate.getAlpha()/255.f));
+ }
+ }
+
+ g.drawImage(image, dleft, dtop, dright, dbottom,
+ sleft, stop, sright, sbottom, null);
+
+ if (paintDelegate != null) {
+ if (paintDelegate.isFilterBitmap()) {
+ g.dispose();
+ }
+ if (c != null) {
+ g.setComposite(c);
+ }
+ }
+ }
+
}
+
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index cc4a80c..713f784 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -689,13 +689,17 @@ public final class Matrix_Delegate {
// ---- Private helper methods ----
private static AffineTransform getAffineTransform(Matrix_Delegate d) {
+ return getAffineTransform(d.mValues);
+ }
+
+ /*package*/ static AffineTransform getAffineTransform(float[] matrix) {
// the AffineTransform constructor takes the value in a different order
// for a matrix [ 0 1 2 ]
// [ 3 4 5 ]
// the order is 0, 3, 1, 4, 2, 5...
return new AffineTransform(
- d.mValues[0], d.mValues[3], d.mValues[1],
- d.mValues[4], d.mValues[2], d.mValues[5]);
+ matrix[0], matrix[3], matrix[1],
+ matrix[4], matrix[2], matrix[5]);
}
@@ -862,7 +866,7 @@ public final class Matrix_Delegate {
* <p/>This in effect does dest = a*b
* dest cannot be the same as a or b.
*/
- private static void multiply(float dest[], float[] a, float[] b) {
+ /*package*/ static void multiply(float dest[], float[] a, float[] b) {
// first row
dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
@@ -885,11 +889,11 @@ public final class Matrix_Delegate {
* @param dy
* @return
*/
- private static float[] getTranslate(float dx, float dy) {
+ /*package*/ static float[] getTranslate(float dx, float dy) {
return setTranslate(new float[9], dx, dy);
}
- private static float[] setTranslate(float[] dest, float dx, float dy) {
+ /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) {
dest[0] = 1;
dest[1] = 0;
dest[2] = dx;
@@ -902,7 +906,7 @@ public final class Matrix_Delegate {
return dest;
}
- private static float[] getScale(float sx, float sy) {
+ /*package*/ static float[] getScale(float sx, float sy) {
return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
}
@@ -913,7 +917,7 @@ public final class Matrix_Delegate {
* @param px
* @param py
*/
- private static float[] getScale(float sx, float sy, float px, float py) {
+ /*package*/ static float[] getScale(float sx, float sy, float px, float py) {
float[] tmp = new float[9];
float[] tmp2 = new float[9];
@@ -932,7 +936,7 @@ public final class Matrix_Delegate {
}
- private static float[] getRotate(float degrees) {
+ /*package*/ static float[] getRotate(float degrees) {
double rad = Math.toRadians(degrees);
float sin = (float)Math.sin(rad);
float cos = (float)Math.cos(rad);
@@ -940,11 +944,11 @@ public final class Matrix_Delegate {
return getRotate(sin, cos);
}
- private static float[] getRotate(float sin, float cos) {
+ /*package*/ static float[] getRotate(float sin, float cos) {
return setRotate(new float[9], sin, cos);
}
- private static float[] setRotate(float[] dest, float degrees) {
+ /*package*/ static float[] setRotate(float[] dest, float degrees) {
double rad = Math.toRadians(degrees);
float sin = (float)Math.sin(rad);
float cos = (float)Math.cos(rad);
@@ -952,7 +956,7 @@ public final class Matrix_Delegate {
return setRotate(dest, sin, cos);
}
- private static float[] setRotate(float[] dest, float sin, float cos) {
+ /*package*/ static float[] setRotate(float[] dest, float sin, float cos) {
dest[0] = cos;
dest[1] = -sin;
dest[2] = 0;
@@ -965,7 +969,7 @@ public final class Matrix_Delegate {
return dest;
}
- private static float[] getRotate(float degrees, float px, float py) {
+ /*package*/ static float[] getRotate(float degrees, float px, float py) {
float[] tmp = new float[9];
float[] tmp2 = new float[9];
@@ -986,11 +990,11 @@ public final class Matrix_Delegate {
return tmp;
}
- private static float[] getSkew(float kx, float ky) {
+ /*package*/ static float[] getSkew(float kx, float ky) {
return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
}
- private static float[] getSkew(float kx, float ky, float px, float py) {
+ /*package*/ static float[] getSkew(float kx, float ky, float px, float py) {
float[] tmp = new float[9];
float[] tmp2 = new float[9];
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index e8079ed..f2602b5 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -20,7 +20,9 @@ import com.android.layoutlib.bridge.DelegateManager;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.FontMetricsInt;
+import android.text.TextUtils;
+import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
@@ -47,7 +49,7 @@ public class Paint_Delegate {
/**
* Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
*/
- public static final class FontInfo {
+ /*package*/ static final class FontInfo {
Font mFont;
java.awt.FontMetrics mMetrics;
}
@@ -67,7 +69,7 @@ public class Paint_Delegate {
private int mStyle;
private int mCap;
private int mJoin;
- private int mAlign;
+ private int mTextAlign;
private int mTypeface;
private float mStrokeWidth;
private float mStrokeMiter;
@@ -78,6 +80,10 @@ public class Paint_Delegate {
// ---- Public Helper methods ----
+ public static Paint_Delegate getDelegate(int native_paint) {
+ return sManager.getDelegate(native_paint);
+ }
+
/**
* 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.
@@ -86,6 +92,57 @@ public class Paint_Delegate {
return mFonts;
}
+ public boolean isFilterBitmap() {
+ return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
+ }
+
+ public int getStyle() {
+ return mStyle;
+ }
+
+ public int getColor() {
+ return mColor;
+ }
+
+ public int getAlpha() {
+ return mColor >>> 24;
+ }
+
+ public int getTextAlign() {
+ return mTextAlign;
+ }
+
+ public float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ public float getStrokeMiter() {
+ return mStrokeMiter;
+ }
+
+ public int getJavaCap() {
+ switch (Paint.sCapArray[mCap]) {
+ case BUTT:
+ return BasicStroke.CAP_BUTT;
+ case ROUND:
+ return BasicStroke.CAP_ROUND;
+ default:
+ case SQUARE:
+ return BasicStroke.CAP_SQUARE;
+ }
+ }
+
+ public int getJavaJoin() {
+ switch (Paint.sJoinArray[mJoin]) {
+ default:
+ case MITER:
+ return BasicStroke.JOIN_MITER;
+ case ROUND:
+ return BasicStroke.JOIN_ROUND;
+ case BEVEL:
+ return BasicStroke.JOIN_BEVEL;
+ }
+ }
// ---- native methods ----
@@ -112,8 +169,7 @@ public class Paint_Delegate {
}
/*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
- // FIXME
- throw new UnsupportedOperationException();
+ setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
}
/*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
@@ -174,7 +230,7 @@ public class Paint_Delegate {
return 0;
}
- return delegate.mColor >>> 24;
+ return delegate.getAlpha();
}
/*package*/ static void setAlpha(Paint thisPaint, int a) {
@@ -315,20 +371,31 @@ public class Paint_Delegate {
}
/*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
- // FIXME
- throw new UnsupportedOperationException();
- }
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
- /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
- // FIXME
- throw new UnsupportedOperationException();
- }
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ if (metrics != null) {
+ // 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();
+ }
- /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
- int count) {
- // WARNING: the logic in this method is similar to Canvas.drawText.
- // Any change to this method should be reflected in Canvas.drawText
+ return javaMetrics.getHeight();
+ }
+ return 0;
+ }
+
+ /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
@@ -337,55 +404,35 @@ public class Paint_Delegate {
}
if (delegate.mFonts.size() > 0) {
- FontInfo mainFont = delegate.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.
- }
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ if (fmi != null) {
+ // Android expects negative ascent so we invert the value from Java.
+ fmi.top = - javaMetrics.getMaxAscent();
+ fmi.ascent = - javaMetrics.getAscent();
+ fmi.descent = javaMetrics.getDescent();
+ fmi.bottom = javaMetrics.getMaxDescent();
+ fmi.leading = javaMetrics.getLeading();
+ }
- // 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 < delegate.mFonts.size() ; f++) {
- FontInfo fontInfo = delegate.mFonts.get(f);
+ return javaMetrics.getHeight();
+ }
- // 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;
+ return 0;
+ }
- }
- }
+ /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
+ int count) {
+ // WARNING: the logic in this method is similar to Canvas.drawText.
+ // Any change to this method should be reflected in Canvas.drawText
- // 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;
- }
- }
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ assert false;
+ return 0;
}
- return 0;
+ return delegate.measureText(text, index, count);
}
/*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
@@ -576,7 +623,7 @@ public class Paint_Delegate {
return 0;
}
- return delegate.mAlign;
+ return delegate.mTextAlign;
}
/*package*/ static void native_setTextAlign(int native_object, int align) {
@@ -587,7 +634,7 @@ public class Paint_Delegate {
return;
}
- delegate.mAlign = align;
+ delegate.mTextAlign = align;
}
/*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
@@ -610,15 +657,58 @@ public class Paint_Delegate {
/*package*/ static float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
int flags, float[] advances, int advancesIndex) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ assert false;
+ return 0.f;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ // FIXME: handle multi-char characters.
+ // see measureText.
+ float totalAdvance = 0;
+ for (int i = 0; i < count; i++) {
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : delegate.mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ float adv = info.mMetrics.charWidth(c);
+ totalAdvance += adv;
+ if (advances != null) {
+ advances[i] = adv;
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // no advance for this char.
+ if (advances != null) {
+ advances[i] = 0.f;
+ }
+ }
+ }
+
+ return totalAdvance;
+ }
+
+ return 0;
+
}
/*package*/ static float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex) {
- // FIXME
- throw new UnsupportedOperationException();
+ // FIXME: support contextStart, contextEnd and direction flag
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
+ contextEnd - contextStart, flags, advances, advancesIndex);
}
/*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
@@ -681,7 +771,7 @@ public class Paint_Delegate {
mStyle = paint.mStyle;
mCap = paint.mCap;
mJoin = paint.mJoin;
- mAlign = paint.mAlign;
+ mTextAlign = paint.mTextAlign;
mTypeface = paint.mTypeface;
mStrokeWidth = paint.mStrokeWidth;
mStrokeMiter = paint.mStrokeMiter;
@@ -696,7 +786,7 @@ public class Paint_Delegate {
mStyle = 0;
mCap = 0;
mJoin = 0;
- mAlign = 0;
+ mTextAlign = 0;
mTypeface = 0;
mStrokeWidth = 1.f;
mStrokeMiter = 2.f;
@@ -733,6 +823,61 @@ public class Paint_Delegate {
}
}
+ /*package*/ float measureText(char[] text, int index, int count) {
+ 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;
+
+ }
+
+
private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);