Hi,
I found a number of mis-matches in our handling of alpha
premultiplication; Cairo data is always pre-multiplied, but we don't
always check for this (sometimes we pass Cairo non-premultiplied data,
and sometimes we assume the raw data is not premultiplied).
This patch should fix those issues, as well as fixing the behaviour of
Graphics.clearRect (it should write the background directly using the
AlphaComposite.SRC rule, instead of doing a regular fill, as shown by a
mauve test).
This also answers my earlier question about the custom composites (the
buffer wasn't clearing properly because the clearRect() method was
buggy).
Cheers,
Francis
2006-10-02 Francis Kung <[EMAIL PROTECTED]>
* gnu/java/awt/peer/gtk/BufferedImageGraphics.java
(updateBufferedImage): Recognise that raw data is alpha-premultiplied.
* gnu/java/awt/peer/gtk/CairoGraphics2D.java
(clearRect): Paint background colour with AlphaComposite.SRC rule.
(drawImage(Image, AffineTransform, Color, ImageObserver)): Alpha
pre-multiply data before drawing.
(fillRect): Draw using regular fill() method.
(setComposite): Handle null case with AlphaComposite.SrcOver default.
* gnu/java/awt/peer/gtk/CairoSurface.java
(nativeModel): Use correct value for alpha premultiplication (true).
* java/awt/image/BufferedImage.java
(coerceData): Update isPremultiplied field.
Index: gnu/java/awt/peer/gtk/BufferedImageGraphics.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java,v
retrieving revision 1.10
diff -u -r1.10 BufferedImageGraphics.java
--- gnu/java/awt/peer/gtk/BufferedImageGraphics.java 19 Sep 2006 19:27:11 -0000 1.10
+++ gnu/java/awt/peer/gtk/BufferedImageGraphics.java 2 Oct 2006 21:33:31 -0000
@@ -183,6 +183,9 @@
width = imageWidth - x;
if( y + height > imageHeight )
height = imageHeight - y;
+
+ boolean wasPremultiplied = image.isAlphaPremultiplied();
+ image.coerceData(true);
if( !hasFastCM )
image.setRGB(x, y, width, height, pixels,
@@ -191,6 +194,8 @@
System.arraycopy(pixels, y * imageWidth,
((DataBufferInt)image.getRaster().getDataBuffer()).
getData(), y * imageWidth, height * imageWidth);
+
+ image.coerceData(wasPremultiplied);
}
/**
Index: gnu/java/awt/peer/gtk/CairoSurface.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoSurface.java,v
retrieving revision 1.17
diff -u -r1.17 CairoSurface.java
--- gnu/java/awt/peer/gtk/CairoSurface.java 14 Sep 2006 18:30:58 -0000 1.17
+++ gnu/java/awt/peer/gtk/CairoSurface.java 2 Oct 2006 21:33:31 -0000
@@ -38,8 +38,11 @@
package gnu.java.awt.peer.gtk;
+import gnu.java.awt.Buffers;
+
import java.awt.Point;
import java.awt.Graphics2D;
+import java.awt.color.ColorSpace;
import java.awt.image.DataBuffer;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
@@ -69,11 +72,15 @@
*/
long bufferPointer;
- static ColorModel nativeModel = new DirectColorModel(32,
- 0x00FF0000,
- 0x0000FF00,
- 0x000000FF,
- 0xFF000000);
+ // nativeGetPixels will return [0]=red, [1]=green, [2]=blue, [3]=alpha
+ static ColorModel nativeModel = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
+ 32,
+ 0x000000FF,
+ 0x0000FF00,
+ 0x00FF0000,
+ 0xFF000000,
+ true,
+ Buffers.smallestAppropriateTransferType(32));
/**
* Allocates and clears the buffer and creates the cairo surface.
Index: gnu/java/awt/peer/gtk/CairoGraphics2D.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,v
retrieving revision 1.40
diff -u -r1.40 CairoGraphics2D.java
--- gnu/java/awt/peer/gtk/CairoGraphics2D.java 14 Sep 2006 18:30:58 -0000 1.40
+++ gnu/java/awt/peer/gtk/CairoGraphics2D.java 2 Oct 2006 21:33:31 -0000
@@ -953,6 +953,9 @@
{
this.comp = comp;
+ if (comp == null)
+ comp = AlphaComposite.SrcOver;
+
if (comp instanceof AlphaComposite)
{
AlphaComposite a = (AlphaComposite) comp;
@@ -1061,8 +1064,14 @@
{
if (bg != null)
cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0,
- bg.getGreen() / 255.0, bg.getBlue() / 255.0, 1.0);
+ bg.getGreen() / 255.0, bg.getBlue() / 255.0,
+ bg.getAlpha() / 255.0);
+
+ Composite oldcomp = comp;
+ setComposite(AlphaComposite.Src);
fillRect(x, y, width, height);
+
+ setComposite(oldcomp);
updateColor();
}
@@ -1109,7 +1118,10 @@
public void fillRect(int x, int y, int width, int height)
{
- cairoFillRect(nativePointer, x, y, width, height);
+ fill(new Rectangle(x, y, width, height));
+ // TODO: If we want to use the more efficient
+ //cairoFillRect(nativePointer, x, y, width, height);
+ // we need to override this method in subclasses
}
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
@@ -1309,6 +1321,9 @@
double[] i2u = new double[6];
int width = b.getWidth();
int height = b.getHeight();
+
+ boolean wasPremultplied = b.isAlphaPremultiplied();
+ b.coerceData(true);
// If this BufferedImage has a BufferedImageGraphics object,
// use the cached CairoSurface that BIG is drawing onto
@@ -1329,6 +1344,7 @@
((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha,
getInterpolation());
updateColor();
+ b.coerceData(wasPremultplied);
return true;
}
@@ -1352,6 +1368,7 @@
// Cairo seems to lose the current color which must be restored.
updateColor();
+ b.coerceData(wasPremultplied);
return true;
}
Index: java/awt/image/BufferedImage.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/awt/image/BufferedImage.java,v
retrieving revision 1.19
diff -u -r1.19 BufferedImage.java
--- java/awt/image/BufferedImage.java 9 Aug 2006 18:31:14 -0000 1.19
+++ java/awt/image/BufferedImage.java 2 Oct 2006 21:33:31 -0000
@@ -347,6 +347,7 @@
public void coerceData(boolean premultiplied)
{
colorModel = colorModel.coerceData(raster, premultiplied);
+ isPremultiplied = premultiplied;
}
public WritableRaster copyData(WritableRaster dest)