javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/graphics/Image.java
branchRCL_3
changeset 65 ae942d28ec0e
equal deleted inserted replaced
60:6c158198356e 65:ae942d28ec0e
       
     1 /*******************************************************************************
       
     2  * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3  * All rights reserved. This program and the accompanying materials
       
     4  * are made available under the terms of the Eclipse Public License v1.0
       
     5  * which accompanies this distribution, and is available at
       
     6  * http://www.eclipse.org/legal/epl-v10.html
       
     7  *
       
     8  * Contributors:
       
     9  *     Nokia Corporation - initial implementation
       
    10  *******************************************************************************/
       
    11 package org.eclipse.swt.internal.qt.graphics;
       
    12 
       
    13 
       
    14 import org.eclipse.swt.graphics.ImageData;
       
    15 import org.eclipse.swt.widgets.Display;
       
    16 import org.eclipse.swt.widgets.Internal_PackageSupport;
       
    17 
       
    18 public final class Image {
       
    19 
       
    20     /**
       
    21      * Specifies no transformation.
       
    22      */
       
    23     public static final int TRANS_NONE = 100;
       
    24     /**
       
    25      * Specifies transformation for 90 degrees clockwise
       
    26      * along z-axis.
       
    27      */
       
    28     public static final int TRANS_ROT90 = 101;
       
    29     /**
       
    30      * Specifies transformation for 180 degrees clockwise
       
    31      * along z-axis.
       
    32      */
       
    33     public static final int TRANS_ROT180 = 102;
       
    34     /**
       
    35      * Specifies transformation for 270 degrees clockwise
       
    36      * along z-axis.
       
    37      */
       
    38     public static final int TRANS_ROT270 = 103;
       
    39     /**
       
    40      * Specifies transformation for image mirror along y-axis.
       
    41      */
       
    42     public static final int TRANS_MIRROR = 104;
       
    43     /**
       
    44      * Specifies transformation for first image mirror along y-axis
       
    45      * and then 90 degrees rotation clockwise along z-axis.
       
    46      */
       
    47     public static final int TRANS_MIRROR_ROT90 = 105;
       
    48     /**
       
    49      * Specifies transformation for first image mirror along y-axis
       
    50      * and then 180 degrees rotation clockwise along z-axis.
       
    51      */
       
    52     public static final int TRANS_MIRROR_ROT180 = 106;
       
    53     /**
       
    54      * Specifies transformation for first image mirror along y-axis
       
    55      * and then 270 degrees rotation clockwise along z-axis.
       
    56      */
       
    57     public static final int TRANS_MIRROR_ROT270 = 107;
       
    58 
       
    59     /**
       
    60      * Specifies transformation for mirror the image along x-axis.
       
    61      */
       
    62     public static final int TRANS_FLIP_HORIZONTAL = 108;
       
    63 
       
    64     /**
       
    65      * Specifies transformation for mirror the image along y-axis.
       
    66      */
       
    67     public static final int TRANS_FLIP_VERTICAL = 109;
       
    68 
       
    69     /**
       
    70      * Specifies default image format.
       
    71      */
       
    72     public static final int FORMAT_IMG_NONE = 0;
       
    73 
       
    74     /**
       
    75      * Specifies 32 bit per pixel image format.
       
    76      */
       
    77     public static final int FORMAT_IMG_RGB32 = 1;
       
    78 
       
    79     /**
       
    80      * Specifies 32 bit per pixel image format with alpha channel.
       
    81      */
       
    82     public static final int FORMAT_IMG_ARGB32 = 2;
       
    83 
       
    84     /**
       
    85      * Specifies 32 bit per pixel image format with alpha channel.
       
    86      */
       
    87     public static final int FORMAT_IMG_ARGB32PREMULTIPLIED = 3;
       
    88 
       
    89     /**
       
    90      * Specifies 16 bit per pixel image format.
       
    91      */
       
    92     public static final int FORMAT_IMG_RGB16 = 4;
       
    93 
       
    94     /**
       
    95      * Specifies 16 bit per pixel image format.
       
    96      */
       
    97     public static final int FORMAT_IMG_RGB555 = 5;
       
    98 
       
    99     /**
       
   100      * Specifies 16 bit per pixel image format.
       
   101      */
       
   102     public static final int FORMAT_IMG_RGB444 = 6;
       
   103 
       
   104     /**
       
   105      * Specifies 16 bit per pixel image format.
       
   106      */
       
   107     public static final int FORMAT_IMG_RGB4444PREMULTIPLIED = 7;
       
   108 
       
   109     /**
       
   110      * Specifies 1 bit per pixel image format.
       
   111      */
       
   112     public static final int FORMAT_IMG_MONO = 8;
       
   113 
       
   114     // Native image handle
       
   115     int handle;
       
   116     // Handle of native QPixmap wrapped by image
       
   117     int pixmapHandle;
       
   118     // Status of native peer
       
   119     private boolean disposed;
       
   120     // Image dimensions
       
   121     private int w;
       
   122     private int h;
       
   123     
       
   124     // Image pixel format
       
   125     private int pixelFormat = FORMAT_IMG_NONE;
       
   126 
       
   127     // flag to indicate if this image is currently
       
   128     // bound as rendering target by GraphicsContext
       
   129     private boolean isBound = false;
       
   130     // GraphicsContext bound to this image
       
   131     private GraphicsContext boundingGc = null;
       
   132 
       
   133     // Image manages copies of itself for command buffering of drawImage and drawRegion. 
       
   134     private Image commandBufferCopy;
       
   135     private int commandBufferCopyRefs;
       
   136     private boolean commandBufferCopyDirty;
       
   137 
       
   138     // A copy-constructed Image remembers what it's a copy of
       
   139     private Image whatAmIACopyOf;
       
   140 
       
   141     private Image() {
       
   142     }
       
   143     
       
   144     /**
       
   145      * Constructs new image with given native image handle.
       
   146      *
       
   147      * @param imgHandle The handle of valid native image
       
   148      * @throws OutOfMemoryError if imgHandlde is invalid
       
   149      */
       
   150     Image(int imgHandle) {
       
   151         Utils.validateUiThread();
       
   152         // validate handle
       
   153         if(imgHandle == 0) {
       
   154             throw new OutOfMemoryError();
       
   155         }
       
   156         // store handle & get dimensions
       
   157         handle = imgHandle;
       
   158         updateSize();
       
   159     }
       
   160 
       
   161     /**
       
   162      * Constructs new image filled with default fill color with specified width and height.
       
   163      *
       
   164      * @param width The width of new image
       
   165      * @param height The height of new image
       
   166      * @throws IllegalArgumetException if width or height is equal or less than zero
       
   167      * @throws OutOfMemoryError if memory allocation for new image fails
       
   168      */
       
   169     public Image(int width, int height) {
       
   170         Utils.validateUiThread();
       
   171         // check width and height
       
   172         if (width <= 0 || height <= 0) {
       
   173             throw new IllegalArgumentException("width or height is equal or less than 0");
       
   174         }
       
   175 
       
   176         // Construct image in native side and store the handle
       
   177         handle = OS.image_create(width, height, Config.IMAGE_DEFAULT_FILL_COLOR);     // may throw outOfMemoryError
       
   178         // set dimensions
       
   179         updateSize();
       
   180     }
       
   181 
       
   182     /**
       
   183      * Constructs new image with specified width, height and fill color.
       
   184      * The RGB values passed in is interpreted with the least significant eight bits giving the blue
       
   185      * component, the next eight more significant bits giving the green component, and the next eight
       
   186      * bits giving the red component. The high order byte of this value, i.e. alpha, is ignored.
       
   187      *
       
   188      * @param width The width of new image
       
   189      * @param height The height of new image
       
   190      * @param fillColor The initial fill color for the image in format #00RRGGBB.
       
   191      * @throws IllegalArgumetException if width or height is equal or less than zero
       
   192      * @throws OutOfMemoryError if memory allocation for new image fails
       
   193      */
       
   194     public Image(int width, int height, int fillColor) {
       
   195         Utils.validateUiThread();
       
   196         // check width and height
       
   197         if (width <= 0 || height <= 0) {
       
   198             throw new IllegalArgumentException("width or height is equal or less than 0");
       
   199         }
       
   200 
       
   201         // Construct image in native side and store the handle
       
   202         handle = OS.image_create(width, height, fillColor);     // may throw outOfMemoryError
       
   203         // set dimensions
       
   204         updateSize();
       
   205     }
       
   206 
       
   207     /**
       
   208      * Constructs a new instance of this class based on given image.
       
   209      *
       
   210      * @param sourceImage The image used as source
       
   211      * @throws NullPointerException if sourceImage is null
       
   212      * @throws OutOfMemoryError if memory allocation for new image fails
       
   213      */
       
   214     public Image(Image sourceImage) {
       
   215         this(sourceImage, 0, 0, 0, 0);
       
   216     }
       
   217 
       
   218     /**
       
   219      * Constructs a new instance of this class based on given image.
       
   220      * If the given copy region is empty, the whole image is copied.
       
   221      *
       
   222      * @param sourceImage The image used as source
       
   223      * @param x The top-left x coordinate of the copy region.
       
   224      * @param y The top-left y coordinate of the copy region.
       
   225      * @param width The width of the copy region.
       
   226      * @param height The height of the copy region.
       
   227      * @throws NullPointerException if sourceImage is null
       
   228      */
       
   229     public Image(Image sourceImage, int x, int y, int width, int height) {
       
   230         // validate sourceImage
       
   231         if (sourceImage == null) {
       
   232             throw new NullPointerException("img is null");
       
   233         }
       
   234         createCopy(sourceImage, x, y, width, height);
       
   235     }
       
   236 
       
   237     /**
       
   238      * Creates a new image from given ImageData
       
   239      * @param imageData
       
   240      * @throws NullPointerException if imageData is null
       
   241      */
       
   242     public Image(ImageData imageData) {
       
   243         if (imageData == null) {
       
   244             throw new NullPointerException("imageData is null");
       
   245         }
       
   246         handle = OS.image_create(imageData);
       
   247         // set dimensions
       
   248         updateSize();
       
   249     }
       
   250 
       
   251     /**
       
   252      * Constructs a new instance of this class based on the given rgb data.
       
   253      *
       
   254      * @param argbData a RGB data array where one pixel is specified as 0xAARRGGBB.
       
   255      * @param width The width of the image
       
   256      * @param height The height of the image
       
   257      * @param hasAlpha If true the rgb data has also an alpha channel,
       
   258      * otherwise all pixels are fully opaque, e.g. 0xFFRRGGBB.
       
   259      * @throws NullPointerException if the <code>argbData</code> is null
       
   260      *
       
   261      */
       
   262     public Image(int[] argbData, int width, int height, boolean hasAlpha) {
       
   263         // input validation
       
   264         if(argbData == null) {
       
   265             throw new NullPointerException("argbData is null");
       
   266         }
       
   267         // Construct an ge in native side and store the handle
       
   268         handle = OS.image_create(argbData, width, height, hasAlpha);
       
   269         // set dimensions
       
   270         updateSize();
       
   271     }
       
   272 
       
   273     /**
       
   274      * Disposes the instance if this image and frees memory.
       
   275      * After disposing image the only valid metdod is isDisposed(), other
       
   276      * methods will throw illegalStateException.
       
   277      *
       
   278      * If this instance is being disposed before gc has released it, the
       
   279      * releaseTarget() of binding gc is called automatically.
       
   280      */
       
   281     public void dispose() {
       
   282         Utils.validateUiThread();
       
   283         if (handle != 0 || !disposed) {
       
   284             // If this instance is being disposed while
       
   285             // gc is still bound, release binding before disposing.
       
   286             if(isBound) {
       
   287                 isBound = false;
       
   288                 if(boundingGc != null) {
       
   289                     boundingGc.releaseTarget();
       
   290                 }
       
   291                 boundingGc = null;
       
   292             }
       
   293 
       
   294             // Delete window surface from cache in case
       
   295             // it is created for this instance
       
   296             SurfaceCache.getInstance().deleteSurface(this);
       
   297 
       
   298             whatAmIACopyOf = null;
       
   299 
       
   300             // dispose native peer
       
   301             OS.image_dispose(handle);
       
   302             handle = 0;
       
   303             pixmapHandle = 0;
       
   304             disposed = true;
       
   305         }
       
   306     }
       
   307 
       
   308     /**
       
   309      * Gets the state of the image, is it disposed or not.
       
   310      *
       
   311      * @return true if this instanace has been disposed, otherwise false
       
   312      */
       
   313     public boolean isDisposed() {
       
   314         return disposed;
       
   315     }
       
   316 
       
   317     /**
       
   318      * Gets the format of the image.
       
   319      *
       
   320      * @return image format
       
   321      */
       
   322     public int getFormat() {
       
   323         checkState();
       
   324         if (pixelFormat == FORMAT_IMG_NONE) {
       
   325             pixelFormat = OS.image_getFormat(handle);
       
   326         }
       
   327         return pixelFormat;
       
   328     }
       
   329     /**
       
   330      * Gets the height of the image in pixels.
       
   331      *
       
   332      * @return The height of this image
       
   333      * @throws IllegalStateException if the image has already been disposed
       
   334      */
       
   335     public int getHeight() {
       
   336         checkState();
       
   337         return h;
       
   338     }
       
   339 
       
   340     /**
       
   341      * Gets the width of the image in pixels.
       
   342      *
       
   343      * @return The width of this image
       
   344      * @throws IllegalStateException if the image has already been disposed
       
   345      */
       
   346     public int getWidth() {
       
   347         checkState();
       
   348         return w;
       
   349     }
       
   350 
       
   351     /**
       
   352      * Copies image data to given integer array from rectangle specified
       
   353      * by x, y, width and height.
       
   354      *
       
   355      * @param argbData The integer array where image data is copied to
       
   356      * @param offset The index into the array where first pixel is stored
       
   357      * @param scanlength The relative offset in the array between pixles in consecutive rows of the region
       
   358      * @param x The x-coordinate of upper left corner of the region
       
   359      * @param y The y-coordinate of upper left corner of the region
       
   360      * @param width The width of the region
       
   361      * @param height The height of the region
       
   362      *
       
   363      * @throws ArrayIndexOutOfBoundsException if the operation tries to access an element in argbData outside is range
       
   364      * @throws IllegalArgumentException if the absolute value of scanlength is less than width
       
   365      * @throws IllegalArgumentException if area to be retrieved exceed the bounds of the image
       
   366      * @throws NullPointerException if argbData is null
       
   367      * @throws OutOfMemoryError if memory allocation failure occurs during operation
       
   368      * @throws IllegalStateException if the image has already been disposed
       
   369      */
       
   370     public void getRGB(int[] argbData, int offset, int scanlength,
       
   371                        int x, int y, int width, int height) {
       
   372         checkState();
       
   373 
       
   374         // input validation
       
   375         if(argbData == null) {
       
   376             throw new NullPointerException("argbData is null");
       
   377         }
       
   378         if(((x+width) > getWidth()) || ((y+height) > getHeight()) || (x < 0) || (y < 0)) {
       
   379                 throw new IllegalArgumentException("Area specified is out of image bounds");
       
   380         }
       
   381         if(scanlength < 0) {
       
   382             // End of first row
       
   383             int a = width - 1;
       
   384             int b = 0;
       
   385             int index = offset + (a - x) + (b -y) * scanlength;
       
   386             if(index > argbData.length - 1) {
       
   387                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   388             }
       
   389             // Beginning of last row
       
   390             a = 0;
       
   391             b = height - 1;
       
   392             index = offset + (a - x) + (b -y) * scanlength;
       
   393             if(index < 0) {
       
   394                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   395             }
       
   396         } else {
       
   397             if((argbData.length < (offset + (scanlength * height))) || offset < 0) {
       
   398                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   399             }
       
   400         }
       
   401         if((scanlength > 0 ? scanlength : -scanlength) < width) {
       
   402             throw new IllegalArgumentException("scanlength is less than width");
       
   403         }
       
   404 
       
   405 
       
   406         OS.image_getRGB(handle, argbData, offset, scanlength, x, y, width, height);
       
   407     }
       
   408 
       
   409 
       
   410     /**TODO: change comments
       
   411      * Copies image data to given integer array from rectangle specified
       
   412      * by x, y, width and height.
       
   413      *
       
   414      * @param argbData The byte array where image data is copied to
       
   415      * @param transparencyMask the byte array where mask values are copied to
       
   416      * @param offset The index into the array where first pixel is stored
       
   417      * @param scanlength The relative offset in the array between pixles in consecutive rows of the region
       
   418      * @param x The x-coordinate of upper left corner of the region
       
   419      * @param y The y-coordinate of upper left corner of the region
       
   420      * @param width The width of the region
       
   421      * @param height The height of the region
       
   422      * @param format The format in which pixels are stored into argbData
       
   423      * @throws ArrayIndexOutOfBoundsException if the operation tries to access an element in argbData outside is range
       
   424      * @throws IllegalArgumentException if the absolute value of scanlength is less than width
       
   425      * @throws IllegalArgumentException if area to be retrieved exceed the bounds of the image
       
   426      * @throws NullPointerException if argbData is null
       
   427      * @throws OutOfMemoryError if memory allocation failure occurs during operation
       
   428      * @throws IllegalStateException if the image has already been disposed
       
   429      */
       
   430     public void getRGB(byte[] argbData, byte[] transparencyMask, int offset, int scanlength,
       
   431                        int x, int y, int width, int height, int format) {
       
   432         checkState();
       
   433 
       
   434         // input validation
       
   435         if(argbData == null) {
       
   436             throw new NullPointerException("argbData is null");
       
   437         }
       
   438         if(transparencyMask == null) {
       
   439             throw new IllegalArgumentException("transparencyMask is null");
       
   440         }
       
   441         if(((x+width) > getWidth()) || ((y+height) > getHeight()) || (x < 0) || (y < 0)) {
       
   442                 throw new IllegalArgumentException("Area specified is out of image bounds");
       
   443         }
       
   444         if(scanlength < 0) {
       
   445             // End of first row
       
   446             int a = width - 1;
       
   447             int b = 0;
       
   448             int index = offset + (a - x) + (b -y) * scanlength;
       
   449             if(index > argbData.length - 1) {
       
   450                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   451             }
       
   452             if(index > transparencyMask.length - 1) {
       
   453                 throw new ArrayIndexOutOfBoundsException("Mask does not fit in given array");
       
   454             }
       
   455             // Beginning of last row
       
   456             a = 0;
       
   457             b = height - 1;
       
   458             index = offset + (a - x) + (b -y) * scanlength;
       
   459             if(index < 0) {
       
   460                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   461             }
       
   462         } else {
       
   463             if((argbData.length < (offset + (scanlength * height))) || offset < 0) {
       
   464                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   465             }
       
   466             if((transparencyMask.length < (offset + (scanlength * height))) || offset < 0) {
       
   467                 throw new ArrayIndexOutOfBoundsException("Mask does not fit in given array");
       
   468             }
       
   469         }
       
   470         if((scanlength > 0 ? scanlength : -scanlength) < width) {
       
   471             throw new IllegalArgumentException("scanlength is less than width");
       
   472         }
       
   473 
       
   474 
       
   475         OS.image_getRGB(handle, argbData, transparencyMask,offset, scanlength, x, y, width, height, format);
       
   476     }
       
   477 
       
   478 
       
   479     /**
       
   480      * Copies image data to given integer array from rectangle specified
       
   481      * by x, y, width and height.
       
   482      *
       
   483      * @param argbData The short array where image data is copied to
       
   484      * @param offset The index into the array where first pixel is stored
       
   485      * @param scanlength The relative offset in the array between pixles in consecutive rows of the region
       
   486      * @param x The x-coordinate of upper left corner of the region
       
   487      * @param y The y-coordinate of upper left corner of the region
       
   488      * @param width The width of the region
       
   489      * @param height The height of the region
       
   490      * @param format Image format in which pixels are store into argbData //TODO:add explanation when format are addewd to image.
       
   491      *
       
   492      * @throws ArrayIndexOutOfBoundsException if the operation tries to access an element in argbData outside is range
       
   493      * @throws IllegalArgumentException if the absolute value of scanlength is less than width
       
   494      * @throws IllegalArgumentException if area to be retrieved exceed the bounds of the image
       
   495      * @throws NullPointerException if argbData is null
       
   496      * @throws OutOfMemoryError if memory allocation failure occurs during operation
       
   497      * @throws IllegalStateException if the image has already been disposed
       
   498      */
       
   499     public void getRGB(short[] argbData, int offset, int scanlength,
       
   500                        int x, int y, int width, int height, int format) {
       
   501         checkState();
       
   502 
       
   503         // input validation
       
   504         if(argbData == null) {
       
   505             throw new NullPointerException("argbData is null");
       
   506         }
       
   507         if(((x+width) > getWidth()) || ((y+height) > getHeight()) || (x < 0) || (y < 0)) {
       
   508                 throw new IllegalArgumentException("Area specified is out of image bounds");
       
   509         }
       
   510         if(scanlength < 0) {
       
   511             // End of first row
       
   512             int a = width - 1;
       
   513             int b = 0;
       
   514             int index = offset + (a - x) + (b -y) * scanlength;
       
   515             if(index > argbData.length - 1) {
       
   516                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   517             }
       
   518             // Beginning of last row
       
   519             a = 0;
       
   520             b = height - 1;
       
   521             index = offset + (a - x) + (b -y) * scanlength;
       
   522             if(index < 0) {
       
   523                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   524             }
       
   525         } else {
       
   526             if((argbData.length < (offset + (scanlength * height))) || offset < 0) {
       
   527                 throw new ArrayIndexOutOfBoundsException("Data does not fit in given array");
       
   528             }
       
   529         }
       
   530         if((scanlength > 0 ? scanlength : -scanlength) < width) {
       
   531             throw new IllegalArgumentException("scanlength is less than width");
       
   532         }
       
   533 
       
   534 
       
   535         OS.image_getRGB(handle, argbData, offset, scanlength, x, y, width, height, format);
       
   536     }
       
   537 
       
   538     /**
       
   539      * Pixel level collision detection.
       
   540      */
       
   541     public static boolean detectCollision(Image image1, int transform1, int p1x, int p1y, int r1x1, int r1y1, int r1x2, int r1y2,
       
   542                                           Image image2, int transform2, int p2x, int p2y, int r2x1, int r2y1, int r2x2, int r2y2) {
       
   543 
       
   544         return OS.image_detectCollision(
       
   545                 image1.getNativePixmapHandle(), transform1, p1x, p1y, r1x1, r1y1, r1x2, r1y2,
       
   546                 image2.getNativePixmapHandle(), transform2, p2x, p2y, r2x1, r2y1, r2x2, r2y2);
       
   547     }
       
   548 
       
   549     /**
       
   550      * Transforms image with given transform.
       
   551      *
       
   552      * @throws IllegalArgumentException if transform is not valid
       
   553      * @throws IllegalStateException if the image has already been disposed
       
   554      */
       
   555     public void transform(int transform) {
       
   556         checkState();
       
   557 
       
   558         // validate transform
       
   559         if (transform != TRANS_NONE &&
       
   560             transform != TRANS_ROT90 &&
       
   561             transform != TRANS_ROT180 &&
       
   562             transform != TRANS_ROT270 &&
       
   563             transform != TRANS_MIRROR &&
       
   564             transform != TRANS_MIRROR_ROT90 &&
       
   565             transform != TRANS_MIRROR_ROT180 &&
       
   566             transform != TRANS_MIRROR_ROT270 ) {
       
   567             throw new IllegalArgumentException("Invalid transform");
       
   568         }
       
   569 
       
   570         // if no transformation is requested, return
       
   571         if(transform == TRANS_NONE) {
       
   572             return;
       
   573         }
       
   574 
       
   575         // perform transform
       
   576         OS.image_transform(handle, transform);
       
   577 
       
   578         // update width and height
       
   579         updateSize();
       
   580     }
       
   581 
       
   582     /**
       
   583      * Package private method to infrom this image that
       
   584      * it has been bound as rendering target by GraphicsContext.
       
   585      *
       
   586      * @param gc The GraphicsContext that binds this image as target
       
   587      */
       
   588     void notifyBind(GraphicsContext gc) {
       
   589         boundingGc = gc;
       
   590         isBound = true;
       
   591     }
       
   592 
       
   593     /**
       
   594      * Package private method to infrom this image that
       
   595      * it is no longer as a rendering target of gc.
       
   596      */
       
   597     void notifyRelease() {
       
   598         boundingGc = null;
       
   599         isBound = false;
       
   600     }
       
   601 
       
   602     /**
       
   603      * Returns native side handle.
       
   604      * @return the native handle.
       
   605      */
       
   606     public int getHandle()
       
   607     {
       
   608         checkState();
       
   609         return handle;
       
   610     }
       
   611 
       
   612     /**
       
   613      * Returns native side QPixmap handle.
       
   614      * @return the native QPixmap handle.
       
   615      */
       
   616     synchronized public int getNativePixmapHandle()
       
   617     {
       
   618         checkState();
       
   619         if(pixmapHandle == 0)
       
   620         {
       
   621             // In the current implementation this will return
       
   622             // pointer to the already existing QPixmap (which
       
   623             // will be destroyed with the object), so the
       
   624             // handle does not need to be released manually.
       
   625             pixmapHandle = OS.image_getPixmapHandle(handle);
       
   626         }
       
   627         return pixmapHandle;
       
   628     }
       
   629 
       
   630     /**
       
   631     /**
       
   632      * Creates <code>ImageData</code> objects
       
   633      * @return New object
       
   634      */
       
   635     public ImageData getImageData() {
       
   636         checkState();
       
   637         return OS.image_getImageData(handle);
       
   638     }
       
   639 
       
   640     /**
       
   641      * Private helper to check the state of the current instance.
       
   642      */
       
   643     private void checkState() {
       
   644         Utils.validateUiThread();
       
   645         if(disposed) {
       
   646             throw new IllegalStateException("Image already disposed");
       
   647         }
       
   648     }
       
   649 
       
   650     /**
       
   651      * private helper for updating iWidth and iHeight from native image.
       
   652      */
       
   653     private void updateSize() {
       
   654         w = OS.image_getWidth(handle);
       
   655         h = OS.image_getHeight(handle);
       
   656     }
       
   657 
       
   658     /**
       
   659      * Contructs an instance of Image based on the given <code>imageData</code>.
       
   660      *
       
   661      * @param imageData Image data @see org.eclipse.swt.graphics.ImageData
       
   662      * @return Instance of loaded image
       
   663      * @throws IllegalArgumentException if <code>imageData</code> is null.
       
   664      */
       
   665     public static Image createImage(ImageData imageData) {
       
   666         if (imageData == null) {
       
   667             throw new IllegalArgumentException("imageData is null");
       
   668         }
       
   669         int imageHandle = OS.image_create(imageData);
       
   670         return new Image(imageHandle);
       
   671     }
       
   672     
       
   673     /**
       
   674      * Constructs new image with given native QPixmap handle.
       
   675      * @param pixmapHandle Handle of native QPixmap.
       
   676      * @return Instance of loaded image.
       
   677      */
       
   678     public static Image createImageFromPixmap(int pixmapHandle) {
       
   679         // input validation
       
   680         if(pixmapHandle <= 0) {
       
   681             throw new IllegalArgumentException("Invalid pixmap handle");
       
   682         }
       
   683         // Construct an ge in native side and store the handle
       
   684         int handle = OS.image_create(pixmapHandle);
       
   685         return new Image(handle);
       
   686     }
       
   687 
       
   688     /**
       
   689      * Obtains a shallow copy of this Image to be placed in the command buffer.
       
   690      * The returned copy must be marked as free by calling freeCommandBufferCopy
       
   691      * when it's no longer needed.
       
   692      * 
       
   693      * @return The copy
       
   694      */
       
   695     Image getCommandBufferCopy() {
       
   696         if(commandBufferCopyDirty) {
       
   697             return copyInUIThread();
       
   698         }
       
   699         if(commandBufferCopy == null) {
       
   700             commandBufferCopyDirty = false;
       
   701             commandBufferCopy = copyInUIThread();
       
   702             commandBufferCopyRefs = 0;
       
   703         }
       
   704         commandBufferCopyRefs++;
       
   705         return commandBufferCopy;
       
   706     }
       
   707 
       
   708     /**
       
   709      * Marks a copy returned from getCommandBufferCopy as free.
       
   710      * 
       
   711      * @param image
       
   712      *            The image returned from getShallowCopy.
       
   713      */
       
   714     void freeCommandBufferCopy() {
       
   715         if(disposed) {
       
   716             throw new RuntimeException("Image referenced by command buffer has been disposed");
       
   717         }
       
   718         if(whatAmIACopyOf == null) {
       
   719             throw new RuntimeException("Image not a copy");
       
   720         }
       
   721         whatAmIACopyOf.freeCommandBufferCopyOfMe(this);
       
   722     }
       
   723     
       
   724     /**
       
   725      * Tells to the Image that it has been modified and any copies returned from
       
   726      * getShallowCopy() have thus become deep copies.
       
   727      */
       
   728     void pixelDataModified() {
       
   729         if(commandBufferCopy != null) {
       
   730             commandBufferCopyDirty = true;
       
   731         }
       
   732     }
       
   733     
       
   734     /*
       
   735      * Copy-construction
       
   736      */
       
   737     private void createCopy(Image sourceImage, int x, int y, int width, int height) {
       
   738         // Construct image in native side and store the handle
       
   739         handle = OS.image_create(sourceImage.handle, x, y, width, height); // may throw outOfMemoryError
       
   740         // set dimensions
       
   741         updateSize();
       
   742         whatAmIACopyOf = sourceImage;
       
   743     }
       
   744 
       
   745     /*
       
   746      * Called on the Image when a copy it has returned from getCommandBufferCopy
       
   747      * is being freed by a call to freeCommandBufferCopy. The Image may be
       
   748      * disposed at this point while the copy is not.
       
   749      */
       
   750     private void freeCommandBufferCopyOfMe(Image copy) {
       
   751         if(copy != commandBufferCopy) {
       
   752             throw new RuntimeException("Copy doesn't exist, freed multiple times?");
       
   753         } else {
       
   754             commandBufferCopyRefs--;
       
   755             if(commandBufferCopyRefs <= 0) {
       
   756                 commandBufferCopy.dispose();
       
   757                 commandBufferCopy = null;
       
   758             }
       
   759         }
       
   760     }
       
   761     
       
   762     /*
       
   763      * Creates a shallow copy of the Image in the UI thread. 
       
   764      */
       
   765     private Image copyInUIThread() {
       
   766         Display d = Internal_PackageSupport.getDisplayInstance();
       
   767         final Image copy = new Image();
       
   768         if(d != null) {
       
   769             d.syncExec(new Runnable() {
       
   770                 public void run() {
       
   771                     copy.createCopy(Image.this, 0, 0, 0, 0);
       
   772                 }
       
   773             });
       
   774         }
       
   775         if(copy.handle == 0) {
       
   776             return null;
       
   777         }
       
   778         return copy;
       
   779     }
       
   780 }