This fixes some clipping problems with the XGraphics.

2006-07-19  Roman Kennke  <[EMAIL PROTECTED]>

        * gnu/java/awt/peer/x/XGraphics.java
        (translate): Don't set the clip on the X server.
        (clipRect): Use setXClip() to set the clip on the X server.
        (hitClip): More efficient and correct implementation.
        (setClip): Use setXClip() to set the clip on the X server.
        (setClip(Shape)): Use setXClip() to set the clip on the X server.
        (copyArea): Translate and clip the source rectangle correctly.
        (dispose): Only flush when object is not yet disposed.
        (clone): Use setXClip() to set the clip on the X server.

/Roman
Index: gnu/java/awt/peer/x/XGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/x/XGraphics.java,v
retrieving revision 1.5
diff -u -1 -2 -r1.5 XGraphics.java
--- gnu/java/awt/peer/x/XGraphics.java	19 Jul 2006 08:17:52 -0000	1.5
+++ gnu/java/awt/peer/x/XGraphics.java	19 Jul 2006 19:20:40 -0000
@@ -126,25 +126,24 @@
 
   /**
    * Translates the origin by (x, y).
    */
   public void translate(int x, int y)
   {
     translateX += x;
     translateY += y;
     if (clip != null)
       {
         clip.x -= x;
         clip.y -= y;
-        setClip(clip);
       }
   }
 
   /**
    * Returns the current foreground color, possibly <code>null</code>.
    *
    * @return the current foreground color, possibly <code>null</code>
    */
   public Color getColor()
   {
     return foreground;
   }
@@ -247,104 +246,136 @@
    */
   public void clipRect(int x, int y, int width, int height)
   {
     if (clip == null)
       {
         clip = new Rectangle(x, y, width, height);
       }
     else
       {
         computeIntersection(x, y, width, height, clip);
       }
     // Update the X clip setting.
-    setClip(clip.x, clip.y, clip.width, clip.height);
+    setXClip(clip.x, clip.y, clip.width, clip.height);
   }
 
   /**
    * Returns <code>true</code> when the specified rectangle intersects with
    * the current clip, <code>false</code> otherwise. This is overridden to
    * avoid unnecessary creation of Rectangles via getBounds().
    *
    * @param x the x coordinate of the rectangle
    * @param y the y coordinate of the rectangle
    * @param w the width of the rectangle
    * @param h the height of the rectangle
    *
    * @return <code>true</code> when the specified rectangle intersects with
    *         the current clip, <code>false</code> otherwise
    */
   public boolean hitClip(int x, int y, int w, int h)
   {
     boolean hit;
     if (clip == null)
       {
         hit = true;
       }
     else
       {
-        hit = clip.intersects(x, y, w, h);
+        // It's easier to determine if the rectangle lies outside the clip,
+        // so we determine that and reverse the result (if it's not completely
+        // outside, it most likely hits the clip rectangle).
+        int x2 = x + w;
+        int y2 = y + h;
+        int clipX2 = clip.x + clip.width;
+        int clipY2 = clip.y + clip.height;
+        boolean outside = (x < clip.x && x2 < clip.x)     // Left.
+                          || (x > clipX2  && x2 > clipX2) // Right.
+                          || (y < clip.y && y2 < clip.y)  // Top.
+                          || (y > clipY2 && y2 > clipY2); // Bottom.
+        hit = ! outside;
       }
-    //System.err.println("hitClip:  " + hit);
     return hit;
   }
 
   public void setClip(int x, int y, int width, int height)
   {
     if (clip != null)
       clip.setBounds(x, y, width, height);
     else
       clip = new Rectangle(x, y, width, height);
+    setXClip(clip.x, clip.y, clip.width, clip.height);
+  }
 
+  /**
+   * Sets the clip on the X server GC. The coordinates are not yet translated,
+   * this will be performed by the X server.
+   *
+   * @param x the clip, X coordinate
+   * @param y the clip, Y coordinate
+   * @param w the clip, width
+   * @param h the clip, height
+   */
+  private void setXClip(int x, int y, int w, int h)
+  {
     gnu.x11.Rectangle[] clipRects = new gnu.x11.Rectangle[] {
-                                  new gnu.x11.Rectangle(x, y, width, height) };
-    xgc.set_clip_rectangles(translateX, translateY, clipRects, GC.UN_SORTED);
+                                  new gnu.x11.Rectangle(x, y, w, h) };
+    xgc.set_clip_rectangles(translateX, translateY, clipRects, GC.YX_BANDED);
   }
 
   public Shape getClip()
   {
     // Return a copy here, so nobody can trash our clip.
     return clip == null ? null : clip.getBounds();
   }
 
   /**
    * Sets the current clip.
    *
-   * @param clip the clip to set
+   * @param c the clip to set
    */
-  public void setClip(Shape clip)
+  public void setClip(Shape c)
   {
-    if (clip != null)
+    if (c != null)
       {
         Rectangle b;
-        if (clip instanceof Rectangle)
+        if (c instanceof Rectangle)
           {
-            b = (Rectangle) clip;
+            b = (Rectangle) c;
           }
         else
           {
-            b = clip.getBounds();
+            b = c.getBounds();
           }
-        setClip(b.x, b.y, b.width, b.height);
+        clip.setBounds(b);
+        setXClip(b.x, b.y, b.width, b.height);
       }
     else
       {
-        setClip(0, 0, xdrawable.width, xdrawable.height);
+        clip.setBounds(0, 0, xdrawable.width, xdrawable.height);
+        setXClip(0, 0, xdrawable.width, xdrawable.height);
       }
   }
 
   public void copyArea(int x, int y, int width, int height, int dx, int dy)
   {
-    int srcX = x + translateX;
-    int srcY = y + translateY;
-    xdrawable.copy_area(xdrawable, xgc, srcX, srcY, width, height,
+    // Clip and translate src rectangle.
+    int srcX = Math.min(Math.max(x, clip.x), clip.x + clip.width)
+               + translateX;
+    int srcY = Math.min(Math.max(y, clip.y), clip.y + clip.height)
+               + translateY;
+    int srcWidth = Math.min(Math.max(x + width, clip.x),
+                            clip.x + clip.width) - x;
+    int srcHeight = Math.min(Math.max(y + height, clip.y),
+                            clip.y + clip.height) - y;
+    xdrawable.copy_area(xdrawable, xgc, srcX, srcY, srcWidth, srcHeight,
                         srcX + dx, srcY + dy);
   }
 
   /**
    * Draws a line from point (x1, y1) to point (x2, y2).
    */
   public void drawLine(int x1, int y1, int x2, int y2)
   {
     //System.err.println("drawLine: " + (x1 + translateX) + ", " + ( y1 + translateY) + ", " + (x2 + translateX) + ", " + (y2 + translateY) + " on: " + xdrawable);
     xdrawable.line(xgc, x1 + translateX, y1 + translateY,
                    x2 + translateX, y2 + translateY);
   }
@@ -597,55 +628,55 @@
 
     // Reset clip.
     setClip(old);
 
     return res;
   }
 
   /**
    * Frees any resources associated with this object.
    */
   public void dispose()
   {
-    xdrawable.display.flush();
     if (! disposed)
       {
         xgc.free();
+        xdrawable.display.flush();
         disposed = true;
       }
   }
 
   // Additional helper methods.
 
   /**
    * Creates and returns an exact copy of this XGraphics.
    */
   protected Object clone()
   {
     try
       {
         XGraphics copy = (XGraphics) super.clone();
         copy.xgc = xgc.copy();
-
-        // Save the original clip.
         if (clip != null)
-          copy.clip = new Rectangle(clip);
+          {
+            copy.clip = new Rectangle(clip);
+            copy.setXClip(clip.x, clip.y, clip.width, clip.height);
+          }
         return copy;
       }
     catch (CloneNotSupportedException ex)
       {
-        AWTError err = new AWTError("Error while cloning XGraphics");
-        err.initCause(ex);
-        throw err;
+        assert false;
       }
+    return null;
   }
   
   /**
    * Computes the intersection between two rectangles and stores the result
    * int the second rectangle.
    *
    * This method has been copied from [EMAIL PROTECTED] javax.swing.SwingUtilities}.
    *
    * @param x the x coordinate of the rectangle #1
    * @param y the y coordinate of the rectangle #1
    * @param w the width of the rectangle #1
    * @param h the height of the rectangle #1

Reply via email to