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;
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil
