1 /*
   2  * Copyright (c) 1997, 2007, 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.awt.BasicStroke;
  29 import java.awt.Rectangle;
  30 import java.awt.Shape;
  31 import java.awt.geom.Rectangle2D;
  32 import java.awt.geom.PathIterator;
  33 import sun.awt.SunHints;
  34 import sun.java2d.SunGraphics2D;
  35 
  36 /**
  37  * This class is used to convert raw geometry into 8-bit alpha tiles
  38  * using an AATileGenerator for application by the next stage of
  39  * the pipeline.
  40  * This class sets up the Generator and computes the alpha tiles
  41  * and then passes them on to a CompositePipe object for painting.
  42  */
  43 public class AAShapePipe
  44     implements ShapeDrawPipe, ParallelogramPipe
  45 {
  46     static RenderingEngine renderengine = RenderingEngine.getInstance();
  47 
  48     CompositePipe outpipe;
  49 
  50     public AAShapePipe(CompositePipe pipe) {
  51         outpipe = pipe;
  52     }
  53 
  54     public void draw(SunGraphics2D sg, Shape s) {
  55         BasicStroke bs;
  56 
  57         if (sg.stroke instanceof BasicStroke) {
  58             bs = (BasicStroke) sg.stroke;
  59         } else {
  60             s = sg.stroke.createStrokedShape(s);
  61             bs = null;
  62         }
  63 
  64         renderPath(sg, s, bs);
  65     }
  66 
  67     public void fill(SunGraphics2D sg, Shape s) {
  68         renderPath(sg, s, null);
  69     }
  70 
  71     private static Rectangle2D computeBBox(double x, double y,
  72                                            double dx1, double dy1,
  73                                            double dx2, double dy2)
  74     {
  75         double lox, loy, hix, hiy;
  76         lox = hix = x;
  77         loy = hiy = y;
  78         if (dx1 < 0) { lox += dx1; } else { hix += dx1; }
  79         if (dy1 < 0) { loy += dy1; } else { hiy += dy1; }
  80         if (dx2 < 0) { lox += dx2; } else { hix += dx2; }
  81         if (dy2 < 0) { loy += dy2; } else { hiy += dy2; }
  82         return new Rectangle2D.Double(lox, loy, hix-lox, hiy-loy);
  83     }
  84 
  85     public void fillParallelogram(SunGraphics2D sg,
  86                                   double x, double y,
  87                                   double dx1, double dy1,
  88                                   double dx2, double dy2)
  89     {
  90         Region clip = sg.getCompClip();
  91         int abox[] = new int[4];
  92         AATileGenerator aatg =
  93             renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
  94                                             clip, abox);
  95         if (aatg == null) {
  96             // Nothing to render
  97             return;
  98         }
  99 
 100         renderTiles(sg, computeBBox(x, y, dx1, dy1, dx2, dy2), aatg, abox);
 101     }
 102 
 103     public void drawParallelogram(SunGraphics2D sg,
 104                                   double x, double y,
 105                                   double dx1, double dy1,
 106                                   double dx2, double dy2,
 107                                   double lw1, double lw2)
 108     {
 109         Region clip = sg.getCompClip();
 110         int abox[] = new int[4];
 111         AATileGenerator aatg =
 112             renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, lw2,
 113                                             clip, abox);
 114         if (aatg == null) {
 115             // Nothing to render
 116             return;
 117         }
 118 
 119         // Note that bbox is of the original shape, not the wide path.
 120         // This is appropriate for handing to Paint methods...
 121         renderTiles(sg, computeBBox(x, y, dx1, dy1, dx2, dy2), aatg, abox);
 122     }
 123 
 124     private static byte[] theTile;
 125 
 126     public synchronized static byte[] getAlphaTile(int len) {
 127         byte[] t = theTile;
 128         if (t == null || t.length < len) {
 129             t = new byte[len];
 130         } else {
 131             theTile = null;
 132         }
 133         return t;
 134     }
 135 
 136     public synchronized static void dropAlphaTile(byte[] t) {
 137         theTile = t;
 138     }
 139 
 140     public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) {
 141         boolean adjust = (bs != null &&
 142                           sg.strokeHint != SunHints.INTVAL_STROKE_PURE);
 143         boolean thin = (sg.strokeState <= sg.STROKE_THINDASHED);
 144 
 145         Region clip = sg.getCompClip();
 146         int abox[] = new int[4];
 147         AATileGenerator aatg =
 148             renderengine.getAATileGenerator(s, sg.transform, clip,
 149                                             bs, thin, adjust, abox);
 150         if (aatg == null) {
 151             // Nothing to render
 152             return;
 153         }
 154 
 155         renderTiles(sg, s, aatg, abox);
 156     }
 157 
 158     public void renderTiles(SunGraphics2D sg, Shape s,
 159                             AATileGenerator aatg, int abox[])
 160     {
 161         Object context = null;
 162         byte alpha[] = null;
 163         try {
 164             context = outpipe.startSequence(sg, s,
 165                                             new Rectangle(abox[0], abox[1],
 166                                                           abox[2] - abox[0],
 167                                                           abox[3] - abox[1]),
 168                                             abox);
 169 
 170             int tw = aatg.getTileWidth();
 171             int th = aatg.getTileHeight();
 172             alpha = getAlphaTile(tw * th);
 173 
 174             byte[] atile;
 175 
 176             for (int y = abox[1]; y < abox[3]; y += th) {
 177                 for (int x = abox[0]; x < abox[2]; x += tw) {
 178                     int w = Math.min(tw, abox[2] - x);
 179                     int h = Math.min(th, abox[3] - y);
 180 
 181                     int a = aatg.getTypicalAlpha();
 182                     if (a == 0x00 ||
 183                         outpipe.needTile(context, x, y, w, h) == false)
 184                     {
 185                         aatg.nextTile();
 186                         outpipe.skipTile(context, x, y);
 187                         continue;
 188                     }
 189                     if (a == 0xff) {
 190                         atile = null;
 191                         aatg.nextTile();
 192                     } else {
 193                         atile = alpha;
 194                         aatg.getAlpha(alpha, 0, tw);
 195                     }
 196 
 197                     outpipe.renderPathTile(context, atile, 0, tw,
 198                                            x, y, w, h);
 199                 }
 200             }
 201         } finally {
 202             aatg.dispose();
 203             if (context != null) {
 204                 outpipe.endSequence(context);
 205             }
 206             if (alpha != null) {
 207                 dropAlphaTile(alpha);
 208             }
 209         }
 210     }
 211 }