Hi,

This patch implements custom composites for the last of the graphics
peers, ComponentGraphics.  With this, we should now have custom
composite support across all the GTK peers.

Cheers,
Francis


2006-11-06  Francis Kung  <[EMAIL PROTECTED]>

        * gnu/java/awt/peer/gtk/ComponentGraphics.java
        (fillRect): Handle custom composites.
        (drawRenderedImage): Handle custom composites.
        (drawImage): Handle custom composites.
        (createBuffer): New method.
        (drawLine): Handle custom composites.
        (drawComposite): New method.
        (fill): Handle custom composites.
        (getNativeCM): New method.
        (drawGlyphVector): Handle custom composites.
        (drawRect): Handle custom composites.
        (draw): Handle custom composites.
        * gnu/java/awt/peer/gtk/VolatileImageGraphics.java
        (drawComposite): Unset composite during draw call, to prevent parent
        from handling composite again.
        * gnu/java/awt/peer/gtk/CairoGraphics2D.java
        (getBufferCM): Added comments.
        (getNativeCM): Made abstract.
        (setComposite): Removed comments.

Index: gnu/java/awt/peer/gtk/CairoGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,v
retrieving revision 1.48
diff -u -r1.48 CairoGraphics2D.java
--- gnu/java/awt/peer/gtk/CairoGraphics2D.java	31 Oct 2006 20:23:23 -0000	1.48
+++ gnu/java/awt/peer/gtk/CairoGraphics2D.java	6 Nov 2006 19:36:58 -0000
@@ -985,10 +985,6 @@
             if (sm != null)
               sm.checkPermission(new AWTPermission("readDisplayPixels"));
     
-            // FIXME: implement general Composite support
-            //throw new java.lang.UnsupportedOperationException();
-            // this is in progress!  yay!
-            //compCtx = comp.createContext(getNativeCM(), getNativeCM(), hints);
             compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints);
           }
       }
@@ -1000,18 +996,17 @@
    *  
    * @return ColorModel the ColorModel of native data in this peer
    */
-  /* protected abstract ColorModel getNativeCM(); */
-  protected ColorModel getNativeCM()
-  {
-    // This stub should be removed and the method made abstract once I'm done
-    // implementing custom composites across all the peers... but we need it
-    // for now, so that the build doesn't break.
-    return null;
-  }
+  protected abstract ColorModel getNativeCM();
   
-  // This may be overridden by some subclasses
+  /**
+   * Returns the Color Model describing the buffer that this peer uses
+   * for custom composites.
+   * 
+   * @return ColorModel the ColorModel of the composite buffer in this peer.
+   */
   protected ColorModel getBufferCM()
   {
+    // This may be overridden by some subclasses
     return getNativeCM();
   }
 
Index: gnu/java/awt/peer/gtk/VolatileImageGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java,v
retrieving revision 1.10
diff -u -r1.10 VolatileImageGraphics.java
--- gnu/java/awt/peer/gtk/VolatileImageGraphics.java	18 Oct 2006 19:00:31 -0000	1.10
+++ gnu/java/awt/peer/gtk/VolatileImageGraphics.java	6 Nov 2006 19:36:58 -0000
@@ -40,6 +40,7 @@
 
 import java.awt.AlphaComposite;
 import java.awt.Color;
+import java.awt.Composite;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.GraphicsConfiguration;
@@ -269,10 +270,13 @@
     // 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;
   }
Index: gnu/java/awt/peer/gtk/ComponentGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java,v
retrieving revision 1.20
diff -u -r1.20 ComponentGraphics.java
--- gnu/java/awt/peer/gtk/ComponentGraphics.java	3 Aug 2006 08:08:13 -0000	1.20
+++ gnu/java/awt/peer/gtk/ComponentGraphics.java	6 Nov 2006 19:36:58 -0000
@@ -38,22 +38,31 @@
 
 package gnu.java.awt.peer.gtk;
 
+import gnu.classpath.Pointer;
+
+import java.awt.AlphaComposite;
 import java.awt.Color;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.GraphicsConfiguration;
 import java.awt.Image;
+import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.Shape;
 import java.awt.Toolkit;
 import java.awt.font.GlyphVector;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+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.RenderedImage;
-import gnu.classpath.Pointer;
+import java.awt.image.WritableRaster;
+import java.util.Hashtable;
 
 /**
  * ComponentGraphics - context for drawing directly to a component,
@@ -67,6 +76,7 @@
 
   private GtkComponentPeer component;
   protected long cairo_t;
+  private BufferedImage buffer, componentBuffer;
 
   private static ThreadLocal hasLock = new ThreadLocal();
   private static Integer ONE = Integer.valueOf(1);
@@ -227,7 +237,20 @@
     lock();
     try
       {
-	super.draw(s);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.draw(s);
+        
+        else
+          {
+            createBuffer();
+            
+            Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+            g2d.setStroke(this.getStroke());
+            g2d.setColor(this.getColor());
+            g2d.draw(s);
+            
+            drawComposite(s.getBounds2D(), null);
+          }
       }
     finally
       {
@@ -240,7 +263,20 @@
     lock();
     try
       {
-	super.fill(s);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.fill(s);
+        
+        else
+          {
+            createBuffer();
+            
+            Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+            g2d.setPaint(this.getPaint());
+            g2d.setColor(this.getColor());
+            g2d.fill(s);
+            
+            drawComposite(s.getBounds2D(), null);
+          }
       }
     finally
       {
@@ -253,7 +289,19 @@
     lock();
     try
       {
-	super.drawRenderedImage(image, xform);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.drawRenderedImage(image, xform);
+        
+        else
+          {
+            createBuffer();
+
+            Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+            g2d.setRenderingHints(this.getRenderingHints());
+            g2d.drawRenderedImage(image, xform);
+            
+            drawComposite(buffer.getRaster().getBounds(), null);
+          }
       }
     finally
       {
@@ -268,7 +316,44 @@
     lock();
     try
       {
-	rv = super.drawImage(img, xform, bgcolor, obs);
+        if (comp == null || comp instanceof AlphaComposite)
+          rv = super.drawImage(img, xform, bgcolor, obs);
+        
+        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 translated bounds
+            Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
+            Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
+                                            bImg.getHeight() + bImg.getMinY());
+            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
+            rv = drawComposite(new Rectangle2D.Double(origin.getX(),
+                                                        origin.getY(),
+                                                        pt.getX(), pt.getY()),
+                                 obs);
+          }
       }
     finally
       {
@@ -282,7 +367,23 @@
     lock();
     try
       {
-	super.drawGlyphVector(gv, x, y);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.drawGlyphVector(gv, x, y);
+        
+        else
+          {
+            createBuffer();
+
+            Graphics2D g2d = (Graphics2D)buffer.getGraphics();
+            g2d.setPaint(this.getPaint());
+            g2d.setStroke(this.getStroke());
+            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);
+          }
       }
     finally
       {
@@ -384,7 +485,11 @@
     lock();
     try
       {
-        super.drawLine(x1, y1, x2, y2);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.drawLine(x1, y1, x2, y2);
+        
+        else
+          draw(new Line2D.Double(x1, y1, x2, y2));
       }
     finally
       {
@@ -397,7 +502,11 @@
     lock();
     try
       {
-        super.drawRect(x, y, width, height);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.drawRect(x, y, width, height);
+        
+        else
+          draw(new Rectangle2D.Double(x, y, width, height));
       }
     finally
       {
@@ -410,7 +519,11 @@
     lock();
     try
       {
-        super.fillRect(x, y, width, height);
+        if (comp == null || comp instanceof AlphaComposite)
+          super.fillRect(x, y, width, height);
+        
+        else
+          fill(new Rectangle2D.Double(x, y, width, height));
       }
     finally
       {
@@ -431,5 +544,99 @@
       }
   }
 
+  
+  private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
+  {
+    // Clip source to visible areas that need updating
+    Rectangle2D clip = this.getClipBounds();
+    Rectangle2D.intersect(bounds, clip, bounds);
+    clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+                         buffer.getWidth(), buffer.getHeight());
+    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 destination clip to bounds
+    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);
+    
+    // Get current image on the component
+    unlock();
+    GtkImage img = grab(component);
+    Graphics gr = componentBuffer.createGraphics();
+    gr.drawImage(img, 0, 0, null);
+    gr.dispose();
+    lock();
+    
+    BufferedImage cBuffer = componentBuffer;
+    if (!deviceBounds.equals(cBuffer.getRaster().getBounds()))
+      cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(),
+                                    (int)deviceBounds.getY(),
+                                    (int)deviceBounds.getWidth(),
+                                    (int)deviceBounds.getHeight());
+    
+    // Perform actual composite operation
+    compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(),
+                    cBuffer.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!
+    boolean rv = super.drawImage(cBuffer,
+                                 AffineTransform.getTranslateInstance(bounds.getX(),
+                                                                      bounds.getY()),
+                                 null, null);
+    return rv;
+  }
+  
+  private void createBuffer()
+  {
+    if (buffer == null)
+      {
+        WritableRaster rst;
+        rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
+                                                                                component.awtComponent.getHeight()),
+                                          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());
+      }
+    
+    if (componentBuffer == null)
+      {
+        WritableRaster rst;
+        rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
+                                                                                component.awtComponent.getHeight()),
+                                          new Point(0,0));
+        
+        componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
+                                   GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
+                                   new Hashtable());
+      }
+  }
+  
+  protected ColorModel getNativeCM()
+  {
+    return GtkVolatileImage.gdkColorModel;
+  }
 }
 

Reply via email to