Hi,
This patch fixes some one-pixel offsets appearing in some images with
custom composites. Any transforms should be applied to the buffered
composite prior to the compositing operation, rather than afterwards.
Also rolled into this patch is some minor fix-up and simplification to
an earlier patch, calculating scanlines and heights for buffered image
updating.
Cheers,
Francis
2006-11-30 Francis Kung <[EMAIL PROTECTED]>
* gnu/java/awt/peer/gtk/BufferedImageGraphics.java
(draw): Set transform in buffered composite.
(drawComposite): Do not transform bounds; round bounds.
(drawGlyphVector): Set transform in buffered composite.
(drawRenderedImage): Set transform in buffered composite.
(fill): Set transform in buffered composite.
(updateBufferedImage): Fix scanline & height calculations.
* gnu/java/awt/peer/gtk/CairoGraphics2D.java
(createPath): Simplify width & height calculation.
(drawImage): Also transform width & height.
Index: gnu/java/awt/peer/gtk/BufferedImageGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java,v
retrieving revision 1.19
diff -u -r1.19 BufferedImageGraphics.java
--- gnu/java/awt/peer/gtk/BufferedImageGraphics.java 24 Nov 2006 16:33:26 -0000 1.19
+++ gnu/java/awt/peer/gtk/BufferedImageGraphics.java 30 Nov 2006 18:37:57 -0000
@@ -248,13 +248,13 @@
if (sm.getScanlineStride() == imageWidth && minX == 0)
{
System.arraycopy(pixels, y * imageWidth,
- db, y * imageWidth - minY,
+ db, (y - minY) * imageWidth,
height * imageWidth);
}
else
{
int scanline = sm.getScanlineStride();
- for (int i = y; i < height; i++)
+ for (int i = y; i < (height + y); i++)
System.arraycopy(pixels, i * imageWidth + x, db,
(i - minY) * scanline + x - minX, width);
@@ -313,6 +313,7 @@
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setStroke(this.getStroke());
g2d.setColor(this.getColor());
+ g2d.setTransform(transform);
g2d.draw(s);
drawComposite(r.getBounds2D(), null);
@@ -334,6 +335,7 @@
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setPaint(this.getPaint());
g2d.setColor(this.getColor());
+ g2d.setTransform(transform);
g2d.fill(s);
drawComposite(s.getBounds2D(), null);
@@ -353,6 +355,7 @@
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setRenderingHints(this.getRenderingHints());
+ g2d.setTransform(transform);
g2d.drawRenderedImage(image, xform);
drawComposite(buffer.getRaster().getBounds(), null);
@@ -427,43 +430,64 @@
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
g2d.setPaint(this.getPaint());
g2d.setStroke(this.getStroke());
+ g2d.setTransform(transform);
g2d.drawGlyphVector(gv, x, y);
drawComposite(bounds, null);
}
}
+ /**
+ * Perform composite drawing from the buffer onto the main image.
+ *
+ * The image to be composited should already be drawn into the buffer, in the
+ * proper place, after all necessary transforms have been applied.
+ *
+ * @param bounds The bounds to draw, in user-space.
+ * @param observer The image observer, if any (may be null).
+ * @return True on success, false on failure.
+ */
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);
+ // Find bounds in device space
+ double[] points = new double[] {bounds.getX(), bounds.getY(),
+ bounds.getMaxX(), bounds.getMaxY()};
+ transform.transform(points, 0, points, 0, 2);
+ bounds = new Rectangle2D.Double(points[0], points[1],
+ (points[2] - points[0]),
+ (points[3] - points[1]));
+
+ // Clip bounds by the stored clip, and by the internal buffer
+ Rectangle2D devClip = this.getClipInDevSpace();
+ Rectangle2D.intersect(bounds, devClip, bounds);
+ devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
+ buffer.getWidth(), buffer.getHeight());
+ Rectangle2D.intersect(bounds, devClip, bounds);
+
+ // Round bounds as needed, but be conservative in our rounding
+ // (otherwise it may leave unpainted stripes)
+ double x = bounds.getX();
+ double y = bounds.getY();
+ double w = bounds.getWidth();
+ double h = bounds.getHeight();
+ if (Math.floor(x) != x)
+ w--;
+ if (Math.floor(y) != y)
+ h--;
+ bounds.setRect(Math.ceil(x), Math.ceil(y), Math.floor(w), Math.floor(h));
+ // Find subimage of internal buffer for updating
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);
-
+
+ // Find subimage of main image for updating
BufferedImage current = image;
- current = current.getSubimage((int)deviceBounds.getX(),
- (int)deviceBounds.getY(),
- (int)deviceBounds.getWidth(),
- (int)deviceBounds.getHeight());
+ current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(),
+ (int)bounds.getWidth(),
+ (int)bounds.getHeight());
// Perform actual composite operation
compCtx.compose(buffer2.getRaster(), current.getRaster(),
Index: gnu/java/awt/peer/gtk/CairoGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,v
retrieving revision 1.55
diff -u -r1.55 CairoGraphics2D.java
--- gnu/java/awt/peer/gtk/CairoGraphics2D.java 29 Nov 2006 15:46:36 -0000 1.55
+++ gnu/java/awt/peer/gtk/CairoGraphics2D.java 30 Nov 2006 18:37:58 -0000
@@ -1153,8 +1153,8 @@
// does not get distorted by this shifting operation
double x = shiftX(r.getX(),shiftDrawCalls && isDraw);
double y = shiftY(r.getY(), shiftDrawCalls && isDraw);
- double w = shiftX(r.getWidth() + r.getX(), shiftDrawCalls && isDraw) - x;
- double h = shiftY(r.getHeight() + r.getY(), shiftDrawCalls && isDraw) - y;
+ double w = Math.round(r.getWidth());
+ double h = Math.round(r.getHeight());
cairoRectangle(nativePointer, x, y, w, h);
}
@@ -1506,8 +1506,11 @@
setBackground(bgcolor);
double[] origin = new double[] {0,0};
+ double[] dimensions = new double[] {width, height};
xform.transform(origin, 0, origin, 0, 1);
- clearRect((int)origin[0], (int)origin[1], width, height);
+ xform.deltaTransform(dimensions, 0, dimensions, 0, 1);
+ clearRect((int)origin[0], (int)origin[1],
+ (int)dimensions[0], (int)dimensions[1]);
setBackground(oldColor);
}
@@ -2051,4 +2054,4 @@
return rect;
}
-}
+}
\ No newline at end of file