summaryrefslogtreecommitdiffstats
path: root/tools
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
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')
-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
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java128
5 files changed, 512 insertions, 184 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);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 103e262..27268fc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -18,12 +18,11 @@ package com.android.layoutlib.bridge.impl;
import com.android.layoutlib.bridge.Bridge;
+import android.graphics.Bitmap_Delegate;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint_Delegate;
import android.graphics.PathEffect_Delegate;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode_Delegate;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@@ -81,11 +80,33 @@ public class GcSnapshot {
*/
private static class Layer {
private final Graphics2D mGraphics;
+ private final Bitmap_Delegate mBitmap;
private final BufferedImage mImage;
private BufferedImage mOriginalCopy;
+ /**
+ * Creates a layer with a graphics and a bitmap.
+ *
+ * @param graphics the graphics
+ * @param bitmap the bitmap
+ */
+ Layer(Graphics2D graphics, Bitmap_Delegate bitmap) {
+ mGraphics = graphics;
+ mBitmap = bitmap;
+ mImage = mBitmap.getImage();
+ }
+
+ /**
+ * Creates a layer with a graphics and an image. If the image belongs to a
+ * {@link Bitmap_Delegate}, then {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should
+ * be used.
+ *
+ * @param graphics the graphics
+ * @param image the image
+ */
Layer(Graphics2D graphics, BufferedImage image) {
mGraphics = graphics;
+ mBitmap = null;
mImage = image;
}
@@ -100,6 +121,10 @@ public class GcSnapshot {
}
Layer makeCopy() {
+ if (mBitmap != null) {
+ return new Layer((Graphics2D) mGraphics.create(), mBitmap);
+ }
+
return new Layer((Graphics2D) mGraphics.create(), mImage);
}
@@ -111,22 +136,28 @@ public class GcSnapshot {
BufferedImage getOriginalCopy() {
return mOriginalCopy;
}
+
+ void change() {
+ if (mBitmap != null) {
+ mBitmap.change();
+ }
+ }
}
/**
- * Creates the root snapshot associating it with a given image.
+ * Creates the root snapshot associating it with a given bitmap.
* <p>
- * If <var>image</var> is null, then {@link GcSnapshot#setImage(BufferedImage)} must be
+ * If <var>bitmap</var> is null, then {@link GcSnapshot#setBitmap(Bitmap_Delegate)} must be
* called before the snapshot can be used to draw. Transform and clip operations are permitted
* before.
*
* @param image the image to associate to the snapshot or null.
* @return the root snapshot
*/
- public static GcSnapshot createDefaultSnapshot(BufferedImage image) {
+ public static GcSnapshot createDefaultSnapshot(Bitmap_Delegate bitmap) {
GcSnapshot snapshot = new GcSnapshot();
- if (image != null) {
- snapshot.setImage(image);
+ if (bitmap != null) {
+ snapshot.setBitmap(bitmap);
}
return snapshot;
@@ -295,19 +326,19 @@ public class GcSnapshot {
}
/**
- * Link the snapshot to a BufferedImage.
+ * Link the snapshot to a Bitmap_Delegate.
* <p/>
* This is only for the case where the snapshot was created with a null image when calling
- * {@link #createDefaultSnapshot(BufferedImage)}, and is therefore not yet linked to
+ * {@link #createDefaultSnapshot(Bitmap_Delegate)}, and is therefore not yet linked to
* a previous snapshot.
* <p/>
* If any transform or clip information was set before, they are put into the Graphics object.
- * @param image the buffered image to link to.
+ * @param bitmap the bitmap to link to.
*/
- public void setImage(BufferedImage image) {
+ public void setBitmap(Bitmap_Delegate bitmap) {
assert mLayers.size() == 0;
- Graphics2D graphics2D = image.createGraphics();
- mLayers.add(new Layer(graphics2D, image));
+ Graphics2D graphics2D = bitmap.getImage().createGraphics();
+ mLayers.add(new Layer(graphics2D, bitmap));
if (mTransform != null) {
graphics2D.setTransform(mTransform);
mTransform = null;
@@ -483,7 +514,7 @@ public class GcSnapshot {
* @param drawable
*/
public void draw(Drawable drawable) {
- draw(drawable, null, false /*compositeOnly*/);
+ draw(drawable, null, false /*compositeOnly*/, false /*forceSrcMode*/);
}
/**
@@ -494,30 +525,33 @@ public class GcSnapshot {
* @param paint
* @param compositeOnly whether the paint is used for composite only. This is typically
* the case for bitmaps.
+ * @param forceSrcMode if true, this overrides the composite to be SRC
*/
- public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly) {
+ public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly,
+ boolean forceSrcMode) {
// if we clip to the layer, then we only draw in the layer
if (mLocalLayer != null && (mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) != 0) {
- drawInLayer(mLocalLayer, drawable, paint, compositeOnly);
+ drawInLayer(mLocalLayer, drawable, paint, compositeOnly, forceSrcMode);
} else {
// draw in all the layers
for (Layer layer : mLayers) {
- drawInLayer(layer, drawable, paint, compositeOnly);
+ drawInLayer(layer, drawable, paint, compositeOnly, forceSrcMode);
}
}
}
private void drawInLayer(Layer layer, Drawable drawable, Paint_Delegate paint,
- boolean compositeOnly) {
+ boolean compositeOnly, boolean forceSrcMode) {
Graphics2D originalGraphics = layer.getGraphics();
// get a Graphics2D object configured with the drawing parameters.
Graphics2D configuredGraphics2D =
paint != null ?
- createCustomGraphics(originalGraphics, paint, compositeOnly) :
+ createCustomGraphics(originalGraphics, paint, compositeOnly, forceSrcMode) :
(Graphics2D) originalGraphics.create();
try {
drawable.draw(configuredGraphics2D, paint);
+ layer.change();
} finally {
// dispose Graphics2D object
configuredGraphics2D.dispose();
@@ -557,7 +591,7 @@ public class GcSnapshot {
// now draw put the content of the local layer onto the layer, using the paint
// information
Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint,
- true /*alphaOnly*/);
+ true /*alphaOnly*/, false /*forceSrcMode*/);
g.drawImage(mLocalLayer.getImage(),
mLocalLayerRegion.left, mLocalLayerRegion.top,
@@ -603,7 +637,7 @@ public class GcSnapshot {
* <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
*/
private Graphics2D createCustomGraphics(Graphics2D original, Paint_Delegate paint,
- boolean compositeOnly) {
+ boolean compositeOnly, boolean forceSrcMode) {
// make new one graphics
Graphics2D g = (Graphics2D) original.create();
@@ -680,39 +714,43 @@ public class GcSnapshot {
// it contains the alpha
int alpha = (compositeOnly || customShader) ? paint.getAlpha() : 0xFF;
- boolean customXfermode = false;
- int xfermode = paint.getXfermode();
- if (xfermode > 0) {
- Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(paint.getXfermode());
- assert xfermodeDelegate != null;
- if (xfermodeDelegate != null) {
- if (xfermodeDelegate.isSupported()) {
- Composite composite = xfermodeDelegate.getComposite(alpha);
- assert composite != null;
- if (composite != null) {
- g.setComposite(composite);
- customXfermode = true;
+ if (forceSrcMode) {
+ g.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC, (float) alpha / 255.f));
+ } else {
+ boolean customXfermode = false;
+ int xfermode = paint.getXfermode();
+ if (xfermode > 0) {
+ Xfermode_Delegate xfermodeDelegate = Xfermode_Delegate.getDelegate(xfermode);
+ assert xfermodeDelegate != null;
+ if (xfermodeDelegate != null) {
+ if (xfermodeDelegate.isSupported()) {
+ Composite composite = xfermodeDelegate.getComposite(alpha);
+ assert composite != null;
+ if (composite != null) {
+ g.setComposite(composite);
+ customXfermode = true;
+ }
+ } else {
+ Bridge.getLog().fidelityWarning(null,
+ xfermodeDelegate.getSupportMessage(),
+ null);
}
- } else {
- Bridge.getLog().fidelityWarning(null,
- xfermodeDelegate.getSupportMessage(),
- null);
}
}
- }
- // if there was no custom xfermode, but we have alpha (due to a shader and a non
- // opaque alpha channel in the paint color), then we create an AlphaComposite anyway
- // that will handle the alpha.
- if (customXfermode == false && alpha != 0xFF) {
- g.setComposite(PorterDuffXfermode_Delegate.getComposite(
- PorterDuff.Mode.SRC_OVER, alpha));
+ // if there was no custom xfermode, but we have alpha (due to a shader and a non
+ // opaque alpha channel in the paint color), then we create an AlphaComposite anyway
+ // that will handle the alpha.
+ if (customXfermode == false && alpha != 0xFF) {
+ g.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC_OVER, (float) alpha / 255.f));
+ }
}
return g;
}
-
private void mapRect(AffineTransform matrix, RectF dst, RectF src) {
// array with 4 corners
float[] corners = new float[] {