1 /* BitwiseXORComposite.java -- Composite for emulating old-style XOR.
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java
.awt
.Color
;
42 import java
.awt
.Composite
;
43 import java
.awt
.CompositeContext
;
44 import java
.awt
.Rectangle
;
45 import java
.awt
.RenderingHints
;
46 import java
.awt
.image
.ColorModel
;
47 import java
.awt
.image
.DataBuffer
;
48 import java
.awt
.image
.Raster
;
49 import java
.awt
.image
.WritableRaster
;
53 * A composite for emulating traditional bitwise XOR of pixel values.
54 * Please note that this composite does <i>not</i> implement the Porter-Duff
55 * XOR operator, but an exclusive or of overlapping subpixel regions.
57 * <p><img src="doc-files/BitwiseXORComposite-1.png" width="545"
58 * height="138" alt="A screen shot of BitwiseXORComposite in action"
61 * <p>The above screen shot shows the result of applying six different
62 * BitwiseXORComposites. They were constructed with the colors colors
63 * white, blue, black, orange, green, and brown, respectively. Each
64 * composite was used to paint a fully white rectangle on top of the
65 * blue bar in the background.
67 * <p>The purpose of this composite is to support the {@link
68 * Graphics#setXORMode(Color)} method in composite-aware graphics
69 * implementations. Applications typically would use
70 * <code>setXORMode</code> for drawing “highlights” such
71 * as text selections or cursors by inverting colors temporarily and
72 * then inverting them back.
74 * <p>A concrete <code>Graphics</code> implementation may contain
77 * <p><pre> public void setXORMode(Color xorColor)
79 * setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor));
82 * public void setPaintMode()
84 * setComposite(java.awt.AlphaComposite.SrcOver);
87 * @author Graydon Hoare (graydon@redhat.com)
88 * @author Sascha Brawer (brawer@dandelis.ch)
90 public class BitwiseXORComposite
94 * The color whose RGB value is xor-ed with the values of each
97 protected Color xorColor
;
101 * Constructs a new composite for xor-ing the pixel value.
103 * @param xorColor the color whose pixel value will be bitwise
104 * xor-ed with the source and destination pixels.
106 public BitwiseXORComposite(Color xorColor
)
108 this.xorColor
= xorColor
;
113 * Creates a context object for performing the compositing
114 * operation. Several contexts may co-exist for one composite; each
115 * context may simultaneously be called from concurrent threads.
117 * @param srcColorModel the color model of the source.
118 * @param dstColorModel the color model of the destination.
119 * @param hints hints for choosing between rendering alternatives.
121 public CompositeContext
createContext(ColorModel srcColorModel
,
122 ColorModel dstColorModel
,
123 RenderingHints hints
)
125 if (IntContext
.isSupported(srcColorModel
, dstColorModel
, hints
))
126 return new IntContext(srcColorModel
, xorColor
);
128 return new GeneralContext(srcColorModel
, dstColorModel
, xorColor
);
133 * A fallback CompositeContext that performs bitwise XOR of pixel
134 * values with the pixel value of the specified <code>xorColor</code>.
136 * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of
137 * <code>TYPE_INT_RGB</code> took 611 ms on a lightly loaded 2.4 GHz
138 * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux
139 * 2.4.20. The timing is the average of ten runs on the same
140 * BufferedImage. Since the measurements were taken with {@link
141 * System#currentTimeMillis()}, they are rather inaccurate.
143 * @author Graydon Hoare (graydon@redhat.com)
145 private static class GeneralContext
146 implements CompositeContext
148 ColorModel srcColorModel
;
149 ColorModel dstColorModel
;
152 public GeneralContext(ColorModel srcColorModel
,
153 ColorModel dstColorModel
,
156 this.srcColorModel
= srcColorModel
;
157 this.dstColorModel
= dstColorModel
;
158 this.xorColor
= xorColor
;
162 public void compose(Raster src
, Raster dstIn
, WritableRaster dstOut
)
164 Rectangle srcRect
= src
.getBounds();
165 Rectangle dstInRect
= dstIn
.getBounds();
166 Rectangle dstOutRect
= dstOut
.getBounds();
168 int xp
= xorColor
.getRGB();
169 int w
= Math
.min(Math
.min(srcRect
.width
, dstOutRect
.width
),
171 int h
= Math
.min(Math
.min(srcRect
.height
, dstOutRect
.height
),
174 Object srcPix
= null, dstPix
= null, rpPix
= null;
176 // Re-using the rpPix object saved 1-2% of execution time in
177 // the 1024x1024 pixel benchmark.
179 for (int y
= 0; y
< h
; y
++)
181 for (int x
= 0; x
< w
; x
++)
183 srcPix
= src
.getDataElements(x
+ srcRect
.x
, y
+ srcRect
.y
, srcPix
);
184 dstPix
= dstIn
.getDataElements(x
+ dstInRect
.x
, y
+ dstInRect
.y
,
186 int sp
= srcColorModel
.getRGB(srcPix
);
187 int dp
= dstColorModel
.getRGB(dstPix
);
188 int rp
= sp ^ xp ^ dp
;
189 dstOut
.setDataElements(x
+ dstOutRect
.x
, y
+ dstOutRect
.y
,
190 dstColorModel
.getDataElements(rp
, rpPix
));
197 * Disposes any cached resources. The default implementation does
198 * nothing because no resources are cached.
200 public void dispose()
207 * An optimized CompositeContext that performs bitwise XOR of
208 * <code>int</code> pixel values with the pixel value of a specified
209 * <code>xorColor</code>. This CompositeContext working only for
210 * rasters whose transfer format is {@link DataBuffer#TYPE_INT}.
212 * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of
213 * <code>TYPE_INT_RGB</code> took 69 ms on a lightly loaded 2.4 GHz
214 * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux
215 * 2.4.20. The timing is the average of ten runs on the same
216 * BufferedImage. Since the measurements were taken with {@link
217 * System#currentTimeMillis()}, they are rather inaccurate.
219 * @author Sascha Brawer (brawer@dandelis.ch)
221 private static class IntContext
222 extends GeneralContext
224 public IntContext(ColorModel colorModel
, Color xorColor
)
226 super(colorModel
, colorModel
, xorColor
);
230 public void compose(Raster src
, Raster dstIn
,
231 WritableRaster dstOut
)
233 int aX
, bX
, dstX
, aY
, bY
, dstY
, width
, height
;
235 int[] srcLine
, dstLine
;
239 bX
= dstIn
.getMinX();
240 bY
= dstIn
.getMinY();
241 dstX
= dstOut
.getMinX();
242 dstY
= dstOut
.getMinY();
243 width
= Math
.min(Math
.min(src
.getWidth(), dstIn
.getWidth()),
245 height
= Math
.min(Math
.min(src
.getHeight(), dstIn
.getHeight()),
247 if ((width
< 1) || (height
< 1))
250 srcLine
= new int[width
];
251 dstLine
= new int[width
];
253 /* We need an int[] array with at least one element here;
254 * srcLine is as good as any other.
256 srcColorModel
.getDataElements(this.xorColor
.getRGB(), srcLine
);
257 xorPixel
= srcLine
[0];
259 for (int y
= 0; y
< height
; y
++)
261 src
.getDataElements(aX
, y
+ aY
, width
, 1, srcLine
);
262 dstIn
.getDataElements(bX
, y
+ bY
, width
, 1, dstLine
);
264 for (int x
= 0; x
< width
; x
++)
265 dstLine
[x
] ^
= srcLine
[x
] ^ xorPixel
;
267 dstOut
.setDataElements(dstX
, y
+ dstY
, width
, 1, dstLine
);
273 * Determines whether an instance of this CompositeContext would
274 * be able to process the specified color models.
276 public static boolean isSupported(ColorModel srcColorModel
,
277 ColorModel dstColorModel
,
278 RenderingHints hints
)
280 // FIXME: It would be good if someone could review these checks.
281 // They probably need to be more restrictive.
285 transferType
= srcColorModel
.getTransferType();
286 if (transferType
!= dstColorModel
.getTransferType())
289 if (transferType
!= DataBuffer
.TYPE_INT
)