/*
 * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.java2d.pipe;

import java.lang.ref.WeakReference;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.PaintContext;
import java.awt.Transparency;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.awt.image.BufferedImage;
import sun.awt.image.BufImgSurfaceData;
import sun.java2d.SunGraphics2D;
import sun.java2d.SurfaceData;
import sun.java2d.loops.Blit;
import sun.java2d.loops.MaskBlit;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.GraphicsPrimitiveMgr;

This class implements a CompositePipe that renders path alpha tiles into a destination according to the Composite attribute of a SunGraphics2D.
/** * This class implements a CompositePipe that renders path alpha tiles * into a destination according to the Composite attribute of a * SunGraphics2D. */
public class AlphaPaintPipe implements CompositePipe { static WeakReference cachedLastRaster; static WeakReference cachedLastColorModel; static WeakReference cachedLastData; static class TileContext { SunGraphics2D sunG2D; PaintContext paintCtxt; ColorModel paintModel; WeakReference lastRaster; WeakReference lastData; MaskBlit lastMask; Blit lastBlit; SurfaceData dstData; public TileContext(SunGraphics2D sg, PaintContext pc) { sunG2D = sg; paintCtxt = pc; paintModel = pc.getColorModel(); dstData = sg.getSurfaceData(); synchronized (AlphaPaintPipe.class) { if (cachedLastColorModel != null && cachedLastColorModel.get() == paintModel) { this.lastRaster = cachedLastRaster; this.lastData = cachedLastData; } } } } public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR, int[] abox) { PaintContext paintContext = sg.paint.createContext(sg.getDeviceColorModel(), devR, s.getBounds2D(), sg.cloneTransform(), sg.getRenderingHints()); return new TileContext(sg, paintContext); } public boolean needTile(Object context, int x, int y, int w, int h) { return true; } private static final int TILE_SIZE = 32; public void renderPathTile(Object ctx, byte[] atile, int offset, int tilesize, int x, int y, int w, int h) { TileContext context = (TileContext) ctx; PaintContext paintCtxt = context.paintCtxt; SunGraphics2D sg = context.sunG2D; SurfaceData dstData = context.dstData; SurfaceData srcData = null; Raster lastRas = null; if (context.lastData != null && context.lastRaster != null) { srcData = (SurfaceData) context.lastData.get(); lastRas = (Raster) context.lastRaster.get(); if (srcData == null || lastRas == null) { srcData = null; lastRas = null; } } ColorModel paintModel = context.paintModel; for (int rely = 0; rely < h; rely += TILE_SIZE) { int ty = y + rely; int th = Math.min(h-rely, TILE_SIZE); for (int relx = 0; relx < w; relx += TILE_SIZE) { int tx = x + relx; int tw = Math.min(w-relx, TILE_SIZE); Raster srcRaster = paintCtxt.getRaster(tx, ty, tw, th); if ((srcRaster.getMinX() != 0) || (srcRaster.getMinY() != 0)) { srcRaster = srcRaster.createTranslatedChild(0, 0); } if (lastRas != srcRaster) { lastRas = srcRaster; context.lastRaster = new WeakReference(lastRas); // REMIND: This will fail for a non-Writable raster! BufferedImage bImg = new BufferedImage(paintModel, (WritableRaster) srcRaster, paintModel.isAlphaPremultiplied(), null); srcData = BufImgSurfaceData.createData(bImg); context.lastData = new WeakReference(srcData); context.lastMask = null; context.lastBlit = null; } if (atile == null) { if (context.lastBlit == null) { CompositeType comptype = sg.imageComp; if (CompositeType.SrcOverNoEa.equals(comptype) && paintModel.getTransparency() == Transparency.OPAQUE) { comptype = CompositeType.SrcNoEa; } context.lastBlit = Blit.getFromCache(srcData.getSurfaceType(), comptype, dstData.getSurfaceType()); } context.lastBlit.Blit(srcData, dstData, sg.composite, null, 0, 0, tx, ty, tw, th); } else { if (context.lastMask == null) { CompositeType comptype = sg.imageComp; if (CompositeType.SrcOverNoEa.equals(comptype) && paintModel.getTransparency() == Transparency.OPAQUE) { comptype = CompositeType.SrcNoEa; } context.lastMask = MaskBlit.getFromCache(srcData.getSurfaceType(), comptype, dstData.getSurfaceType()); } int toff = offset + rely * tilesize + relx; context.lastMask.MaskBlit(srcData, dstData, sg.composite, null, 0, 0, tx, ty, tw, th, atile, toff, tilesize); } } } } public void skipTile(Object context, int x, int y) { return; } public void endSequence(Object ctx) { TileContext context = (TileContext) ctx; if (context.paintCtxt != null) { context.paintCtxt.dispose(); } synchronized (AlphaPaintPipe.class) { if (context.lastData != null) { cachedLastRaster = context.lastRaster; if (cachedLastColorModel == null || cachedLastColorModel.get() != context.paintModel) { // Avoid creating new WeakReference if possible cachedLastColorModel = new WeakReference(context.paintModel); } cachedLastData = context.lastData; } } } }