Source for gnu.java.awt.peer.gtk.CairoSurface

   1: /* CairoSurface.java
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.awt.peer.gtk;
  40: 
  41: import java.awt.Point;
  42: import java.awt.Graphics2D;
  43: import java.awt.image.DataBuffer;
  44: import java.awt.image.Raster;
  45: import java.awt.image.WritableRaster;
  46: import java.awt.image.BufferedImage;
  47: import java.awt.image.ColorModel;
  48: import java.awt.image.DirectColorModel;
  49: import java.nio.ByteOrder;
  50: import java.util.Hashtable;
  51: 
  52: /**
  53:  * CairoSurface - wraps a Cairo surface.
  54:  *
  55:  * @author Sven de Marothy
  56:  */
  57: public class CairoSurface extends DataBuffer
  58: {
  59:   int width = -1, height = -1;
  60: 
  61:   /**
  62:    * The native pointer to the Cairo surface. 
  63:    */
  64:   long surfacePointer;
  65: 
  66:   /**
  67:    * The native pointer to the image's data buffer
  68:    */
  69:   long bufferPointer;
  70: 
  71: 
  72:   static ColorModel nativeModel = new DirectColorModel(32,
  73:                                0x00FF0000,
  74:                                0x0000FF00,
  75:                                0x000000FF,
  76:                                0xFF000000);
  77: 
  78:   /**
  79:    * Allocates and clears the buffer and creates the cairo surface.
  80:    * @param width, height - the image size
  81:    * @param stride - the buffer row stride. (in ints)
  82:    */
  83:   private native void create(int width, int height, int stride);
  84: 
  85:   /**
  86:    * Destroys the cairo surface and frees the buffer.
  87:    */
  88:   private native void destroy(long surfacePointer, long bufferPointer);
  89: 
  90:   /**
  91:    * Gets buffer elements
  92:    */
  93:   private native int nativeGetElem(long bufferPointer, int i);
  94:   
  95:   /**
  96:    * Sets buffer elements.
  97:    */
  98:   private native void nativeSetElem(long bufferPointer, int i, int val);
  99: 
 100:   /**
 101:    * Draws this image to a given CairoGraphics context, 
 102:    * with an affine transform given by i2u.
 103:    */
 104:   public native void nativeDrawSurface(long surfacePointer, long contextPointer,
 105:                                        double[] i2u, double alpha);
 106: 
 107:   public void drawSurface(long contextPointer, double[] i2u, double alpha)
 108:   {
 109:     nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha);
 110:   }
 111: 
 112:   /**
 113:    * getPixels -return the pixels as a java array.
 114:    */
 115:   native int[] nativeGetPixels(long bufferPointer, int size);
 116: 
 117:   public int[] getPixels(int size)
 118:   {
 119:     return nativeGetPixels(bufferPointer, size);
 120:   }
 121: 
 122:   /**
 123:    * getPixels -return the pixels as a java array.
 124:    */
 125:   native void nativeSetPixels(long bufferPointer, int[] pixels);
 126: 
 127:   public void setPixels(int[] pixels)
 128:   {
 129:     nativeSetPixels(bufferPointer, pixels);
 130:   }
 131: 
 132:   native long getFlippedBuffer(long bufferPointer, int size);
 133: 
 134:   /**
 135:    * Create a cairo_surface_t with specified width and height.
 136:    * The format will be ARGB32 with premultiplied alpha and native bit 
 137:    * and word ordering.
 138:    */
 139:   public CairoSurface(int width, int height)
 140:   {
 141:     super(DataBuffer.TYPE_INT, width * height);
 142: 
 143:     if(width <= 0 || height <= 0)
 144:       throw new IllegalArgumentException("Image must be at least 1x1 pixels.");
 145: 
 146:     this.width = width;
 147:     this.height = height;
 148: 
 149:     create(width, height, width);
 150: 
 151:     if(surfacePointer == 0 || bufferPointer == 0)
 152:       throw new Error("Could not allocate bitmap.");
 153:   }
 154: 
 155:   /**
 156:    * Create a cairo_surface_t from a GtkImage instance.
 157:    * (data is copied, not shared)
 158:    */
 159:   CairoSurface(GtkImage image)
 160:   {
 161:     super(DataBuffer.TYPE_INT, image.width * image.height);
 162: 
 163:     if(image.width <= 0 || image.height <= 0)
 164:       throw new IllegalArgumentException("Image must be at least 1x1 pixels.");
 165: 
 166:     width = image.width;
 167:     height = image.height;
 168: 
 169:     create(width, height, width);
 170: 
 171:     if(surfacePointer == 0 || bufferPointer == 0)
 172:       throw new Error("Could not allocate bitmap.");
 173: 
 174:     // Copy the pixel data from the GtkImage.
 175:     int[] data = image.getPixels();
 176: 
 177:     // Swap ordering from GdkPixbuf to Cairo
 178:     if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
 179:       {
 180:     for (int i = 0; i < data.length; i++ )
 181:       {
 182:         // On a big endian system we get a RRGGBBAA data array.
 183:         int alpha = data[i] & 0xFF;
 184:         if( alpha == 0 ) // I do not know why we need this, but it works.
 185:           data[i] = 0;
 186:         else
 187:           {
 188:         // Cairo needs a ARGB32 native array.
 189:         data[i] = (data[i] >>> 8) | (alpha << 24);
 190:           }
 191:       }
 192:       }
 193:     else
 194:       {
 195:     for (int i = 0; i < data.length; i++ )
 196:       {
 197:         // On a little endian system we get a AABBGGRR data array.
 198:         int alpha = data[i] & 0xFF000000;
 199:         if( alpha == 0 ) // I do not know why we need this, but it works.
 200:           data[i] = 0;
 201:         else
 202:           {
 203:         int b = (data[i] & 0xFF0000) >> 16;
 204:         int g = (data[i] & 0xFF00);
 205:         int r = (data[i] & 0xFF) << 16;
 206:         // Cairo needs a ARGB32 native array.
 207:         data[i] = alpha | r | g | b;
 208:           }
 209:       }
 210:       }
 211: 
 212:     setPixels( data );
 213:   }
 214: 
 215:   /**
 216:    * Dispose of the native data.
 217:    */
 218:   public void dispose()
 219:   {
 220:     if(surfacePointer != 0)
 221:       destroy(surfacePointer, bufferPointer);
 222:   }
 223: 
 224:   /**
 225:    * Call dispose() to clean up any native resources allocated.
 226:    */
 227:   protected void finalize()
 228:   {
 229:     dispose();
 230:   }
 231: 
 232:   /**
 233:    * Return a GtkImage from this Cairo surface.
 234:    */
 235:   public GtkImage getGtkImage()
 236:   {
 237:     return new GtkImage( width, height,
 238:                          getFlippedBuffer(bufferPointer, width * height ));
 239:   }
 240: 
 241:   /**
 242:    * Returns a BufferedImage backed by a Cairo surface.
 243:    */    
 244:   public static BufferedImage getBufferedImage(int width, int height)
 245:   {
 246:     return getBufferedImage(new CairoSurface(width, height));
 247:   }
 248: 
 249:   /**
 250:    * Returns a BufferedImage backed by a Cairo surface, 
 251:    * created from a GtkImage.
 252:    */    
 253:   public static BufferedImage getBufferedImage(GtkImage image)
 254:   {
 255:     return getBufferedImage(new CairoSurface(image));
 256:   }
 257: 
 258:   /**
 259:    * Returns a BufferedImage backed by a Cairo surface.
 260:    */    
 261:   public static BufferedImage getBufferedImage(CairoSurface surface)
 262:   {
 263:     WritableRaster raster = Raster.createPackedRaster
 264:       (surface, surface.width, surface.height, surface.width, 
 265:        new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 },
 266:        new Point(0,0));
 267: 
 268:     return new BufferedImage(nativeModel, raster, true, new Hashtable());
 269:   }
 270: 
 271:   /**
 272:    * DataBank.getElem implementation
 273:    */
 274:   public int getElem(int bank, int i)
 275:   {
 276:     if(bank != 0 || i < 0 || i >= width*height)
 277:       throw new IndexOutOfBoundsException(i+" size: "+width*height);
 278:     return nativeGetElem(bufferPointer, i);
 279:   }
 280:   
 281:   /**
 282:    * DataBank.setElem implementation
 283:    */
 284:   public void setElem(int bank, int i, int val)
 285:   {
 286:     if(bank != 0 || i < 0 || i >= width*height)
 287:       throw new IndexOutOfBoundsException(i+" size: "+width*height);
 288:     nativeSetElem(bufferPointer, i, val);
 289:   }
 290: 
 291:   /**
 292:    * Return a Graphics2D drawing to the CairoSurface.
 293:    */
 294:   public Graphics2D getGraphics()
 295:   {
 296:     return new CairoSurfaceGraphics(this);
 297:   } 
 298: 
 299:   ///// Methods used by CairoSurfaceGraphics /////
 300:   /**
 301:    * Creates a cairo_t drawing context, returns the pointer as a long.
 302:    * Used by CairoSurfaceGraphics.
 303:    */
 304:   native long nativeNewCairoContext(long surfacePointer);
 305: 
 306:   public long newCairoContext()
 307:   {
 308:     return nativeNewCairoContext(surfacePointer);
 309:   }
 310: 
 311:   /**
 312:    * Copy an area of the surface. Expects parameters must be within bounds. 
 313:    * Count on a segfault otherwise.
 314:    */
 315:   native void copyAreaNative2(long bufferPointer, int x, int y, int width,
 316:                              int height, int dx, int dy, int stride);
 317:   public void copyAreaNative(int x, int y, int width,
 318:                              int height, int dx, int dy, int stride)
 319:   {
 320:     copyAreaNative2(bufferPointer, x, y, width, height, dx, dy, stride);
 321:   }
 322: }