javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/graphics/Image.java
changeset 78 71ad690e91f5
parent 21 2a9601315dfc
child 80 d6dafc5d983f
--- 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;
+    }
 }