OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / awt / peer / gtk / VolatileImageGraphics.java
index 5849655..62dbb45 100644 (file)
@@ -38,15 +38,32 @@ exception statement from your version. */
 
 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)
   {
@@ -77,10 +94,118 @@ public class VolatileImageGraphics extends ComponentGraphics
     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,
@@ -94,7 +219,8 @@ public class VolatileImageGraphics extends ComponentGraphics
   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 );
@@ -107,5 +233,84 @@ public class VolatileImageGraphics extends ComponentGraphics
   {
     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;
+  }
 }