1 /* BitwiseXORComposite.java -- Composite for emulating old-style XOR.
2 Copyright (C) 2003 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., 59 Temple Place, Suite 330, 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.Graphics;
45 import java.awt.Rectangle;
46 import java.awt.RenderingHints;
47 import java.awt.image.ColorModel;
48 import java.awt.image.DataBuffer;
49 import java.awt.image.Raster;
50 import java.awt.image.WritableRaster;
54 * A composite for emulating traditional bitwise XOR of pixel values.
55 * Please note that this composite does <i>not</i> implement the Porter-Duff
56 * XOR operator, but an exclusive or of overlapping subpixel regions.
58 * <p><img src="doc-files/BitwiseXORComposite-1.png" width="545"
59 * height="138" alt="A screen shot of BitwiseXORComposite in action"
62 * <p>The above screen shot shows the result of applying six different
63 * BitwiseXORComposites. They were constructed with the colors colors
64 * white, blue, black, orange, green, and brown, respectively. Each
65 * composite was used to paint a fully white rectangle on top of the
66 * blue bar in the background.
68 * <p>The purpose of this composite is to support the {@link
69 * Graphics#setXORMode(Color)} method in composite-aware graphics
70 * implementations. Applications typically would use
71 * <code>setXORMode</code> for drawing “highlights” such
72 * as text selections or cursors by inverting colors temporarily and
73 * then inverting them back.
75 * <p>A concrete <code>Graphics</code> implementation may contain
78 * <p><pre> public void setXORMode(Color xorColor)
80 * setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor));
83 * public void setPaintMode()
85 * setComposite(java.awt.AlphaComposite.SrcOver);
88 * @author Graydon Hoare (graydon@redhat.com)
89 * @author Sascha Brawer (brawer@dandelis.ch)
91 public class BitwiseXORComposite
95 * The color whose RGB value is xor-ed with the values of each
98 protected Color xorColor;
102 * Constructs a new composite for xor-ing the pixel value.
104 * @param xorColor the color whose pixel value will be bitwise
105 * xor-ed with the source and destination pixels.
107 public BitwiseXORComposite(Color xorColor)
109 this.xorColor = xorColor;
114 * Creates a context object for performing the compositing
115 * operation. Several contexts may co-exist for one composite; each
116 * context may simultaneously be called from concurrent threads.
118 * @param srcColorModel the color model of the source.
119 * @param dstColorModel the color model of the destination.
120 * @param hints hints for choosing between rendering alternatives.
122 public CompositeContext createContext(ColorModel srcColorModel,
123 ColorModel dstColorModel,
124 RenderingHints hints)
126 if (IntContext.isSupported(srcColorModel, dstColorModel, hints))
127 return new IntContext(srcColorModel, xorColor);
129 return new GeneralContext(srcColorModel, dstColorModel, xorColor);
134 * A fallback CompositeContext that performs bitwise XOR of pixel
135 * values with the pixel value of the specified <code>xorColor</code>.
137 * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of
138 * <code>TYPE_INT_RGB</code> took 611 ms on a lightly loaded 2.4 GHz
139 * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux
140 * 2.4.20. The timing is the average of ten runs on the same
141 * BufferedImage. Since the measurements were taken with {@link
142 * System#currentTimeMillis()}, they are rather inaccurate.
144 * @author Graydon Hoare (graydon@redhat.com)
146 private static class GeneralContext
147 implements CompositeContext
149 ColorModel srcColorModel;
150 ColorModel dstColorModel;
153 public GeneralContext(ColorModel srcColorModel,
154 ColorModel dstColorModel,
157 this.srcColorModel = srcColorModel;
158 this.dstColorModel = dstColorModel;
159 this.xorColor = xorColor;
163 public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
165 Rectangle srcRect = src.getBounds();
166 Rectangle dstInRect = dstIn.getBounds();
167 Rectangle dstOutRect = dstOut.getBounds();
169 int xp = xorColor.getRGB();
170 int w = Math.min(Math.min(srcRect.width, dstOutRect.width),
172 int h = Math.min(Math.min(srcRect.height, dstOutRect.height),
175 Object srcPix = null, dstPix = null, rpPix = null;
177 // Re-using the rpPix object saved 1-2% of execution time in
178 // the 1024x1024 pixel benchmark.
180 for (int y = 0; y < h; y++)
182 for (int x = 0; x < w; x++)
184 srcPix = src.getDataElements(x + srcRect.x, y + srcRect.y, srcPix);
185 dstPix = dstIn.getDataElements(x + dstInRect.x, y + dstInRect.y,
187 int sp = srcColorModel.getRGB(srcPix);
188 int dp = dstColorModel.getRGB(dstPix);
189 int rp = sp ^ xp ^ dp;
190 dstOut.setDataElements(x + dstOutRect.x, y + dstOutRect.y,
191 dstColorModel.getDataElements(rp, rpPix));
198 * Disposes any cached resources. The default implementation does
199 * nothing because no resources are cached.
201 public void dispose()
208 * An optimized CompositeContext that performs bitwise XOR of
209 * <code>int</code> pixel values with the pixel value of a specified
210 * <code>xorColor</code>. This CompositeContext working only for
211 * rasters whose transfer format is {@link DataBuffer#TYPE_INT}.
213 * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of
214 * <code>TYPE_INT_RGB</code> took 69 ms on a lightly loaded 2.4 GHz
215 * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux
216 * 2.4.20. The timing is the average of ten runs on the same
217 * BufferedImage. Since the measurements were taken with {@link
218 * System#currentTimeMillis()}, they are rather inaccurate.
220 * @author Sascha Brawer (brawer@dandelis.ch)
222 private static class IntContext
223 extends GeneralContext
225 public IntContext(ColorModel colorModel, Color xorColor)
227 super(colorModel, colorModel, xorColor);
231 public void compose(Raster src, Raster dstIn,
232 WritableRaster dstOut)
234 int aX, bX, dstX, aY, bY, dstY, width, height;
236 int[] srcLine, dstLine;
240 bX = dstIn.getMinX();
241 bY = dstIn.getMinY();
242 dstX = dstOut.getMinX();
243 dstY = dstOut.getMinY();
244 width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()),
246 height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()),
248 if ((width < 1) || (height < 1))
251 srcLine = new int[width];
252 dstLine = new int[width];
254 /* We need an int[] array with at least one element here;
255 * srcLine is as good as any other.
257 srcColorModel.getDataElements(this.xorColor.getRGB(), srcLine);
258 xorPixel = srcLine[0];
260 for (int y = 0; y < height; y++)
262 src.getDataElements(aX, y + aY, width, 1, srcLine);
263 dstIn.getDataElements(bX, y + bY, width, 1, dstLine);
265 for (int x = 0; x < width; x++)
266 dstLine[x] ^= srcLine[x] ^ xorPixel;
268 dstOut.setDataElements(dstX, y + dstY, width, 1, dstLine);
274 * Determines whether an instance of this CompositeContext would
275 * be able to process the specified color models.
277 public static boolean isSupported(ColorModel srcColorModel,
278 ColorModel dstColorModel,
279 RenderingHints hints)
281 // FIXME: It would be good if someone could review these checks.
282 // They probably need to be more restrictive.
286 transferType = srcColorModel.getTransferType();
287 if (transferType != dstColorModel.getTransferType())
290 if (transferType != DataBuffer.TYPE_INT)