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

   1: /* BufferedImageGraphics.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.Color;
  42: import java.awt.Graphics;
  43: import java.awt.GraphicsConfiguration;
  44: import java.awt.Image;
  45: import java.awt.Rectangle;
  46: import java.awt.Shape;
  47: import java.awt.font.GlyphVector;
  48: import java.awt.geom.AffineTransform;
  49: import java.awt.geom.Rectangle2D;
  50: import java.awt.image.BufferedImage;
  51: import java.awt.image.DataBuffer;
  52: import java.awt.image.DataBufferInt;
  53: import java.awt.image.ColorModel;
  54: import java.awt.image.DirectColorModel;
  55: import java.awt.image.RenderedImage;
  56: import java.awt.image.ImageObserver;
  57: import java.util.WeakHashMap;
  58: 
  59: /**
  60:  * Implementation of Graphics2D on a Cairo surface.
  61:  *
  62:  * Simutanously maintains a CairoSurface and updates the 
  63:  * BufferedImage from that after each drawing operation.
  64:  */
  65: public class BufferedImageGraphics extends CairoGraphics2D
  66: {
  67:   /**
  68:    * the buffered Image.
  69:    */
  70:   private BufferedImage image;
  71: 
  72:   /**
  73:    * Image size.
  74:    */
  75:   private int imageWidth, imageHeight;
  76: 
  77:   /**
  78:    * The cairo surface that we actually draw on.
  79:    */
  80:   CairoSurface surface;
  81: 
  82:   /**
  83:    * Cache BufferedImageGraphics surfaces.
  84:    */
  85:   static WeakHashMap bufferedImages = new WeakHashMap();
  86: 
  87:   /**
  88:    * Its corresponding cairo_t.
  89:    */
  90:   private long cairo_t;
  91: 
  92:   /**
  93:    * Colormodels we recognize for fast copying.
  94:    */  
  95:   static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
  96:   static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
  97:                           0xFF000000);
  98:   private boolean hasFastCM;
  99:   private boolean hasAlpha;
 100: 
 101: 
 102:   public BufferedImageGraphics(BufferedImage bi)
 103:   {
 104:     this.image = bi;
 105:     imageWidth = bi.getWidth();
 106:     imageHeight = bi.getHeight();
 107:     if(bi.getColorModel().equals(rgb32))
 108:       {
 109:     hasFastCM = true;
 110:     hasAlpha = false;
 111:       }
 112:     else if(bi.getColorModel().equals(argb32))
 113:       {
 114:     hasFastCM = true;
 115:     hasAlpha = false;
 116:       }
 117:     else
 118:       hasFastCM = false;
 119: 
 120:     // Cache surfaces.
 121:     if( bufferedImages.get( bi ) != null )
 122:       surface = (CairoSurface)bufferedImages.get( bi );
 123:     else
 124:       {
 125:     surface = new CairoSurface( imageWidth, imageHeight );
 126:     bufferedImages.put(bi, surface);
 127:       }
 128: 
 129:     cairo_t = surface.newCairoContext();
 130: 
 131:     DataBuffer db = bi.getRaster().getDataBuffer();
 132:     int[] pixels;
 133:     // get pixels
 134: 
 135:     if(db instanceof CairoSurface)
 136:       pixels = ((CairoSurface)db).getPixels(imageWidth * imageHeight);
 137:     else
 138:       {
 139:     if( hasFastCM )
 140:       {
 141:         pixels = ((DataBufferInt)db).getData();
 142:         if( !hasAlpha )
 143:           for(int i = 0; i < pixels.length; i++)
 144:         pixels[i] &= 0xFFFFFFFF;
 145:       }
 146:     else
 147:       {
 148:         pixels = CairoGraphics2D.findSimpleIntegerArray
 149:           (image.getColorModel(),image.getData());
 150:       }
 151:       }
 152:     surface.setPixels( pixels );
 153: 
 154:     setup( cairo_t );
 155:     setClip(0, 0, imageWidth, imageHeight);
 156:   }
 157:   
 158:   BufferedImageGraphics(BufferedImageGraphics copyFrom)
 159:   {
 160:     surface = copyFrom.surface;
 161:     cairo_t = surface.newCairoContext();
 162:     imageWidth = copyFrom.imageWidth;
 163:     imageHeight = copyFrom.imageHeight;
 164:     copy( copyFrom, cairo_t );
 165:     setClip(0, 0, surface.width, surface.height);
 166:   }
 167: 
 168:   /**
 169:    * Update a rectangle of the bufferedImage. This can be improved upon a lot.
 170:    */
 171:   private void updateBufferedImage(int x, int y, int width, int height)
 172:   {  
 173:     int[] pixels = surface.getPixels(imageWidth * imageHeight);
 174: 
 175:     if( x > imageWidth || y > imageHeight )
 176:       return;
 177:     // Clip edges.
 178:     if( x < 0 ){ width = width + x; x = 0; }
 179:     if( y < 0 ){ height = height + y; y = 0; }
 180:     if( x + width > imageWidth ) 
 181:       width = imageWidth - x;
 182:     if( y + height > imageHeight ) 
 183:       height = imageHeight - y;
 184: 
 185:     if( !hasFastCM )
 186:       image.setRGB(x, y, width, height, pixels, 
 187:            x + y * imageWidth, imageWidth);
 188:     else
 189:       System.arraycopy(pixels, y * imageWidth, 
 190:                ((DataBufferInt)image.getRaster().getDataBuffer()).
 191:                getData(), y * imageWidth, height * imageWidth);
 192:   }
 193: 
 194:   /**
 195:    * Abstract methods.
 196:    */  
 197:   public Graphics create()
 198:   {
 199:     return new BufferedImageGraphics(this);
 200:   }
 201:   
 202:   public GraphicsConfiguration getDeviceConfiguration()
 203:   {
 204:     return null;
 205:   }
 206: 
 207:   protected Rectangle2D getRealBounds()
 208:   {
 209:     return new Rectangle2D.Double(0.0, 0.0, imageWidth, imageHeight);
 210:   }
 211:   
 212:   public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy)
 213:   {
 214:     surface.copyAreaNative(x, y, width, height, dx, dy, surface.width);
 215:     updateBufferedImage(x + dx, y + dy, width, height);
 216:   }
 217: 
 218:   /**
 219:    * Overloaded methods that do actual drawing need to enter the gdk threads 
 220:    * and also do certain things before and after.
 221:    */
 222:   public void draw(Shape s)
 223:   {
 224:     super.draw(s);
 225:     Rectangle r = s.getBounds();
 226:     updateBufferedImage(r.x, r.y, r.width, r.height);
 227:   }
 228: 
 229:   public void fill(Shape s)
 230:   {
 231:     super.fill(s);
 232:     Rectangle r = s.getBounds();
 233:     updateBufferedImage(r.x, r.y, r.width, r.height);
 234:   }
 235: 
 236:   public void drawRenderedImage(RenderedImage image, AffineTransform xform)
 237:   {
 238:     super.drawRenderedImage(image, xform);
 239:     updateBufferedImage(0, 0, imageWidth, imageHeight);
 240:   }
 241: 
 242:   protected boolean drawImage(Image img, AffineTransform xform,
 243:                   Color bgcolor, ImageObserver obs)
 244:   {
 245:     boolean rv = super.drawImage(img, xform, bgcolor, obs);
 246:     updateBufferedImage(0, 0, imageWidth, imageHeight);
 247:     return rv;
 248:   }
 249: 
 250:   public void drawGlyphVector(GlyphVector gv, float x, float y)
 251:   {
 252:     super.drawGlyphVector(gv, x, y);
 253:     updateBufferedImage(0, 0, imageWidth, imageHeight);
 254:   }
 255: }