This patch fixes most remaining issues wrt clipping/translation and
painting that can be observed in Swing. (There's one issue left, which
is a Swing issue indeed, coming next).

2006-06-12  Roman Kennke  <[EMAIL PROTECTED]>

        * gnu/java/awt/peer/gtk/CairoGraphics2D.java
        (copy): Use getClip() to copy the clip. Make copied transform
        null when original transform is null. Set clip here.
        (setTransform): Correctly update the clip.
        (setTransformImpl): New method. Updates the actual transform for
        Cairo.
        (transform): Correctly update the clip.
        (translate): Correctly update the clip.
        (clip): Handle null clip and argument correctly.
        (clipRect): Avoid creating new Rectangle objects.
        (getClip): Get the correct copy of the clip.
        (setClip): Correctly handle null argument.
        * gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
        (CairoSurfaceGraphics): Don't set the clip here. The clip can either
        be null or whatever has been set in copy().
        * gnu/java/awt/peer/gtk/ComponentGraphics.java
        (drawImage): Add translation to the image coordinates.
        * gnu/java/awt/peer/gtk/VolatileImageGraphics.java
        (VolatileImageGraphics): Don't set clip here. The clip can either
        be null or whatever has been set in copy().


/Roman

-- 
“Improvement makes straight roads, but the crooked roads, without
Improvement, are roads of Genius.” - William Blake
Index: gnu/java/awt/peer/gtk/CairoGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,v
retrieving revision 1.20
diff -u -1 -0 -r1.20 CairoGraphics2D.java
--- gnu/java/awt/peer/gtk/CairoGraphics2D.java	12 Jun 2006 10:32:44 -0000	1.20
+++ gnu/java/awt/peer/gtk/CairoGraphics2D.java	12 Jun 2006 21:07:08 -0000
@@ -231,37 +231,35 @@
 
     if (g.bg != null)
       {
         if (g.bg.getAlpha() != -1)
           bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(),
                          g.bg.getAlpha());
         else
           bg = new Color(g.bg.getRGB());
       }
 
-    if (g.clip == null)
-      clip = null;
-    else
-      clip = new Rectangle(g.getClipBounds());
+    clip = g.getClip();
 
     if (g.transform == null)
-      transform = new AffineTransform();
+      transform = null;
     else
       transform = new AffineTransform(g.transform);
 
     font = g.font;
 
     setColor(foreground);
     setBackground(bg);
     setPaint(paint);
     setStroke(stroke);
-    setTransform(transform);
+    setTransformImpl(transform);
+    setClip(clip);
   }
 
   /**
    * Generic destructor - call the native dispose() method.
    */
   public void finalize()
   {
     dispose();
   }
 
@@ -428,57 +426,74 @@
    * Set interpolation types
    */
   private native void cairoSurfaceSetFilter(long pointer, int filter);
 
   ///////////////////////// TRANSFORMS ///////////////////////////////////
   /**
    * Set the current transform
    */ 
   public void setTransform(AffineTransform tx)
   {
+    // Transform clip into target space using the old transform.
+    updateClip(transform);
+
+    // Update the native transform.
+    setTransformImpl(tx);
+
+    // Transform the clip back into user space using the inverse new transform.
+    try
+      {
+        updateClip(transform.createInverse());
+      }
+    catch (NoninvertibleTransformException ex)
+      {
+        // TODO: How can we deal properly with this?
+        ex.printStackTrace();
+      }
+
+    if (clip != null)
+      setClip(clip);
+  }
+
+  private void setTransformImpl(AffineTransform tx)
+  {
     transform = tx;
     if (transform != null)
       {
-	double[] m = new double[6];
-	transform.getMatrix(m);
-	cairoSetMatrix(nativePointer, m);
+        double[] m = new double[6];
+        transform.getMatrix(m);
+        cairoSetMatrix(nativePointer, m);
       }
   }
-  
+
   public void transform(AffineTransform tx)
   {
     if (transform == null)
       transform = new AffineTransform(tx);
     else
       transform.concatenate(tx);
-    setTransform(transform);
+
     if (clip != null)
       {
-	// FIXME: this should actuall try to transform the shape
-	// rather than degrade to bounds.
-	Rectangle2D r = clip.getBounds2D();
-	double[] coords = new double[]
-	  {
-	    r.getX(), r.getY(), r.getX() + r.getWidth(),
-	    r.getY() + r.getHeight()
-	  };
-	try
-	  {
-	    tx.createInverse().transform(coords, 0, coords, 0, 2);
-	    r.setRect(coords[0], coords[1], coords[2] - coords[0],
-	              coords[3] - coords[1]);
-	    clip = r;
-	  }
-	catch (java.awt.geom.NoninvertibleTransformException e)
-	  {
-	  }
+        try
+          {
+            AffineTransform clipTransform = tx.createInverse();
+            updateClip(clipTransform);
+          }
+        catch (NoninvertibleTransformException ex)
+          {
+            // TODO: How can we deal properly with this?
+            ex.printStackTrace();
+          }
       }
+
+    setTransformImpl(transform);
   }
 
   public void rotate(double theta)
   {
     transform(AffineTransform.getRotateInstance(theta));
   }
 
   public void rotate(double theta, double x, double y)
   {
     transform(AffineTransform.getRotateInstance(theta, x, y));
@@ -497,63 +512,74 @@
   {
     if (transform != null)
       transform.translate(tx, ty);
     else
       transform = AffineTransform.getTranslateInstance(tx, ty);
 
     if (clip != null)
       {
         // FIXME: this should actuall try to transform the shape
         // rather than degrade to bounds.
-        Rectangle2D r;
-
         if (clip instanceof Rectangle2D)
-          r = (Rectangle2D) clip;
+          {
+            Rectangle2D r = (Rectangle2D) clip;
+            r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(),
+                      r.getHeight());
+          }
         else
-          r = clip.getBounds2D();
-
-        r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(), r.getHeight());
-        clip = r;
+          {
+            AffineTransform clipTransform =
+              AffineTransform.getTranslateInstance(-tx, -ty);
+            updateClip(clipTransform);
+          }
       }
 
-    setTransform(transform);
+    setTransformImpl(transform);
   }
   
   public void translate(int x, int y)
   {
     translate((double) x, (double) y);
   }
 
   public void shear(double shearX, double shearY)
   {
     transform(AffineTransform.getShearInstance(shearX, shearY));
   }
 
   ///////////////////////// DRAWING STATE ///////////////////////////////////
 
   public void clip(Shape s)
   {
     // Do not touch clip when s == null.
     if (s == null)
-      return;
+      {
+        // The spec says this should clear the clip. The reference
+        // implementation throws a NullPointerException instead. I think,
+        // in this case we should conform to the specs, as it shouldn't
+        // affect compatibility.
+        setClip(null);
+        return;
+      }
 
     // If the current clip is still null, initialize it.
     if (clip == null)
-      clip = originalClip;
-    
-    // This is so common, let's optimize this. 
+      {
+        clip = getRealBounds();
+      }
+
+    // This is so common, let's optimize this.
     if (clip instanceof Rectangle2D && s instanceof Rectangle2D)
       {
         Rectangle2D clipRect = (Rectangle2D) clip;
         Rectangle2D r = (Rectangle2D) s;
         Rectangle2D.intersect(clipRect, r, clipRect);
-        // Call setClip so that subclasses get notified.
         setClip(clipRect);
       }
    else
      {
        Area current;
        if (clip instanceof Area)
          current = (Area) clip;
        else
          current = new Area(clip);
 
@@ -684,29 +710,44 @@
                       fg.getAlpha() / 255.0);
   }
 
   public Color getColor()
   {
     return fg;
   }
 
   public void clipRect(int x, int y, int width, int height)
   {
-    clip(new Rectangle(x, y, width, height));
+    if (clip == null)
+      setClip(new Rectangle(x, y, width, height));
+    else if (clip instanceof Rectangle)
+      {
+        computeIntersection(x, y, width, height, (Rectangle) clip);
+        setClip(clip);
+      }
+    else
+      clip(new Rectangle(x, y, width, height));
   }
 
   public Shape getClip()
   {
     if (clip == null)
       return null;
-    else
+    else if (clip instanceof Rectangle2D)
       return clip.getBounds2D(); //getClipInDevSpace();
+    else
+      {
+        GeneralPath p = new GeneralPath();
+        PathIterator pi = clip.getPathIterator(new AffineTransform());
+        p.append(pi, false);
+        return p;
+      }
   }
 
   public Rectangle getClipBounds()
   {
     if (clip == null)
       return null;
     else
       return clip.getBounds();
   }
 
@@ -732,48 +773,48 @@
 
   public void setClip(int x, int y, int width, int height)
   {
     if( width < 0 || height < 0 )
       return;
 
     setClip(new Rectangle2D.Double(x, y, width, height));
   }
 
   public void setClip(Shape s)
-  {    
+  {
     // The first time the clip is set, save it as the original clip 
     // to reset to on s == null. We can rely on this being non-null 
     // because the constructor in subclasses is expected to set the 
     // initial clip properly.
     if( firstClip )
       {
 	originalClip = s;
 	firstClip = false;
       }
 
-    if (s == null)
-      clip = originalClip;
-    else
-      clip = s;
+    clip = s;
     cairoResetClip(nativePointer);
 
-    cairoNewPath(nativePointer);
-    if (clip instanceof Rectangle2D)
+    if (clip != null)
       {
-	Rectangle2D r = (Rectangle2D) clip;
-	cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(),
-                       r.getHeight());
+        cairoNewPath(nativePointer);
+        if (clip instanceof Rectangle2D)
+          {
+            Rectangle2D r = (Rectangle2D) clip;
+            cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(),
+                           r.getHeight());
+          }
+        else
+          walkPath(clip.getPathIterator(null), false);
+        
+        cairoClip(nativePointer);
       }
-    else
-      walkPath(clip.getPathIterator(null), false);
-    
-    cairoClip(nativePointer);
   }
 
   public void setBackground(Color c)
   {
     if (c == null)
       c = Color.WHITE;
     bg = c;
   }
 
   public Color getBackground()
@@ -1619,11 +1660,54 @@
     if (db.getNumBanks() != 1)
       return null;
 
     // Finally, we have determined that this is a single bank, [A]RGB-int
     // buffer in sRGB space. It's worth checking all this, because it means
     // that cairo can paint directly into the data buffer, which is very
     // fast compared to all the normal copying and converting.
 
     return db.getData();
   }
+
+  /**
+   * Helper method to transform the clip. This is called by the various
+   * transformation-manipulation methods to update the clip (which is in
+   * userspace) accordingly.
+   *
+   * The transform usually is the inverse transform that was applied to the
+   * graphics object.
+   *
+   * @param t the transform to apply to the clip
+   */
+  private void updateClip(AffineTransform t)
+  {
+    if (clip == null)
+      return;
+
+    if (! (clip instanceof GeneralPath))
+      clip = new GeneralPath(clip);
+
+    GeneralPath p = (GeneralPath) clip;
+    p.transform(t);
+  }
+
+  private static Rectangle computeIntersection(int x, int y, int w, int h,
+                                               Rectangle rect)
+  {
+    int x2 = (int) rect.x;
+    int y2 = (int) rect.y;
+    int w2 = (int) rect.width;
+    int h2 = (int) rect.height;
+
+    int dx = (x > x2) ? x : x2;
+    int dy = (y > y2) ? y : y2;
+    int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
+    int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
+
+    if (dw >= 0 && dh >= 0)
+      rect.setBounds(dx, dy, dw, dh);
+    else
+      rect.setBounds(0, 0, 0, 0);
+
+    return rect;
+  }
 }
Index: gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java,v
retrieving revision 1.5
diff -u -1 -0 -r1.5 CairoSurfaceGraphics.java
--- gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java	10 Jun 2006 10:33:18 -0000	1.5
+++ gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java	12 Jun 2006 21:07:08 -0000
@@ -57,33 +57,31 @@
   private long cairo_t;
   
   /**
    * Create a graphics context from a cairo surface
    */
   public CairoSurfaceGraphics(CairoSurface surface)
   {
     this.surface = surface;
     cairo_t = surface.newCairoContext();
     setup( cairo_t );
-    setClip(0, 0, surface.width, surface.height);
   }
 
   /**
    * Creates another context from a surface.
    * Used by create().
    */ 
   private CairoSurfaceGraphics(CairoSurfaceGraphics copyFrom)
   {
     surface = copyFrom.surface;
     cairo_t = surface.newCairoContext();
     copy( copyFrom, cairo_t );
-    setClip(0, 0, surface.width, surface.height);
   }
   
   public Graphics create()
   {
     return new CairoSurfaceGraphics(this);
   }
   
   public GraphicsConfiguration getDeviceConfiguration()
   {
     return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
Index: gnu/java/awt/peer/gtk/ComponentGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java,v
retrieving revision 1.14
diff -u -1 -0 -r1.14 ComponentGraphics.java
--- gnu/java/awt/peer/gtk/ComponentGraphics.java	12 Jun 2006 12:25:03 -0000	1.14
+++ gnu/java/awt/peer/gtk/ComponentGraphics.java	12 Jun 2006 21:07:08 -0000
@@ -270,35 +270,41 @@
 	super.drawGlyphVector(gv, x, y);
       }
     finally
       {
 	unlock();
       }
   }
   
   public boolean drawImage(Image img, int x, int y, ImageObserver observer)
   {
-    if( img instanceof GtkVolatileImage )
+    if (img instanceof GtkVolatileImage
+        && transform.getType() == AffineTransform.TYPE_TRANSLATION)
       {
+        x += transform.getTranslateX();
+        y += transform.getTranslateY();
         GtkVolatileImage vimg = (GtkVolatileImage) img;
 	drawVolatile( component, vimg.nativePointer,
-                      x, y - 20, vimg.width, vimg.height );
+                      x, y, vimg.width, vimg.height );
 	return true;
       }      
     return super.drawImage( img, x, y, observer );
   }
   
   public boolean drawImage(Image img, int x, int y, int width, int height,
                            ImageObserver observer)
   {
-    if( img instanceof GtkVolatileImage )
+    if( img instanceof GtkVolatileImage
+        && transform.getType() == AffineTransform.TYPE_TRANSLATION)
       {
+        x += transform.getTranslateX();
+        y += transform.getTranslateY();
         GtkVolatileImage vimg = (GtkVolatileImage) img;
-	drawVolatile( component, vimg.nativePointer, x, y - 20, 
+	drawVolatile( component, vimg.nativePointer, x, y, 
 		      width, height );
 	return true;
       }      
     return super.drawImage( img, x, y, width, height, observer );
   }
 
 }
 
Index: gnu/java/awt/peer/gtk/VolatileImageGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java,v
retrieving revision 1.4
diff -u -1 -0 -r1.4 VolatileImageGraphics.java
--- gnu/java/awt/peer/gtk/VolatileImageGraphics.java	10 Jun 2006 14:06:23 -0000	1.4
+++ gnu/java/awt/peer/gtk/VolatileImageGraphics.java	12 Jun 2006 21:07:08 -0000
@@ -60,29 +60,27 @@
 
 public class VolatileImageGraphics extends ComponentGraphics
 {
   private GtkVolatileImage owner;
 
   public VolatileImageGraphics(GtkVolatileImage img)
   {
     this.owner = img;
     cairo_t = initFromVolatile( owner.nativePointer, img.width, img.height );
     setup( cairo_t );
-    setClip( new Rectangle( 0, 0, img.width, img.height) );
   }
 
   private VolatileImageGraphics(VolatileImageGraphics copy)
   {
     this.owner = copy.owner;
     cairo_t = initFromVolatile(owner.nativePointer, owner.width, owner.height);
     copy( copy, cairo_t );
-    clipRect(0, 0, owner.width, owner.height);
   }
 
   public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy)
   {
     owner.copyArea(x, y, width, height, dx, dy);
   }
 
   public GraphicsConfiguration getDeviceConfiguration()
   {
     return null;

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil

Reply via email to