diff -r 1f0034e370aa -r 71ad690e91f5 javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/graphics/Image.java --- a/javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/graphics/Image.java Fri Sep 17 16:44:34 2010 +0300 +++ b/javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/graphics/Image.java Mon Oct 04 11:29:25 2010 +0300 @@ -12,6 +12,8 @@ import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Internal_PackageSupport; public final class Image { @@ -128,6 +130,17 @@ // GraphicsContext bound to this image private GraphicsContext boundingGc = null; + // Image manages copies of itself for command buffering of drawImage and drawRegion. + private Image commandBufferCopy; + private int commandBufferCopyRefs; + private boolean commandBufferCopyDirty; + + // A copy-constructed Image remembers what it's a copy of + private Image whatAmIACopyOf; + + private Image() { + } + /** * Constructs new image with given native image handle. * @@ -135,7 +148,7 @@ * @throws OutOfMemoryError if imgHandlde is invalid */ Image(int imgHandle) { - Utils.validateUiThread(); + Utils.validateUiThread(); // validate handle if(imgHandle == 0) { throw new OutOfMemoryError(); @@ -218,10 +231,7 @@ if (sourceImage == null) { throw new NullPointerException("img is null"); } - // Construct image in native side and store the handle - handle = OS.image_create(sourceImage.handle, x, y, width, height); // may throw outOfMemoryError - // set dimensions - updateSize(); + createCopy(sourceImage, x, y, width, height); } /** @@ -269,7 +279,7 @@ * releaseTarget() of binding gc is called automatically. */ public void dispose() { - Utils.validateUiThread(); + Utils.validateUiThread(); if (handle != 0 || !disposed) { // If this instance is being disposed while // gc is still bound, release binding before disposing. @@ -285,6 +295,8 @@ // it is created for this instance SurfaceCache.getInstance().deleteSurface(this); + whatAmIACopyOf = null; + // dispose native peer OS.image_dispose(handle); handle = 0; @@ -308,10 +320,10 @@ * @return image format */ public int getFormat() { - checkState(); - if (pixelFormat == FORMAT_IMG_NONE) { - pixelFormat = OS.image_getFormat(handle); - } + checkState(); + if (pixelFormat == FORMAT_IMG_NONE) { + pixelFormat = OS.image_getFormat(handle); + } return pixelFormat; } /** @@ -593,7 +605,7 @@ */ public int getHandle() { - checkState(); + checkState(); return handle; } @@ -603,7 +615,7 @@ */ synchronized public int getNativePixmapHandle() { - checkState(); + checkState(); if(pixmapHandle == 0) { // In the current implementation this will return @@ -621,7 +633,7 @@ * @return New object */ public ImageData getImageData() { - checkState(); + checkState(); return OS.image_getImageData(handle); } @@ -629,7 +641,7 @@ * Private helper to check the state of the current instance. */ private void checkState() { - Utils.validateUiThread(); + Utils.validateUiThread(); if(disposed) { throw new IllegalStateException("Image already disposed"); } @@ -657,4 +669,112 @@ int imageHandle = OS.image_create(imageData); return new Image(imageHandle); } + + /** + * Constructs new image with given native QPixmap handle. + * @param pixmapHandle Handle of native QPixmap. + * @return Instance of loaded image. + */ + public static Image createImageFromPixmap(int pixmapHandle) { + // input validation + if(pixmapHandle <= 0) { + throw new IllegalArgumentException("Invalid pixmap handle"); + } + // Construct an ge in native side and store the handle + int handle = OS.image_create(pixmapHandle); + return new Image(handle); + } + + /** + * Obtains a shallow copy of this Image to be placed in the command buffer. + * The returned copy must be marked as free by calling freeCommandBufferCopy + * when it's no longer needed. + * + * @return The copy + */ + Image getCommandBufferCopy() { + if(commandBufferCopyDirty) { + return copyInUIThread(); + } + if(commandBufferCopy == null) { + commandBufferCopyDirty = false; + commandBufferCopy = copyInUIThread(); + commandBufferCopyRefs = 0; + } + commandBufferCopyRefs++; + return commandBufferCopy; + } + + /** + * Marks a copy returned from getCommandBufferCopy as free. + * + * @param image + * The image returned from getShallowCopy. + */ + void freeCommandBufferCopy() { + if(disposed) { + throw new RuntimeException("Image referenced by command buffer has been disposed"); + } + if(whatAmIACopyOf == null) { + throw new RuntimeException("Image not a copy"); + } + whatAmIACopyOf.freeCommandBufferCopyOfMe(this); + } + + /** + * Tells to the Image that it has been modified and any copies returned from + * getShallowCopy() have thus become deep copies. + */ + void pixelDataModified() { + if(commandBufferCopy != null) { + commandBufferCopyDirty = true; + } + } + + /* + * Copy-construction + */ + private void createCopy(Image sourceImage, int x, int y, int width, int height) { + // Construct image in native side and store the handle + handle = OS.image_create(sourceImage.handle, x, y, width, height); // may throw outOfMemoryError + // set dimensions + updateSize(); + whatAmIACopyOf = sourceImage; + } + + /* + * Called on the Image when a copy it has returned from getCommandBufferCopy + * is being freed by a call to freeCommandBufferCopy. The Image may be + * disposed at this point while the copy is not. + */ + private void freeCommandBufferCopyOfMe(Image copy) { + if(copy != commandBufferCopy) { + throw new RuntimeException("Copy doesn't exist, freed multiple times?"); + } else { + commandBufferCopyRefs--; + if(commandBufferCopyRefs <= 0) { + commandBufferCopy.dispose(); + commandBufferCopy = null; + } + } + } + + /* + * Creates a shallow copy of the Image in the UI thread. + */ + private Image copyInUIThread() { + Display d = Internal_PackageSupport.getDisplayInstance(); + final Image copy = new Image(); + if(d != null) { + d.syncExec(new Runnable() { + public void run() { + copy.createCopy(Image.this, 0, 0, 0, 0); + } + }); + } + if(copy.handle == 0) { + return null; + } + return copy; + } }