1 /* VolatileImageGraphics.java
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package gnu
.java
.awt
.peer
.gtk
;
41 import java
.awt
.AlphaComposite
;
42 import java
.awt
.Color
;
43 import java
.awt
.Composite
;
44 import java
.awt
.Graphics
;
45 import java
.awt
.Graphics2D
;
46 import java
.awt
.GraphicsConfiguration
;
47 import java
.awt
.Image
;
48 import java
.awt
.Point
;
49 import java
.awt
.Shape
;
50 import java
.awt
.Toolkit
;
51 import java
.awt
.font
.GlyphVector
;
52 import java
.awt
.geom
.AffineTransform
;
53 import java
.awt
.geom
.Point2D
;
54 import java
.awt
.geom
.Rectangle2D
;
55 import java
.awt
.image
.BufferedImage
;
56 import java
.awt
.image
.ColorModel
;
57 import java
.awt
.image
.ImageObserver
;
58 import java
.awt
.image
.ImageProducer
;
59 import java
.awt
.image
.Raster
;
60 import java
.awt
.image
.WritableRaster
;
61 import java
.util
.Hashtable
;
63 public class VolatileImageGraphics
extends ComponentGraphics
65 private GtkVolatileImage owner
;
66 private BufferedImage buffer
;
68 public VolatileImageGraphics(GtkVolatileImage img
)
71 cairo_t
= initFromVolatile( owner
.nativePointer
, img
.width
, img
.height
);
75 private VolatileImageGraphics(VolatileImageGraphics copy
)
77 this.owner
= copy
.owner
;
78 cairo_t
= initFromVolatile(owner
.nativePointer
, owner
.width
, owner
.height
);
79 copy( copy
, cairo_t
);
82 public void copyAreaImpl(int x
, int y
, int width
, int height
, int dx
, int dy
)
84 owner
.copyArea(x
, y
, width
, height
, dx
, dy
);
87 public GraphicsConfiguration
getDeviceConfiguration()
89 GraphicsConfiguration conf
;
90 if (owner
.component
!= null)
92 conf
= owner
.component
.getGraphicsConfiguration();
96 return java
.awt
.GraphicsEnvironment
.getLocalGraphicsEnvironment()
97 .getDefaultScreenDevice().getDefaultConfiguration();
102 public Graphics
create()
104 return new VolatileImageGraphics( this );
107 public void draw(Shape s
)
109 if (comp
== null || comp
instanceof AlphaComposite
)
115 // Draw operation to temporary buffer
118 Graphics2D g2d
= (Graphics2D
)buffer
.getGraphics();
119 g2d
.setColor(this.getColor());
120 g2d
.setStroke(this.getStroke());
123 drawComposite(s
.getBounds2D(), null);
127 public void fill(Shape s
)
129 if (comp
== null || comp
instanceof AlphaComposite
)
135 // Draw operation to temporary buffer
138 Graphics2D g2d
= (Graphics2D
)buffer
.getGraphics();
139 g2d
.setPaint(this.getPaint());
140 g2d
.setColor(this.getColor());
143 drawComposite(s
.getBounds2D(), null);
147 public void drawGlyphVector(GlyphVector gv
, float x
, float y
)
149 if (comp
== null || comp
instanceof AlphaComposite
)
150 super.drawGlyphVector(gv
, x
, y
);
155 // Draw operation to temporary buffer
158 Graphics2D g2d
= (Graphics2D
)buffer
.getGraphics();
160 g2d
.setPaint(this.getPaint());
161 g2d
.setColor(this.getColor());
162 g2d
.drawGlyphVector(gv
, x
, y
);
164 Rectangle2D bounds
= gv
.getLogicalBounds();
165 bounds
= new Rectangle2D
.Double(x
+ bounds
.getX(), y
+ bounds
.getY(),
166 bounds
.getWidth(), bounds
.getHeight());
167 drawComposite(bounds
, null);
171 protected boolean drawImage(Image img
, AffineTransform xform
,
172 Color bgcolor
, ImageObserver obs
)
174 if (comp
== null || comp
instanceof AlphaComposite
)
175 return super.drawImage(img
, xform
, bgcolor
, obs
);
180 // Get buffered image of source
181 if( !(img
instanceof BufferedImage
) )
183 ImageProducer source
= img
.getSource();
186 img
= Toolkit
.getDefaultToolkit().createImage(source
);
188 BufferedImage bImg
= (BufferedImage
) img
;
190 // Find dimensions of translation
191 Point2D origin
= new Point2D
.Double(bImg
.getMinX(), bImg
.getMinY());
192 Point2D pt
= new Point2D
.Double(bImg
.getWidth(), bImg
.getHeight());
195 origin
= xform
.transform(origin
, origin
);
196 pt
= xform
.transform(pt
, pt
);
199 // Create buffer and draw image
202 Graphics2D g2d
= (Graphics2D
)buffer
.getGraphics();
203 g2d
.setRenderingHints(this.getRenderingHints());
204 g2d
.drawImage(img
, xform
, obs
);
206 // Perform compositing from buffer to screen
207 return drawComposite(new Rectangle2D
.Double((int)origin
.getX(),
215 public boolean drawImage(Image img
, int x
, int y
, ImageObserver observer
)
217 if (img
instanceof GtkVolatileImage
218 && (comp
== null || comp
instanceof AlphaComposite
))
220 owner
.drawVolatile( ((GtkVolatileImage
)img
).nativePointer
,
222 ((GtkVolatileImage
)img
).width
,
223 ((GtkVolatileImage
)img
).height
);
226 return super.drawImage( img
, x
, y
, observer
);
229 public boolean drawImage(Image img
, int x
, int y
, int width
, int height
,
230 ImageObserver observer
)
232 if ((img
instanceof GtkVolatileImage
)
233 && (comp
== null || comp
instanceof AlphaComposite
))
235 owner
.drawVolatile( ((GtkVolatileImage
)img
).nativePointer
,
236 x
, y
, width
, height
);
239 return super.drawImage( img
, x
, y
, width
, height
, observer
);
242 protected Rectangle2D
getRealBounds()
244 return new Rectangle2D
.Double(0, 0, owner
.width
, owner
.height
);
247 private boolean drawComposite(Rectangle2D bounds
, ImageObserver observer
)
249 // Clip source to visible areas that need updating
250 Rectangle2D clip
= this.getClipBounds();
251 Rectangle2D
.intersect(bounds
, clip
, bounds
);
253 BufferedImage buffer2
= buffer
;
254 if (!bounds
.equals(buffer2
.getRaster().getBounds()))
255 buffer2
= buffer2
.getSubimage((int)bounds
.getX(), (int)bounds
.getY(),
256 (int)bounds
.getWidth(),
257 (int)bounds
.getHeight());
259 // Get current on-screen pixels (destination) and clip to bounds
260 BufferedImage current
= owner
.getSnapshot();
262 double[] points
= new double[] {bounds
.getX(), bounds
.getY(),
263 bounds
.getMaxX(), bounds
.getMaxY()};
264 transform
.transform(points
, 0, points
, 0, 2);
266 Rectangle2D deviceBounds
= new Rectangle2D
.Double(points
[0], points
[1],
267 points
[2] - points
[0],
268 points
[3] - points
[1]);
269 Rectangle2D
.intersect(deviceBounds
, this.getClipInDevSpace(), deviceBounds
);
271 current
= current
.getSubimage((int)deviceBounds
.getX(),
272 (int)deviceBounds
.getY(),
273 (int)deviceBounds
.getWidth(),
274 (int)deviceBounds
.getHeight());
276 // Perform actual composite operation
277 compCtx
.compose(buffer2
.getRaster(), current
.getRaster(),
278 buffer2
.getRaster());
280 // This MUST call directly into the "action" method in CairoGraphics2D,
281 // not one of the wrappers, to ensure that the composite isn't processed
283 Composite oldComp
= comp
; // so that ComponentGraphics doesn't
284 comp
= null; // process the composite again
285 boolean rv
= super.drawImage(buffer2
,
286 AffineTransform
.getTranslateInstance(bounds
.getX(),
294 private void createBuffer()
299 rst
= Raster
.createWritableRaster(GtkVolatileImage
.createGdkSampleModel(owner
.width
,
303 buffer
= new BufferedImage(GtkVolatileImage
.gdkColorModel
, rst
,
304 GtkVolatileImage
.gdkColorModel
.isAlphaPremultiplied(),
309 Graphics2D g2d
= ((Graphics2D
)buffer
.getGraphics());
311 g2d
.setBackground(new Color(0,0,0,0));
312 g2d
.clearRect(0, 0, buffer
.getWidth(), buffer
.getHeight());
316 protected ColorModel
getNativeCM()
318 // We should really return GtkVolatileImage.gdkColorModel ,
319 // but CairoGraphics2D doesn't handle alpha premultiplication properly (see
320 // the fixme in drawImage) so we use the naive Cairo model instead to trick
321 // the compositing context.
322 // Because getNativeCM() == getBufferCM() for this peer, it doesn't break.
323 return CairoSurface
.cairoCM_pre
;