1 /*
   2  * Copyright (c) 1999, 2018, 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.Composite;
  29 import java.awt.image.BufferedImage;
  30 import sun.awt.image.BufImgSurfaceData;
  31 import sun.java2d.loops.GraphicsPrimitive;
  32 import sun.java2d.SunGraphics2D;
  33 import sun.java2d.SurfaceData;
  34 import 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  */
  46 public 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 }