package gnu.java.awt.peer.gtk;
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
+import java.awt.Point;
+import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
+import java.awt.image.ImageProducer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
public class VolatileImageGraphics extends ComponentGraphics
{
private GtkVolatileImage owner;
+ private BufferedImage buffer;
public VolatileImageGraphics(GtkVolatileImage img)
{
return new VolatileImageGraphics( this );
}
+ public void draw(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.draw(s);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setColor(this.getColor());
+ g2d.setStroke(this.getStroke());
+ g2d.draw(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void fill(Shape s)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.fill(s);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.fill(s);
+
+ drawComposite(s.getBounds2D(), null);
+ }
+ }
+
+ public void drawGlyphVector(GlyphVector gv, float x, float y)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ super.drawGlyphVector(gv, x, y);
+
+ // Custom composite
+ else
+ {
+ // Draw operation to temporary buffer
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+
+ g2d.setPaint(this.getPaint());
+ g2d.setColor(this.getColor());
+ g2d.drawGlyphVector(gv, x, y);
+
+ Rectangle2D bounds = gv.getLogicalBounds();
+ bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
+ bounds.getWidth(), bounds.getHeight());
+ drawComposite(bounds, null);
+ }
+ }
+
+ protected boolean drawImage(Image img, AffineTransform xform,
+ Color bgcolor, ImageObserver obs)
+ {
+ if (comp == null || comp instanceof AlphaComposite)
+ return super.drawImage(img, xform, bgcolor, obs);
+
+ // Custom composite
+ else
+ {
+ // Get buffered image of source
+ if( !(img instanceof BufferedImage) )
+ {
+ ImageProducer source = img.getSource();
+ if (source == null)
+ return false;
+ img = Toolkit.getDefaultToolkit().createImage(source);
+ }
+ BufferedImage bImg = (BufferedImage) img;
+
+ // Find dimensions of translation
+ Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+ Point2D pt = new Point2D.Double(bImg.getWidth(), bImg.getHeight());
+ if (xform != null)
+ {
+ origin = xform.transform(origin, origin);
+ pt = xform.transform(pt, pt);
+ }
+
+ // Create buffer and draw image
+ createBuffer();
+
+ Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+ g2d.setRenderingHints(this.getRenderingHints());
+ g2d.drawImage(img, xform, obs);
+ // Perform compositing from buffer to screen
+ return drawComposite(new Rectangle2D.Double((int)origin.getX(),
+ (int)origin.getY(),
+ (int)pt.getX(),
+ (int)pt.getY()),
+ obs);
+ }
+ }
+
public boolean drawImage(Image img, int x, int y, ImageObserver observer)
{
- if( img instanceof GtkVolatileImage )
+ if (img instanceof GtkVolatileImage
+ && (comp == null || comp instanceof AlphaComposite))
{
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
x, y,
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer)
{
- if( img instanceof GtkVolatileImage )
+ if ((img instanceof GtkVolatileImage)
+ && (comp == null || comp instanceof AlphaComposite))
{
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
x, y, width, height );
{
return new Rectangle2D.Double(0, 0, owner.width, owner.height);
}
+
+ private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+ {
+ // Clip source to visible areas that need updating
+ Rectangle2D clip = this.getClipBounds();
+ Rectangle2D.intersect(bounds, clip, bounds);
+
+ BufferedImage buffer2 = buffer;
+ if (!bounds.equals(buffer2.getRaster().getBounds()))
+ buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
+
+ // Get current on-screen pixels (destination) and clip to bounds
+ BufferedImage current = owner.getSnapshot();
+
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+
+ Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
+ points[2] - points[0],
+ points[3] - points[1]);
+ Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
+
+ current = current.getSubimage((int)deviceBounds.getX(),
+ (int)deviceBounds.getY(),
+ (int)deviceBounds.getWidth(),
+ (int)deviceBounds.getHeight());
+
+ // Perform actual composite operation
+ compCtx.compose(buffer2.getRaster(), current.getRaster(),
+ buffer2.getRaster());
+
+ // This MUST call directly into the "action" method in CairoGraphics2D,
+ // not one of the wrappers, to ensure that the composite isn't processed
+ // more than once!
+ Composite oldComp = comp; // so that ComponentGraphics doesn't
+ comp = null; // process the composite again
+ boolean rv = super.drawImage(buffer2,
+ AffineTransform.getTranslateInstance(bounds.getX(),
+ bounds.getY()),
+ null, null);
+ comp = oldComp;
+
+ return rv;
+ }
+
+ private void createBuffer()
+ {
+ if (buffer == null)
+ {
+ WritableRaster rst;
+ rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(owner.width,
+ owner.height),
+ new Point(0,0));
+
+ buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
+ GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
+ new Hashtable());
+ }
+ else
+ {
+ Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
+
+ g2d.setBackground(new Color(0,0,0,0));
+ g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
+ }
+ }
+
+ protected ColorModel getNativeCM()
+ {
+ // We should really return GtkVolatileImage.gdkColorModel ,
+ // but CairoGraphics2D doesn't handle alpha premultiplication properly (see
+ // the fixme in drawImage) so we use the naive Cairo model instead to trick
+ // the compositing context.
+ // Because getNativeCM() == getBufferCM() for this peer, it doesn't break.
+ return CairoSurface.cairoCM_pre;
+ }
}