OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / java / awt / BitwiseXORComposite.java
1 /* BitwiseXORComposite.java -- Composite for emulating old-style XOR.
2    Copyright (C) 2003, 2004  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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)
9 any later version.
10
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.
15
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
19 02110-1301 USA.
20
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
24 combination.
25
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. */
37
38
39 package gnu.java.awt;
40
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;
50
51
52 /**
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.
56  *
57  * <p><img src="doc-files/BitwiseXORComposite-1.png" width="545"
58  * height="138" alt="A screen shot of BitwiseXORComposite in action"
59  * />
60  *
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.
66  * 
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 &#x201c;highlights&#x201d; such
71  * as text selections or cursors by inverting colors temporarily and
72  * then inverting them back.
73  *
74  * <p>A concrete <code>Graphics</code> implementation may contain
75  * the following code:
76  *
77  * <p><pre> public void setXORMode(Color xorColor)
78  * {
79  *   setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor));
80  * }
81  *
82  * public void setPaintMode()
83  * {
84  *   setComposite(java.awt.AlphaComposite.SrcOver);
85  * }</pre>
86  *
87  * @author Graydon Hoare (graydon@redhat.com)
88  * @author Sascha Brawer (brawer@dandelis.ch)
89  */
90 public class BitwiseXORComposite
91   implements Composite
92 {
93   /**
94    * The color whose RGB value is xor-ed with the values of each
95    * pixel.
96    */
97   protected Color xorColor;
98
99   
100   /**
101    * Constructs a new composite for xor-ing the pixel value.
102    *
103    * @param xorColor the color whose pixel value will be bitwise
104    * xor-ed with the source and destination pixels.
105    */
106   public BitwiseXORComposite(Color xorColor)
107   {
108     this.xorColor = xorColor;
109   }
110
111
112   /**
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.
116    *
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.
120    */
121   public CompositeContext createContext(ColorModel srcColorModel,
122                                         ColorModel dstColorModel,
123                                         RenderingHints hints)
124   {
125     if (IntContext.isSupported(srcColorModel, dstColorModel, hints))
126       return new IntContext(srcColorModel, xorColor);
127
128     return new GeneralContext(srcColorModel, dstColorModel, xorColor);
129   }
130
131   
132   /**
133    * A fallback CompositeContext that performs bitwise XOR of pixel
134    * values with the pixel value of the specified <code>xorColor</code>.
135    *
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.
142    *
143    * @author Graydon Hoare (graydon@redhat.com)
144    */
145   private static class GeneralContext
146     implements CompositeContext
147   {
148     ColorModel srcColorModel;
149     ColorModel dstColorModel;
150     Color xorColor;
151
152     public GeneralContext(ColorModel srcColorModel,
153                           ColorModel dstColorModel,
154                           Color xorColor)
155     {
156       this.srcColorModel = srcColorModel;
157       this.dstColorModel = dstColorModel;
158       this.xorColor = xorColor;
159     }
160
161
162     public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
163     {
164       Rectangle srcRect = src.getBounds();
165       Rectangle dstInRect = dstIn.getBounds();
166       Rectangle dstOutRect = dstOut.getBounds();
167       
168       int xp = xorColor.getRGB();
169       int w = Math.min(Math.min(srcRect.width, dstOutRect.width),
170                        dstInRect.width);
171       int h = Math.min(Math.min(srcRect.height, dstOutRect.height),
172                        dstInRect.height);
173
174       Object srcPix = null, dstPix = null, rpPix = null;
175
176       // Re-using the rpPix object saved 1-2% of execution time in
177       // the 1024x1024 pixel benchmark.
178
179       for (int y = 0; y < h; y++)
180       {
181         for (int x = 0; x < w; x++)
182         {
183           srcPix = src.getDataElements(x + srcRect.x, y + srcRect.y, srcPix);
184           dstPix = dstIn.getDataElements(x + dstInRect.x, y + dstInRect.y,
185                                          dstPix);
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));
191         }
192       }
193     }
194
195
196     /**
197      * Disposes any cached resources. The default implementation does
198      * nothing because no resources are cached.
199      */
200     public void dispose()
201     {
202     }
203   }
204
205
206   /**
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}.
211    *
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.
218    *
219    * @author Sascha Brawer (brawer@dandelis.ch)
220    */
221   private static class IntContext
222     extends GeneralContext
223   {
224     public IntContext(ColorModel colorModel, Color xorColor)
225     {
226       super(colorModel, colorModel, xorColor);
227     }
228
229
230     public void compose(Raster src, Raster dstIn,
231                         WritableRaster dstOut)
232     {
233       int aX, bX, dstX, aY, bY, dstY, width, height;
234       int xorPixel;
235       int[] srcLine, dstLine;
236
237       aX = src.getMinX();
238       aY = src.getMinY();
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()),
244                        dstOut.getWidth());
245       height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()),
246                         dstOut.getHeight());
247       if ((width < 1) || (height < 1))
248         return;
249
250       srcLine = new int[width];
251       dstLine = new int[width];
252       
253       /* We need an int[] array with at least one element here;
254        * srcLine is as good as any other.
255        */
256       srcColorModel.getDataElements(this.xorColor.getRGB(), srcLine);
257       xorPixel = srcLine[0];
258
259       for (int y = 0; y < height; y++)
260       {
261         src.getDataElements(aX, y + aY, width, 1, srcLine);
262         dstIn.getDataElements(bX, y + bY, width, 1, dstLine);
263
264         for (int x = 0; x < width; x++)
265           dstLine[x] ^= srcLine[x] ^ xorPixel;
266
267         dstOut.setDataElements(dstX, y + dstY, width, 1, dstLine);
268       }
269     }
270
271     
272     /**
273      * Determines whether an instance of this CompositeContext would
274      * be able to process the specified color models.
275      */
276     public static boolean isSupported(ColorModel srcColorModel,
277                                       ColorModel dstColorModel,
278                                       RenderingHints hints)
279     {
280       // FIXME: It would be good if someone could review these checks.
281       // They probably need to be more restrictive.
282
283       int transferType;
284
285       transferType = srcColorModel.getTransferType();
286       if (transferType != dstColorModel.getTransferType())
287         return false;
288
289       if (transferType != DataBuffer.TYPE_INT)
290         return false;
291
292       return true;
293     }
294   }
295 }