diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java | 447 |
1 files changed, 0 insertions, 447 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 deleted file mode 100644 index a1363ecb1..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.eclipse.org/org/documents/epl-v10.php - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.ide.eclipse.adt.internal.editors.layout.gle2; - -import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils.SHADOW_SIZE; - -import com.android.SdkConstants; -import com.android.annotations.Nullable; -import com.android.ide.common.api.Rect; -import com.android.ide.common.rendering.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.image.BufferedImage; -import java.awt.image.DataBufferInt; -import java.awt.image.WritableRaster; -import java.lang.ref.SoftReference; - -/** - * The {@link ImageOverlay} class renders an image as an overlay. - */ -public class ImageOverlay extends Overlay implements IImageFactory { - /** - * Whether the image should be pre-scaled (scaled to the zoom level) once - * instead of dynamically during each paint; this is necessary on some - * platforms (see issue #19447) - */ - private static final boolean PRESCALE = - // Currently this is necessary on Linux because the "Cairo" library - // seems to be a bottleneck - SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_LINUX - && !(Boolean.getBoolean("adt.noprescale")); //$NON-NLS-1$ - - /** Current background image. Null when there's no image. */ - private Image mImage; - - /** A pre-scaled version of the image */ - private Image mPreScaledImage; - - /** Whether the rendered image should have a drop shadow */ - private boolean mShowDropShadow; - - /** Current background AWT image. This is created by {@link #getImage()}, which is called - * by the LayoutLib. */ - private SoftReference<BufferedImage> mAwtImage = new SoftReference<BufferedImage>(null); - - /** - * Strong reference to the image in the above soft reference, to prevent - * garbage collection when {@link PRESCALE} is set, until the scaled image - * is created (lazily as part of the next paint call, where this strong - * reference is nulled out and the above soft reference becomes eligible to - * be reclaimed when memory is low.) - */ - @SuppressWarnings("unused") // Used by the garbage collector to keep mAwtImage non-soft - private BufferedImage mAwtImageStrongRef; - - /** The associated {@link LayoutCanvas}. */ - private LayoutCanvas mCanvas; - - /** Vertical scaling & scrollbar information. */ - private CanvasTransform mVScale; - - /** Horizontal scaling & scrollbar information. */ - private CanvasTransform mHScale; - - /** - * Constructs an {@link ImageOverlay} tied to the given canvas. - * - * @param canvas The {@link LayoutCanvas} to paint the overlay over. - * @param hScale The horizontal scale information. - * @param vScale The vertical scale information. - */ - public ImageOverlay(LayoutCanvas canvas, CanvasTransform hScale, CanvasTransform vScale) { - mCanvas = canvas; - mHScale = hScale; - mVScale = vScale; - } - - @Override - public void create(Device device) { - super.create(device); - } - - @Override - public void dispose() { - if (mImage != null) { - mImage.dispose(); - mImage = null; - } - if (mPreScaledImage != null) { - mPreScaledImage.dispose(); - mPreScaledImage = null; - } - } - - /** - * Sets the image to be drawn as an overlay from the passed in AWT - * {@link BufferedImage} (which will be converted to an SWT image). - * <p/> - * The image <b>can</b> be null, which is the case when we are dealing with - * an empty document. - * - * @param awtImage The AWT image to be rendered as an SWT image. - * @param isAlphaChannelImage whether the alpha channel of the image is relevant - * @return The corresponding SWT image, or null. - */ - public synchronized Image setImage(BufferedImage awtImage, boolean isAlphaChannelImage) { - mShowDropShadow = !isAlphaChannelImage; - - BufferedImage oldAwtImage = mAwtImage.get(); - if (awtImage != oldAwtImage || awtImage == null) { - mAwtImage.clear(); - mAwtImageStrongRef = null; - - if (mImage != null) { - mImage.dispose(); - } - - if (awtImage == null) { - mImage = null; - } else { - mImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), awtImage, - isAlphaChannelImage, -1); - } - } else { - assert awtImage instanceof SwtReadyBufferedImage; - - if (isAlphaChannelImage) { - if (mImage != null) { - mImage.dispose(); - } - - mImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), awtImage, true, -1); - } else { - Image prev = mImage; - mImage = ((SwtReadyBufferedImage)awtImage).getSwtImage(); - if (prev != mImage && prev != null) { - prev.dispose(); - } - } - } - - if (mPreScaledImage != null) { - // Force refresh on next paint - mPreScaledImage.dispose(); - mPreScaledImage = null; - } - - return mImage; - } - - /** - * Returns the currently painted image, or null if none has been set - * - * @return the currently painted image or null - */ - public Image getImage() { - return mImage; - } - - /** - * Returns the currently rendered image, or null if none has been set - * - * @return the currently rendered image or null - */ - @Nullable - BufferedImage getAwtImage() { - BufferedImage awtImage = mAwtImage.get(); - if (awtImage == null && mImage != null) { - awtImage = SwtUtils.convertToAwt(mImage); - } - - return awtImage; - } - - /** - * Returns whether this image overlay should be painted with a drop shadow. - * This is usually the case, but not for transparent themes like the dialog - * theme (Theme.*Dialog), which already provides its own shadow. - * - * @return true if the image overlay should be shown with a drop shadow. - */ - public boolean getShowDropShadow() { - return mShowDropShadow; - } - - @Override - public synchronized void paint(GC gc) { - if (mImage != null) { - boolean valid = mCanvas.getViewHierarchy().isValid(); - mCanvas.ensureZoomed(); - if (!valid) { - gc_setAlpha(gc, 128); // half-transparent - } - - CanvasTransform hi = mHScale; - CanvasTransform vi = mVScale; - - // On some platforms, dynamic image scaling is very slow (see issue #19447) so - // compute a pre-scaled version of the image once and render that instead. - // This is done lazily in paint rather than when the image changes because - // the image must be rescaled each time the zoom level changes, which varies - // independently from when the image changes. - BufferedImage awtImage = mAwtImage.get(); - if (PRESCALE && awtImage != null) { - int imageWidth = (mPreScaledImage == null) ? 0 - : mPreScaledImage.getImageData().width - - (mShowDropShadow ? SHADOW_SIZE : 0); - if (mPreScaledImage == null || imageWidth != hi.getScaledImgSize()) { - double xScale = hi.getScaledImgSize() / (double) awtImage.getWidth(); - double yScale = vi.getScaledImgSize() / (double) awtImage.getHeight(); - BufferedImage scaledAwtImage; - - // NOTE: == comparison on floating point numbers is okay - // here because we normalize the scaling factor - // to an exact 1.0 in the zooming code when the value gets - // near 1.0 to make painting more efficient in the presence - // of rounding errors. - if (xScale == 1.0 && yScale == 1.0) { - // Scaling to 100% is easy! - scaledAwtImage = awtImage; - - if (mShowDropShadow) { - // Just need to draw drop shadows - scaledAwtImage = ImageUtils.createRectangularDropShadow(awtImage); - } - } else { - if (mShowDropShadow) { - scaledAwtImage = ImageUtils.scale(awtImage, xScale, yScale, - SHADOW_SIZE, SHADOW_SIZE); - ImageUtils.drawRectangleShadow(scaledAwtImage, 0, 0, - scaledAwtImage.getWidth() - SHADOW_SIZE, - scaledAwtImage.getHeight() - SHADOW_SIZE); - } else { - scaledAwtImage = ImageUtils.scale(awtImage, xScale, yScale); - } - } - - if (mPreScaledImage != null && !mPreScaledImage.isDisposed()) { - mPreScaledImage.dispose(); - } - mPreScaledImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), scaledAwtImage, - true /*transferAlpha*/, -1); - // We can't just clear the mAwtImageStrongRef here, because if the - // zooming factor changes, we may need to use it again - } - - if (mPreScaledImage != null) { - gc.drawImage(mPreScaledImage, hi.translate(0), vi.translate(0)); - } - return; - } - - // we only anti-alias when reducing the image size. - int oldAlias = -2; - if (hi.getScale() < 1.0) { - oldAlias = gc_setAntialias(gc, SWT.ON); - } - - int srcX = 0; - int srcY = 0; - int srcWidth = hi.getImgSize(); - int srcHeight = vi.getImgSize(); - int destX = hi.translate(0); - int destY = vi.translate(0); - int destWidth = hi.getScaledImgSize(); - int destHeight = vi.getScaledImgSize(); - - gc.drawImage(mImage, - srcX, srcY, srcWidth, srcHeight, - destX, destY, destWidth, destHeight); - - if (mShowDropShadow) { - SwtUtils.drawRectangleShadow(gc, destX, destY, destWidth, destHeight); - } - - if (oldAlias != -2) { - gc_setAntialias(gc, oldAlias); - } - - if (!valid) { - gc_setAlpha(gc, 255); // opaque - } - } - } - - /** - * Sets the alpha for the given GC. - * <p/> - * Alpha may not work on all platforms and may fail with an exception, which - * is hidden here (false is returned in that case). - * - * @param gc the GC to change - * @param alpha the new alpha, 0 for transparent, 255 for opaque. - * @return True if the operation worked, false if it failed with an - * exception. - * @see GC#setAlpha(int) - */ - private boolean gc_setAlpha(GC gc, int alpha) { - try { - gc.setAlpha(alpha); - return true; - } catch (SWTException e) { - return false; - } - } - - /** - * Sets the non-text antialias flag for the given GC. - * <p/> - * Antialias may not work on all platforms and may fail with an exception, - * which is hidden here (-2 is returned in that case). - * - * @param gc the GC to change - * @param alias One of {@link SWT#DEFAULT}, {@link SWT#ON}, {@link SWT#OFF}. - * @return The previous aliasing mode if the operation worked, or -2 if it - * failed with an exception. - * @see GC#setAntialias(int) - */ - private int gc_setAntialias(GC gc, int alias) { - try { - int old = gc.getAntialias(); - gc.setAntialias(alias); - return old; - } catch (SWTException e) { - return -2; - } - } - - /** - * 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; - } - - /** - * 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(); - - mImageData.setPixels(0, 0, imageDataBuffer.length, imageDataBuffer, 0); - - return new Image(mDevice, mImageData); - } - - /** - * 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) { - // NOTE: We can't make this image bigger to accommodate the drop shadow directly - // (such that we could paint one into the image after a layoutlib render) - // since this image is in the full resolution of the device, and gets scaled - // to fit in the layout editor. This would have the net effect of causing - // the drop shadow to get zoomed/scaled along with the scene, making a tiny - // drop shadow for tablet layouts, a huge drop shadow for tiny QVGA screens, etc. - - ImageData imageData = new ImageData(w, h, 32, - new PaletteData(0x00FF0000, 0x0000FF00, 0x000000FF)); - - SwtReadyBufferedImage swtReadyImage = new SwtReadyBufferedImage(w, h, - imageData, device); - - return swtReadyImage; - } - } - - /** - * Implementation of {@link IImageFactory#getImage(int, int)}. - */ - @Override - public BufferedImage getImage(int w, int h) { - BufferedImage awtImage = mAwtImage.get(); - if (awtImage == null || - awtImage.getWidth() != w || - awtImage.getHeight() != h) { - mAwtImage.clear(); - awtImage = SwtReadyBufferedImage.createImage(w, h, getDevice()); - mAwtImage = new SoftReference<BufferedImage>(awtImage); - if (PRESCALE) { - mAwtImageStrongRef = awtImage; - } - } - - return awtImage; - } - - /** - * Returns the bounds of the current image, or null - * - * @return the bounds of the current image, or null - */ - public Rect getImageBounds() { - if (mImage == null) { - return null; - } - - return new Rect(0, 0, mImage.getImageData().width, mImage.getImageData().height); - } -} |