diff options
author | Xavier Ducrohet <xav@android.com> | 2010-12-22 10:13:23 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-12-22 10:30:53 -0800 |
commit | b1da1afa7418960b650780250bbd34c81af61aa3 (patch) | |
tree | 45b4798c9a796223bb854d8a5c56a2b5b2c9461b /tools/layoutlib/bridge/src/android/graphics | |
parent | d38e776a3cc8cb53945cbebafbe6f6c2e3501fa5 (diff) | |
download | frameworks_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')
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); |