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