1 /* AlphaCompositeContext.java -- CompositeContext impl for AlphaComposite
2    Copyright (C) 2006 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.java2d;
40 
41 import java.awt.AWTError;
42 import java.awt.AlphaComposite;
43 import java.awt.CompositeContext;
44 import java.awt.image.ColorModel;
45 import java.awt.image.Raster;
46 import java.awt.image.WritableRaster;
47 
48 /**
49  * A CompositeContext implementation for {@link AlphaComposite}.
50  *
51  * @author Roman Kennke (kennke@aicas.com)
52  */
53 public class AlphaCompositeContext
54   implements CompositeContext
55 {
56 
57   /**
58    * The Composite object for which we perform compositing.
59    */
60   private AlphaComposite composite;
61 
62   /**
63    * The source color model.
64    */
65   private ColorModel srcColorModel;
66 
67   /**
68    * The destination color model.
69    */
70   private ColorModel dstColorModel;
71 
72   /**
73    * The blending factor for the source.
74    */
75   private float fs;
76 
77   /**
78    * The blending factor for the destination.
79    */
80   private float fd;
81 
82   /**
83    * Creates a new AlphaCompositeContext.
84    *
85    * @param aComp the AlphaComposite object
86    * @param srcCM the source color model
87    * @param dstCM the destination color model
88    */
AlphaCompositeContext(AlphaComposite aComp, ColorModel srcCM, ColorModel dstCM)89   public AlphaCompositeContext(AlphaComposite aComp, ColorModel srcCM,
90                                ColorModel dstCM)
91   {
92     composite = aComp;
93     srcColorModel = srcCM;
94     dstColorModel = dstCM;
95 
96 
97     // Determine the blending factors according to the rule in the
98     // AlphaComposite. For some rules the factors must be determined
99     // dynamically because they depend on the actual pixel value.
100     switch (composite.getRule())
101     {
102       case AlphaComposite.CLEAR:
103         fs = 0.F;
104         fd= 0.F;
105         break;
106       case AlphaComposite.DST:
107         fs = 0.F;
108         fd= 1.F;
109         break;
110       case AlphaComposite.DST_ATOP:
111         fs = 1.F; // Determined later as 1 - alpha_dst;
112         fd = 1.F; // Determined later as alpha_src;
113         break;
114       case AlphaComposite.DST_IN:
115         fs = 0.F;
116         fd = 0.F; // Determined later as alpha_src;
117         break;
118       case AlphaComposite.DST_OUT:
119         fs = 0.F;
120         fd = 0.F; // Determined later as 1 - alpha_src;
121         break;
122       case AlphaComposite.DST_OVER:
123         fs = 1.F; // Determined later as 1 - alpha_dst.
124         fd= 1.F;
125         break;
126       case AlphaComposite.SRC:
127         fs = 1.F;
128         fd= 0.F;
129         break;
130       case AlphaComposite.SRC_ATOP:
131         fs = 1.F; // Determined later as alpha_dst;
132         fd = 1.F; // Determined later as 1 - alpha_src;
133         break;
134       case AlphaComposite.SRC_IN:
135         fs = 0.F; // Determined later as alpha_dst;
136         fd = 0.F;
137         break;
138       case AlphaComposite.SRC_OUT:
139         fs = 0.F; // Determined later as 1 - alpha_dst;
140         fd = 0.F;
141         break;
142       case AlphaComposite.SRC_OVER:
143         fs = 1.F;
144         fd= 1.F; // Determined later as 1 - alpha_src.
145         break;
146       case AlphaComposite.XOR:
147         fs = 1.F; // Determined later as 1 - alpha_dst.
148         fd= 1.F; // Determined later as 1 - alpha_src.
149         break;
150       default:
151         throw new AWTError("Illegal AlphaComposite rule");
152     }
153 
154   }
155 
156   /**
157    * Releases all resources held by this composite object.
158    */
dispose()159   public void dispose()
160   {
161     // Nothing to do here yet.
162   }
163 
164   /**
165    * Performs compositing according to the rules specified in the
166    * AlphaComposite from the constructor.
167    */
compose(Raster src, Raster dstIn, WritableRaster dstOut)168   public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
169   {
170 
171     // TODO: This implementation is very general and highly inefficient. There
172     // are two possible ways to optimize this:
173     // 1. Special cased implementations for common ColorModels and transfer
174     //    types.
175     // 2. Native implementation.
176 
177     int x0 = src.getMinX();
178     int y0 = src.getMinY();
179     int width = src.getWidth();
180     int height = src.getHeight();
181     int x1 = x0 + width;
182     int y1 = y0 + height;
183 
184     Object srcPixel = null;
185     Object dstPixel = null;
186 
187     // Prepare the array that holds the color and alpha components of the
188     // source pixels.
189     float[] srcComponents;
190     int srcComponentsLength = srcColorModel.getNumComponents();
191     if (! srcColorModel.hasAlpha())
192       srcComponentsLength += 1;
193     srcComponents = new float[srcComponentsLength];
194 
195     // Prepare the array that holds the color and alpha components of the
196     // destination pixels.
197     float[] dstComponents;
198     int dstComponentsLength = dstColorModel.getNumComponents();
199     if (! dstColorModel.hasAlpha())
200       dstComponentsLength += 1;
201     dstComponents = new float[dstComponentsLength];
202 
203     if (srcComponentsLength != dstComponentsLength)
204       throw new AWTError("The color models of the source and destination have"
205                          + "incompatible number of color components");
206 
207     int srcTransferType = srcColorModel.getTransferType();
208     int dstTransferType = dstColorModel.getTransferType();
209 
210     for (int y = y0; y < y1; y++)
211       {
212         for (int x = x0; x < x1; x++)
213           {
214             // Fetch source pixel.
215             srcPixel = src.getDataElements(x, y, (int[]) srcPixel);
216             // Fetch destination pixel.
217             dstPixel = dstIn.getDataElements(x, y, dstPixel);
218             // Get normalized components. This is the only type that is
219             // guaranteed to be supported by all ColorModels.
220             srcComponents =
221               srcColorModel.getNormalizedComponents(srcPixel, srcComponents, 0);
222             if (! srcColorModel.hasAlpha())
223               srcComponents[srcComponentsLength - 1] = 1.0F;
224             dstComponents =
225               dstColorModel.getNormalizedComponents(dstPixel, dstComponents, 0);
226             if (! dstColorModel.hasAlpha())
227               dstComponents[dstComponentsLength - 1] = 1.0F;
228 
229             // Prepare the input.
230             float compositeAlpha = composite.getAlpha();
231             srcComponents[srcComponentsLength - 1] *= compositeAlpha;
232             if (srcColorModel.isAlphaPremultiplied())
233               {
234                 for (int i = srcComponentsLength - 2; i >= 0; i--)
235                   srcComponents[i] *= compositeAlpha;
236               }
237             else
238               {
239                 for (int i = srcComponentsLength - 2; i >= 0; i--)
240                   srcComponents[i] *= srcComponents[srcComponentsLength - 1];
241               }
242             if (! dstColorModel.isAlphaPremultiplied())
243               {
244                 for (int i = dstComponentsLength - 2; i >= 0; i--)
245                   dstComponents[i] *= dstComponents[dstComponents.length - 1];
246               }
247 
248             // Determine the blending factors according to the rule in the
249             // AlphaComposite. For some rules the factors must be determined
250             // dynamically because they depend on the actual pixel value.
251             float srcAlpha = srcComponents[srcComponentsLength - 1];
252             float dstAlpha = dstComponents[dstComponentsLength - 1];
253             switch (composite.getRule())
254             {
255               case AlphaComposite.DST_ATOP:
256                 fs = 1.F - dstAlpha;
257                 fd = srcAlpha;
258                 break;
259               case AlphaComposite.DST_IN:
260                 fd = srcAlpha;
261                 break;
262               case AlphaComposite.DST_OUT:
263                 fd = 1.F - srcAlpha;
264                 break;
265               case AlphaComposite.DST_OVER:
266                 fs = 1.F - dstAlpha;
267                 break;
268               case AlphaComposite.SRC_ATOP:
269                 fs = srcAlpha;
270                 fd = 1.F - srcAlpha;
271                 break;
272               case AlphaComposite.SRC_IN:
273                 fs = dstAlpha;
274                 break;
275               case AlphaComposite.SRC_OUT:
276                 fs = 1.F - dstAlpha;
277                 break;
278               case AlphaComposite.SRC_OVER:
279                 fd= 1.F - srcAlpha;
280                 break;
281               case AlphaComposite.XOR:
282                 fs = 1.F - dstAlpha;
283                 fd= 1.F - srcAlpha;
284                 break;
285               default:
286                 // For the other cases the factors have already been determined
287                 // in the constructor.
288             }
289 
290             // Apply the blending equation to the pixels.
291             for (int i = 0; i < srcComponentsLength; i++)
292               {
293                 dstComponents[i] = srcComponents[i] * fs
294                                    + dstComponents[i] * fd;
295               }
296 
297             // Convert the result back when the destination is not
298             // alpha-premultiplied.
299             dstAlpha = dstComponents[dstComponentsLength - 1];
300             if (!dstColorModel.isAlphaPremultiplied() && dstAlpha != 0.F)
301               {
302                 for (int i = 0; i < dstComponentsLength - 1; i++)
303                   {
304                     dstComponents[i] = dstComponents[i] / dstAlpha;
305                   }
306               }
307 
308             // Store the result in the destination raster.
309             dstPixel = dstColorModel.getDataElements(dstComponents, 0,
310                                                      dstPixel);
311             dstOut.setDataElements(x, y, dstPixel);
312           } // End X loop.
313       } // End Y loop.
314   }
315 
316 }
317