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 cachedLastRaster;
  52     static WeakReference cachedLastColorModel;
  53     static WeakReference cachedLastData;
  54 
  55     static class TileContext {
  56         SunGraphics2D sunG2D;
  57         PaintContext paintCtxt;
  58         ColorModel paintModel;
  59         WeakReference lastRaster;
  60         WeakReference lastData;
  61         MaskBlit lastMask;
  62         Blit     lastBlit;
  63         SurfaceData dstData;
  64 
  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 
  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 
  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 
  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 = (SurfaceData) context.lastData.get();
 109             lastRas = (Raster) 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 
 183     public void skipTile(Object context, int x, int y) {
 184         return;
 185     }
 186 
 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 }