1 /*
2  * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.java2d.pipe;
27 
28 import java.lang.ref.WeakReference;
29 import java.awt.Rectangle;
30 import java.awt.Shape;
31 import java.awt.PaintContext;
32 import java.awt.Transparency;
33 import java.awt.image.ColorModel;
34 import java.awt.image.Raster;
35 import java.awt.image.WritableRaster;
36 import java.awt.image.BufferedImage;
37 import sun.awt.image.BufImgSurfaceData;
38 import sun.java2d.SunGraphics2D;
39 import sun.java2d.SurfaceData;
40 import sun.java2d.loops.Blit;
41 import sun.java2d.loops.MaskBlit;
42 import sun.java2d.loops.CompositeType;
43 import sun.java2d.loops.GraphicsPrimitiveMgr;
44 
45 /**
46  * This class implements a CompositePipe that renders path alpha tiles
47  * into a destination according to the Composite attribute of a
48  * SunGraphics2D.
49  */
50 public class AlphaPaintPipe implements CompositePipe {
51     static WeakReference<Raster> cachedLastRaster;
52     static WeakReference<ColorModel> cachedLastColorModel;
53     static WeakReference<SurfaceData> cachedLastData;
54 
55     static class TileContext {
56         SunGraphics2D sunG2D;
57         PaintContext paintCtxt;
58         ColorModel paintModel;
59         WeakReference<Raster> lastRaster;
60         WeakReference<SurfaceData> lastData;
61         MaskBlit lastMask;
62         Blit     lastBlit;
63         SurfaceData dstData;
64 
TileContext(SunGraphics2D sg, PaintContext pc)65         public TileContext(SunGraphics2D sg, PaintContext pc) {
66             sunG2D = sg;
67             paintCtxt = pc;
68             paintModel = pc.getColorModel();
69             dstData = sg.getSurfaceData();
70             synchronized (AlphaPaintPipe.class) {
71                 if (cachedLastColorModel != null &&
72                     cachedLastColorModel.get() == paintModel)
73                 {
74                     this.lastRaster = cachedLastRaster;
75                     this.lastData = cachedLastData;
76                 }
77             }
78         }
79     }
80 
startSequence(SunGraphics2D sg, Shape s, Rectangle devR, int[] abox)81     public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR,
82                                 int[] abox) {
83         PaintContext paintContext =
84             sg.paint.createContext(sg.getDeviceColorModel(),
85                                    devR,
86                                    s.getBounds2D(),
87                                    sg.cloneTransform(),
88                                    sg.getRenderingHints());
89         return new TileContext(sg, paintContext);
90     }
91 
needTile(Object context, int x, int y, int w, int h)92     public boolean needTile(Object context, int x, int y, int w, int h) {
93         return true;
94     }
95 
96     private static final int TILE_SIZE = 32;
97 
renderPathTile(Object ctx, byte[] atile, int offset, int tilesize, int x, int y, int w, int h)98     public void renderPathTile(Object ctx,
99                                byte[] atile, int offset, int tilesize,
100                                int x, int y, int w, int h) {
101         TileContext context = (TileContext) ctx;
102         PaintContext paintCtxt = context.paintCtxt;
103         SunGraphics2D sg = context.sunG2D;
104         SurfaceData dstData = context.dstData;
105         SurfaceData srcData = null;
106         Raster lastRas = null;
107         if (context.lastData != null && context.lastRaster != null) {
108             srcData = context.lastData.get();
109             lastRas = context.lastRaster.get();
110             if (srcData == null || lastRas == null) {
111                 srcData = null;
112                 lastRas = null;
113             }
114         }
115         ColorModel paintModel = context.paintModel;
116 
117         for (int rely = 0; rely < h; rely += TILE_SIZE) {
118             int ty = y + rely;
119             int th = Math.min(h-rely, TILE_SIZE);
120             for (int relx = 0; relx < w; relx += TILE_SIZE) {
121                 int tx = x + relx;
122                 int tw = Math.min(w-relx, TILE_SIZE);
123 
124                 Raster srcRaster = paintCtxt.getRaster(tx, ty, tw, th);
125                 if ((srcRaster.getMinX() != 0) || (srcRaster.getMinY() != 0)) {
126                     srcRaster = srcRaster.createTranslatedChild(0, 0);
127                 }
128                 if (lastRas != srcRaster) {
129                     lastRas = srcRaster;
130                     context.lastRaster = new WeakReference<>(lastRas);
131                     // REMIND: This will fail for a non-Writable raster!
132                     BufferedImage bImg =
133                         new BufferedImage(paintModel,
134                                           (WritableRaster) srcRaster,
135                                           paintModel.isAlphaPremultiplied(),
136                                           null);
137                     srcData = BufImgSurfaceData.createData(bImg);
138                     context.lastData = new WeakReference<>(srcData);
139                     context.lastMask = null;
140                     context.lastBlit = null;
141                 }
142 
143                 if (atile == null) {
144                     if (context.lastBlit == null) {
145                         CompositeType comptype = sg.imageComp;
146                         if (CompositeType.SrcOverNoEa.equals(comptype) &&
147                             paintModel.getTransparency() == Transparency.OPAQUE)
148                         {
149                             comptype = CompositeType.SrcNoEa;
150                         }
151                         context.lastBlit =
152                             Blit.getFromCache(srcData.getSurfaceType(),
153                                               comptype,
154                                               dstData.getSurfaceType());
155                     }
156                     context.lastBlit.Blit(srcData, dstData,
157                                           sg.composite, null,
158                                           0, 0, tx, ty, tw, th);
159                 } else {
160                     if (context.lastMask == null) {
161                         CompositeType comptype = sg.imageComp;
162                         if (CompositeType.SrcOverNoEa.equals(comptype) &&
163                             paintModel.getTransparency() == Transparency.OPAQUE)
164                         {
165                             comptype = CompositeType.SrcNoEa;
166                         }
167                         context.lastMask =
168                             MaskBlit.getFromCache(srcData.getSurfaceType(),
169                                                   comptype,
170                                                   dstData.getSurfaceType());
171                     }
172 
173                     int toff = offset + rely * tilesize + relx;
174                     context.lastMask.MaskBlit(srcData, dstData,
175                                               sg.composite, null,
176                                               0, 0, tx, ty, tw, th,
177                                               atile, toff, tilesize);
178                 }
179             }
180         }
181     }
182 
skipTile(Object context, int x, int y)183     public void skipTile(Object context, int x, int y) {
184         return;
185     }
186 
endSequence(Object ctx)187     public void endSequence(Object ctx) {
188         TileContext context = (TileContext) ctx;
189         if (context.paintCtxt != null) {
190             context.paintCtxt.dispose();
191         }
192         synchronized (AlphaPaintPipe.class) {
193             if (context.lastData != null) {
194                 cachedLastRaster = context.lastRaster;
195                 if (cachedLastColorModel == null ||
196                     cachedLastColorModel.get() != context.paintModel)
197                 {
198                     // Avoid creating new WeakReference if possible
199                     cachedLastColorModel =
200                         new WeakReference<>(context.paintModel);
201                 }
202                 cachedLastData = context.lastData;
203             }
204         }
205     }
206 }
207