summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src/android/graphics
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2010-12-22 10:13:23 -0800
committerXavier Ducrohet <xav@android.com>2010-12-22 10:30:53 -0800
commitb1da1afa7418960b650780250bbd34c81af61aa3 (patch)
tree45b4798c9a796223bb854d8a5c56a2b5b2c9461b /tools/layoutlib/bridge/src/android/graphics
parentd38e776a3cc8cb53945cbebafbe6f6c2e3501fa5 (diff)
downloadframeworks_base-b1da1afa7418960b650780250bbd34c81af61aa3.zip
frameworks_base-b1da1afa7418960b650780250bbd34c81af61aa3.tar.gz
frameworks_base-b1da1afa7418960b650780250bbd34c81af61aa3.tar.bz2
LayoutLib: improve bitmap support.
Change-Id: I703c2bdf51380b54fd5c20b08d3bc74833d9bc6e
Diffstat (limited to 'tools/layoutlib/bridge/src/android/graphics')
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java219
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java343
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java2
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java4
4 files changed, 429 insertions, 139 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index b5f5005..2ce6a36 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.ide.common.rendering.api.ResourceDensity;
+import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import android.graphics.Bitmap.Config;
@@ -29,6 +30,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.Buffer;
+import java.util.Arrays;
import javax.imageio.ImageIO;
@@ -57,6 +59,7 @@ public final class Bitmap_Delegate {
private final Config mConfig;
private BufferedImage mImage;
private boolean mHasAlpha = true;
+ private int mGenerationId = 0;
// ---- Public Helper methods ----
@@ -173,6 +176,22 @@ public final class Bitmap_Delegate {
return mConfig;
}
+ /**
+ * Returns the hasAlpha rendering hint
+ * @return true if the bitmap alpha should be used at render time
+ */
+ public boolean hasAlpha() {
+ return mHasAlpha && mConfig != Config.RGB_565;
+ }
+
+ /**
+ * Update the generationId.
+ *
+ * @see Bitmap#getGenerationId()
+ */
+ public void change() {
+ mGenerationId++;
+ }
// ---- native methods ----
@@ -183,7 +202,9 @@ public final class Bitmap_Delegate {
// create the image
BufferedImage image = new BufferedImage(width, height, imageType);
- // FIXME fill the bitmap!
+ if (colors != null) {
+ image.setRGB(0, 0, width, height, colors, offset, stride);
+ }
// create a delegate with the content of the stream.
Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
@@ -192,8 +213,31 @@ public final class Bitmap_Delegate {
}
/*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+ Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
+ if (srcBmpDelegate == null) {
+ assert false;
+ return null;
+ }
+
+ BufferedImage srcImage = srcBmpDelegate.getImage();
+
+ int width = srcImage.getWidth();
+ int height = srcImage.getHeight();
+
+ int imageType = getBufferedImageType(nativeConfig);
+
+ // create the image
+ BufferedImage image = new BufferedImage(width, height, imageType);
+
+ // copy the source image into the image.
+ int[] argb = new int[width * height];
+ srcImage.getRGB(0, 0, width, height, argb, 0, width);
+ image.setRGB(0, 0, width, height, argb, 0, width);
+
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
+
+ return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
}
/*package*/ static void nativeDestructor(int nativeBitmap) {
@@ -206,8 +250,8 @@ public final class Bitmap_Delegate {
/*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
OutputStream stream, byte[] tempStorage) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+ Bridge.getLog().error(null, "Bitmap.compress() is not supported");
+ return true;
}
/*package*/ static void nativeErase(int nativeBitmap, int color) {
@@ -222,7 +266,7 @@ public final class Bitmap_Delegate {
Graphics2D g = image.createGraphics();
try {
- g.setColor(new java.awt.Color(color, delegate.mHasAlpha));
+ g.setColor(new java.awt.Color(color, true));
g.fillRect(0, 0, image.getWidth(), image.getHeight());
} finally {
@@ -298,20 +342,35 @@ public final class Bitmap_Delegate {
/*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
int stride, int x, int y, int width, int height) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeGetPixels");
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride);
}
/*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSetPixel");
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.getImage().setRGB(x, y, color);
}
/*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
int stride, int x, int y, int width, int height) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSetPixels");
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ assert false;
+ return;
+ }
+
+ delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
}
/*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
@@ -325,31 +384,68 @@ public final class Bitmap_Delegate {
}
/*package*/ static int nativeGenerationId(int nativeBitmap) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeGenerationId");
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ assert false;
+ return 0;
+ }
+
+ return delegate.mGenerationId;
}
/*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCreateFromParcel");
+ // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
+ // used during aidl call so really this should not be called.
+ Bridge.getLog().error(null,
+ "AIDL is not suppored, and therefore bitmap cannot be created from parcels");
+ return null;
}
/*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
int density, Parcel p) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeWriteToParcel");
+ // This is only called when sending a bitmap through aidl, so really this should not
+ // be called.
+ Bridge.getLog().error(null,
+ "AIDL is not suppored, and therefore bitmap cannot be written to parcels");
+ return false;
}
/*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
int[] offsetXY) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeExtractAlpha");
- }
+ Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
+ if (bitmap == null) {
+ assert false;
+ return null;
+ }
+
+ Paint_Delegate paint = null;
+ if (nativePaint > 0) {
+ paint = Paint_Delegate.getDelegate(nativePaint);
+ if (paint == null) {
+ assert false;
+ return null;
+ }
+ }
+
+ if (paint != null && paint.getMaskFilter() != 0) {
+ Bridge.getLog().fidelityWarning(null,
+ "MaskFilter not supported in Bitmap.extractAlpha",
+ null);
+ }
+ int alpha = paint != null ? paint.getAlpha() : 0xFF;
+ BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha);
+
+ // create the delegate. The actual Bitmap config is only an alpha channel
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
+
+ // the density doesn't matter, it's set by the Java method.
+ return createBitmap(delegate, false /*isMutable*/,
+ ResourceDensity.DEFAULT_DENSITY /*density*/);
+ }
/*package*/ static void nativePrepareToDraw(int nativeBitmap) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativePrepareToDraw");
+ // nothing to be done here.
}
/*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
@@ -364,8 +460,48 @@ public final class Bitmap_Delegate {
}
/*package*/ static boolean nativeSameAs(int nb0, int nb1) {
- // FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSameAs");
+ Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
+ if (delegate1 == null) {
+ assert false;
+ return false;
+ }
+
+ Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
+ if (delegate2 == null) {
+ assert false;
+ return false;
+ }
+
+ BufferedImage image1 = delegate1.getImage();
+ BufferedImage image2 = delegate2.getImage();
+ if (delegate1.mConfig != delegate2.mConfig ||
+ image1.getWidth() != image2.getWidth() ||
+ image1.getHeight() != image2.getHeight()) {
+ return false;
+ }
+
+ // get the internal data
+ int w = image1.getWidth();
+ int h = image2.getHeight();
+ int[] argb1 = new int[w*h];
+ int[] argb2 = new int[w*h];
+
+ image1.getRGB(0, 0, w, h, argb1, 0, w);
+ image2.getRGB(0, 0, w, h, argb2, 0, w);
+
+ // compares
+ if (delegate1.mConfig == Config.ALPHA_8) {
+ // in this case we have to manually compare the alpha channel as the rest is garbage.
+ final int length = w*h;
+ for (int i = 0 ; i < length ; i++) {
+ if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return Arrays.equals(argb1, argb2);
}
// ---- Private delegate/helper methods ----
@@ -382,4 +518,37 @@ public final class Bitmap_Delegate {
// and create/return a new Bitmap with it
return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density);
}
+
+ /**
+ * Creates and returns a copy of a given BufferedImage.
+ * <p/>
+ * if alpha is different than 255, then it is applied to the alpha channel of each pixel.
+ *
+ * @param image the image to copy
+ * @param imageType the type of the new image
+ * @param alpha an optional alpha modifier
+ * @return a new BufferedImage
+ */
+ /*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+
+ BufferedImage result = new BufferedImage(w, h, imageType);
+
+ int[] argb = new int[w * h];
+ image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
+
+ if (alpha != 255) {
+ final int length = argb.length;
+ for (int i = 0 ; i < length; i++) {
+ int a = (argb[i] >>> 24 * alpha) / 255;
+ argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF);
+ }
+ }
+
+ result.setRGB(0, 0, w, h, argb, 0, w);
+
+ return result;
+ }
+
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index df0b997..88ec88e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -55,8 +55,10 @@ public final class Canvas_Delegate {
// ---- delegate helper data ----
+ private final static boolean[] sBoolOut = new boolean[1];
+
// ---- delegate data ----
- private BufferedImage mBufferedImage;
+ private Bitmap_Delegate mBitmap;
private GcSnapshot mSnapshot;
// ---- Public Helper methods ----
@@ -97,7 +99,7 @@ public final class Canvas_Delegate {
return 0;
}
- return canvasDelegate.mBufferedImage.getWidth();
+ return canvasDelegate.mBitmap.getImage().getWidth();
}
/*package*/ static int getHeight(Canvas thisCanvas) {
@@ -108,7 +110,7 @@ public final class Canvas_Delegate {
return 0;
}
- return canvasDelegate.mBufferedImage.getHeight();
+ return canvasDelegate.mBitmap.getImage().getHeight();
}
/*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
@@ -258,7 +260,7 @@ public final class Canvas_Delegate {
final float[] pts, final int offset, final int count,
Paint paint) {
draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
- new GcSnapshot.Drawable() {
+ false /*forceSrcMode*/, new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
for (int i = 0 ; i < count ; i += 4) {
graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
@@ -279,7 +281,7 @@ public final class Canvas_Delegate {
Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
// create a new Canvas_Delegate with the given bitmap and return its new native int.
- Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate.getImage());
+ Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
return sManager.addDelegate(newDelegate);
} else {
@@ -305,7 +307,7 @@ public final class Canvas_Delegate {
return;
}
- canvasDelegate.setBitmap(bitmapDelegate.getImage());
+ canvasDelegate.setBitmap(bitmapDelegate);
}
/*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
@@ -535,8 +537,8 @@ public final class Canvas_Delegate {
return;
}
- final int w = canvasDelegate.mBufferedImage.getWidth();
- final int h = canvasDelegate.mBufferedImage.getHeight();
+ final int w = canvasDelegate.mBitmap.getImage().getWidth();
+ final int h = canvasDelegate.mBitmap.getImage().getHeight();
draw(nativeCanvas, new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
@@ -566,10 +568,11 @@ public final class Canvas_Delegate {
final float startX, final float startY, final float stopX, final float stopY,
int paint) {
- draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
- }
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
+ }
});
}
@@ -581,43 +584,47 @@ public final class Canvas_Delegate {
/*package*/ static void native_drawRect(int nativeCanvas,
final float left, final float top, final float right, final float bottom, int paint) {
- draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- int style = paint.getStyle();
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ int style = paint.getStyle();
- // draw
- if (style == Paint.Style.FILL.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
- }
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillRect((int)left, (int)top,
+ (int)(right-left), (int)(bottom-top));
+ }
- if (style == Paint.Style.STROKE.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
- }
- }
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawRect((int)left, (int)top,
+ (int)(right-left), (int)(bottom-top));
+ }
+ }
});
}
/*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) {
if (oval.right > oval.left && oval.bottom > oval.top) {
- draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- int style = paint.getStyle();
-
- // draw
- if (style == Paint.Style.FILL.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.fillOval((int)oval.left, (int)oval.top,
- (int)oval.width(), (int)oval.height());
- }
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ int style = paint.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillOval((int)oval.left, (int)oval.top,
+ (int)oval.width(), (int)oval.height());
+ }
- if (style == Paint.Style.STROKE.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.drawOval((int)oval.left, (int)oval.top,
- (int)oval.width(), (int)oval.height());
- }
- }
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawOval((int)oval.left, (int)oval.top,
+ (int)oval.width(), (int)oval.height());
+ }
+ }
});
}
}
@@ -640,26 +647,28 @@ public final class Canvas_Delegate {
/*package*/ static void native_drawRoundRect(int nativeCanvas,
final RectF rect, final float rx, final float ry, int paint) {
- draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
-
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- int style = paint.getStyle();
-
- // draw
- if (style == Paint.Style.FILL.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.fillRoundRect(
- (int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- (int)rx, (int)ry);
- }
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ int style = paint.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillRoundRect(
+ (int)rect.left, (int)rect.top,
+ (int)rect.width(), (int)rect.height(),
+ (int)rx, (int)ry);
+ }
- if (style == Paint.Style.STROKE.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.drawRoundRect(
- (int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- (int)rx, (int)ry);
- }
- }
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawRoundRect(
+ (int)rect.left, (int)rect.top,
+ (int)rect.width(), (int)rect.height(),
+ (int)rx, (int)ry);
+ }
+ }
});
}
@@ -671,21 +680,22 @@ public final class Canvas_Delegate {
return;
}
- draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- Shape shape = pathDelegate.getJavaShape();
- int style = paint.getStyle();
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ Shape shape = pathDelegate.getJavaShape();
+ int style = paint.getStyle();
- if (style == Paint.Style.FILL.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.fill(shape);
- }
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fill(shape);
+ }
- if (style == Paint.Style.STROKE.nativeInt ||
- style == Paint.Style.FILL_AND_STROKE.nativeInt) {
- graphics.draw(shape);
- }
- }
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.draw(shape);
+ }
+ }
});
}
@@ -706,7 +716,7 @@ public final class Canvas_Delegate {
float right = left + image.getWidth();
float bottom = top + image.getHeight();
- drawBitmap(nativeCanvas, image, bitmapDelegate.getConfig(), nativePaintOrZero,
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
0, 0, image.getWidth(), image.getHeight(),
(int)left, (int)top, (int)right, (int)bottom);
}
@@ -726,11 +736,11 @@ public final class Canvas_Delegate {
BufferedImage image = bitmapDelegate.getImage();
if (src == null) {
- drawBitmap(nativeCanvas, image, bitmapDelegate.getConfig(), nativePaintOrZero,
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
0, 0, image.getWidth(), image.getHeight(),
(int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
} else {
- drawBitmap(nativeCanvas, image, bitmapDelegate.getConfig(), nativePaintOrZero,
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
src.left, src.top, src.width(), src.height(),
(int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
}
@@ -751,29 +761,87 @@ public final class Canvas_Delegate {
BufferedImage image = bitmapDelegate.getImage();
if (src == null) {
- drawBitmap(nativeCanvas, image, bitmapDelegate.getConfig(), nativePaintOrZero,
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
0, 0, image.getWidth(), image.getHeight(),
dst.left, dst.top, dst.right, dst.bottom);
} else {
- drawBitmap(nativeCanvas, image, bitmapDelegate.getConfig(), nativePaintOrZero,
+ drawBitmap(nativeCanvas, bitmapDelegate, 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,
- int offset, int stride, float x,
- float y, int width, int height,
+ int offset, int stride, final float x,
+ final float y, int width, int height,
boolean hasAlpha,
int nativePaintOrZero) {
- // FIXME
- throw new UnsupportedOperationException();
+
+ // create a temp BufferedImage containing the content.
+ final BufferedImage image = new BufferedImage(width, height,
+ hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
+ image.setRGB(0, 0, width, height, colors, offset, stride);
+
+ draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ graphics.drawImage(image, (int) x, (int) y, null);
+ }
+ });
}
/*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
int nMatrix, int nPaint) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate paintDelegate = null;
+ if (nPaint > 0) {
+ paintDelegate = Paint_Delegate.getDelegate(nPaint);
+ if (paintDelegate == null) {
+ assert false;
+ return;
+ }
+ }
+
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
+ if (bitmapDelegate == null) {
+ assert false;
+ return;
+ }
+
+ final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ assert false;
+ return;
+ }
+
+ final AffineTransform mtx = matrixDelegate.getAffineTransform();
+
+ canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ //FIXME add support for canvas, screen and bitmap densities.
+ graphics.drawImage(image, mtx, null);
+ }
+ }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
}
/*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
@@ -795,8 +863,8 @@ public final class Canvas_Delegate {
/*package*/ static void native_drawText(int nativeCanvas,
final char[] text, final int index, final int count,
final float startX, final float startY, int flags, int paint) {
- draw(nativeCanvas, paint, false /*compositeOnly*/, new GcSnapshot.Drawable() {
-
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
// WARNING: the logic in this method is similar to Paint.measureText.
// Any change to this method should be reflected in Paint.measureText
@@ -974,11 +1042,11 @@ public final class Canvas_Delegate {
// ---- Private delegate/helper methods ----
/**
- * Executes a {@link Drawable} with a given canvas and paint.
+ * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
* <p>Note that the drawable may actually be executed several times if there are
* layers involved (see {@link #saveLayer(RectF, int, int)}.
*/
- private static void draw(int nCanvas, int nPaint, boolean compositeOnly,
+ private static void draw(int nCanvas, int nPaint, boolean compositeOnly, boolean forceSrcMode,
GcSnapshot.Drawable drawable) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -997,11 +1065,11 @@ public final class Canvas_Delegate {
}
}
- canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly);
+ canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
}
/**
- * Executes a {@link Drawable} with a given canvas. No paint object will be provided
+ * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
* to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
* <p>Note that the drawable may actually be executed several times if there are
* layers involved (see {@link #saveLayer(RectF, int, int)}.
@@ -1017,8 +1085,8 @@ public final class Canvas_Delegate {
canvasDelegate.mSnapshot.draw(drawable);
}
- private Canvas_Delegate(BufferedImage image) {
- mSnapshot = GcSnapshot.createDefaultSnapshot(mBufferedImage = image);
+ private Canvas_Delegate(Bitmap_Delegate bitmap) {
+ mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
}
private Canvas_Delegate() {
@@ -1078,16 +1146,15 @@ public final class Canvas_Delegate {
return mSnapshot.clipRect(left, top, right, bottom, regionOp);
}
- private void setBitmap(BufferedImage image) {
- mBufferedImage = image;
+ private void setBitmap(Bitmap_Delegate bitmap) {
+ mBitmap = bitmap;
assert mSnapshot.size() == 1;
- mSnapshot.setImage(mBufferedImage);
+ mSnapshot.setBitmap(mBitmap);
}
private static void drawBitmap(
int nativeCanvas,
- final BufferedImage image,
- final Bitmap.Config mBitmapConfig,
+ Bitmap_Delegate bitmap,
int nativePaintOrZero,
final int sleft, final int stop, final int sright, final int sbottom,
final int dleft, final int dtop, final int dright, final int dbottom) {
@@ -1108,23 +1175,9 @@ public final class Canvas_Delegate {
}
}
- // if the bitmap config is alpha_8, then we erase all color value from it
- // before drawing it.
- if (mBitmapConfig == Bitmap.Config.ALPHA_8) {
- int w = image.getWidth();
- int h = image.getHeight();
- int[] argb = new int[w*h];
- image.getRGB(0, 0, image.getWidth(), image.getHeight(),
- argb, 0, image.getWidth());
-
- final int length = argb.length;
- for (int i = 0 ; i < length; i++) {
- argb[i] &= 0xFF000000;
- }
- image.setRGB(0, 0, w, h, argb, 0, w);
- }
+ final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
- draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/,
+ draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
if (paint != null && paint.isFilterBitmap()) {
@@ -1138,5 +1191,69 @@ public final class Canvas_Delegate {
}
});
}
+
+
+ /**
+ * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate.
+ * The image returns, through a 1-size boolean array, whether the drawing code should
+ * use a SRC composite no matter what the paint says.
+ *
+ * @param bitmap the bitmap
+ * @param paint the paint that will be used to draw
+ * @param forceSrcMode whether the composite will have to be SRC
+ * @return the image to draw
+ */
+ private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint,
+ boolean[] forceSrcMode) {
+ BufferedImage image = bitmap.getImage();
+ forceSrcMode[0] = false;
+
+ // if the bitmap config is alpha_8, then we erase all color value from it
+ // before drawing it.
+ if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
+ fixAlpha8Bitmap(image);
+ } else if (bitmap.hasAlpha() == false) {
+ // hasAlpha is merely a rendering hint. There can in fact be alpha values
+ // in the bitmap but it should be ignored at drawing time.
+ // There is two ways to do this:
+ // - override the composite to be SRC. This can only be used if the composite
+ // was going to be SRC or SRC_OVER in the first place
+ // - Create a different bitmap to draw in which all the alpha channel values is set
+ // to 0xFF.
+ if (paint != null) {
+ int xfermode = paint.getXfermode();
+ if (xfermode > 0) {
+ Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(xfermode);
+ if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
+ PorterDuff.Mode mode =
+ ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
+
+ forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
+ mode == PorterDuff.Mode.SRC;
+ }
+ }
+ }
+
+ // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
+ if (forceSrcMode[0] == false) {
+ image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
+ }
+ }
+
+ return image;
+ }
+
+ private static void fixAlpha8Bitmap(final BufferedImage image) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+ int[] argb = new int[w * h];
+ image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
+
+ final int length = argb.length;
+ for (int i = 0 ; i < length; i++) {
+ argb[i] &= 0xFF000000;
+ }
+ image.setRGB(0, 0, w, h, argb, 0, w);
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index e64a69a..25e0795 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -164,7 +164,7 @@ public final class NinePatch_Delegate {
chunkObject.draw(bitmap_delegate.getImage(), graphics,
left, top, right - left, bottom - top, destDensity, srcDensity);
}
- }, paint_delegate, true /*compositeOnly*/);
+ }, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
index 097dfce..b7d5dc9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
@@ -45,6 +45,10 @@ public class PorterDuffXfermode_Delegate extends Xfermode_Delegate {
// ---- Public Helper methods ----
+ public PorterDuff.Mode getMode() {
+ return getPorterDuffMode(mMode);
+ }
+
@Override
public Composite getComposite(int alpha) {
return getComposite(getPorterDuffMode(mMode), alpha);