1/*
2 * Copyright (c) 1999, 2016, 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
26package sun.java2d.loops;
27
28import java.awt.Composite;
29import java.awt.image.BufferedImage;
30import sun.awt.image.BufImgSurfaceData;
31import sun.java2d.loops.GraphicsPrimitive;
32import sun.java2d.SunGraphics2D;
33import sun.java2d.SurfaceData;
34import sun.java2d.pipe.Region;
35
36/**
37 * MaskFill
38 * 1) fills rectangles of pixels on a surface
39 * 2) performs compositing of colors based upon a Composite
40 *    parameter
41 * 3) blends result of composite with destination using an
42 *    alpha coverage mask
43 * 4) the mask may be null in which case it should be treated
44 *    as if it were an array of all opaque values (0xff)
45 */
46public class MaskFill extends GraphicsPrimitive
47{
48    public static final String methodSignature = "MaskFill(...)".toString();
49    public static final String fillPgramSignature =
50        "FillAAPgram(...)".toString();
51    public static final String drawPgramSignature =
52        "DrawAAPgram(...)".toString();
53
54    public static final int primTypeID = makePrimTypeID();
55
56    private static RenderCache fillcache = new RenderCache(10);
57
58    public static MaskFill locate(SurfaceType srctype,
59                                  CompositeType comptype,
60                                  SurfaceType dsttype)
61    {
62        return (MaskFill)
63            GraphicsPrimitiveMgr.locate(primTypeID,
64                                        srctype, comptype, dsttype);
65    }
66
67    public static MaskFill locatePrim(SurfaceType srctype,
68                                      CompositeType comptype,
69                                      SurfaceType dsttype)
70    {
71        return (MaskFill)
72            GraphicsPrimitiveMgr.locatePrim(primTypeID,
73                                            srctype, comptype, dsttype);
74    }
75
76    /*
77     * Note that this uses locatePrim, not locate, so it can return
78     * null if there is no specific loop to handle this op...
79     */
80    public static MaskFill getFromCache(SurfaceType src,
81                                        CompositeType comp,
82                                        SurfaceType dst)
83    {
84        Object o = fillcache.get(src, comp, dst);
85        if (o != null) {
86            return (MaskFill) o;
87        }
88        MaskFill fill = locatePrim(src, comp, dst);
89        if (fill != null) {
90            fillcache.put(src, comp, dst, fill);
91        }
92        return fill;
93    }
94
95    protected MaskFill(String alternateSignature,
96                       SurfaceType srctype,
97                       CompositeType comptype,
98                       SurfaceType dsttype)
99    {
100        super(alternateSignature, primTypeID, srctype, comptype, dsttype);
101    }
102
103    protected MaskFill(SurfaceType srctype,
104                       CompositeType comptype,
105                       SurfaceType dsttype)
106    {
107        super(methodSignature, primTypeID, srctype, comptype, dsttype);
108    }
109
110    public MaskFill(long pNativePrim,
111                    SurfaceType srctype,
112                    CompositeType comptype,
113                    SurfaceType dsttype)
114    {
115        super(pNativePrim, methodSignature, primTypeID, srctype, comptype, dsttype);
116    }
117
118    /**
119     * All MaskFill implementors must have this invoker method
120     */
121    public native void MaskFill(SunGraphics2D sg2d, SurfaceData sData,
122                                Composite comp,
123                                int x, int y, int w, int h,
124                                byte[] mask, int maskoff, int maskscan);
125
126    public native void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData,
127                                   Composite comp,
128                                   double x, double y,
129                                   double dx1, double dy1,
130                                   double dx2, double dy2);
131
132    public native void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData,
133                                   Composite comp,
134                                   double x, double y,
135                                   double dx1, double dy1,
136                                   double dx2, double dy2,
137                                   double lw1, double lw2);
138
139    public boolean canDoParallelograms() {
140        return (getNativePrim() != 0);
141    }
142
143    static {
144        GraphicsPrimitiveMgr.registerGeneral(new MaskFill(null, null, null));
145    }
146
147    public GraphicsPrimitive makePrimitive(SurfaceType srctype,
148                                           CompositeType comptype,
149                                           SurfaceType dsttype)
150    {
151        if (SurfaceType.OpaqueColor.equals(srctype) ||
152            SurfaceType.AnyColor.equals(srctype))
153        {
154            if (CompositeType.Xor.equals(comptype)) {
155                throw new InternalError("Cannot construct MaskFill for " +
156                                        "XOR mode");
157            } else {
158                return new General(srctype, comptype, dsttype);
159            }
160        } else {
161            throw new InternalError("MaskFill can only fill with colors");
162        }
163    }
164
165    private static class General extends MaskFill {
166        FillRect fillop;
167        MaskBlit maskop;
168
169        public General(SurfaceType srctype,
170                       CompositeType comptype,
171                       SurfaceType dsttype)
172        {
173            super(srctype, comptype, dsttype);
174            fillop = FillRect.locate(srctype,
175                                     CompositeType.SrcNoEa,
176                                     SurfaceType.IntArgb);
177            maskop = MaskBlit.locate(SurfaceType.IntArgb, comptype, dsttype);
178        }
179
180        public void MaskFill(SunGraphics2D sg2d,
181                             SurfaceData sData,
182                             Composite comp,
183                             int x, int y, int w, int h,
184                             byte mask[], int offset, int scan)
185        {
186            BufferedImage dstBI =
187                new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
188            SurfaceData tmpData = BufImgSurfaceData.createData(dstBI);
189
190            // REMIND: This is not pretty.  It would be nicer if we
191            // passed a "FillData" object to the Pixel loops, instead
192            // of a SunGraphics2D parameter...
193            Region clip = sg2d.clipRegion;
194            sg2d.clipRegion = null;
195            int pixel = sg2d.pixel;
196            sg2d.pixel = tmpData.pixelFor(sg2d.getColor());
197            fillop.FillRect(sg2d, tmpData, 0, 0, w, h);
198            sg2d.pixel = pixel;
199            sg2d.clipRegion = clip;
200
201            maskop.MaskBlit(tmpData, sData, comp, null,
202                            0, 0, x, y, w, h,
203                            mask, offset, scan);
204        }
205    }
206
207    public GraphicsPrimitive traceWrap() {
208        return new TraceMaskFill(this);
209    }
210
211    private static class TraceMaskFill extends MaskFill {
212        MaskFill target;
213        MaskFill fillPgramTarget;
214        MaskFill drawPgramTarget;
215
216        public TraceMaskFill(MaskFill target) {
217            super(target.getSourceType(),
218                  target.getCompositeType(),
219                  target.getDestType());
220            this.target = target;
221            this.fillPgramTarget = new MaskFill(fillPgramSignature,
222                                                target.getSourceType(),
223                                                target.getCompositeType(),
224                                                target.getDestType());
225            this.drawPgramTarget = new MaskFill(drawPgramSignature,
226                                                target.getSourceType(),
227                                                target.getCompositeType(),
228                                                target.getDestType());
229        }
230
231        public GraphicsPrimitive traceWrap() {
232            return this;
233        }
234
235        public void MaskFill(SunGraphics2D sg2d, SurfaceData sData,
236                             Composite comp,
237                             int x, int y, int w, int h,
238                             byte[] mask, int maskoff, int maskscan)
239        {
240            tracePrimitive(target);
241            target.MaskFill(sg2d, sData, comp, x, y, w, h,
242                            mask, maskoff, maskscan);
243        }
244
245        public void FillAAPgram(SunGraphics2D sg2d, SurfaceData sData,
246                                Composite comp,
247                                double x, double y,
248                                double dx1, double dy1,
249                                double dx2, double dy2)
250        {
251            tracePrimitive(fillPgramTarget);
252            target.FillAAPgram(sg2d, sData, comp,
253                               x, y, dx1, dy1, dx2, dy2);
254        }
255
256        public void DrawAAPgram(SunGraphics2D sg2d, SurfaceData sData,
257                                Composite comp,
258                                double x, double y,
259                                double dx1, double dy1,
260                                double dx2, double dy2,
261                                double lw1, double lw2)
262        {
263            tracePrimitive(drawPgramTarget);
264            target.DrawAAPgram(sg2d, sData, comp,
265                               x, y, dx1, dy1, dx2, dy2, lw1, lw2);
266        }
267
268        public boolean canDoParallelograms() {
269            return target.canDoParallelograms();
270        }
271    }
272}
273