diff options
author | Xavier Ducrohet <xav@android.com> | 2010-11-29 17:49:19 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-11-30 14:59:48 -0800 |
commit | 645b8a905ad70a7d0623dfbbfe6da720da038de9 (patch) | |
tree | 539839f309b7d83d10002c31de932c3580da6b27 /eclipse/plugins | |
parent | 7aebcab2414437c477570804d602a8b163d964de (diff) | |
download | sdk-645b8a905ad70a7d0623dfbbfe6da720da038de9.zip sdk-645b8a905ad70a7d0623dfbbfe6da720da038de9.tar.gz sdk-645b8a905ad70a7d0623dfbbfe6da720da038de9.tar.bz2 |
ADT/Layoutlib: New API to let the caller instantiate the bitmap.
This allows us to use a bitmap more compatible with SWT.
In ADT's case, because the bitmap needs to be converted to SWT
before being displayed, we create a BufferedImage using a byte[]
instead of a int[] so that we can simply do an array copy.
Also, we reuse the generated BufferedImage unless the size changed,
which lets us see less GC during animation playback.
Change-Id: I0062a4f4442ff6469cf0ad4f501c1fbe8c719400
Diffstat (limited to 'eclipse/plugins')
4 files changed, 106 insertions, 10 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java index 8cb13e6..1e51994 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java @@ -1436,12 +1436,17 @@ public class GraphicalEditorPart extends EditorPart theme, isProjectTheme, configuredProjectRes, frameworkResources, mProjectCallback, mLogger); + if (transparentBackground) { // It doesn't matter what the background color is as long as the alpha // is 0 (fully transparent). We're using red to make it more obvious if // for some reason the background is painted when it shouldn't be. params.setCustomBackgroundColor(0x00FF0000); } + + // set the Image Overlay as the image factory. + params.setImageFactory(getCanvasControl().getImageOverlay()); + LayoutScene scene = layoutLib.getBridge().createScene(params); return scene; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java index 893ed8f..4e5f56a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java @@ -16,20 +16,37 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.layoutlib.api.IImageFactory; + import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.PaletteData; +import java.awt.Point; +import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; /** * The {@link ImageOverlay} class renders an image as an overlay. */ -public class ImageOverlay extends Overlay { +public class ImageOverlay extends Overlay implements IImageFactory { /** Current background image. Null when there's no image. */ private Image mImage; + /** Current background AWT image. This is created by {@link #getImage()}, which is called + * by the LayoutLib. */ + private BufferedImage mAwtImage; /** The associated {@link LayoutCanvas}. */ private LayoutCanvas mCanvas; @@ -41,6 +58,12 @@ public class ImageOverlay extends Overlay { private CanvasTransform mHScale; /** + * A lazily instantiated SWT sample model + */ + private PixelInterleavedSampleModel mSampleModel; + + + /** * Constructs an {@link ImageOverlay} tied to the given canvas. * * @param canvas The {@link LayoutCanvas} to paint the overlay over. @@ -77,14 +100,34 @@ public class ImageOverlay extends Overlay { * @return The corresponding SWT image, or null. */ public Image setImage(BufferedImage awtImage) { - if (mImage != null) { - mImage.dispose(); - } - if (awtImage == null) { - mImage = null; + if (awtImage != mAwtImage) { + mAwtImage = null; + + if (mImage != null) { + mImage.dispose(); + } + if (awtImage == null) { + mImage = null; + } else { + mImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), awtImage, false, -1); + } } else { - mImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), awtImage, false, -1); + // The image being passed is the one that was created in #getImage(int,int), + // we can create an SWT image more efficiently. + WritableRaster awtRaster = mAwtImage.getRaster(); + DataBufferByte byteBuffer = (DataBufferByte) awtRaster.getDataBuffer(); + byte[] data = byteBuffer.getData(); + + ImageData imageData = new ImageData(mAwtImage.getWidth(), mAwtImage.getHeight(), 32, + new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); + + // normally we'd use ImageData.setPixels() but it only accepts int[] for 32 bits image. + // However from #getImage(int, int), we know the raster data is the same exact format + // as the SWT image, so we just do a copy. + System.arraycopy(data, 0, imageData.data, 0, data.length); + + mImage = new Image(getDevice(), imageData); } return mImage; @@ -180,4 +223,47 @@ public class ImageOverlay extends Overlay { } } + public BufferedImage getImage(int w, int h) { + if (mAwtImage == null || + mAwtImage.getWidth() != w || + mAwtImage.getHeight() != h) { + + ImageData imageData = + new ImageData(w, h, 32, new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); + Image image = new Image(getDevice(), imageData); + + // get the new imageData in case the host OS forced a different format. + imageData = image.getImageData(); + + // create a writable raster around the image data. + WritableRaster raster = (WritableRaster) Raster.createRaster( + getSampleModel(imageData.palette, w, h), + new DataBufferByte(imageData.data, imageData.data.length), + new Point(0,0)); + + ColorModel colorModel = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), + true /*hasAlpha*/, true /*isAlphaPremultiplied*/, + ColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + mAwtImage = new BufferedImage(colorModel, raster, false, null); + } + + return mAwtImage; + } + + private SampleModel getSampleModel(PaletteData palette, int w, int h) { + if (mSampleModel == null) { + return mSampleModel = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, w, h, + 4 /*pixel stride*/, w * 4 /*scanlineStride*/, + getBandOffset(palette)); + } + + return mSampleModel.createCompatibleSampleModel(w, h); + } + + private int[] getBandOffset(PaletteData palette) { + // FIXME actually figure out the PixelInterleavedSampleModel's band offset from the image data palette. + return new int[] {3, 2, 1, 0}; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java index 430fd68..e05db27 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java @@ -1025,14 +1025,12 @@ class LayoutCanvas extends Canvas { */ public void drawImage() { // get last image - BufferedImage image; synchronized (this) { - image = mImage; + mImageOverlay.setImage(mImage); mImage = null; mPendingDrawing = false; } - mImageOverlay.setImage(image); redraw(); } }); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/Overlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/Overlay.java index ac96d76..432d074 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/Overlay.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/Overlay.java @@ -26,6 +26,8 @@ import org.eclipse.swt.graphics.GC; * {@link MoveGesture}. */ public abstract class Overlay { + private Device mDevice; + /** * Construct the overlay, using the given graphics context for painting. */ @@ -41,6 +43,7 @@ public abstract class Overlay { * to {@link #paint} will correspond to this device. */ public void create(Device device) { + mDevice = device; } /** @@ -59,4 +62,8 @@ public abstract class Overlay { throw new IllegalArgumentException("paint() not implemented, probably done " + "with specialized paint signature"); } + + public Device getDevice() { + return mDevice; + } } |