diff options
author | Xavier Ducrohet <xav@android.com> | 2010-11-30 14:57:49 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-11-30 18:55:37 -0800 |
commit | 8dcbdc76135c8cc6a48cfa9b3e05c183522aff41 (patch) | |
tree | 50a10db2553f593d32da0a2d969270992d5ba877 /eclipse/plugins/com.android.ide.eclipse.adt/src/com | |
parent | 645b8a905ad70a7d0623dfbbfe6da720da038de9 (diff) | |
download | sdk-8dcbdc76135c8cc6a48cfa9b3e05c183522aff41.zip sdk-8dcbdc76135c8cc6a48cfa9b3e05c183522aff41.tar.gz sdk-8dcbdc76135c8cc6a48cfa9b3e05c183522aff41.tar.bz2 |
ADT: The image given to layoutlib now shares data with ImageData
We now create a custom BufferedImage that also includes a reusable
ImageData to generate SWT images. While there is still the AWT to
SWT conversion, at least most buffers aren't re-allocated every
time during animation. The only new allocation is the one done
in the Image constructor to pass the ImageData content to the native
image object.
This also fixes the tearing issue introduced in the previous
commit by calling ImageOverlay.setImage from the animation
listener callback. This should not be done in the UI thread
runnable as each rendering reuse the same bitmap.
When the animation listener callback returns, the image
will be reused for a new rendering so it's content will
change.
Also fixes the windows rendering by computing the proper
band offset based on the SWT palette Data.
Change-Id: Id57a3696bd92441271f6bee9681edefd12140b02
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com')
3 files changed, 81 insertions, 79 deletions
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 4e5f56a..3177f32 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 @@ -26,16 +26,8 @@ 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.DataBufferInt; import java.awt.image.WritableRaster; /** @@ -57,11 +49,6 @@ public class ImageOverlay extends Overlay implements IImageFactory { /** Horizontal scaling & scrollbar information. */ private CanvasTransform mHScale; - /** - * A lazily instantiated SWT sample model - */ - private PixelInterleavedSampleModel mSampleModel; - /** * Constructs an {@link ImageOverlay} tied to the given canvas. @@ -99,8 +86,8 @@ public class ImageOverlay extends Overlay implements IImageFactory { * @param awtImage The AWT image to be rendered as an SWT image. * @return The corresponding SWT image, or null. */ - public Image setImage(BufferedImage awtImage) { - if (awtImage != mAwtImage) { + public synchronized Image setImage(BufferedImage awtImage) { + if (awtImage != mAwtImage || awtImage == null) { mAwtImage = null; if (mImage != null) { @@ -113,21 +100,8 @@ public class ImageOverlay extends Overlay implements IImageFactory { mImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), awtImage, false, -1); } } else { - // 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); + assert awtImage instanceof SwtReadyBufferedImage; + mImage = ((SwtReadyBufferedImage)awtImage).getSwtImage(); } return mImage; @@ -143,7 +117,7 @@ public class ImageOverlay extends Overlay implements IImageFactory { } @Override - public void paint(GC gc) { + public synchronized void paint(GC gc) { if (mImage != null) { boolean valid = mCanvas.getViewHierarchy().isValid(); if (!valid) { @@ -223,47 +197,76 @@ public class ImageOverlay extends Overlay implements IImageFactory { } } - 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(); + /** + * Custom {@link BufferedImage} class able to convert itself into an SWT {@link Image} + * efficiently. + * + * The BufferedImage also contains an instance of {@link ImageData} that's kept around + * and used to create new SWT {@link Image} objects in {@link #getSwtImage()}. + * + */ + private static final class SwtReadyBufferedImage extends BufferedImage { + + private final ImageData mImageData; + private final Device mDevice; + + /** + * Creates the image with a given model, raster and SWT {@link ImageData} + * @param model the color model + * @param raster the image raster + * @param imageData the SWT image data. + * @param device the {@link Device} in which the SWT image will be painted. + */ + private SwtReadyBufferedImage(int width, int height, ImageData imageData, Device device) { + super(width, height, BufferedImage.TYPE_INT_ARGB); + mImageData = imageData; + mDevice = device; + } - // 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)); + /** + * Returns a new {@link Image} object initialized with the content of the BufferedImage. + * @return the image object. + */ + private Image getSwtImage() { + // transfer the content of the bufferedImage into the image data. + WritableRaster raster = getRaster(); + int[] imageDataBuffer = ((DataBufferInt) raster.getDataBuffer()).getData(); - ColorModel colorModel = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), - true /*hasAlpha*/, true /*isAlphaPremultiplied*/, - ColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE); + mImageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0); - mAwtImage = new BufferedImage(colorModel, raster, false, null); + return new Image(mDevice, mImageData); } - return mAwtImage; + /** + * Creates a new {@link SwtReadyBufferedImage}. + * @param w the width of the image + * @param h the height of the image + * @param device the device in which the SWT image will be painted + * @return a new {@link SwtReadyBufferedImage} object + */ + private static SwtReadyBufferedImage createImage(int w, int h, Device device) { + ImageData imageData = new ImageData(w, h, 32, + new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); + + SwtReadyBufferedImage swtReadyImage = new SwtReadyBufferedImage(w, h, + imageData, device); + + return swtReadyImage; + } } - 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)); + /** + * Implementation of {@link IImageFactory#getImage(int, int)}. + */ + public BufferedImage getImage(int w, int h) { + if (mAwtImage == null || + mAwtImage.getWidth() != w || + mAwtImage.getHeight() != h) { + + mAwtImage = SwtReadyBufferedImage.createImage(w, h, getDevice()); } - return mSampleModel.createCompatibleSampleModel(w, h); + return mAwtImage; } - 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 e05db27..ed42207 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 @@ -996,19 +996,20 @@ class LayoutCanvas extends Canvas { scene.animate(viewObject, "testanim", false /*isFrameworkAnimation*/, new IAnimationListener() { private int mCount = 0; - private BufferedImage mImage; private boolean mPendingDrawing = false; - public synchronized void onNewFrame(final BufferedImage image) { + public void onNewFrame(final BufferedImage image) { mCount++; - mImage = image; - if (mPendingDrawing == false) { - getDisplay().asyncExec(new Runnable() { - public void run() { - drawImage(); - } - }); - - mPendingDrawing = true; + mImageOverlay.setImage(image); + synchronized (this) { + if (mPendingDrawing == false) { + getDisplay().asyncExec(new Runnable() { + public void run() { + drawImage(); + } + }); + + mPendingDrawing = true; + } } } @@ -1026,8 +1027,6 @@ class LayoutCanvas extends Canvas { public void drawImage() { // get last image synchronized (this) { - mImageOverlay.setImage(mImage); - mImage = null; mPendingDrawing = false; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java index 854ebf5..29a6059 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SwtUtils.java @@ -27,7 +27,7 @@ import org.eclipse.swt.widgets.Display; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; -import java.awt.image.Raster; +import java.awt.image.WritableRaster; import java.lang.reflect.Field; import java.util.List; @@ -85,7 +85,7 @@ public class SwtUtils { int width = awtImage.getWidth(); int height = awtImage.getHeight(); - Raster raster = awtImage.getData(new java.awt.Rectangle(width, height)); + WritableRaster raster = awtImage.getRaster(); int[] imageDataBuffer = ((DataBufferInt) raster.getDataBuffer()).getData(); ImageData imageData = |