Showing the changes to java/pkg/sun/java2d/pipe (114 of 18352 files). Show all
Unified · Split
Binary file not shown.
| @@ -0,0 +1,215 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2011, 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 ux1, double uy1, | ||
| 72 | double ux2, double uy2) | ||
| 73 | { | ||
| 74 | if ((ux2 -= ux1) < 0) { | ||
| 75 | ux1 += ux2; | ||
| 76 | ux2 = -ux2; | ||
| 77 | } | ||
| 78 | if ((uy2 -= uy1) < 0) { | ||
| 79 | uy1 += uy2; | ||
| 80 | uy2 = -uy2; | ||
| 81 | } | ||
| 82 | return new Rectangle2D.Double(ux1, uy1, ux2, uy2); | ||
| 83 | } | ||
| 84 | |||
| 85 | public void fillParallelogram(SunGraphics2D sg, | ||
| 86 | double ux1, double uy1, | ||
| 87 | double ux2, double uy2, | ||
| 88 | double x, double y, | ||
| 89 | double dx1, double dy1, | ||
| 90 | double dx2, double dy2) | ||
| 91 | { | ||
| 92 | Region clip = sg.getCompClip(); | ||
| 93 | int abox[] = new int[4]; | ||
| 94 | AATileGenerator aatg = | ||
| 95 | renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, | ||
| 96 | clip, abox); | ||
| 97 | if (aatg == null) { | ||
| 98 | // Nothing to render | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | |||
| 102 | renderTiles(sg, computeBBox(ux1, uy1, ux2, uy2), aatg, abox); | ||
| 103 | } | ||
| 104 | |||
| 105 | public void drawParallelogram(SunGraphics2D sg, | ||
| 106 | double ux1, double uy1, | ||
| 107 | double ux2, double uy2, | ||
| 108 | double x, double y, | ||
| 109 | double dx1, double dy1, | ||
| 110 | double dx2, double dy2, | ||
| 111 | double lw1, double lw2) | ||
| 112 | { | ||
| 113 | Region clip = sg.getCompClip(); | ||
| 114 | int abox[] = new int[4]; | ||
| 115 | AATileGenerator aatg = | ||
| 116 | renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, lw2, | ||
| 117 | clip, abox); | ||
| 118 | if (aatg == null) { | ||
| 119 | // Nothing to render | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | |||
| 123 | // Note that bbox is of the original shape, not the wide path. | ||
| 124 | // This is appropriate for handing to Paint methods... | ||
| 125 | renderTiles(sg, computeBBox(ux1, uy1, ux2, uy2), aatg, abox); | ||
| 126 | } | ||
| 127 | |||
| 128 | private static byte[] theTile; | ||
| 129 | |||
| 130 | public synchronized static byte[] getAlphaTile(int len) { | ||
| 131 | byte[] t = theTile; | ||
| 132 | if (t == null || t.length < len) { | ||
| 133 | t = new byte[len]; | ||
| 134 | } else { | ||
| 135 | theTile = null; | ||
| 136 | } | ||
| 137 | return t; | ||
| 138 | } | ||
| 139 | |||
| 140 | public synchronized static void dropAlphaTile(byte[] t) { | ||
| 141 | theTile = t; | ||
| 142 | } | ||
| 143 | |||
| 144 | public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) { | ||
| 145 | boolean adjust = (bs != null && | ||
| 146 | sg.strokeHint != SunHints.INTVAL_STROKE_PURE); | ||
| 147 | boolean thin = (sg.strokeState <= sg.STROKE_THINDASHED); | ||
| 148 | |||
| 149 | Region clip = sg.getCompClip(); | ||
| 150 | int abox[] = new int[4]; | ||
| 151 | AATileGenerator aatg = | ||
| 152 | renderengine.getAATileGenerator(s, sg.transform, clip, | ||
| 153 | bs, thin, adjust, abox); | ||
| 154 | if (aatg == null) { | ||
| 155 | // Nothing to render | ||
| 156 | return; | ||
| 157 | } | ||
| 158 | |||
| 159 | renderTiles(sg, s, aatg, abox); | ||
| 160 | } | ||
| 161 | |||
| 162 | public void renderTiles(SunGraphics2D sg, Shape s, | ||
| 163 | AATileGenerator aatg, int abox[]) | ||
| 164 | { | ||
| 165 | Object context = null; | ||
| 166 | byte alpha[] = null; | ||
| 167 | try { | ||
| 168 | context = outpipe.startSequence(sg, s, | ||
| 169 | new Rectangle(abox[0], abox[1], | ||
| 170 | abox[2] - abox[0], | ||
| 171 | abox[3] - abox[1]), | ||
| 172 | abox); | ||
| 173 | |||
| 174 | int tw = aatg.getTileWidth(); | ||
| 175 | int th = aatg.getTileHeight(); | ||
| 176 | alpha = getAlphaTile(tw * th); | ||
| 177 | |||
| 178 | byte[] atile; | ||
| 179 | |||
| 180 | for (int y = abox[1]; y < abox[3]; y += th) { | ||
| 181 | for (int x = abox[0]; x < abox[2]; x += tw) { | ||
| 182 | int w = Math.min(tw, abox[2] - x); | ||
| 183 | int h = Math.min(th, abox[3] - y); | ||
| 184 | |||
| 185 | int a = aatg.getTypicalAlpha(); | ||
| 186 | if (a == 0x00 || | ||
| 187 | outpipe.needTile(context, x, y, w, h) == false) | ||
| 188 | { | ||
| 189 | aatg.nextTile(); | ||
| 190 | outpipe.skipTile(context, x, y); | ||
| 191 | continue; | ||
| 192 | } | ||
| 193 | if (a == 0xff) { | ||
| 194 | atile = null; | ||
| 195 | aatg.nextTile(); | ||
| 196 | } else { | ||
| 197 | atile = alpha; | ||
| 198 | aatg.getAlpha(alpha, 0, tw); | ||
| 199 | } | ||
| 200 | |||
| 201 | outpipe.renderPathTile(context, atile, 0, tw, | ||
| 202 | x, y, w, h); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | } finally { | ||
| 206 | aatg.dispose(); | ||
| 207 | if (context != null) { | ||
| 208 | outpipe.endSequence(context); | ||
| 209 | } | ||
| 210 | if (alpha != null) { | ||
| 211 | dropAlphaTile(alpha); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
Binary file not shown.
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2005, 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.font.GlyphVector; | ||
| 29 | import sun.java2d.SunGraphics2D; | ||
| 30 | import sun.font.GlyphList; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * A delegate pipe of SG2D for drawing anti-aliased text with | ||
| 34 | * a solid source colour to an opaque destination. | ||
| 35 | */ | ||
| 36 | |||
| 37 | public class AATextRenderer extends GlyphListLoopPipe | ||
| 38 | implements LoopBasedPipe | ||
| 39 | { | ||
| 40 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { | ||
| 41 | sg2d.loops.drawGlyphListAALoop.DrawGlyphListAA(sg2d, sg2d.surfaceData, | ||
| 42 | gl); | ||
| 43 | } | ||
| 44 | |||
| 45 | } | ||
Binary file not shown.
| @@ -0,0 +1,111 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 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 | /** | ||
| 29 | * The API for an object that generates alpha coverage tiles for a given | ||
| 30 | * path. | ||
| 31 | * The {@link RenderingEngine} will be consulted as a factory to return | ||
| 32 | * one of these objects for a given Shape and a given set of rendering | ||
| 33 | * attributes. | ||
| 34 | * This object will iterate through the bounds of the rendering primitive | ||
| 35 | * and return tiles of a constant size as specified by the getTileWidth() | ||
| 36 | * and getTileHeight() parameters. | ||
| 37 | * The iteration order of the tiles will be as specified by the pseudo-code: | ||
| 38 | * <pre> | ||
| 39 | * int bbox[] = {left, top, right, bottom}; | ||
| 40 | * AATileGenerator aatg = renderengine.getAATileGenerator(..., bbox); | ||
| 41 | * int tw = aatg.getTileWidth(); | ||
| 42 | * int th = aatg.getTileHeight(); | ||
| 43 | * byte tile[] = new byte[tw * th]; | ||
| 44 | * for (y = top; y < bottom; y += th) { | ||
| 45 | * for (x = left; x < right; x += tw) { | ||
| 46 | * int a = aatg.getTypicalAlpha(); | ||
| 47 | * int w = Math.min(tw, right-x); | ||
| 48 | * int h = Math.min(th, bottom-y); | ||
| 49 | * if (a == 0x00) { | ||
| 50 | * // can skip this tile... | ||
| 51 | * aatg.nextTile(); | ||
| 52 | * } else if (a == 0xff) { | ||
| 53 | * // can treat this tile like a fillRect | ||
| 54 | * aatg.nextTile(); | ||
| 55 | * doFill(x, y, w, h); | ||
| 56 | * } else { | ||
| 57 | * aatg.getAlpha(tile, 0, tw); | ||
| 58 | * handleAlpha(tile, x, y, w, h); | ||
| 59 | * } | ||
| 60 | * } | ||
| 61 | * } | ||
| 62 | * aatg.dispose(); | ||
| 63 | * </pre> | ||
| 64 | * The bounding box for the iteration will be returned by the | ||
| 65 | * {@code RenderingEngine} via an argument to the getAATileGenerator() method. | ||
| 66 | */ | ||
| 67 | public interface AATileGenerator { | ||
| 68 | /** | ||
| 69 | * Gets the width of the tiles that the generator batches output into. | ||
| 70 | * @return the width of the standard alpha tile | ||
| 71 | */ | ||
| 72 | public int getTileWidth(); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Gets the height of the tiles that the generator batches output into. | ||
| 76 | * @return the height of the standard alpha tile | ||
| 77 | */ | ||
| 78 | public int getTileHeight(); | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Gets the typical alpha value that will characterize the current | ||
| 82 | * tile. | ||
| 83 | * The answer may be 0x00 to indicate that the current tile has | ||
| 84 | * no coverage in any of its pixels, or it may be 0xff to indicate | ||
| 85 | * that the current tile is completely covered by the path, or any | ||
| 86 | * other value to indicate non-trivial coverage cases. | ||
| 87 | * @return 0x00 for no coverage, 0xff for total coverage, or any other | ||
| 88 | * value for partial coverage of the tile | ||
| 89 | */ | ||
| 90 | public int getTypicalAlpha(); | ||
| 91 | |||
| 92 | /** | ||
| 93 | * Skips the current tile and moves on to the next tile. | ||
| 94 | * Either this method, or the getAlpha() method should be called | ||
| 95 | * once per tile, but not both. | ||
| 96 | */ | ||
| 97 | public void nextTile(); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Gets the alpha coverage values for the current tile. | ||
| 101 | * Either this method, or the nextTile() method should be called | ||
| 102 | * once per tile, but not both. | ||
| 103 | */ | ||
| 104 | public void getAlpha(byte tile[], int offset, int rowstride); | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Disposes this tile generator. | ||
| 108 | * No further calls will be made on this instance. | ||
| 109 | */ | ||
| 110 | public void dispose(); | ||
| 111 | } | ||
Binary file not shown.
| @@ -0,0 +1,90 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 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.pipe; | ||
| 27 | |||
| 28 | import java.awt.Rectangle; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import sun.java2d.SunGraphics2D; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * This class implements a CompositePipe that renders path alpha tiles | ||
| 34 | * into a destination that supports direct alpha compositing of a solid | ||
| 35 | * color, according to one of the rules in the AlphaComposite class. | ||
| 36 | */ | ||
| 37 | public class AlphaColorPipe implements CompositePipe, ParallelogramPipe { | ||
| 38 | public AlphaColorPipe() { | ||
| 39 | } | ||
| 40 | |||
| 41 | public Object startSequence(SunGraphics2D sg, Shape s, Rectangle dev, | ||
| 42 | int[] abox) { | ||
| 43 | return sg; | ||
| 44 | } | ||
| 45 | |||
| 46 | public boolean needTile(Object context, int x, int y, int w, int h) { | ||
| 47 | return true; | ||
| 48 | } | ||
| 49 | |||
| 50 | public void renderPathTile(Object context, | ||
| 51 | byte[] atile, int offset, int tilesize, | ||
| 52 | int x, int y, int w, int h) { | ||
| 53 | SunGraphics2D sg = (SunGraphics2D) context; | ||
| 54 | |||
| 55 | sg.alphafill.MaskFill(sg, sg.getSurfaceData(), sg.composite, | ||
| 56 | x, y, w, h, | ||
| 57 | atile, offset, tilesize); | ||
| 58 | } | ||
| 59 | |||
| 60 | public void skipTile(Object context, int x, int y) { | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | public void endSequence(Object context) { | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | public void fillParallelogram(SunGraphics2D sg, | ||
| 69 | double ux1, double uy1, | ||
| 70 | double ux2, double uy2, | ||
| 71 | double x, double y, | ||
| 72 | double dx1, double dy1, | ||
| 73 | double dx2, double dy2) | ||
| 74 | { | ||
| 75 | sg.alphafill.FillAAPgram(sg, sg.getSurfaceData(), sg.composite, | ||
| 76 | x, y, dx1, dy1, dx2, dy2); | ||
| 77 | } | ||
| 78 | |||
| 79 | public void drawParallelogram(SunGraphics2D sg, | ||
| 80 | double ux1, double uy1, | ||
| 81 | double ux2, double uy2, | ||
| 82 | double x, double y, | ||
| 83 | double dx1, double dy1, | ||
| 84 | double dx2, double dy2, | ||
| 85 | double lw1, double lw2) | ||
| 86 | { | ||
| 87 | sg.alphafill.DrawAAPgram(sg, sg.getSurfaceData(), sg.composite, | ||
| 88 | x, y, dx1, dy1, dx2, dy2, lw1, lw2); | ||
| 89 | } | ||
| 90 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,206 @@ | |||
| 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 | } | ||
| @@ -0,0 +1,393 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 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.color.ColorSpace; | ||
| 29 | import java.awt.image.AffineTransformOp; | ||
| 30 | import java.awt.image.BufferedImage; | ||
| 31 | import java.awt.image.BufferedImageOp; | ||
| 32 | import java.awt.image.BufferedImageOp; | ||
| 33 | import java.awt.image.ByteLookupTable; | ||
| 34 | import java.awt.image.ColorModel; | ||
| 35 | import java.awt.image.ConvolveOp; | ||
| 36 | import java.awt.image.IndexColorModel; | ||
| 37 | import java.awt.image.Kernel; | ||
| 38 | import java.awt.image.LookupOp; | ||
| 39 | import java.awt.image.LookupTable; | ||
| 40 | import java.awt.image.RescaleOp; | ||
| 41 | import java.awt.image.ShortLookupTable; | ||
| 42 | import sun.java2d.SurfaceData; | ||
| 43 | import sun.java2d.loops.CompositeType; | ||
| 44 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 45 | |||
| 46 | public class BufferedBufImgOps { | ||
| 47 | |||
| 48 | public static void enableBufImgOp(RenderQueue rq, SurfaceData srcData, | ||
| 49 | BufferedImage srcImg, | ||
| 50 | BufferedImageOp biop) | ||
| 51 | { | ||
| 52 | if (biop instanceof ConvolveOp) { | ||
| 53 | enableConvolveOp(rq, srcData, (ConvolveOp)biop); | ||
| 54 | } else if (biop instanceof RescaleOp) { | ||
| 55 | enableRescaleOp(rq, srcData, srcImg, (RescaleOp)biop); | ||
| 56 | } else if (biop instanceof LookupOp) { | ||
| 57 | enableLookupOp(rq, srcData, srcImg, (LookupOp)biop); | ||
| 58 | } else { | ||
| 59 | throw new InternalError("Unknown BufferedImageOp"); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | public static void disableBufImgOp(RenderQueue rq, BufferedImageOp biop) { | ||
| 64 | if (biop instanceof ConvolveOp) { | ||
| 65 | disableConvolveOp(rq); | ||
| 66 | } else if (biop instanceof RescaleOp) { | ||
| 67 | disableRescaleOp(rq); | ||
| 68 | } else if (biop instanceof LookupOp) { | ||
| 69 | disableLookupOp(rq); | ||
| 70 | } else { | ||
| 71 | throw new InternalError("Unknown BufferedImageOp"); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | /**************************** ConvolveOp support ****************************/ | ||
| 76 | |||
| 77 | public static boolean isConvolveOpValid(ConvolveOp cop) { | ||
| 78 | Kernel kernel = cop.getKernel(); | ||
| 79 | int kw = kernel.getWidth(); | ||
| 80 | int kh = kernel.getHeight(); | ||
| 81 | // REMIND: we currently can only handle 3x3 and 5x5 kernels, | ||
| 82 | // but hopefully this is just a temporary restriction; | ||
| 83 | // see native shader comments for more details | ||
| 84 | if (!(kw == 3 && kh == 3) && !(kw == 5 && kh == 5)) { | ||
| 85 | return false; | ||
| 86 | } | ||
| 87 | return true; | ||
| 88 | } | ||
| 89 | |||
| 90 | private static void enableConvolveOp(RenderQueue rq, | ||
| 91 | SurfaceData srcData, | ||
| 92 | ConvolveOp cop) | ||
| 93 | { | ||
| 94 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 95 | boolean edgeZero = | ||
| 96 | cop.getEdgeCondition() == ConvolveOp.EDGE_ZERO_FILL; | ||
| 97 | Kernel kernel = cop.getKernel(); | ||
| 98 | int kernelWidth = kernel.getWidth(); | ||
| 99 | int kernelHeight = kernel.getHeight(); | ||
| 100 | int kernelSize = kernelWidth * kernelHeight; | ||
| 101 | int sizeofFloat = 4; | ||
| 102 | int totalBytesRequired = 4 + 8 + 12 + (kernelSize * sizeofFloat); | ||
| 103 | |||
| 104 | RenderBuffer buf = rq.getBuffer(); | ||
| 105 | rq.ensureCapacityAndAlignment(totalBytesRequired, 4); | ||
| 106 | buf.putInt(ENABLE_CONVOLVE_OP); | ||
| 107 | buf.putLong(srcData.getNativeOps()); | ||
| 108 | buf.putInt(edgeZero ? 1 : 0); | ||
| 109 | buf.putInt(kernelWidth); | ||
| 110 | buf.putInt(kernelHeight); | ||
| 111 | buf.put(kernel.getKernelData(null)); | ||
| 112 | } | ||
| 113 | |||
| 114 | private static void disableConvolveOp(RenderQueue rq) { | ||
| 115 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 116 | RenderBuffer buf = rq.getBuffer(); | ||
| 117 | rq.ensureCapacity(4); | ||
| 118 | buf.putInt(DISABLE_CONVOLVE_OP); | ||
| 119 | } | ||
| 120 | |||
| 121 | /**************************** RescaleOp support *****************************/ | ||
| 122 | |||
| 123 | public static boolean isRescaleOpValid(RescaleOp rop, | ||
| 124 | BufferedImage srcImg) | ||
| 125 | { | ||
| 126 | int numFactors = rop.getNumFactors(); | ||
| 127 | ColorModel srcCM = srcImg.getColorModel(); | ||
| 128 | |||
| 129 | if (srcCM instanceof IndexColorModel) { | ||
| 130 | throw new | ||
| 131 | IllegalArgumentException("Rescaling cannot be "+ | ||
| 132 | "performed on an indexed image"); | ||
| 133 | } | ||
| 134 | if (numFactors != 1 && | ||
| 135 | numFactors != srcCM.getNumColorComponents() && | ||
| 136 | numFactors != srcCM.getNumComponents()) | ||
| 137 | { | ||
| 138 | throw new IllegalArgumentException("Number of scaling constants "+ | ||
| 139 | "does not equal the number of"+ | ||
| 140 | " of color or color/alpha "+ | ||
| 141 | " components"); | ||
| 142 | } | ||
| 143 | |||
| 144 | int csType = srcCM.getColorSpace().getType(); | ||
| 145 | if (csType != ColorSpace.TYPE_RGB && | ||
| 146 | csType != ColorSpace.TYPE_GRAY) | ||
| 147 | { | ||
| 148 | // Not prepared to deal with other color spaces | ||
| 149 | return false; | ||
| 150 | } | ||
| 151 | |||
| 152 | if (numFactors == 2 || numFactors > 4) { | ||
| 153 | // Not really prepared to handle this at the native level, so... | ||
| 154 | return false; | ||
| 155 | } | ||
| 156 | |||
| 157 | return true; | ||
| 158 | } | ||
| 159 | |||
| 160 | private static void enableRescaleOp(RenderQueue rq, | ||
| 161 | SurfaceData srcData, | ||
| 162 | BufferedImage srcImg, | ||
| 163 | RescaleOp rop) | ||
| 164 | { | ||
| 165 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 166 | ColorModel srcCM = srcImg.getColorModel(); | ||
| 167 | boolean nonPremult = | ||
| 168 | srcCM.hasAlpha() && | ||
| 169 | srcCM.isAlphaPremultiplied(); | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Note: The user-provided scale factors and offsets are arranged | ||
| 173 | * in R/G/B/A order, regardless of the raw data order of the | ||
| 174 | * underlying Raster/DataBuffer. The source image data is ultimately | ||
| 175 | * converted into RGBA data when uploaded to an OpenGL texture | ||
| 176 | * (even for TYPE_GRAY), so the scale factors and offsets are already | ||
| 177 | * in the order expected by the native OpenGL code. | ||
| 178 | * | ||
| 179 | * However, the offsets provided by the user are in a range dictated | ||
| 180 | * by the size of each color/alpha band in the source image. For | ||
| 181 | * example, for 8/8/8 data each offset is in the range [0,255], | ||
| 182 | * for 5/5/5 data each offset is in the range [0,31], and so on. | ||
| 183 | * The OpenGL shader only thinks in terms of [0,1], so below we need | ||
| 184 | * to normalize the user-provided offset values into the range [0,1]. | ||
| 185 | */ | ||
| 186 | int numFactors = rop.getNumFactors(); | ||
| 187 | float[] origScaleFactors = rop.getScaleFactors(null); | ||
| 188 | float[] origOffsets = rop.getOffsets(null); | ||
| 189 | |||
| 190 | // To make things easier, we will always pass all four bands | ||
| 191 | // down to native code... | ||
| 192 | float[] normScaleFactors; | ||
| 193 | float[] normOffsets; | ||
| 194 | |||
| 195 | if (numFactors == 1) { | ||
| 196 | normScaleFactors = new float[4]; | ||
| 197 | normOffsets = new float[4]; | ||
| 198 | for (int i = 0; i < 3; i++) { | ||
| 199 | normScaleFactors[i] = origScaleFactors[0]; | ||
| 200 | normOffsets[i] = origOffsets[0]; | ||
| 201 | } | ||
| 202 | // Leave alpha untouched... | ||
| 203 | normScaleFactors[3] = 1.0f; | ||
| 204 | normOffsets[3] = 0.0f; | ||
| 205 | } else if (numFactors == 3) { | ||
| 206 | normScaleFactors = new float[4]; | ||
| 207 | normOffsets = new float[4]; | ||
| 208 | for (int i = 0; i < 3; i++) { | ||
| 209 | normScaleFactors[i] = origScaleFactors[i]; | ||
| 210 | normOffsets[i] = origOffsets[i]; | ||
| 211 | } | ||
| 212 | // Leave alpha untouched... | ||
| 213 | normScaleFactors[3] = 1.0f; | ||
| 214 | normOffsets[3] = 0.0f; | ||
| 215 | } else { // (numFactors == 4) | ||
| 216 | normScaleFactors = origScaleFactors; | ||
| 217 | normOffsets = origOffsets; | ||
| 218 | } | ||
| 219 | |||
| 220 | // The user-provided offsets are specified in the range | ||
| 221 | // of each source color band, but the OpenGL shader only wants | ||
| 222 | // to deal with data in the range [0,1], so we need to normalize | ||
| 223 | // each offset value to the range [0,1] here. | ||
| 224 | if (srcCM.getNumComponents() == 1) { | ||
| 225 | // Gray data | ||
| 226 | int nBits = srcCM.getComponentSize(0); | ||
| 227 | int maxValue = (1 << nBits) - 1; | ||
| 228 | for (int i = 0; i < 3; i++) { | ||
| 229 | normOffsets[i] /= maxValue; | ||
| 230 | } | ||
| 231 | } else { | ||
| 232 | // RGB(A) data | ||
| 233 | for (int i = 0; i < srcCM.getNumComponents(); i++) { | ||
| 234 | int nBits = srcCM.getComponentSize(i); | ||
| 235 | int maxValue = (1 << nBits) - 1; | ||
| 236 | normOffsets[i] /= maxValue; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | int sizeofFloat = 4; | ||
| 241 | int totalBytesRequired = 4 + 8 + 4 + (4 * sizeofFloat * 2); | ||
| 242 | |||
| 243 | RenderBuffer buf = rq.getBuffer(); | ||
| 244 | rq.ensureCapacityAndAlignment(totalBytesRequired, 4); | ||
| 245 | buf.putInt(ENABLE_RESCALE_OP); | ||
| 246 | buf.putLong(srcData.getNativeOps()); | ||
| 247 | buf.putInt(nonPremult ? 1 : 0); | ||
| 248 | buf.put(normScaleFactors); | ||
| 249 | buf.put(normOffsets); | ||
| 250 | } | ||
| 251 | |||
| 252 | private static void disableRescaleOp(RenderQueue rq) { | ||
| 253 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 254 | RenderBuffer buf = rq.getBuffer(); | ||
| 255 | rq.ensureCapacity(4); | ||
| 256 | buf.putInt(DISABLE_RESCALE_OP); | ||
| 257 | } | ||
| 258 | |||
| 259 | /**************************** LookupOp support ******************************/ | ||
| 260 | |||
| 261 | public static boolean isLookupOpValid(LookupOp lop, | ||
| 262 | BufferedImage srcImg) | ||
| 263 | { | ||
| 264 | LookupTable table = lop.getTable(); | ||
| 265 | int numComps = table.getNumComponents(); | ||
| 266 | ColorModel srcCM = srcImg.getColorModel(); | ||
| 267 | |||
| 268 | if (srcCM instanceof IndexColorModel) { | ||
| 269 | throw new | ||
| 270 | IllegalArgumentException("LookupOp cannot be "+ | ||
| 271 | "performed on an indexed image"); | ||
| 272 | } | ||
| 273 | if (numComps != 1 && | ||
| 274 | numComps != srcCM.getNumComponents() && | ||
| 275 | numComps != srcCM.getNumColorComponents()) | ||
| 276 | { | ||
| 277 | throw new IllegalArgumentException("Number of arrays in the "+ | ||
| 278 | " lookup table ("+ | ||
| 279 | numComps+ | ||
| 280 | ") is not compatible with"+ | ||
| 281 | " the src image: "+srcImg); | ||
| 282 | } | ||
| 283 | |||
| 284 | int csType = srcCM.getColorSpace().getType(); | ||
| 285 | if (csType != ColorSpace.TYPE_RGB && | ||
| 286 | csType != ColorSpace.TYPE_GRAY) | ||
| 287 | { | ||
| 288 | // Not prepared to deal with other color spaces | ||
| 289 | return false; | ||
| 290 | } | ||
| 291 | |||
| 292 | if (numComps == 2 || numComps > 4) { | ||
| 293 | // Not really prepared to handle this at the native level, so... | ||
| 294 | return false; | ||
| 295 | } | ||
| 296 | |||
| 297 | // The LookupTable spec says that "all arrays must be the | ||
| 298 | // same size" but unfortunately the constructors do not | ||
| 299 | // enforce that. Also, our native code only works with | ||
| 300 | // arrays no larger than 256 elements, so check both of | ||
| 301 | // these restrictions here. | ||
| 302 | if (table instanceof ByteLookupTable) { | ||
| 303 | byte[][] data = ((ByteLookupTable)table).getTable(); | ||
| 304 | for (int i = 1; i < data.length; i++) { | ||
| 305 | if (data[i].length > 256 || | ||
| 306 | data[i].length != data[i-1].length) | ||
| 307 | { | ||
| 308 | return false; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | } else if (table instanceof ShortLookupTable) { | ||
| 312 | short[][] data = ((ShortLookupTable)table).getTable(); | ||
| 313 | for (int i = 1; i < data.length; i++) { | ||
| 314 | if (data[i].length > 256 || | ||
| 315 | data[i].length != data[i-1].length) | ||
| 316 | { | ||
| 317 | return false; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } else { | ||
| 321 | return false; | ||
| 322 | } | ||
| 323 | |||
| 324 | return true; | ||
| 325 | } | ||
| 326 | |||
| 327 | private static void enableLookupOp(RenderQueue rq, | ||
| 328 | SurfaceData srcData, | ||
| 329 | BufferedImage srcImg, | ||
| 330 | LookupOp lop) | ||
| 331 | { | ||
| 332 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 333 | boolean nonPremult = | ||
| 334 | srcImg.getColorModel().hasAlpha() && | ||
| 335 | srcImg.isAlphaPremultiplied(); | ||
| 336 | |||
| 337 | LookupTable table = lop.getTable(); | ||
| 338 | int numBands = table.getNumComponents(); | ||
| 339 | int offset = table.getOffset(); | ||
| 340 | int bandLength; | ||
| 341 | int bytesPerElem; | ||
| 342 | boolean shortData; | ||
| 343 | |||
| 344 | if (table instanceof ShortLookupTable) { | ||
| 345 | short[][] data = ((ShortLookupTable)table).getTable(); | ||
| 346 | bandLength = data[0].length; | ||
| 347 | bytesPerElem = 2; | ||
| 348 | shortData = true; | ||
| 349 | } else { // (table instanceof ByteLookupTable) | ||
| 350 | byte[][] data = ((ByteLookupTable)table).getTable(); | ||
| 351 | bandLength = data[0].length; | ||
| 352 | bytesPerElem = 1; | ||
| 353 | shortData = false; | ||
| 354 | } | ||
| 355 | |||
| 356 | // Adjust the LUT length so that it ends on a 4-byte boundary | ||
| 357 | int totalLutBytes = numBands * bandLength * bytesPerElem; | ||
| 358 | int paddedLutBytes = (totalLutBytes + 3) & (~3); | ||
| 359 | int padding = paddedLutBytes - totalLutBytes; | ||
| 360 | int totalBytesRequired = 4 + 8 + 20 + paddedLutBytes; | ||
| 361 | |||
| 362 | RenderBuffer buf = rq.getBuffer(); | ||
| 363 | rq.ensureCapacityAndAlignment(totalBytesRequired, 4); | ||
| 364 | buf.putInt(ENABLE_LOOKUP_OP); | ||
| 365 | buf.putLong(srcData.getNativeOps()); | ||
| 366 | buf.putInt(nonPremult ? 1 : 0); | ||
| 367 | buf.putInt(shortData ? 1 : 0); | ||
| 368 | buf.putInt(numBands); | ||
| 369 | buf.putInt(bandLength); | ||
| 370 | buf.putInt(offset); | ||
| 371 | if (shortData) { | ||
| 372 | short[][] data = ((ShortLookupTable)table).getTable(); | ||
| 373 | for (int i = 0; i < numBands; i++) { | ||
| 374 | buf.put(data[i]); | ||
| 375 | } | ||
| 376 | } else { | ||
| 377 | byte[][] data = ((ByteLookupTable)table).getTable(); | ||
| 378 | for (int i = 0; i < numBands; i++) { | ||
| 379 | buf.put(data[i]); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | if (padding != 0) { | ||
| 383 | buf.position(buf.position() + padding); | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | private static void disableLookupOp(RenderQueue rq) { | ||
| 388 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 389 | RenderBuffer buf = rq.getBuffer(); | ||
| 390 | rq.ensureCapacity(4); | ||
| 391 | buf.putInt(DISABLE_LOOKUP_OP); | ||
| 392 | } | ||
| 393 | } | ||
Binary file not shown.
| @@ -0,0 +1,470 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 2008, 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.AlphaComposite; | ||
| 29 | import java.awt.Color; | ||
| 30 | import java.awt.Composite; | ||
| 31 | import java.awt.Paint; | ||
| 32 | import java.awt.geom.AffineTransform; | ||
| 33 | import sun.java2d.pipe.hw.AccelSurface; | ||
| 34 | import sun.java2d.InvalidPipeException; | ||
| 35 | import sun.java2d.SunGraphics2D; | ||
| 36 | import sun.java2d.loops.XORComposite; | ||
| 37 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 38 | import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Base context class for managing state in a single-threaded rendering | ||
| 42 | * environment. Each state-setting operation (e.g. SET_COLOR) is added to | ||
| 43 | * the provided RenderQueue, which will be processed at a later time by a | ||
| 44 | * single thread. Note that the RenderQueue lock must be acquired before | ||
| 45 | * calling the validate() method (or any other method in this class). See | ||
| 46 | * the RenderQueue class comments for a sample usage scenario. | ||
| 47 | * | ||
| 48 | * @see RenderQueue | ||
| 49 | */ | ||
| 50 | public abstract class BufferedContext { | ||
| 51 | |||
| 52 | /* | ||
| 53 | * The following flags help the internals of validate() determine | ||
| 54 | * the appropriate (meaning correct, or optimal) code path when | ||
| 55 | * setting up the current context. The flags can be bitwise OR'd | ||
| 56 | * together as needed. | ||
| 57 | */ | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Indicates that no flags are needed; take all default code paths. | ||
| 61 | */ | ||
| 62 | public static final int NO_CONTEXT_FLAGS = (0 << 0); | ||
| 63 | /** | ||
| 64 | * Indicates that the source surface (or color value, if it is a simple | ||
| 65 | * rendering operation) is opaque (has an alpha value of 1.0). If this | ||
| 66 | * flag is present, it allows us to disable blending in certain | ||
| 67 | * situations in order to improve performance. | ||
| 68 | */ | ||
| 69 | public static final int SRC_IS_OPAQUE = (1 << 0); | ||
| 70 | /** | ||
| 71 | * Indicates that the operation uses an alpha mask, which may determine | ||
| 72 | * the code path that is used when setting up the current paint state. | ||
| 73 | */ | ||
| 74 | public static final int USE_MASK = (1 << 1); | ||
| 75 | |||
| 76 | protected RenderQueue rq; | ||
| 77 | protected RenderBuffer buf; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * This is a reference to the most recently validated BufferedContext. If | ||
| 81 | * this value is null, it means that there is no current context. It is | ||
| 82 | * provided here so that validate() only needs to do a quick reference | ||
| 83 | * check to see if the BufferedContext passed to that method is the same | ||
| 84 | * as the one we've cached here. | ||
| 85 | */ | ||
| 86 | protected static BufferedContext currentContext; | ||
| 87 | |||
| 88 | private AccelSurface validatedSrcData; | ||
| 89 | private AccelSurface validatedDstData; | ||
| 90 | private Region validatedClip; | ||
| 91 | private Composite validatedComp; | ||
| 92 | private Paint validatedPaint; | ||
| 93 | // renamed from isValidatedPaintAColor as part of a work around for 6764257 | ||
| 94 | private boolean isValidatedPaintJustAColor; | ||
| 95 | private int validatedRGB; | ||
| 96 | private int validatedFlags; | ||
| 97 | private boolean xformInUse; | ||
| 98 | private int transX; | ||
| 99 | private int transY; | ||
| 100 | |||
| 101 | protected BufferedContext(RenderQueue rq) { | ||
| 102 | this.rq = rq; | ||
| 103 | this.buf = rq.getBuffer(); | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Fetches the BufferedContextContext associated with the dst. surface | ||
| 108 | * and validates the context using the given parameters. Most rendering | ||
| 109 | * operations will call this method first in order to set the necessary | ||
| 110 | * state before issuing rendering commands. | ||
| 111 | * | ||
| 112 | * Note: must be called while the RenderQueue lock is held. | ||
| 113 | * | ||
| 114 | * @throws InvalidPipeException if either src or dest surface is not valid | ||
| 115 | * or lost | ||
| 116 | * @see RenderQueue#lock | ||
| 117 | * @see RenderQueue#unlock | ||
| 118 | */ | ||
| 119 | public static void validateContext(AccelSurface srcData, | ||
| 120 | AccelSurface dstData, | ||
| 121 | Region clip, Composite comp, | ||
| 122 | AffineTransform xform, | ||
| 123 | Paint paint, SunGraphics2D sg2d, | ||
| 124 | int flags) | ||
| 125 | { | ||
| 126 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 127 | BufferedContext d3dc = dstData.getContext(); | ||
| 128 | d3dc.validate(srcData, dstData, | ||
| 129 | clip, comp, xform, paint, sg2d, flags); | ||
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * Fetches the BufferedContextassociated with the surface | ||
| 134 | * and disables all context state settings. | ||
| 135 | * | ||
| 136 | * Note: must be called while the RenderQueue lock is held. | ||
| 137 | * | ||
| 138 | * @throws InvalidPipeException if the surface is not valid | ||
| 139 | * or lost | ||
| 140 | * @see RenderQueue#lock | ||
| 141 | * @see RenderQueue#unlock | ||
| 142 | */ | ||
| 143 | public static void validateContext(AccelSurface surface) { | ||
| 144 | // assert rt.lock.isHeldByCurrentThread(); | ||
| 145 | validateContext(surface, surface, | ||
| 146 | null, null, null, null, null, NO_CONTEXT_FLAGS); | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * Validates the given parameters against the current state for this | ||
| 151 | * context. If this context is not current, it will be made current | ||
| 152 | * for the given source and destination surfaces, and the viewport will | ||
| 153 | * be updated. Then each part of the context state (clip, composite, | ||
| 154 | * etc.) is checked against the previous value. If the value has changed | ||
| 155 | * since the last call to validate(), it will be updated accordingly. | ||
| 156 | * | ||
| 157 | * Note that the SunGraphics2D parameter is only used for the purposes | ||
| 158 | * of validating a (non-null) Paint parameter. In all other cases it | ||
| 159 | * is safe to pass a null SunGraphics2D and it will be ignored. | ||
| 160 | * | ||
| 161 | * Note: must be called while the RenderQueue lock is held. | ||
| 162 | * | ||
| 163 | * @throws InvalidPipeException if either src or dest surface is not valid | ||
| 164 | * or lost | ||
| 165 | */ | ||
| 166 | public void validate(AccelSurface srcData, AccelSurface dstData, | ||
| 167 | Region clip, Composite comp, | ||
| 168 | AffineTransform xform, | ||
| 169 | Paint paint, SunGraphics2D sg2d, int flags) | ||
| 170 | { | ||
| 171 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 172 | |||
| 173 | boolean updateClip = false; | ||
| 174 | boolean updatePaint = false; | ||
| 175 | |||
| 176 | if (!dstData.isValid() || | ||
| 177 | dstData.isSurfaceLost() || srcData.isSurfaceLost()) | ||
| 178 | { | ||
| 179 | invalidateContext(); | ||
| 180 | throw new InvalidPipeException("bounds changed or surface lost"); | ||
| 181 | } | ||
| 182 | |||
| 183 | if (paint instanceof Color) { | ||
| 184 | // REMIND: not 30-bit friendly | ||
| 185 | int newRGB = ((Color)paint).getRGB(); | ||
| 186 | if (isValidatedPaintJustAColor) { | ||
| 187 | if (newRGB != validatedRGB) { | ||
| 188 | validatedRGB = newRGB; | ||
| 189 | updatePaint = true; | ||
| 190 | } | ||
| 191 | } else { | ||
| 192 | validatedRGB = newRGB; | ||
| 193 | updatePaint = true; | ||
| 194 | isValidatedPaintJustAColor = true; | ||
| 195 | } | ||
| 196 | } else if (validatedPaint != paint) { | ||
| 197 | updatePaint = true; | ||
| 198 | // this should be set when we are switching from paint to color | ||
| 199 | // in which case this condition will be true | ||
| 200 | isValidatedPaintJustAColor = false; | ||
| 201 | } | ||
| 202 | |||
| 203 | if ((currentContext != this) || | ||
| 204 | (srcData != validatedSrcData) || | ||
| 205 | (dstData != validatedDstData)) | ||
| 206 | { | ||
| 207 | if (dstData != validatedDstData) { | ||
| 208 | // the clip is dependent on the destination surface, so we | ||
| 209 | // need to update it if we have a new destination surface | ||
| 210 | updateClip = true; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (paint == null) { | ||
| 214 | // make sure we update the color state (otherwise, it might | ||
| 215 | // not be updated if this is the first time the context | ||
| 216 | // is being validated) | ||
| 217 | updatePaint = true; | ||
| 218 | } | ||
| 219 | |||
| 220 | // update the current source and destination surfaces | ||
| 221 | setSurfaces(srcData, dstData); | ||
| 222 | |||
| 223 | currentContext = this; | ||
| 224 | validatedSrcData = srcData; | ||
| 225 | validatedDstData = dstData; | ||
| 226 | } | ||
| 227 | |||
| 228 | // validate clip | ||
| 229 | if ((clip != validatedClip) || updateClip) { | ||
| 230 | if (clip != null) { | ||
| 231 | if (updateClip || | ||
| 232 | validatedClip == null || | ||
| 233 | !(validatedClip.isRectangular() && clip.isRectangular()) || | ||
| 234 | ((clip.getLoX() != validatedClip.getLoX() || | ||
| 235 | clip.getLoY() != validatedClip.getLoY() || | ||
| 236 | clip.getHiX() != validatedClip.getHiX() || | ||
| 237 | clip.getHiY() != validatedClip.getHiY()))) | ||
| 238 | { | ||
| 239 | setClip(clip); | ||
| 240 | } | ||
| 241 | } else { | ||
| 242 | resetClip(); | ||
| 243 | } | ||
| 244 | validatedClip = clip; | ||
| 245 | } | ||
| 246 | |||
| 247 | // validate composite (note that a change in the context flags | ||
| 248 | // may require us to update the composite state, even if the | ||
| 249 | // composite has not changed) | ||
| 250 | if ((comp != validatedComp) || (flags != validatedFlags)) { | ||
| 251 | if (comp != null) { | ||
| 252 | setComposite(comp, flags); | ||
| 253 | } else { | ||
| 254 | resetComposite(); | ||
| 255 | } | ||
| 256 | // the paint state is dependent on the composite state, so make | ||
| 257 | // sure we update the color below | ||
| 258 | updatePaint = true; | ||
| 259 | validatedComp = comp; | ||
| 260 | validatedFlags = flags; | ||
| 261 | } | ||
| 262 | |||
| 263 | // validate transform | ||
| 264 | boolean txChanged = false; | ||
| 265 | if (xform == null) { | ||
| 266 | if (xformInUse) { | ||
| 267 | resetTransform(); | ||
| 268 | xformInUse = false; | ||
| 269 | txChanged = true; | ||
| 270 | } else if (sg2d != null) { | ||
| 271 | if (transX != sg2d.transX || transY != sg2d.transY) { | ||
| 272 | txChanged = true; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | if (sg2d != null) { | ||
| 276 | transX = sg2d.transX; | ||
| 277 | transY = sg2d.transY; | ||
| 278 | } | ||
| 279 | } else { | ||
| 280 | setTransform(xform); | ||
| 281 | xformInUse = true; | ||
| 282 | txChanged = true; | ||
| 283 | } | ||
| 284 | // non-Color paints may require paint revalidation | ||
| 285 | if (!isValidatedPaintJustAColor && txChanged) { | ||
| 286 | updatePaint = true; | ||
| 287 | } | ||
| 288 | |||
| 289 | // validate paint | ||
| 290 | if (updatePaint) { | ||
| 291 | if (paint != null) { | ||
| 292 | BufferedPaints.setPaint(rq, sg2d, paint, flags); | ||
| 293 | } else { | ||
| 294 | BufferedPaints.resetPaint(rq); | ||
| 295 | } | ||
| 296 | validatedPaint = paint; | ||
| 297 | } | ||
| 298 | |||
| 299 | // mark dstData dirty | ||
| 300 | // REMIND: is this really needed now? we do it in SunGraphics2D.. | ||
| 301 | dstData.markDirty(); | ||
| 302 | } | ||
| 303 | |||
| 304 | /** | ||
| 305 | * Invalidates the surfaces associated with this context. This is | ||
| 306 | * useful when the context is no longer needed, and we want to break | ||
| 307 | * the chain caused by these surface references. | ||
| 308 | * | ||
| 309 | * Note: must be called while the RenderQueue lock is held. | ||
| 310 | * | ||
| 311 | * @see RenderQueue#lock | ||
| 312 | * @see RenderQueue#unlock | ||
| 313 | */ | ||
| 314 | public void invalidateSurfaces() { | ||
| 315 | validatedSrcData = null; | ||
| 316 | validatedDstData = null; | ||
| 317 | } | ||
| 318 | |||
| 319 | private void setSurfaces(AccelSurface srcData, | ||
| 320 | AccelSurface dstData) | ||
| 321 | { | ||
| 322 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 323 | rq.ensureCapacityAndAlignment(20, 4); | ||
| 324 | buf.putInt(SET_SURFACES); | ||
| 325 | buf.putLong(srcData.getNativeOps()); | ||
| 326 | buf.putLong(dstData.getNativeOps()); | ||
| 327 | } | ||
| 328 | |||
| 329 | private void resetClip() { | ||
| 330 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 331 | rq.ensureCapacity(4); | ||
| 332 | buf.putInt(RESET_CLIP); | ||
| 333 | } | ||
| 334 | |||
| 335 | private void setClip(Region clip) { | ||
| 336 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 337 | if (clip.isRectangular()) { | ||
| 338 | rq.ensureCapacity(20); | ||
| 339 | buf.putInt(SET_RECT_CLIP); | ||
| 340 | buf.putInt(clip.getLoX()).putInt(clip.getLoY()); | ||
| 341 | buf.putInt(clip.getHiX()).putInt(clip.getHiY()); | ||
| 342 | } else { | ||
| 343 | rq.ensureCapacity(28); // so that we have room for at least a span | ||
| 344 | buf.putInt(BEGIN_SHAPE_CLIP); | ||
| 345 | buf.putInt(SET_SHAPE_CLIP_SPANS); | ||
| 346 | // include a placeholder for the span count | ||
| 347 | int countIndex = buf.position(); | ||
| 348 | buf.putInt(0); | ||
| 349 | int spanCount = 0; | ||
| 350 | int remainingSpans = buf.remaining() / BYTES_PER_SPAN; | ||
| 351 | int span[] = new int[4]; | ||
| 352 | SpanIterator si = clip.getSpanIterator(); | ||
| 353 | while (si.nextSpan(span)) { | ||
| 354 | if (remainingSpans == 0) { | ||
| 355 | buf.putInt(countIndex, spanCount); | ||
| 356 | rq.flushNow(); | ||
| 357 | buf.putInt(SET_SHAPE_CLIP_SPANS); | ||
| 358 | countIndex = buf.position(); | ||
| 359 | buf.putInt(0); | ||
| 360 | spanCount = 0; | ||
| 361 | remainingSpans = buf.remaining() / BYTES_PER_SPAN; | ||
| 362 | } | ||
| 363 | buf.putInt(span[0]); // x1 | ||
| 364 | buf.putInt(span[1]); // y1 | ||
| 365 | buf.putInt(span[2]); // x2 | ||
| 366 | buf.putInt(span[3]); // y2 | ||
| 367 | spanCount++; | ||
| 368 | remainingSpans--; | ||
| 369 | } | ||
| 370 | buf.putInt(countIndex, spanCount); | ||
| 371 | rq.ensureCapacity(4); | ||
| 372 | buf.putInt(END_SHAPE_CLIP); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | private void resetComposite() { | ||
| 377 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 378 | rq.ensureCapacity(4); | ||
| 379 | buf.putInt(RESET_COMPOSITE); | ||
| 380 | } | ||
| 381 | |||
| 382 | private void setComposite(Composite comp, int flags) { | ||
| 383 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 384 | if (comp instanceof AlphaComposite) { | ||
| 385 | AlphaComposite ac = (AlphaComposite)comp; | ||
| 386 | rq.ensureCapacity(16); | ||
| 387 | buf.putInt(SET_ALPHA_COMPOSITE); | ||
| 388 | buf.putInt(ac.getRule()); | ||
| 389 | buf.putFloat(ac.getAlpha()); | ||
| 390 | buf.putInt(flags); | ||
| 391 | } else if (comp instanceof XORComposite) { | ||
| 392 | int xorPixel = ((XORComposite)comp).getXorPixel(); | ||
| 393 | rq.ensureCapacity(8); | ||
| 394 | buf.putInt(SET_XOR_COMPOSITE); | ||
| 395 | buf.putInt(xorPixel); | ||
| 396 | } else { | ||
| 397 | throw new InternalError("not yet implemented"); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | private void resetTransform() { | ||
| 402 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 403 | rq.ensureCapacity(4); | ||
| 404 | buf.putInt(RESET_TRANSFORM); | ||
| 405 | } | ||
| 406 | |||
| 407 | private void setTransform(AffineTransform xform) { | ||
| 408 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 409 | rq.ensureCapacityAndAlignment(52, 4); | ||
| 410 | buf.putInt(SET_TRANSFORM); | ||
| 411 | buf.putDouble(xform.getScaleX()); | ||
| 412 | buf.putDouble(xform.getShearY()); | ||
| 413 | buf.putDouble(xform.getShearX()); | ||
| 414 | buf.putDouble(xform.getScaleY()); | ||
| 415 | buf.putDouble(xform.getTranslateX()); | ||
| 416 | buf.putDouble(xform.getTranslateY()); | ||
| 417 | } | ||
| 418 | |||
| 419 | /** | ||
| 420 | * Resets this context's surfaces and all attributes. | ||
| 421 | * | ||
| 422 | * Note: must be called while the RenderQueue lock is held. | ||
| 423 | * | ||
| 424 | * @see RenderQueue#lock | ||
| 425 | * @see RenderQueue#unlock | ||
| 426 | */ | ||
| 427 | public void invalidateContext() { | ||
| 428 | resetTransform(); | ||
| 429 | resetComposite(); | ||
| 430 | resetClip(); | ||
| 431 | BufferedPaints.resetPaint(rq); | ||
| 432 | invalidateSurfaces(); | ||
| 433 | validatedComp = null; | ||
| 434 | validatedClip = null; | ||
| 435 | validatedPaint = null; | ||
| 436 | isValidatedPaintJustAColor = false; | ||
| 437 | xformInUse = false; | ||
| 438 | } | ||
| 439 | |||
| 440 | /** | ||
| 441 | * Returns a singleton {@code RenderQueue} object used by the rendering | ||
| 442 | * pipeline. | ||
| 443 | * | ||
| 444 | * @return a render queue | ||
| 445 | * @see RenderQueue | ||
| 446 | */ | ||
| 447 | public abstract RenderQueue getRenderQueue(); | ||
| 448 | |||
| 449 | /** | ||
| 450 | * Saves the the state of this context. | ||
| 451 | * It may reset the current context. | ||
| 452 | * | ||
| 453 | * Note: must be called while the RenderQueue lock is held. | ||
| 454 | * | ||
| 455 | * @see RenderQueue#lock | ||
| 456 | * @see RenderQueue#unlock | ||
| 457 | */ | ||
| 458 | public abstract void saveState(); | ||
| 459 | |||
| 460 | /** | ||
| 461 | * Restores the native state of this context. | ||
| 462 | * It may reset the current context. | ||
| 463 | * | ||
| 464 | * Note: must be called while the RenderQueue lock is held. | ||
| 465 | * | ||
| 466 | * @see RenderQueue#lock | ||
| 467 | * @see RenderQueue#unlock | ||
| 468 | */ | ||
| 469 | public abstract void restoreState(); | ||
| 470 | } | ||
| @@ -0,0 +1,163 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 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.AlphaComposite; | ||
| 29 | import java.awt.Composite; | ||
| 30 | import sun.java2d.SurfaceData; | ||
| 31 | import sun.java2d.loops.Blit; | ||
| 32 | import sun.java2d.loops.CompositeType; | ||
| 33 | import sun.java2d.loops.MaskBlit; | ||
| 34 | import sun.java2d.loops.SurfaceType; | ||
| 35 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * The MaskBlit operation is expressed as: | ||
| 39 | * dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA)) | ||
| 40 | * | ||
| 41 | * The OGL/D3D implementation of the MaskBlit operation differs from the above | ||
| 42 | * equation because it is not possible to perform such a complex operation in | ||
| 43 | * OpenGL/Direct3D (without the use of advanced techniques like fragment | ||
| 44 | * shaders and multitexturing). Therefore, the BufferedMaskBlit operation | ||
| 45 | * is expressed as: | ||
| 46 | * dst = (src * pathA) <SrcOver> dst | ||
| 47 | * | ||
| 48 | * This simplified formula is only equivalent to the "true" MaskBlit equation | ||
| 49 | * in the following situations: | ||
| 50 | * - <MODE> is SrcOver | ||
| 51 | * - <MODE> is Src, extra alpha == 1.0, and the source surface is opaque | ||
| 52 | * | ||
| 53 | * Therefore, we register BufferedMaskBlit primitives for only the SurfaceType | ||
| 54 | * and CompositeType restrictions mentioned above. In addition for the Src | ||
| 55 | * case, we must override the composite with a SrcOver (no extra alpha) | ||
| 56 | * instance, so that we set up the OpenGL/Direct3D blending mode to match the | ||
| 57 | * BufferedMaskBlit equation. | ||
| 58 | */ | ||
| 59 | public abstract class BufferedMaskBlit extends MaskBlit { | ||
| 60 | |||
| 61 | private static final int ST_INT_ARGB = 0; | ||
| 62 | private static final int ST_INT_ARGB_PRE = 1; | ||
| 63 | private static final int ST_INT_RGB = 2; | ||
| 64 | private static final int ST_INT_BGR = 3; | ||
| 65 | |||
| 66 | private final RenderQueue rq; | ||
| 67 | private final int srcTypeVal; | ||
| 68 | private Blit blitop; | ||
| 69 | |||
| 70 | protected BufferedMaskBlit(RenderQueue rq, | ||
| 71 | SurfaceType srcType, | ||
| 72 | CompositeType compType, | ||
| 73 | SurfaceType dstType) | ||
| 74 | { | ||
| 75 | super(srcType, compType, dstType); | ||
| 76 | this.rq = rq; | ||
| 77 | if (srcType == SurfaceType.IntArgb) { | ||
| 78 | this.srcTypeVal = ST_INT_ARGB; | ||
| 79 | } else if (srcType == SurfaceType.IntArgbPre) { | ||
| 80 | this.srcTypeVal = ST_INT_ARGB_PRE; | ||
| 81 | } else if (srcType == SurfaceType.IntRgb) { | ||
| 82 | this.srcTypeVal = ST_INT_RGB; | ||
| 83 | } else if (srcType == SurfaceType.IntBgr) { | ||
| 84 | this.srcTypeVal = ST_INT_BGR; | ||
| 85 | } else { | ||
| 86 | throw new InternalError("unrecognized source surface type"); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | @Override | ||
| 91 | public void MaskBlit(SurfaceData src, SurfaceData dst, | ||
| 92 | Composite comp, Region clip, | ||
| 93 | int srcx, int srcy, | ||
| 94 | int dstx, int dsty, | ||
| 95 | int width, int height, | ||
| 96 | byte[] mask, int maskoff, int maskscan) | ||
| 97 | { | ||
| 98 | if (width <= 0 || height <= 0) { | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | |||
| 102 | if (mask == null) { | ||
| 103 | // no mask involved; delegate to regular blit loop | ||
| 104 | if (blitop == null) { | ||
| 105 | blitop = Blit.getFromCache(src.getSurfaceType(), | ||
| 106 | CompositeType.AnyAlpha, | ||
| 107 | this.getDestType()); | ||
| 108 | } | ||
| 109 | blitop.Blit(src, dst, | ||
| 110 | comp, clip, | ||
| 111 | srcx, srcy, dstx, dsty, | ||
| 112 | width, height); | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | |||
| 116 | AlphaComposite acomp = (AlphaComposite)comp; | ||
| 117 | if (acomp.getRule() != AlphaComposite.SRC_OVER) { | ||
| 118 | comp = AlphaComposite.SrcOver; | ||
| 119 | } | ||
| 120 | |||
| 121 | rq.lock(); | ||
| 122 | try { | ||
| 123 | validateContext(dst, comp, clip); | ||
| 124 | |||
| 125 | RenderBuffer buf = rq.getBuffer(); | ||
| 126 | int totalBytesRequired = 20 + (width * height * 4); | ||
| 127 | |||
| 128 | /* | ||
| 129 | * REMIND: we should fix this so that it works with tiles that | ||
| 130 | * are larger than the entire buffer, but the native | ||
| 131 | * OGL/D3DMaskBlit isn't even prepared for tiles larger | ||
| 132 | * than 32x32 pixels, so there's no urgency here... | ||
| 133 | */ | ||
| 134 | rq.ensureCapacity(totalBytesRequired); | ||
| 135 | |||
| 136 | // enqueue parameters and tile pixels | ||
| 137 | int newpos = enqueueTile(buf.getAddress(), buf.position(), | ||
| 138 | src, src.getNativeOps(), srcTypeVal, | ||
| 139 | mask, mask.length, maskoff, maskscan, | ||
| 140 | srcx, srcy, dstx, dsty, | ||
| 141 | width, height); | ||
| 142 | |||
| 143 | buf.position(newpos); | ||
| 144 | } finally { | ||
| 145 | rq.unlock(); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | private native int enqueueTile(long buf, int bpos, | ||
| 150 | SurfaceData srcData, | ||
| 151 | long pSrcOps, int srcType, | ||
| 152 | byte[] mask, int masklen, | ||
| 153 | int maskoff, int maskscan, | ||
| 154 | int srcx, int srcy, int dstx, int dsty, | ||
| 155 | int width, int height); | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Validates the context state using the given destination surface | ||
| 159 | * and composite/clip values. | ||
| 160 | */ | ||
| 161 | protected abstract void validateContext(SurfaceData dstData, | ||
| 162 | Composite comp, Region clip); | ||
| 163 | } | ||
| @@ -0,0 +1,153 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 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.AlphaComposite; | ||
| 29 | import java.awt.Composite; | ||
| 30 | import sun.java2d.SunGraphics2D; | ||
| 31 | import sun.java2d.SurfaceData; | ||
| 32 | import sun.java2d.loops.CompositeType; | ||
| 33 | import sun.java2d.loops.MaskFill; | ||
| 34 | import sun.java2d.loops.SurfaceType; | ||
| 35 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * The MaskFill operation is expressed as: | ||
| 39 | * dst = ((src <MODE> dst) * pathA) + (dst * (1 - pathA)) | ||
| 40 | * | ||
| 41 | * The OGL/D3D implementation of the MaskFill operation differs from the above | ||
| 42 | * equation because it is not possible to perform such a complex operation in | ||
| 43 | * OpenGL/Direct3D (without the use of advanced techniques like fragment | ||
| 44 | * shaders and multitexturing). Therefore, the BufferedMaskFill operation | ||
| 45 | * is expressed as: | ||
| 46 | * dst = (src * pathA) <SrcOver> dst | ||
| 47 | * | ||
| 48 | * This simplified formula is only equivalent to the "true" MaskFill equation | ||
| 49 | * in the following situations: | ||
| 50 | * - <MODE> is SrcOver | ||
| 51 | * - <MODE> is Src, extra alpha == 1.0, and the source paint is opaque | ||
| 52 | * | ||
| 53 | * Therefore, we register BufferedMaskFill primitives for only the SurfaceType | ||
| 54 | * and CompositeType restrictions mentioned above. In addition, for the | ||
| 55 | * SrcNoEa case we must override the incoming composite with a SrcOver (no | ||
| 56 | * extra alpha) instance, so that we set up the OpenGL/Direct3D blending | ||
| 57 | * mode to match the BufferedMaskFill equation. | ||
| 58 | */ | ||
| 59 | public abstract class BufferedMaskFill extends MaskFill { | ||
| 60 | |||
| 61 | protected final RenderQueue rq; | ||
| 62 | |||
| 63 | protected BufferedMaskFill(RenderQueue rq, | ||
| 64 | SurfaceType srcType, | ||
| 65 | CompositeType compType, | ||
| 66 | SurfaceType dstType) | ||
| 67 | { | ||
| 68 | super(srcType, compType, dstType); | ||
| 69 | this.rq = rq; | ||
| 70 | } | ||
| 71 | |||
| 72 | @Override | ||
| 73 | public void MaskFill(SunGraphics2D sg2d, SurfaceData sData, | ||
| 74 | Composite comp, | ||
| 75 | final int x, final int y, final int w, final int h, | ||
| 76 | final byte[] mask, | ||
| 77 | final int maskoff, final int maskscan) | ||
| 78 | { | ||
| 79 | AlphaComposite acomp = (AlphaComposite)comp; | ||
| 80 | if (acomp.getRule() != AlphaComposite.SRC_OVER) { | ||
| 81 | comp = AlphaComposite.SrcOver; | ||
| 82 | } | ||
| 83 | |||
| 84 | rq.lock(); | ||
| 85 | try { | ||
| 86 | validateContext(sg2d, comp, BufferedContext.USE_MASK); | ||
| 87 | |||
| 88 | // we adjust the mask length so that the mask ends on a | ||
| 89 | // 4-byte boundary | ||
| 90 | int maskBytesRequired; | ||
| 91 | if (mask != null) { | ||
| 92 | // we adjust the mask length so that the mask ends on a | ||
| 93 | // 4-byte boundary | ||
| 94 | maskBytesRequired = (mask.length + 3) & (~3); | ||
| 95 | } else { | ||
| 96 | // mask not needed | ||
| 97 | maskBytesRequired = 0; | ||
| 98 | } | ||
| 99 | int totalBytesRequired = 32 + maskBytesRequired; | ||
| 100 | |||
| 101 | RenderBuffer buf = rq.getBuffer(); | ||
| 102 | if (totalBytesRequired <= buf.capacity()) { | ||
| 103 | if (totalBytesRequired > buf.remaining()) { | ||
| 104 | // process the queue first and then enqueue the mask | ||
| 105 | rq.flushNow(); | ||
| 106 | } | ||
| 107 | |||
| 108 | buf.putInt(MASK_FILL); | ||
| 109 | // enqueue parameters | ||
| 110 | buf.putInt(x).putInt(y).putInt(w).putInt(h); | ||
| 111 | buf.putInt(maskoff); | ||
| 112 | buf.putInt(maskscan); | ||
| 113 | buf.putInt(maskBytesRequired); | ||
| 114 | if (mask != null) { | ||
| 115 | // enqueue the mask | ||
| 116 | int padding = maskBytesRequired - mask.length; | ||
| 117 | buf.put(mask); | ||
| 118 | if (padding != 0) { | ||
| 119 | buf.position(buf.position() + padding); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } else { | ||
| 123 | // queue is too small to accomodate entire mask; perform | ||
| 124 | // the operation directly on the queue flushing thread | ||
| 125 | rq.flushAndInvokeNow(new Runnable() { | ||
| 126 | public void run() { | ||
| 127 | maskFill(x, y, w, h, | ||
| 128 | maskoff, maskscan, mask.length, mask); | ||
| 129 | } | ||
| 130 | }); | ||
| 131 | } | ||
| 132 | } finally { | ||
| 133 | rq.unlock(); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * Called as a separate Runnable when the operation is too large to fit | ||
| 139 | * on the RenderQueue. The OGL/D3D pipelines each have their own (small) | ||
| 140 | * native implementation of this method. | ||
| 141 | */ | ||
| 142 | protected abstract void maskFill(int x, int y, int w, int h, | ||
| 143 | int maskoff, int maskscan, int masklen, | ||
| 144 | byte[] mask); | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Validates the state in the provided SunGraphics2D object and sets up | ||
| 148 | * any special resources for this operation (e.g. enabling gradient | ||
| 149 | * shading). | ||
| 150 | */ | ||
| 151 | protected abstract void validateContext(SunGraphics2D sg2d, | ||
| 152 | Composite comp, int ctxflags); | ||
| 153 | } | ||
Binary file not shown.
| @@ -0,0 +1,99 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 2008, 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 | public class BufferedOpCodes { | ||
| 29 | // draw ops | ||
| 30 | public static final int DRAW_LINE = 10; | ||
| 31 | public static final int DRAW_RECT = 11; | ||
| 32 | public static final int DRAW_POLY = 12; | ||
| 33 | public static final int DRAW_PIXEL = 13; | ||
| 34 | public static final int DRAW_SCANLINES = 14; | ||
| 35 | public static final int DRAW_PARALLELOGRAM = 15; | ||
| 36 | public static final int DRAW_AAPARALLELOGRAM = 16; | ||
| 37 | |||
| 38 | // fill ops | ||
| 39 | public static final int FILL_RECT = 20; | ||
| 40 | public static final int FILL_SPANS = 21; | ||
| 41 | public static final int FILL_PARALLELOGRAM = 22; | ||
| 42 | public static final int FILL_AAPARALLELOGRAM = 23; | ||
| 43 | |||
| 44 | // copy-related ops | ||
| 45 | public static final int COPY_AREA = 30; | ||
| 46 | public static final int BLIT = 31; | ||
| 47 | public static final int MASK_FILL = 32; | ||
| 48 | public static final int MASK_BLIT = 33; | ||
| 49 | public static final int SURFACE_TO_SW_BLIT = 34; | ||
| 50 | |||
| 51 | // text-related ops | ||
| 52 | public static final int DRAW_GLYPH_LIST = 40; | ||
| 53 | |||
| 54 | // state-related ops | ||
| 55 | public static final int SET_RECT_CLIP = 51; | ||
| 56 | public static final int BEGIN_SHAPE_CLIP = 52; | ||
| 57 | public static final int SET_SHAPE_CLIP_SPANS = 53; | ||
| 58 | public static final int END_SHAPE_CLIP = 54; | ||
| 59 | public static final int RESET_CLIP = 55; | ||
| 60 | public static final int SET_ALPHA_COMPOSITE = 56; | ||
| 61 | public static final int SET_XOR_COMPOSITE = 57; | ||
| 62 | public static final int RESET_COMPOSITE = 58; | ||
| 63 | public static final int SET_TRANSFORM = 59; | ||
| 64 | public static final int RESET_TRANSFORM = 60; | ||
| 65 | |||
| 66 | // context-related ops | ||
| 67 | public static final int SET_SURFACES = 70; | ||
| 68 | public static final int SET_SCRATCH_SURFACE = 71; | ||
| 69 | public static final int FLUSH_SURFACE = 72; | ||
| 70 | public static final int DISPOSE_SURFACE = 73; | ||
| 71 | public static final int DISPOSE_CONFIG = 74; | ||
| 72 | public static final int INVALIDATE_CONTEXT = 75; | ||
| 73 | public static final int SYNC = 76; | ||
| 74 | public static final int RESTORE_DEVICES = 77; | ||
| 75 | public static final int SAVE_STATE = 78; | ||
| 76 | public static final int RESTORE_STATE = 79; | ||
| 77 | |||
| 78 | // multibuffering ops | ||
| 79 | public static final int SWAP_BUFFERS = 80; | ||
| 80 | |||
| 81 | // special no-op op code (mainly used for achieving 8-byte alignment) | ||
| 82 | public static final int NOOP = 90; | ||
| 83 | |||
| 84 | // paint-related ops | ||
| 85 | public static final int RESET_PAINT = 100; | ||
| 86 | public static final int SET_COLOR = 101; | ||
| 87 | public static final int SET_GRADIENT_PAINT = 102; | ||
| 88 | public static final int SET_LINEAR_GRADIENT_PAINT = 103; | ||
| 89 | public static final int SET_RADIAL_GRADIENT_PAINT = 104; | ||
| 90 | public static final int SET_TEXTURE_PAINT = 105; | ||
| 91 | |||
| 92 | // BufferedImageOp-related ops | ||
| 93 | public static final int ENABLE_CONVOLVE_OP = 120; | ||
| 94 | public static final int DISABLE_CONVOLVE_OP = 121; | ||
| 95 | public static final int ENABLE_RESCALE_OP = 122; | ||
| 96 | public static final int DISABLE_RESCALE_OP = 123; | ||
| 97 | public static final int ENABLE_LOOKUP_OP = 124; | ||
| 98 | public static final int DISABLE_LOOKUP_OP = 125; | ||
| 99 | } | ||
Binary file not shown.
| @@ -0,0 +1,533 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 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.pipe; | ||
| 27 | |||
| 28 | import java.awt.Color; | ||
| 29 | import java.awt.GradientPaint; | ||
| 30 | import java.awt.LinearGradientPaint; | ||
| 31 | import java.awt.MultipleGradientPaint; | ||
| 32 | import java.awt.MultipleGradientPaint.ColorSpaceType; | ||
| 33 | import java.awt.MultipleGradientPaint.CycleMethod; | ||
| 34 | import java.awt.Paint; | ||
| 35 | import java.awt.RadialGradientPaint; | ||
| 36 | import java.awt.TexturePaint; | ||
| 37 | import java.awt.geom.AffineTransform; | ||
| 38 | import java.awt.geom.Point2D; | ||
| 39 | import java.awt.geom.Rectangle2D; | ||
| 40 | import java.awt.image.AffineTransformOp; | ||
| 41 | import java.awt.image.BufferedImage; | ||
| 42 | import sun.awt.image.PixelConverter; | ||
| 43 | import sun.java2d.SunGraphics2D; | ||
| 44 | import sun.java2d.SurfaceData; | ||
| 45 | import sun.java2d.loops.CompositeType; | ||
| 46 | import sun.java2d.loops.SurfaceType; | ||
| 47 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 48 | |||
| 49 | public class BufferedPaints { | ||
| 50 | |||
| 51 | static void setPaint(RenderQueue rq, SunGraphics2D sg2d, | ||
| 52 | Paint paint, int ctxflags) | ||
| 53 | { | ||
| 54 | if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { | ||
| 55 | setColor(rq, sg2d.pixel); | ||
| 56 | } else { | ||
| 57 | boolean useMask = (ctxflags & BufferedContext.USE_MASK) != 0; | ||
| 58 | switch (sg2d.paintState) { | ||
| 59 | case SunGraphics2D.PAINT_GRADIENT: | ||
| 60 | setGradientPaint(rq, sg2d, | ||
| 61 | (GradientPaint)paint, useMask); | ||
| 62 | break; | ||
| 63 | case SunGraphics2D.PAINT_LIN_GRADIENT: | ||
| 64 | setLinearGradientPaint(rq, sg2d, | ||
| 65 | (LinearGradientPaint)paint, useMask); | ||
| 66 | break; | ||
| 67 | case SunGraphics2D.PAINT_RAD_GRADIENT: | ||
| 68 | setRadialGradientPaint(rq, sg2d, | ||
| 69 | (RadialGradientPaint)paint, useMask); | ||
| 70 | break; | ||
| 71 | case SunGraphics2D.PAINT_TEXTURE: | ||
| 72 | setTexturePaint(rq, sg2d, | ||
| 73 | (TexturePaint)paint, useMask); | ||
| 74 | break; | ||
| 75 | default: | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | static void resetPaint(RenderQueue rq) { | ||
| 82 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 83 | rq.ensureCapacity(4); | ||
| 84 | RenderBuffer buf = rq.getBuffer(); | ||
| 85 | buf.putInt(RESET_PAINT); | ||
| 86 | } | ||
| 87 | |||
| 88 | /****************************** Color support *******************************/ | ||
| 89 | |||
| 90 | private static void setColor(RenderQueue rq, int pixel) { | ||
| 91 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 92 | rq.ensureCapacity(8); | ||
| 93 | RenderBuffer buf = rq.getBuffer(); | ||
| 94 | buf.putInt(SET_COLOR); | ||
| 95 | buf.putInt(pixel); | ||
| 96 | } | ||
| 97 | |||
| 98 | /************************* GradientPaint support ****************************/ | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Note: This code is factored out into a separate static method | ||
| 102 | * so that it can be shared by both the Gradient and LinearGradient | ||
| 103 | * implementations. LinearGradient uses this code (for the | ||
| 104 | * two-color sRGB case only) because it can be much faster than the | ||
| 105 | * equivalent implementation that uses fragment shaders. | ||
| 106 | * | ||
| 107 | * We use OpenGL's texture coordinate generator to automatically | ||
| 108 | * apply a smooth gradient (either cyclic or acyclic) to the geometry | ||
| 109 | * being rendered. This technique is almost identical to the one | ||
| 110 | * described in the comments for BufferedPaints.setTexturePaint(), | ||
| 111 | * except the calculations take place in one dimension instead of two. | ||
| 112 | * Instead of an anchor rectangle in the TexturePaint case, we use | ||
| 113 | * the vector between the two GradientPaint end points in our | ||
| 114 | * calculations. The generator uses a single plane equation that | ||
| 115 | * takes the (x,y) location (in device space) of the fragment being | ||
| 116 | * rendered to calculate a (u) texture coordinate for that fragment: | ||
| 117 | * u = Ax + By + Cz + Dw | ||
| 118 | * | ||
| 119 | * The gradient renderer uses a two-pixel 1D texture where the first | ||
| 120 | * pixel contains the first GradientPaint color, and the second pixel | ||
| 121 | * contains the second GradientPaint color. (Note that we use the | ||
| 122 | * GL_CLAMP_TO_EDGE wrapping mode for acyclic gradients so that we | ||
| 123 | * clamp the colors properly at the extremes.) The following diagram | ||
| 124 | * attempts to show the layout of the texture containing the two | ||
| 125 | * GradientPaint colors (C1 and C2): | ||
| 126 | * | ||
| 127 | * +-----------------+ | ||
| 128 | * | C1 | C2 | | ||
| 129 | * | | | | ||
| 130 | * +-----------------+ | ||
| 131 | * u=0 .25 .5 .75 1 | ||
| 132 | * | ||
| 133 | * We calculate our plane equation constants (A,B,D) such that u=0.25 | ||
| 134 | * corresponds to the first GradientPaint end point in user space and | ||
| 135 | * u=0.75 corresponds to the second end point. This is somewhat | ||
| 136 | * non-obvious, but since the gradient colors are generated by | ||
| 137 | * interpolating between C1 and C2, we want the pure color at the | ||
| 138 | * end points, and we will get the pure color only when u correlates | ||
| 139 | * to the center of a texel. The following chart shows the expected | ||
| 140 | * color for some sample values of u (where C' is the color halfway | ||
| 141 | * between C1 and C2): | ||
| 142 | * | ||
| 143 | * u value acyclic (GL_CLAMP) cyclic (GL_REPEAT) | ||
| 144 | * ------- ------------------ ------------------ | ||
| 145 | * -0.25 C1 C2 | ||
| 146 | * 0.0 C1 C' | ||
| 147 | * 0.25 C1 C1 | ||
| 148 | * 0.5 C' C' | ||
| 149 | * 0.75 C2 C2 | ||
| 150 | * 1.0 C2 C' | ||
| 151 | * 1.25 C2 C1 | ||
| 152 | * | ||
| 153 | * Original inspiration for this technique came from UMD's Agile2D | ||
| 154 | * project (GradientManager.java). | ||
| 155 | */ | ||
| 156 | private static void setGradientPaint(RenderQueue rq, AffineTransform at, | ||
| 157 | Color c1, Color c2, | ||
| 158 | Point2D pt1, Point2D pt2, | ||
| 159 | boolean isCyclic, boolean useMask) | ||
| 160 | { | ||
| 161 | // convert gradient colors to IntArgbPre format | ||
| 162 | PixelConverter pc = PixelConverter.ArgbPre.instance; | ||
| 163 | int pixel1 = pc.rgbToPixel(c1.getRGB(), null); | ||
| 164 | int pixel2 = pc.rgbToPixel(c2.getRGB(), null); | ||
| 165 | |||
| 166 | // calculate plane equation constants | ||
| 167 | double x = pt1.getX(); | ||
| 168 | double y = pt1.getY(); | ||
| 169 | at.translate(x, y); | ||
| 170 | // now gradient point 1 is at the origin | ||
| 171 | x = pt2.getX() - x; | ||
| 172 | y = pt2.getY() - y; | ||
| 173 | double len = Math.sqrt(x * x + y * y); | ||
| 174 | at.rotate(x, y); | ||
| 175 | // now gradient point 2 is on the positive x-axis | ||
| 176 | at.scale(2*len, 1); | ||
| 177 | // now gradient point 2 is at (0.5, 0) | ||
| 178 | at.translate(-0.25, 0); | ||
| 179 | // now gradient point 1 is at (0.25, 0), point 2 is at (0.75, 0) | ||
| 180 | |||
| 181 | double p0, p1, p3; | ||
| 182 | try { | ||
| 183 | at.invert(); | ||
| 184 | p0 = at.getScaleX(); | ||
| 185 | p1 = at.getShearX(); | ||
| 186 | p3 = at.getTranslateX(); | ||
| 187 | } catch (java.awt.geom.NoninvertibleTransformException e) { | ||
| 188 | p0 = p1 = p3 = 0.0; | ||
| 189 | } | ||
| 190 | |||
| 191 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 192 | rq.ensureCapacityAndAlignment(44, 12); | ||
| 193 | RenderBuffer buf = rq.getBuffer(); | ||
| 194 | buf.putInt(SET_GRADIENT_PAINT); | ||
| 195 | buf.putInt(useMask ? 1 : 0); | ||
| 196 | buf.putInt(isCyclic ? 1 : 0); | ||
| 197 | buf.putDouble(p0).putDouble(p1).putDouble(p3); | ||
| 198 | buf.putInt(pixel1).putInt(pixel2); | ||
| 199 | } | ||
| 200 | |||
| 201 | private static void setGradientPaint(RenderQueue rq, | ||
| 202 | SunGraphics2D sg2d, | ||
| 203 | GradientPaint paint, | ||
| 204 | boolean useMask) | ||
| 205 | { | ||
| 206 | setGradientPaint(rq, (AffineTransform)sg2d.transform.clone(), | ||
| 207 | paint.getColor1(), paint.getColor2(), | ||
| 208 | paint.getPoint1(), paint.getPoint2(), | ||
| 209 | paint.isCyclic(), useMask); | ||
| 210 | } | ||
| 211 | |||
| 212 | /************************** TexturePaint support ****************************/ | ||
| 213 | |||
| 214 | /** | ||
| 215 | * We use OpenGL's texture coordinate generator to automatically | ||
| 216 | * map the TexturePaint image to the geometry being rendered. The | ||
| 217 | * generator uses two separate plane equations that take the (x,y) | ||
| 218 | * location (in device space) of the fragment being rendered to | ||
| 219 | * calculate (u,v) texture coordinates for that fragment: | ||
| 220 | * u = Ax + By + Cz + Dw | ||
| 221 | * v = Ex + Fy + Gz + Hw | ||
| 222 | * | ||
| 223 | * Since we use a 2D orthographic projection, we can assume that z=0 | ||
| 224 | * and w=1 for any fragment. So we need to calculate appropriate | ||
| 225 | * values for the plane equation constants (A,B,D) and (E,F,H) such | ||
| 226 | * that {u,v}=0 for the top-left of the TexturePaint's anchor | ||
| 227 | * rectangle and {u,v}=1 for the bottom-right of the anchor rectangle. | ||
| 228 | * We can easily make the texture image repeat for {u,v} values | ||
| 229 | * outside the range [0,1] by specifying the GL_REPEAT texture wrap | ||
| 230 | * mode. | ||
| 231 | * | ||
| 232 | * Calculating the plane equation constants is surprisingly simple. | ||
| 233 | * We can think of it as an inverse matrix operation that takes | ||
| 234 | * device space coordinates and transforms them into user space | ||
| 235 | * coordinates that correspond to a location relative to the anchor | ||
| 236 | * rectangle. First, we translate and scale the current user space | ||
| 237 | * transform by applying the anchor rectangle bounds. We then take | ||
| 238 | * the inverse of this affine transform. The rows of the resulting | ||
| 239 | * inverse matrix correlate nicely to the plane equation constants | ||
| 240 | * we were seeking. | ||
| 241 | */ | ||
| 242 | private static void setTexturePaint(RenderQueue rq, | ||
| 243 | SunGraphics2D sg2d, | ||
| 244 | TexturePaint paint, | ||
| 245 | boolean useMask) | ||
| 246 | { | ||
| 247 | BufferedImage bi = paint.getImage(); | ||
| 248 | SurfaceData dstData = sg2d.surfaceData; | ||
| 249 | SurfaceData srcData = | ||
| 250 | dstData.getSourceSurfaceData(bi, sg2d.TRANSFORM_ISIDENT, | ||
| 251 | CompositeType.SrcOver, null); | ||
| 252 | boolean filter = | ||
| 253 | (sg2d.interpolationType != | ||
| 254 | AffineTransformOp.TYPE_NEAREST_NEIGHBOR); | ||
| 255 | |||
| 256 | // calculate plane equation constants | ||
| 257 | AffineTransform at = (AffineTransform)sg2d.transform.clone(); | ||
| 258 | Rectangle2D anchor = paint.getAnchorRect(); | ||
| 259 | at.translate(anchor.getX(), anchor.getY()); | ||
| 260 | at.scale(anchor.getWidth(), anchor.getHeight()); | ||
| 261 | |||
| 262 | double xp0, xp1, xp3, yp0, yp1, yp3; | ||
| 263 | try { | ||
| 264 | at.invert(); | ||
| 265 | xp0 = at.getScaleX(); | ||
| 266 | xp1 = at.getShearX(); | ||
| 267 | xp3 = at.getTranslateX(); | ||
| 268 | yp0 = at.getShearY(); | ||
| 269 | yp1 = at.getScaleY(); | ||
| 270 | yp3 = at.getTranslateY(); | ||
| 271 | } catch (java.awt.geom.NoninvertibleTransformException e) { | ||
| 272 | xp0 = xp1 = xp3 = yp0 = yp1 = yp3 = 0.0; | ||
| 273 | } | ||
| 274 | |||
| 275 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 276 | rq.ensureCapacityAndAlignment(68, 12); | ||
| 277 | RenderBuffer buf = rq.getBuffer(); | ||
| 278 | buf.putInt(SET_TEXTURE_PAINT); | ||
| 279 | buf.putInt(useMask ? 1 : 0); | ||
| 280 | buf.putInt(filter ? 1 : 0); | ||
| 281 | buf.putLong(srcData.getNativeOps()); | ||
| 282 | buf.putDouble(xp0).putDouble(xp1).putDouble(xp3); | ||
| 283 | buf.putDouble(yp0).putDouble(yp1).putDouble(yp3); | ||
| 284 | } | ||
| 285 | |||
| 286 | /****************** Shared MultipleGradientPaint support ********************/ | ||
| 287 | |||
| 288 | /** | ||
| 289 | * The maximum number of gradient "stops" supported by our native | ||
| 290 | * fragment shader implementations. | ||
| 291 | * | ||
| 292 | * This value has been empirically determined and capped to allow | ||
| 293 | * our native shaders to run on all shader-level graphics hardware, | ||
| 294 | * even on the older, more limited GPUs. Even the oldest Nvidia | ||
| 295 | * hardware could handle 16, or even 32 fractions without any problem. | ||
| 296 | * But the first-generation boards from ATI would fall back into | ||
| 297 | * software mode (which is unusably slow) for values larger than 12; | ||
| 298 | * it appears that those boards do not have enough native registers | ||
| 299 | * to support the number of array accesses required by our gradient | ||
| 300 | * shaders. So for now we will cap this value at 12, but we can | ||
| 301 | * re-evaluate this in the future as hardware becomes more capable. | ||
| 302 | */ | ||
| 303 | public static final int MULTI_MAX_FRACTIONS = 12; | ||
| 304 | |||
| 305 | /** | ||
| 306 | * Helper function to convert a color component in sRGB space to | ||
| 307 | * linear RGB space. Copied directly from the | ||
| 308 | * MultipleGradientPaintContext class. | ||
| 309 | */ | ||
| 310 | public static int convertSRGBtoLinearRGB(int color) { | ||
| 311 | float input, output; | ||
| 312 | |||
| 313 | input = color / 255.0f; | ||
| 314 | if (input <= 0.04045f) { | ||
| 315 | output = input / 12.92f; | ||
| 316 | } else { | ||
| 317 | output = (float)Math.pow((input + 0.055) / 1.055, 2.4); | ||
| 318 | } | ||
| 319 | |||
| 320 | return Math.round(output * 255.0f); | ||
| 321 | } | ||
| 322 | |||
| 323 | /** | ||
| 324 | * Helper function to convert a (non-premultiplied) Color in sRGB | ||
| 325 | * space to an IntArgbPre pixel value, optionally in linear RGB space. | ||
| 326 | * Based on the PixelConverter.ArgbPre.rgbToPixel() method. | ||
| 327 | */ | ||
| 328 | private static int colorToIntArgbPrePixel(Color c, boolean linear) { | ||
| 329 | int rgb = c.getRGB(); | ||
| 330 | if (!linear && ((rgb >> 24) == -1)) { | ||
| 331 | return rgb; | ||
| 332 | } | ||
| 333 | int a = rgb >>> 24; | ||
| 334 | int r = (rgb >> 16) & 0xff; | ||
| 335 | int g = (rgb >> 8) & 0xff; | ||
| 336 | int b = (rgb ) & 0xff; | ||
| 337 | if (linear) { | ||
| 338 | r = convertSRGBtoLinearRGB(r); | ||
| 339 | g = convertSRGBtoLinearRGB(g); | ||
| 340 | b = convertSRGBtoLinearRGB(b); | ||
| 341 | } | ||
| 342 | int a2 = a + (a >> 7); | ||
| 343 | r = (r * a2) >> 8; | ||
| 344 | g = (g * a2) >> 8; | ||
| 345 | b = (b * a2) >> 8; | ||
| 346 | return ((a << 24) | (r << 16) | (g << 8) | (b)); | ||
| 347 | } | ||
| 348 | |||
| 349 | /** | ||
| 350 | * Converts the given array of Color objects into an int array | ||
| 351 | * containing IntArgbPre pixel values. If the linear parameter | ||
| 352 | * is true, the Color values will be converted into a linear RGB | ||
| 353 | * color space before being returned. | ||
| 354 | */ | ||
| 355 | private static int[] convertToIntArgbPrePixels(Color[] colors, | ||
| 356 | boolean linear) | ||
| 357 | { | ||
| 358 | int[] pixels = new int[colors.length]; | ||
| 359 | for (int i = 0; i < colors.length; i++) { | ||
| 360 | pixels[i] = colorToIntArgbPrePixel(colors[i], linear); | ||
| 361 | } | ||
| 362 | return pixels; | ||
| 363 | } | ||
| 364 | |||
| 365 | /********************** LinearGradientPaint support *************************/ | ||
| 366 | |||
| 367 | /** | ||
| 368 | * This method uses techniques that are nearly identical to those | ||
| 369 | * employed in setGradientPaint() above. The primary difference | ||
| 370 | * is that at the native level we use a fragment shader to manually | ||
| 371 | * apply the plane equation constants to the current fragment position | ||
| 372 | * to calculate the gradient position in the range [0,1] (the native | ||
| 373 | * code for GradientPaint does the same, except that it uses OpenGL's | ||
| 374 | * automatic texture coordinate generation facilities). | ||
| 375 | * | ||
| 376 | * One other minor difference worth mentioning is that | ||
| 377 | * setGradientPaint() calculates the plane equation constants | ||
| 378 | * such that the gradient end points are positioned at 0.25 and 0.75 | ||
| 379 | * (for reasons discussed in the comments for that method). In | ||
| 380 | * contrast, for LinearGradientPaint we setup the equation constants | ||
| 381 | * such that the gradient end points fall at 0.0 and 1.0. The | ||
| 382 | * reason for this difference is that in the fragment shader we | ||
| 383 | * have more control over how the gradient values are interpreted | ||
| 384 | * (depending on the paint's CycleMethod). | ||
| 385 | */ | ||
| 386 | private static void setLinearGradientPaint(RenderQueue rq, | ||
| 387 | SunGraphics2D sg2d, | ||
| 388 | LinearGradientPaint paint, | ||
| 389 | boolean useMask) | ||
| 390 | { | ||
| 391 | boolean linear = | ||
| 392 | (paint.getColorSpace() == ColorSpaceType.LINEAR_RGB); | ||
| 393 | Color[] colors = paint.getColors(); | ||
| 394 | int numStops = colors.length; | ||
| 395 | Point2D pt1 = paint.getStartPoint(); | ||
| 396 | Point2D pt2 = paint.getEndPoint(); | ||
| 397 | AffineTransform at = paint.getTransform(); | ||
| 398 | at.preConcatenate(sg2d.transform); | ||
| 399 | |||
| 400 | if (!linear && numStops == 2 && | ||
| 401 | paint.getCycleMethod() != CycleMethod.REPEAT) | ||
| 402 | { | ||
| 403 | // delegate to the optimized two-color gradient codepath | ||
| 404 | boolean isCyclic = | ||
| 405 | (paint.getCycleMethod() != CycleMethod.NO_CYCLE); | ||
| 406 | setGradientPaint(rq, at, | ||
| 407 | colors[0], colors[1], | ||
| 408 | pt1, pt2, | ||
| 409 | isCyclic, useMask); | ||
| 410 | return; | ||
| 411 | } | ||
| 412 | |||
| 413 | int cycleMethod = paint.getCycleMethod().ordinal(); | ||
| 414 | float[] fractions = paint.getFractions(); | ||
| 415 | int[] pixels = convertToIntArgbPrePixels(colors, linear); | ||
| 416 | |||
| 417 | // calculate plane equation constants | ||
| 418 | double x = pt1.getX(); | ||
| 419 | double y = pt1.getY(); | ||
| 420 | at.translate(x, y); | ||
| 421 | // now gradient point 1 is at the origin | ||
| 422 | x = pt2.getX() - x; | ||
| 423 | y = pt2.getY() - y; | ||
| 424 | double len = Math.sqrt(x * x + y * y); | ||
| 425 | at.rotate(x, y); | ||
| 426 | // now gradient point 2 is on the positive x-axis | ||
| 427 | at.scale(len, 1); | ||
| 428 | // now gradient point 1 is at (0.0, 0), point 2 is at (1.0, 0) | ||
| 429 | |||
| 430 | float p0, p1, p3; | ||
| 431 | try { | ||
| 432 | at.invert(); | ||
| 433 | p0 = (float)at.getScaleX(); | ||
| 434 | p1 = (float)at.getShearX(); | ||
| 435 | p3 = (float)at.getTranslateX(); | ||
| 436 | } catch (java.awt.geom.NoninvertibleTransformException e) { | ||
| 437 | p0 = p1 = p3 = 0.0f; | ||
| 438 | } | ||
| 439 | |||
| 440 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 441 | rq.ensureCapacity(20 + 12 + (numStops*4*2)); | ||
| 442 | RenderBuffer buf = rq.getBuffer(); | ||
| 443 | buf.putInt(SET_LINEAR_GRADIENT_PAINT); | ||
| 444 | buf.putInt(useMask ? 1 : 0); | ||
| 445 | buf.putInt(linear ? 1 : 0); | ||
| 446 | buf.putInt(cycleMethod); | ||
| 447 | buf.putInt(numStops); | ||
| 448 | buf.putFloat(p0); | ||
| 449 | buf.putFloat(p1); | ||
| 450 | buf.putFloat(p3); | ||
| 451 | buf.put(fractions); | ||
| 452 | buf.put(pixels); | ||
| 453 | } | ||
| 454 | |||
| 455 | /********************** RadialGradientPaint support *************************/ | ||
| 456 | |||
| 457 | /** | ||
| 458 | * This method calculates six m** values and a focusX value that | ||
| 459 | * are used by the native fragment shader. These techniques are | ||
| 460 | * based on a whitepaper by Daniel Rice on radial gradient performance | ||
| 461 | * (attached to the bug report for 6521533). One can refer to that | ||
| 462 | * document for the complete set of formulas and calculations, but | ||
| 463 | * the basic goal is to compose a transform that will convert an | ||
| 464 | * (x,y) position in device space into a "u" value that represents | ||
| 465 | * the relative distance to the gradient focus point. The resulting | ||
| 466 | * value can be used to look up the appropriate color by linearly | ||
| 467 | * interpolating between the two nearest colors in the gradient. | ||
| 468 | */ | ||
| 469 | private static void setRadialGradientPaint(RenderQueue rq, | ||
| 470 | SunGraphics2D sg2d, | ||
| 471 | RadialGradientPaint paint, | ||
| 472 | boolean useMask) | ||
| 473 | { | ||
| 474 | boolean linear = | ||
| 475 | (paint.getColorSpace() == ColorSpaceType.LINEAR_RGB); | ||
| 476 | int cycleMethod = paint.getCycleMethod().ordinal(); | ||
| 477 | float[] fractions = paint.getFractions(); | ||
| 478 | Color[] colors = paint.getColors(); | ||
| 479 | int numStops = colors.length; | ||
| 480 | int[] pixels = convertToIntArgbPrePixels(colors, linear); | ||
| 481 | Point2D center = paint.getCenterPoint(); | ||
| 482 | Point2D focus = paint.getFocusPoint(); | ||
| 483 | float radius = paint.getRadius(); | ||
| 484 | |||
| 485 | // save original (untransformed) center and focus points | ||
| 486 | double cx = center.getX(); | ||
| 487 | double cy = center.getY(); | ||
| 488 | double fx = focus.getX(); | ||
| 489 | double fy = focus.getY(); | ||
| 490 | |||
| 491 | // transform from gradient coords to device coords | ||
| 492 | AffineTransform at = paint.getTransform(); | ||
| 493 | at.preConcatenate(sg2d.transform); | ||
| 494 | focus = at.transform(focus, focus); | ||
| 495 | |||
| 496 | // transform unit circle to gradient coords; we start with the | ||
| 497 | // unit circle (center=(0,0), focus on positive x-axis, radius=1) | ||
| 498 | // and then transform into gradient space | ||
| 499 | at.translate(cx, cy); | ||
| 500 | at.rotate(fx - cx, fy - cy); | ||
| 501 | at.scale(radius, radius); | ||
| 502 | |||
| 503 | // invert to get mapping from device coords to unit circle | ||
| 504 | try { | ||
| 505 | at.invert(); | ||
| 506 | } catch (Exception e) { | ||
| 507 | at.setToScale(0.0, 0.0); | ||
| 508 | } | ||
| 509 | focus = at.transform(focus, focus); | ||
| 510 | |||
| 511 | // clamp the focus point so that it does not rest on, or outside | ||
| 512 | // of, the circumference of the gradient circle | ||
| 513 | fx = Math.min(focus.getX(), 0.99); | ||
| 514 | |||
| 515 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 516 | rq.ensureCapacity(20 + 28 + (numStops*4*2)); | ||
| 517 | RenderBuffer buf = rq.getBuffer(); | ||
| 518 | buf.putInt(SET_RADIAL_GRADIENT_PAINT); | ||
| 519 | buf.putInt(useMask ? 1 : 0); | ||
| 520 | buf.putInt(linear ? 1 : 0); | ||
| 521 | buf.putInt(numStops); | ||
| 522 | buf.putInt(cycleMethod); | ||
| 523 | buf.putFloat((float)at.getScaleX()); | ||
| 524 | buf.putFloat((float)at.getShearX()); | ||
| 525 | buf.putFloat((float)at.getTranslateX()); | ||
| 526 | buf.putFloat((float)at.getShearY()); | ||
| 527 | buf.putFloat((float)at.getScaleY()); | ||
| 528 | buf.putFloat((float)at.getTranslateY()); | ||
| 529 | buf.putFloat((float)fx); | ||
| 530 | buf.put(fractions); | ||
| 531 | buf.put(pixels); | ||
| 532 | } | ||
| 533 | } | ||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,601 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 2008, 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.Polygon; | ||
| 30 | import java.awt.Shape; | ||
| 31 | import java.awt.geom.AffineTransform; | ||
| 32 | import java.awt.geom.Arc2D; | ||
| 33 | import java.awt.geom.Ellipse2D; | ||
| 34 | import java.awt.geom.Path2D; | ||
| 35 | import java.awt.geom.IllegalPathStateException; | ||
| 36 | import java.awt.geom.PathIterator; | ||
| 37 | import java.awt.geom.Rectangle2D; | ||
| 38 | import java.awt.geom.RoundRectangle2D; | ||
| 39 | import sun.java2d.SunGraphics2D; | ||
| 40 | import sun.java2d.loops.ProcessPath; | ||
| 41 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Base class for enqueuing rendering operations in a single-threaded | ||
| 45 | * rendering environment. Instead of each operation being rendered | ||
| 46 | * immediately by the underlying graphics library, the operation will be | ||
| 47 | * added to the provided RenderQueue, which will be processed at a later | ||
| 48 | * time by a single thread. | ||
| 49 | * | ||
| 50 | * This class provides implementations of drawLine(), drawRect(), drawPoly(), | ||
| 51 | * fillRect(), draw(Shape), and fill(Shape), which are useful for a | ||
| 52 | * hardware-accelerated renderer. The other draw*() and fill*() methods | ||
| 53 | * simply delegate to draw(Shape) and fill(Shape), respectively. | ||
| 54 | */ | ||
| 55 | public abstract class BufferedRenderPipe | ||
| 56 | implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, ParallelogramPipe | ||
| 57 | { | ||
| 58 | ParallelogramPipe aapgrampipe = new AAParallelogramPipe(); | ||
| 59 | |||
| 60 | static final int BYTES_PER_POLY_POINT = 8; | ||
| 61 | static final int BYTES_PER_SCANLINE = 12; | ||
| 62 | static final int BYTES_PER_SPAN = 16; | ||
| 63 | |||
| 64 | protected RenderQueue rq; | ||
| 65 | protected RenderBuffer buf; | ||
| 66 | private BufferedDrawHandler drawHandler; | ||
| 67 | |||
| 68 | public BufferedRenderPipe(RenderQueue rq) { | ||
| 69 | this.rq = rq; | ||
| 70 | this.buf = rq.getBuffer(); | ||
| 71 | this.drawHandler = new BufferedDrawHandler(); | ||
| 72 | } | ||
| 73 | |||
| 74 | public ParallelogramPipe getAAParallelogramPipe() { | ||
| 75 | return aapgrampipe; | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Validates the state in the provided SunGraphics2D object and sets up | ||
| 80 | * any special resources for this operation (e.g. enabling gradient | ||
| 81 | * shading). | ||
| 82 | */ | ||
| 83 | protected abstract void validateContext(SunGraphics2D sg2d); | ||
| 84 | protected abstract void validateContextAA(SunGraphics2D sg2d); | ||
| 85 | |||
| 86 | public void drawLine(SunGraphics2D sg2d, | ||
| 87 | int x1, int y1, int x2, int y2) | ||
| 88 | { | ||
| 89 | int transx = sg2d.transX; | ||
| 90 | int transy = sg2d.transY; | ||
| 91 | rq.lock(); | ||
| 92 | try { | ||
| 93 | validateContext(sg2d); | ||
| 94 | rq.ensureCapacity(20); | ||
| 95 | buf.putInt(DRAW_LINE); | ||
| 96 | buf.putInt(x1 + transx); | ||
| 97 | buf.putInt(y1 + transy); | ||
| 98 | buf.putInt(x2 + transx); | ||
| 99 | buf.putInt(y2 + transy); | ||
| 100 | } finally { | ||
| 101 | rq.unlock(); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | public void drawRect(SunGraphics2D sg2d, | ||
| 106 | int x, int y, int width, int height) | ||
| 107 | { | ||
| 108 | rq.lock(); | ||
| 109 | try { | ||
| 110 | validateContext(sg2d); | ||
| 111 | rq.ensureCapacity(20); | ||
| 112 | buf.putInt(DRAW_RECT); | ||
| 113 | buf.putInt(x + sg2d.transX); | ||
| 114 | buf.putInt(y + sg2d.transY); | ||
| 115 | buf.putInt(width); | ||
| 116 | buf.putInt(height); | ||
| 117 | } finally { | ||
| 118 | rq.unlock(); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | public void fillRect(SunGraphics2D sg2d, | ||
| 123 | int x, int y, int width, int height) | ||
| 124 | { | ||
| 125 | rq.lock(); | ||
| 126 | try { | ||
| 127 | validateContext(sg2d); | ||
| 128 | rq.ensureCapacity(20); | ||
| 129 | buf.putInt(FILL_RECT); | ||
| 130 | buf.putInt(x + sg2d.transX); | ||
| 131 | buf.putInt(y + sg2d.transY); | ||
| 132 | buf.putInt(width); | ||
| 133 | buf.putInt(height); | ||
| 134 | } finally { | ||
| 135 | rq.unlock(); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | public void drawRoundRect(SunGraphics2D sg2d, | ||
| 140 | int x, int y, int width, int height, | ||
| 141 | int arcWidth, int arcHeight) | ||
| 142 | { | ||
| 143 | draw(sg2d, new RoundRectangle2D.Float(x, y, width, height, | ||
| 144 | arcWidth, arcHeight)); | ||
| 145 | } | ||
| 146 | |||
| 147 | public void fillRoundRect(SunGraphics2D sg2d, | ||
| 148 | int x, int y, int width, int height, | ||
| 149 | int arcWidth, int arcHeight) | ||
| 150 | { | ||
| 151 | fill(sg2d, new RoundRectangle2D.Float(x, y, width, height, | ||
| 152 | arcWidth, arcHeight)); | ||
| 153 | } | ||
| 154 | |||
| 155 | public void drawOval(SunGraphics2D sg2d, | ||
| 156 | int x, int y, int width, int height) | ||
| 157 | { | ||
| 158 | draw(sg2d, new Ellipse2D.Float(x, y, width, height)); | ||
| 159 | } | ||
| 160 | |||
| 161 | public void fillOval(SunGraphics2D sg2d, | ||
| 162 | int x, int y, int width, int height) | ||
| 163 | { | ||
| 164 | fill(sg2d, new Ellipse2D.Float(x, y, width, height)); | ||
| 165 | } | ||
| 166 | |||
| 167 | public void drawArc(SunGraphics2D sg2d, | ||
| 168 | int x, int y, int width, int height, | ||
| 169 | int startAngle, int arcAngle) | ||
| 170 | { | ||
| 171 | draw(sg2d, new Arc2D.Float(x, y, width, height, | ||
| 172 | startAngle, arcAngle, | ||
| 173 | Arc2D.OPEN)); | ||
| 174 | } | ||
| 175 | |||
| 176 | public void fillArc(SunGraphics2D sg2d, | ||
| 177 | int x, int y, int width, int height, | ||
| 178 | int startAngle, int arcAngle) | ||
| 179 | { | ||
| 180 | fill(sg2d, new Arc2D.Float(x, y, width, height, | ||
| 181 | startAngle, arcAngle, | ||
| 182 | Arc2D.PIE)); | ||
| 183 | } | ||
| 184 | |||
| 185 | protected void drawPoly(final SunGraphics2D sg2d, | ||
| 186 | final int[] xPoints, final int[] yPoints, | ||
| 187 | final int nPoints, final boolean isClosed) | ||
| 188 | { | ||
| 189 | if (xPoints == null || yPoints == null) { | ||
| 190 | throw new NullPointerException("coordinate array"); | ||
| 191 | } | ||
| 192 | if (xPoints.length < nPoints || yPoints.length < nPoints) { | ||
| 193 | throw new ArrayIndexOutOfBoundsException("coordinate array"); | ||
| 194 | } | ||
| 195 | |||
| 196 | if (nPoints < 2) { | ||
| 197 | // render nothing | ||
| 198 | return; | ||
| 199 | } else if (nPoints == 2 && !isClosed) { | ||
| 200 | // render a simple line | ||
| 201 | drawLine(sg2d, xPoints[0], yPoints[0], xPoints[1], yPoints[1]); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | rq.lock(); | ||
| 206 | try { | ||
| 207 | validateContext(sg2d); | ||
| 208 | |||
| 209 | int pointBytesRequired = nPoints * BYTES_PER_POLY_POINT; | ||
| 210 | int totalBytesRequired = 20 + pointBytesRequired; | ||
| 211 | |||
| 212 | if (totalBytesRequired <= buf.capacity()) { | ||
| 213 | if (totalBytesRequired > buf.remaining()) { | ||
| 214 | // process the queue first and then enqueue the points | ||
| 215 | rq.flushNow(); | ||
| 216 | } | ||
| 217 | buf.putInt(DRAW_POLY); | ||
| 218 | // enqueue parameters | ||
| 219 | buf.putInt(nPoints); | ||
| 220 | buf.putInt(isClosed ? 1 : 0); | ||
| 221 | buf.putInt(sg2d.transX); | ||
| 222 | buf.putInt(sg2d.transY); | ||
| 223 | // enqueue the points | ||
| 224 | buf.put(xPoints, 0, nPoints); | ||
| 225 | buf.put(yPoints, 0, nPoints); | ||
| 226 | } else { | ||
| 227 | // queue is too small to accomodate all points; perform the | ||
| 228 | // operation directly on the queue flushing thread | ||
| 229 | rq.flushAndInvokeNow(new Runnable() { | ||
| 230 | public void run() { | ||
| 231 | drawPoly(xPoints, yPoints, | ||
| 232 | nPoints, isClosed, | ||
| 233 | sg2d.transX, sg2d.transY); | ||
| 234 | } | ||
| 235 | }); | ||
| 236 | } | ||
| 237 | } finally { | ||
| 238 | rq.unlock(); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | protected abstract void drawPoly(int[] xPoints, int[] yPoints, | ||
| 243 | int nPoints, boolean isClosed, | ||
| 244 | int transX, int transY); | ||
| 245 | |||
| 246 | public void drawPolyline(SunGraphics2D sg2d, | ||
| 247 | int[] xPoints, int[] yPoints, | ||
| 248 | int nPoints) | ||
| 249 | { | ||
| 250 | drawPoly(sg2d, xPoints, yPoints, nPoints, false); | ||
| 251 | } | ||
| 252 | |||
| 253 | public void drawPolygon(SunGraphics2D sg2d, | ||
| 254 | int[] xPoints, int[] yPoints, | ||
| 255 | int nPoints) | ||
| 256 | { | ||
| 257 | drawPoly(sg2d, xPoints, yPoints, nPoints, true); | ||
| 258 | } | ||
| 259 | |||
| 260 | public void fillPolygon(SunGraphics2D sg2d, | ||
| 261 | int[] xPoints, int[] yPoints, | ||
| 262 | int nPoints) | ||
| 263 | { | ||
| 264 | fill(sg2d, new Polygon(xPoints, yPoints, nPoints)); | ||
| 265 | } | ||
| 266 | |||
| 267 | private class BufferedDrawHandler | ||
| 268 | extends ProcessPath.DrawHandler | ||
| 269 | { | ||
| 270 | BufferedDrawHandler() { | ||
| 271 | // these are bogus values; the caller will use validate() | ||
| 272 | // to ensure that they are set properly prior to each usage | ||
| 273 | super(0, 0, 0, 0); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * This method needs to be called prior to each draw/fillPath() | ||
| 278 | * operation to ensure the clip bounds are up to date. | ||
| 279 | */ | ||
| 280 | void validate(SunGraphics2D sg2d) { | ||
| 281 | Region clip = sg2d.getCompClip(); | ||
| 282 | setBounds(clip.getLoX(), clip.getLoY(), | ||
| 283 | clip.getHiX(), clip.getHiY(), | ||
| 284 | sg2d.strokeHint); | ||
| 285 | } | ||
| 286 | |||
| 287 | /** | ||
| 288 | * drawPath() support... | ||
| 289 | */ | ||
| 290 | |||
| 291 | public void drawLine(int x1, int y1, int x2, int y2) { | ||
| 292 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 293 | rq.ensureCapacity(20); | ||
| 294 | buf.putInt(DRAW_LINE); | ||
| 295 | buf.putInt(x1); | ||
| 296 | buf.putInt(y1); | ||
| 297 | buf.putInt(x2); | ||
| 298 | buf.putInt(y2); | ||
| 299 | } | ||
| 300 | |||
| 301 | public void drawPixel(int x, int y) { | ||
| 302 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 303 | rq.ensureCapacity(12); | ||
| 304 | buf.putInt(DRAW_PIXEL); | ||
| 305 | buf.putInt(x); | ||
| 306 | buf.putInt(y); | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * fillPath() support... | ||
| 311 | */ | ||
| 312 | |||
| 313 | private int scanlineCount; | ||
| 314 | private int scanlineCountIndex; | ||
| 315 | private int remainingScanlines; | ||
| 316 | |||
| 317 | private void resetFillPath() { | ||
| 318 | buf.putInt(DRAW_SCANLINES); | ||
| 319 | scanlineCountIndex = buf.position(); | ||
| 320 | buf.putInt(0); | ||
| 321 | scanlineCount = 0; | ||
| 322 | remainingScanlines = buf.remaining() / BYTES_PER_SCANLINE; | ||
| 323 | } | ||
| 324 | |||
| 325 | private void updateScanlineCount() { | ||
| 326 | buf.putInt(scanlineCountIndex, scanlineCount); | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * Called from fillPath() to indicate that we are about to | ||
| 331 | * start issuing drawScanline() calls. | ||
| 332 | */ | ||
| 333 | public void startFillPath() { | ||
| 334 | rq.ensureCapacity(20); // to ensure room for at least a scanline | ||
| 335 | resetFillPath(); | ||
| 336 | } | ||
| 337 | |||
| 338 | public void drawScanline(int x1, int x2, int y) { | ||
| 339 | if (remainingScanlines == 0) { | ||
| 340 | updateScanlineCount(); | ||
| 341 | rq.flushNow(); | ||
| 342 | resetFillPath(); | ||
| 343 | } | ||
| 344 | buf.putInt(x1); | ||
| 345 | buf.putInt(x2); | ||
| 346 | buf.putInt(y); | ||
| 347 | scanlineCount++; | ||
| 348 | remainingScanlines--; | ||
| 349 | } | ||
| 350 | |||
| 351 | /** | ||
| 352 | * Called from fillPath() to indicate that we are done | ||
| 353 | * issuing drawScanline() calls. | ||
| 354 | */ | ||
| 355 | public void endFillPath() { | ||
| 356 | updateScanlineCount(); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | protected void drawPath(SunGraphics2D sg2d, | ||
| 361 | Path2D.Float p2df, int transx, int transy) | ||
| 362 | { | ||
| 363 | rq.lock(); | ||
| 364 | try { | ||
| 365 | validateContext(sg2d); | ||
| 366 | drawHandler.validate(sg2d); | ||
| 367 | ProcessPath.drawPath(drawHandler, p2df, transx, transy); | ||
| 368 | } finally { | ||
| 369 | rq.unlock(); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | protected void fillPath(SunGraphics2D sg2d, | ||
| 374 | Path2D.Float p2df, int transx, int transy) | ||
| 375 | { | ||
| 376 | rq.lock(); | ||
| 377 | try { | ||
| 378 | validateContext(sg2d); | ||
| 379 | drawHandler.validate(sg2d); | ||
| 380 | drawHandler.startFillPath(); | ||
| 381 | ProcessPath.fillPath(drawHandler, p2df, transx, transy); | ||
| 382 | drawHandler.endFillPath(); | ||
| 383 | } finally { | ||
| 384 | rq.unlock(); | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | private native int fillSpans(RenderQueue rq, long buf, | ||
| 389 | int pos, int limit, | ||
| 390 | SpanIterator si, long iterator, | ||
| 391 | int transx, int transy); | ||
| 392 | |||
| 393 | protected void fillSpans(SunGraphics2D sg2d, SpanIterator si, | ||
| 394 | int transx, int transy) | ||
| 395 | { | ||
| 396 | rq.lock(); | ||
| 397 | try { | ||
| 398 | validateContext(sg2d); | ||
| 399 | rq.ensureCapacity(24); // so that we have room for at least a span | ||
| 400 | int newpos = fillSpans(rq, buf.getAddress(), | ||
| 401 | buf.position(), buf.capacity(), | ||
| 402 | si, si.getNativeIterator(), | ||
| 403 | transx, transy); | ||
| 404 | buf.position(newpos); | ||
| 405 | } finally { | ||
| 406 | rq.unlock(); | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | public void fillParallelogram(SunGraphics2D sg2d, | ||
| 411 | double ux1, double uy1, | ||
| 412 | double ux2, double uy2, | ||
| 413 | double x, double y, | ||
| 414 | double dx1, double dy1, | ||
| 415 | double dx2, double dy2) | ||
| 416 | { | ||
| 417 | rq.lock(); | ||
| 418 | try { | ||
| 419 | validateContext(sg2d); | ||
| 420 | rq.ensureCapacity(28); | ||
| 421 | buf.putInt(FILL_PARALLELOGRAM); | ||
| 422 | buf.putFloat((float) x); | ||
| 423 | buf.putFloat((float) y); | ||
| 424 | buf.putFloat((float) dx1); | ||
| 425 | buf.putFloat((float) dy1); | ||
| 426 | buf.putFloat((float) dx2); | ||
| 427 | buf.putFloat((float) dy2); | ||
| 428 | } finally { | ||
| 429 | rq.unlock(); | ||
| 430 | } | ||
| 431 | } | ||
| 432 | |||
| 433 | public void drawParallelogram(SunGraphics2D sg2d, | ||
| 434 | double ux1, double uy1, | ||
| 435 | double ux2, double uy2, | ||
| 436 | double x, double y, | ||
| 437 | double dx1, double dy1, | ||
| 438 | double dx2, double dy2, | ||
| 439 | double lw1, double lw2) | ||
| 440 | { | ||
| 441 | rq.lock(); | ||
| 442 | try { | ||
| 443 | validateContext(sg2d); | ||
| 444 | rq.ensureCapacity(36); | ||
| 445 | buf.putInt(DRAW_PARALLELOGRAM); | ||
| 446 | buf.putFloat((float) x); | ||
| 447 | buf.putFloat((float) y); | ||
| 448 | buf.putFloat((float) dx1); | ||
| 449 | buf.putFloat((float) dy1); | ||
| 450 | buf.putFloat((float) dx2); | ||
| 451 | buf.putFloat((float) dy2); | ||
| 452 | buf.putFloat((float) lw1); | ||
| 453 | buf.putFloat((float) lw2); | ||
| 454 | } finally { | ||
| 455 | rq.unlock(); | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | private class AAParallelogramPipe implements ParallelogramPipe { | ||
| 460 | public void fillParallelogram(SunGraphics2D sg2d, | ||
| 461 | double ux1, double uy1, | ||
| 462 | double ux2, double uy2, | ||
| 463 | double x, double y, | ||
| 464 | double dx1, double dy1, | ||
| 465 | double dx2, double dy2) | ||
| 466 | { | ||
| 467 | rq.lock(); | ||
| 468 | try { | ||
| 469 | validateContextAA(sg2d); | ||
| 470 | rq.ensureCapacity(28); | ||
| 471 | buf.putInt(FILL_AAPARALLELOGRAM); | ||
| 472 | buf.putFloat((float) x); | ||
| 473 | buf.putFloat((float) y); | ||
| 474 | buf.putFloat((float) dx1); | ||
| 475 | buf.putFloat((float) dy1); | ||
| 476 | buf.putFloat((float) dx2); | ||
| 477 | buf.putFloat((float) dy2); | ||
| 478 | } finally { | ||
| 479 | rq.unlock(); | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | public void drawParallelogram(SunGraphics2D sg2d, | ||
| 484 | double ux1, double uy1, | ||
| 485 | double ux2, double uy2, | ||
| 486 | double x, double y, | ||
| 487 | double dx1, double dy1, | ||
| 488 | double dx2, double dy2, | ||
| 489 | double lw1, double lw2) | ||
| 490 | { | ||
| 491 | rq.lock(); | ||
| 492 | try { | ||
| 493 | validateContextAA(sg2d); | ||
| 494 | rq.ensureCapacity(36); | ||
| 495 | buf.putInt(DRAW_AAPARALLELOGRAM); | ||
| 496 | buf.putFloat((float) x); | ||
| 497 | buf.putFloat((float) y); | ||
| 498 | buf.putFloat((float) dx1); | ||
| 499 | buf.putFloat((float) dy1); | ||
| 500 | buf.putFloat((float) dx2); | ||
| 501 | buf.putFloat((float) dy2); | ||
| 502 | buf.putFloat((float) lw1); | ||
| 503 | buf.putFloat((float) lw2); | ||
| 504 | } finally { | ||
| 505 | rq.unlock(); | ||
| 506 | } | ||
| 507 | } | ||
| 508 | } | ||
| 509 | |||
| 510 | public void draw(SunGraphics2D sg2d, Shape s) { | ||
| 511 | if (sg2d.strokeState == sg2d.STROKE_THIN) { | ||
| 512 | if (s instanceof Polygon) { | ||
| 513 | if (sg2d.transformState < sg2d.TRANSFORM_TRANSLATESCALE) { | ||
| 514 | Polygon p = (Polygon)s; | ||
| 515 | drawPolygon(sg2d, p.xpoints, p.ypoints, p.npoints); | ||
| 516 | return; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | Path2D.Float p2df; | ||
| 520 | int transx, transy; | ||
| 521 | if (sg2d.transformState <= sg2d.TRANSFORM_INT_TRANSLATE) { | ||
| 522 | if (s instanceof Path2D.Float) { | ||
| 523 | p2df = (Path2D.Float)s; | ||
| 524 | } else { | ||
| 525 | p2df = new Path2D.Float(s); | ||
| 526 | } | ||
| 527 | transx = sg2d.transX; | ||
| 528 | transy = sg2d.transY; | ||
| 529 | } else { | ||
| 530 | p2df = new Path2D.Float(s, sg2d.transform); | ||
| 531 | transx = 0; | ||
| 532 | transy = 0; | ||
| 533 | } | ||
| 534 | drawPath(sg2d, p2df, transx, transy); | ||
| 535 | } else if (sg2d.strokeState < sg2d.STROKE_CUSTOM) { | ||
| 536 | ShapeSpanIterator si = LoopPipe.getStrokeSpans(sg2d, s); | ||
| 537 | try { | ||
| 538 | fillSpans(sg2d, si, 0, 0); | ||
| 539 | } finally { | ||
| 540 | si.dispose(); | ||
| 541 | } | ||
| 542 | } else { | ||
| 543 | fill(sg2d, sg2d.stroke.createStrokedShape(s)); | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | public void fill(SunGraphics2D sg2d, Shape s) { | ||
| 548 | int transx, transy; | ||
| 549 | |||
| 550 | if (sg2d.strokeState == sg2d.STROKE_THIN) { | ||
| 551 | // Here we are able to use fillPath() for | ||
| 552 | // high-quality fills. | ||
| 553 | Path2D.Float p2df; | ||
| 554 | if (sg2d.transformState <= sg2d.TRANSFORM_INT_TRANSLATE) { | ||
| 555 | if (s instanceof Path2D.Float) { | ||
| 556 | p2df = (Path2D.Float)s; | ||
| 557 | } else { | ||
| 558 | p2df = new Path2D.Float(s); | ||
| 559 | } | ||
| 560 | transx = sg2d.transX; | ||
| 561 | transy = sg2d.transY; | ||
| 562 | } else { | ||
| 563 | p2df = new Path2D.Float(s, sg2d.transform); | ||
| 564 | transx = 0; | ||
| 565 | transy = 0; | ||
| 566 | } | ||
| 567 | fillPath(sg2d, p2df, transx, transy); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | |||
| 571 | AffineTransform at; | ||
| 572 | if (sg2d.transformState <= sg2d.TRANSFORM_INT_TRANSLATE) { | ||
| 573 | // Transform (translation) will be done by FillSpans (we could | ||
| 574 | // delegate to fillPolygon() here, but most hardware accelerated | ||
| 575 | // libraries cannot handle non-convex polygons, so we will use | ||
| 576 | // the FillSpans approach by default) | ||
| 577 | at = null; | ||
| 578 | transx = sg2d.transX; | ||
| 579 | transy = sg2d.transY; | ||
| 580 | } else { | ||
| 581 | // Transform will be done by the PathIterator | ||
| 582 | at = sg2d.transform; | ||
| 583 | transx = transy = 0; | ||
| 584 | } | ||
| 585 | |||
| 586 | ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d); | ||
| 587 | try { | ||
| 588 | // Subtract transx/y from the SSI clip to match the | ||
| 589 | // (potentially untranslated) geometry fed to it | ||
| 590 | Region clip = sg2d.getCompClip(); | ||
| 591 | ssi.setOutputAreaXYXY(clip.getLoX() - transx, | ||
| 592 | clip.getLoY() - transy, | ||
| 593 | clip.getHiX() - transx, | ||
| 594 | clip.getHiY() - transy); | ||
| 595 | ssi.appendPath(s.getPathIterator(at)); | ||
| 596 | fillSpans(sg2d, ssi, transx, transy); | ||
| 597 | } finally { | ||
| 598 | ssi.dispose(); | ||
| 599 | } | ||
| 600 | } | ||
| 601 | } | ||
| @@ -0,0 +1,168 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 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.AlphaComposite; | ||
| 29 | import java.awt.Composite; | ||
| 30 | import sun.font.GlyphList; | ||
| 31 | import sun.java2d.SunGraphics2D; | ||
| 32 | import sun.java2d.SurfaceData; | ||
| 33 | import static sun.java2d.pipe.BufferedOpCodes.*; | ||
| 34 | |||
| 35 | public abstract class BufferedTextPipe extends GlyphListPipe { | ||
| 36 | |||
| 37 | private static final int BYTES_PER_GLYPH_IMAGE = 8; | ||
| 38 | private static final int BYTES_PER_GLYPH_POSITION = 8; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * The following offsets are used to pack the parameters in | ||
| 42 | * createPackedParams(). (They are also used at the native level when | ||
| 43 | * unpacking the params.) | ||
| 44 | */ | ||
| 45 | private static final int OFFSET_CONTRAST = 8; | ||
| 46 | private static final int OFFSET_RGBORDER = 2; | ||
| 47 | private static final int OFFSET_SUBPIXPOS = 1; | ||
| 48 | private static final int OFFSET_POSITIONS = 0; | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Packs the given parameters into a single int value in order to save | ||
| 52 | * space on the rendering queue. Note that most of these parameters | ||
| 53 | * are only used for rendering LCD-optimized text, but conditionalizing | ||
| 54 | * this work wouldn't make any impact on performance, so we will pack | ||
| 55 | * those parameters even in the non-LCD case. | ||
| 56 | */ | ||
| 57 | private static int createPackedParams(SunGraphics2D sg2d, GlyphList gl) { | ||
| 58 | return | ||
| 59 | (((gl.usePositions() ? 1 : 0) << OFFSET_POSITIONS) | | ||
| 60 | ((gl.isSubPixPos() ? 1 : 0) << OFFSET_SUBPIXPOS) | | ||
| 61 | ((gl.isRGBOrder() ? 1 : 0) << OFFSET_RGBORDER ) | | ||
| 62 | ((sg2d.lcdTextContrast & 0xff) << OFFSET_CONTRAST )); | ||
| 63 | } | ||
| 64 | |||
| 65 | protected final RenderQueue rq; | ||
| 66 | |||
| 67 | protected BufferedTextPipe(RenderQueue rq) { | ||
| 68 | this.rq = rq; | ||
| 69 | } | ||
| 70 | |||
| 71 | @Override | ||
| 72 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { | ||
| 73 | /* | ||
| 74 | * The native drawGlyphList() only works with two composite types: | ||
| 75 | * - CompositeType.SrcOver (with any extra alpha), or | ||
| 76 | * - CompositeType.Xor | ||
| 77 | */ | ||
| 78 | Composite comp = sg2d.composite; | ||
| 79 | if (comp == AlphaComposite.Src) { | ||
| 80 | /* | ||
| 81 | * In addition to the composite types listed above, the logic | ||
| 82 | * in OGL/D3DSurfaceData.validatePipe() allows for | ||
| 83 | * CompositeType.SrcNoEa, but only in the presence of an opaque | ||
| 84 | * color. If we reach this case, we know the color is opaque, | ||
| 85 | * and therefore SrcNoEa is the same as SrcOverNoEa, so we | ||
| 86 | * override the composite here. | ||
| 87 | */ | ||
| 88 | comp = AlphaComposite.SrcOver; | ||
| 89 | } | ||
| 90 | |||
| 91 | rq.lock(); | ||
| 92 | try { | ||
| 93 | validateContext(sg2d, comp); | ||
| 94 | enqueueGlyphList(sg2d, gl); | ||
| 95 | } finally { | ||
| 96 | rq.unlock(); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | private void enqueueGlyphList(final SunGraphics2D sg2d, | ||
| 101 | final GlyphList gl) | ||
| 102 | { | ||
| 103 | // assert rq.lock.isHeldByCurrentThread(); | ||
| 104 | RenderBuffer buf = rq.getBuffer(); | ||
| 105 | final int totalGlyphs = gl.getNumGlyphs(); | ||
| 106 | int glyphBytesRequired = totalGlyphs * BYTES_PER_GLYPH_IMAGE; | ||
| 107 | int posBytesRequired = | ||
| 108 | gl.usePositions() ? totalGlyphs * BYTES_PER_GLYPH_POSITION : 0; | ||
| 109 | int totalBytesRequired = 24 + glyphBytesRequired + posBytesRequired; | ||
| 110 | |||
| 111 | final long[] images = gl.getImages(); | ||
| 112 | final float glyphListOrigX = gl.getX() + 0.5f; | ||
| 113 | final float glyphListOrigY = gl.getY() + 0.5f; | ||
| 114 | |||
| 115 | // make sure the RenderQueue keeps a hard reference to the FontStrike | ||
| 116 | // so that the associated glyph images are not disposed while enqueued | ||
| 117 | rq.addReference(gl.getStrike()); | ||
| 118 | |||
| 119 | if (totalBytesRequired <= buf.capacity()) { | ||
| 120 | if (totalBytesRequired > buf.remaining()) { | ||
| 121 | // process the queue first and then enqueue the glyphs | ||
| 122 | rq.flushNow(); | ||
| 123 | } | ||
| 124 | rq.ensureAlignment(20); | ||
| 125 | buf.putInt(DRAW_GLYPH_LIST); | ||
| 126 | // enqueue parameters | ||
| 127 | buf.putInt(totalGlyphs); | ||
| 128 | buf.putInt(createPackedParams(sg2d, gl)); | ||
| 129 | buf.putFloat(glyphListOrigX); | ||
| 130 | buf.putFloat(glyphListOrigY); | ||
| 131 | // now enqueue glyph information | ||
| 132 | buf.put(images, 0, totalGlyphs); | ||
| 133 | if (gl.usePositions()) { | ||
| 134 | float[] positions = gl.getPositions(); | ||
| 135 | buf.put(positions, 0, 2*totalGlyphs); | ||
| 136 | } | ||
| 137 | } else { | ||
| 138 | // queue is too small to accomodate glyphs; perform | ||
| 139 | // the operation directly on the queue flushing thread | ||
| 140 | rq.flushAndInvokeNow(new Runnable() { | ||
| 141 | public void run() { | ||
| 142 | drawGlyphList(totalGlyphs, gl.usePositions(), | ||
| 143 | gl.isSubPixPos(), gl.isRGBOrder(), | ||
| 144 | sg2d.lcdTextContrast, | ||
| 145 | glyphListOrigX, glyphListOrigY, | ||
| 146 | images, gl.getPositions()); | ||
| 147 | } | ||
| 148 | }); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * Called as a separate Runnable when the operation is too large to fit | ||
| 154 | * on the RenderQueue. The OGL/D3D pipelines each have their own (small) | ||
| 155 | * native implementation of this method. | ||
| 156 | */ | ||
| 157 | protected abstract void drawGlyphList(int numGlyphs, boolean usePositions, | ||
| 158 | boolean subPixPos, boolean rgbOrder, | ||
| 159 | int lcdContrast, | ||
| 160 | float glOrigX, float glOrigY, | ||
| 161 | long[] images, float[] positions); | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Validates the state in the provided SunGraphics2D object. | ||
| 165 | */ | ||
| 166 | protected abstract void validateContext(SunGraphics2D sg2d, | ||
| 167 | Composite comp); | ||
| 168 | } | ||
Binary file not shown.
| @@ -0,0 +1,50 @@ | |||
| 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.Rectangle; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import sun.java2d.SunGraphics2D; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * This interface defines the set of calls used by a rendering pipeline | ||
| 34 | * based on an AATileGenerator to communicate the alpha tile sequence | ||
| 35 | * to the output (compositing) stages of the pipeline. | ||
| 36 | */ | ||
| 37 | public interface CompositePipe { | ||
| 38 | public Object startSequence(SunGraphics2D sg, Shape s, Rectangle dev, | ||
| 39 | int[] abox); | ||
| 40 | |||
| 41 | public boolean needTile(Object context, int x, int y, int w, int h); | ||
| 42 | |||
| 43 | public void renderPathTile(Object context, | ||
| 44 | byte[] atile, int offset, int tilesize, | ||
| 45 | int x, int y, int w, int h); | ||
| 46 | |||
| 47 | public void skipTile(Object context, int x, int y); | ||
| 48 | |||
| 49 | public void endSequence(Object context); | ||
| 50 | } | ||
Binary file not shown.
| @@ -0,0 +1,1110 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2001, 2008, 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.AlphaComposite; | ||
| 29 | import java.awt.Color; | ||
| 30 | import java.awt.Graphics2D; | ||
| 31 | import java.awt.Image; | ||
| 32 | import java.awt.Rectangle; | ||
| 33 | import java.awt.Transparency; | ||
| 34 | import java.awt.geom.AffineTransform; | ||
| 35 | import java.awt.geom.NoninvertibleTransformException; | ||
| 36 | import java.awt.image.AffineTransformOp; | ||
| 37 | import java.awt.image.BufferedImage; | ||
| 38 | import java.awt.image.BufferedImageOp; | ||
| 39 | import java.awt.image.ColorModel; | ||
| 40 | import java.awt.image.DataBuffer; | ||
| 41 | import java.awt.image.DirectColorModel; | ||
| 42 | import java.awt.image.ImageObserver; | ||
| 43 | import java.awt.image.IndexColorModel; | ||
| 44 | import java.awt.image.Raster; | ||
| 45 | import java.awt.image.VolatileImage; | ||
| 46 | import java.awt.image.WritableRaster; | ||
| 47 | import java.awt.image.ImagingOpException; | ||
| 48 | import sun.awt.SunHints; | ||
| 49 | import sun.awt.image.ImageRepresentation; | ||
| 50 | import sun.awt.image.ToolkitImage; | ||
| 51 | import sun.java2d.InvalidPipeException; | ||
| 52 | import sun.java2d.SunGraphics2D; | ||
| 53 | import sun.java2d.SurfaceData; | ||
| 54 | import sun.java2d.loops.Blit; | ||
| 55 | import sun.java2d.loops.BlitBg; | ||
| 56 | import sun.java2d.loops.TransformHelper; | ||
| 57 | import sun.java2d.loops.MaskBlit; | ||
| 58 | import sun.java2d.loops.CompositeType; | ||
| 59 | import sun.java2d.loops.ScaledBlit; | ||
| 60 | import sun.java2d.loops.SurfaceType; | ||
| 61 | |||
| 62 | public class DrawImage implements DrawImagePipe | ||
| 63 | { | ||
| 64 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 65 | int x, int y, | ||
| 66 | Color bgColor) | ||
| 67 | { | ||
| 68 | int imgw = img.getWidth(null); | ||
| 69 | int imgh = img.getHeight(null); | ||
| 70 | if (isSimpleTranslate(sg)) { | ||
| 71 | return renderImageCopy(sg, img, bgColor, | ||
| 72 | x + sg.transX, y + sg.transY, | ||
| 73 | 0, 0, imgw, imgh); | ||
| 74 | } | ||
| 75 | AffineTransform atfm = sg.transform; | ||
| 76 | if ((x | y) != 0) { | ||
| 77 | atfm = new AffineTransform(atfm); | ||
| 78 | atfm.translate(x, y); | ||
| 79 | } | ||
| 80 | transformImage(sg, img, atfm, sg.interpolationType, | ||
| 81 | 0, 0, imgw, imgh, bgColor); | ||
| 82 | return true; | ||
| 83 | } | ||
| 84 | |||
| 85 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 86 | int dx, int dy, int sx, int sy, int w, int h, | ||
| 87 | Color bgColor) | ||
| 88 | { | ||
| 89 | if (isSimpleTranslate(sg)) { | ||
| 90 | return renderImageCopy(sg, img, bgColor, | ||
| 91 | dx + sg.transX, dy + sg.transY, | ||
| 92 | sx, sy, w, h); | ||
| 93 | } | ||
| 94 | scaleImage(sg, img, dx, dy, (dx + w), (dy + h), | ||
| 95 | sx, sy, (sx + w), (sy + h), bgColor); | ||
| 96 | return true; | ||
| 97 | } | ||
| 98 | |||
| 99 | public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y, | ||
| 100 | int width, int height, | ||
| 101 | Color bgColor) | ||
| 102 | { | ||
| 103 | int imgw = img.getWidth(null); | ||
| 104 | int imgh = img.getHeight(null); | ||
| 105 | // Only accelerate scale if: | ||
| 106 | // - w/h positive values | ||
| 107 | // - sg transform integer translate/identity only | ||
| 108 | // - no bgColor in operation | ||
| 109 | if ((width > 0) && (height > 0) && isSimpleTranslate(sg)) { | ||
| 110 | double dx1 = x + sg.transX; | ||
| 111 | double dy1 = y + sg.transY; | ||
| 112 | double dx2 = dx1 + width; | ||
| 113 | double dy2 = dy1 + height; | ||
| 114 | if (renderImageScale(sg, img, bgColor, sg.interpolationType, | ||
| 115 | 0, 0, imgw, imgh, | ||
| 116 | dx1, dy1, dx2, dy2)) | ||
| 117 | { | ||
| 118 | return true; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | AffineTransform atfm = sg.transform; | ||
| 123 | if ((x | y) != 0 || width != imgw || height != imgh) { | ||
| 124 | atfm = new AffineTransform(atfm); | ||
| 125 | atfm.translate(x, y); | ||
| 126 | atfm.scale(((double)width)/imgw, ((double)height)/imgh); | ||
| 127 | } | ||
| 128 | transformImage(sg, img, atfm, sg.interpolationType, | ||
| 129 | 0, 0, imgw, imgh, bgColor); | ||
| 130 | return true; | ||
| 131 | } | ||
| 132 | |||
| 133 | /* | ||
| 134 | * This method is only called in those circumstances where the | ||
| 135 | * operation has a non-null secondary transform specfied. Its | ||
| 136 | * role is to check for various optimizations based on the types | ||
| 137 | * of both the secondary and SG2D transforms and to do some | ||
| 138 | * quick calculations to avoid having to combine the transforms | ||
| 139 | * and/or to call a more generalized method. | ||
| 140 | */ | ||
| 141 | protected void transformImage(SunGraphics2D sg, Image img, int x, int y, | ||
| 142 | AffineTransform extraAT, int interpType) | ||
| 143 | { | ||
| 144 | int txtype = extraAT.getType(); | ||
| 145 | int imgw = img.getWidth(null); | ||
| 146 | int imgh = img.getHeight(null); | ||
| 147 | boolean checkfinalxform; | ||
| 148 | |||
| 149 | if (sg.transformState <= sg.TRANSFORM_ANY_TRANSLATE && | ||
| 150 | (txtype == AffineTransform.TYPE_IDENTITY || | ||
| 151 | txtype == AffineTransform.TYPE_TRANSLATION)) | ||
| 152 | { | ||
| 153 | // First optimization - both are some kind of translate | ||
| 154 | |||
| 155 | // Combine the translations and check if interpolation is necessary. | ||
| 156 | double tx = extraAT.getTranslateX(); | ||
| 157 | double ty = extraAT.getTranslateY(); | ||
| 158 | tx += sg.transform.getTranslateX(); | ||
| 159 | ty += sg.transform.getTranslateY(); | ||
| 160 | int itx = (int) Math.floor(tx + 0.5); | ||
| 161 | int ity = (int) Math.floor(ty + 0.5); | ||
| 162 | if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR || | ||
| 163 | (closeToInteger(itx, tx) && closeToInteger(ity, ty))) | ||
| 164 | { | ||
| 165 | renderImageCopy(sg, img, null, x+itx, y+ity, 0, 0, imgw, imgh); | ||
| 166 | return; | ||
| 167 | } | ||
| 168 | checkfinalxform = false; | ||
| 169 | } else if (sg.transformState <= sg.TRANSFORM_TRANSLATESCALE && | ||
| 170 | ((txtype & (AffineTransform.TYPE_FLIP | | ||
| 171 | AffineTransform.TYPE_MASK_ROTATION | | ||
| 172 | AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0)) | ||
| 173 | { | ||
| 174 | // Second optimization - both are some kind of translate or scale | ||
| 175 | |||
| 176 | // Combine the scales and check if interpolation is necessary. | ||
| 177 | |||
| 178 | // Transform source bounds by extraAT, | ||
| 179 | // then translate the bounds again by x, y | ||
| 180 | // then transform the bounds again by sg.transform | ||
| 181 | double coords[] = new double[] { | ||
| 182 | 0, 0, imgw, imgh, | ||
| 183 | }; | ||
| 184 | extraAT.transform(coords, 0, coords, 0, 2); | ||
| 185 | coords[0] += x; | ||
| 186 | coords[1] += y; | ||
| 187 | coords[2] += x; | ||
| 188 | coords[3] += y; | ||
| 189 | sg.transform.transform(coords, 0, coords, 0, 2); | ||
| 190 | |||
| 191 | if (tryCopyOrScale(sg, img, 0, 0, imgw, imgh, | ||
| 192 | null, interpType, coords)) | ||
| 193 | { | ||
| 194 | return; | ||
| 195 | } | ||
| 196 | checkfinalxform = false; | ||
| 197 | } else { | ||
| 198 | checkfinalxform = true; | ||
| 199 | } | ||
| 200 | |||
| 201 | // Begin Transform | ||
| 202 | AffineTransform tx = new AffineTransform(sg.transform); | ||
| 203 | tx.translate(x, y); | ||
| 204 | tx.concatenate(extraAT); | ||
| 205 | |||
| 206 | // Do not try any more optimizations if either of the cases | ||
| 207 | // above was tried as we have already verified that the | ||
| 208 | // resulting transform will not simplify. | ||
| 209 | if (checkfinalxform) { | ||
| 210 | // In this case neither of the above simple transform | ||
| 211 | // pairs was found so we will do some final tests on | ||
| 212 | // the final rendering transform which may be the | ||
| 213 | // simple product of two complex transforms. | ||
| 214 | transformImage(sg, img, tx, interpType, 0, 0, imgw, imgh, null); | ||
| 215 | } else { | ||
| 216 | renderImageXform(sg, img, tx, interpType, 0, 0, imgw, imgh, null); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | /* | ||
| 221 | * This method is called with a final rendering transform that | ||
| 222 | * has combined all of the information about the Graphics2D | ||
| 223 | * transform attribute with the transformations specified by | ||
| 224 | * the arguments to the drawImage call. | ||
| 225 | * Its role is to see if the combined transform ends up being | ||
| 226 | * acceleratable by either a renderImageCopy or renderImageScale | ||
| 227 | * once all of the math is done. | ||
| 228 | * | ||
| 229 | * Note: The transform supplied here has an origin that is | ||
| 230 | * already adjusted to point to the device location where | ||
| 231 | * the (sx1, sy1) location of the source image should be placed. | ||
| 232 | */ | ||
| 233 | protected void transformImage(SunGraphics2D sg, Image img, | ||
| 234 | AffineTransform tx, int interpType, | ||
| 235 | int sx1, int sy1, int sx2, int sy2, | ||
| 236 | Color bgColor) | ||
| 237 | { | ||
| 238 | // Transform 3 source corners by tx and analyze them | ||
| 239 | // for simplified operations (Copy or Scale). Using | ||
| 240 | // 3 points lets us analyze any kind of transform, | ||
| 241 | // even transforms that involve very tiny amounts of | ||
| 242 | // rotation or skew to see if they degenerate to a | ||
| 243 | // simple scale or copy operation within the allowable | ||
| 244 | // error bounds. | ||
| 245 | // Note that we use (0,0,w,h) instead of (sx1,sy1,sx2,sy2) | ||
| 246 | // because the transform is already translated such that | ||
| 247 | // the origin is where sx1, sy1 should go. | ||
| 248 | double coords[] = new double[6]; | ||
| 249 | /* index: 0 1 2 3 4 5 */ | ||
| 250 | /* coord: (0, 0), (w, h), (0, h) */ | ||
| 251 | coords[2] = sx2 - sx1; | ||
| 252 | coords[3] = coords[5] = sy2 - sy1; | ||
| 253 | tx.transform(coords, 0, coords, 0, 3); | ||
| 254 | // First test if the X coords of the transformed UL | ||
| 255 | // and LL points match and that the Y coords of the | ||
| 256 | // transformed LR and LL points also match. | ||
| 257 | // If they do then it is a "rectilinear" transform and | ||
| 258 | // tryCopyOrScale will make sure it is upright and | ||
| 259 | // integer-based. | ||
| 260 | if (Math.abs(coords[0] - coords[4]) < MAX_TX_ERROR && | ||
| 261 | Math.abs(coords[3] - coords[5]) < MAX_TX_ERROR && | ||
| 262 | tryCopyOrScale(sg, img, sx1, sy1, sx2, sy2, | ||
| 263 | bgColor, interpType, coords)) | ||
| 264 | { | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | renderImageXform(sg, img, tx, interpType, sx1, sy1, sx2, sy2, bgColor); | ||
| 269 | } | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Check the bounding coordinates of the transformed source | ||
| 273 | * image to see if they fall on integer coordinates such | ||
| 274 | * that they will cause no interpolation anomalies if we | ||
| 275 | * use our simplified Blit or ScaledBlit operations instead | ||
| 276 | * of a full transform operation. | ||
| 277 | */ | ||
| 278 | protected boolean tryCopyOrScale(SunGraphics2D sg, | ||
| 279 | Image img, | ||
| 280 | int sx1, int sy1, | ||
| 281 | int sx2, int sy2, | ||
| 282 | Color bgColor, int interpType, | ||
| 283 | double coords[]) | ||
| 284 | { | ||
| 285 | double dx = coords[0]; | ||
| 286 | double dy = coords[1]; | ||
| 287 | double dw = coords[2] - dx; | ||
| 288 | double dh = coords[3] - dy; | ||
| 289 | // First check if width and height are very close to img w&h. | ||
| 290 | if (closeToInteger(sx2-sx1, dw) && closeToInteger(sy2-sy1, dh)) { | ||
| 291 | // Round location to nearest pixel and then test | ||
| 292 | // if it will cause interpolation anomalies. | ||
| 293 | int idx = (int) Math.floor(dx + 0.5); | ||
| 294 | int idy = (int) Math.floor(dy + 0.5); | ||
| 295 | if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR || | ||
| 296 | (closeToInteger(idx, dx) && closeToInteger(idy, dy))) | ||
| 297 | { | ||
| 298 | renderImageCopy(sg, img, bgColor, | ||
| 299 | idx, idy, | ||
| 300 | sx1, sy1, sx2-sx1, sy2-sy1); | ||
| 301 | return true; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | // (For now) We can only use our ScaledBlits if the image | ||
| 305 | // is upright (i.e. dw & dh both > 0) | ||
| 306 | if (dw > 0 && dh > 0) { | ||
| 307 | if (renderImageScale(sg, img, bgColor, interpType, | ||
| 308 | sx1, sy1, sx2, sy2, | ||
| 309 | coords[0], coords[1], coords[2], coords[3])) | ||
| 310 | { | ||
| 311 | return true; | ||
| 312 | } | ||
| 313 | } | ||
| 314 | return false; | ||
| 315 | } | ||
| 316 | |||
| 317 | /* | ||
| 318 | * Return a BufferedImage of the requested type with the indicated | ||
| 319 | * subimage of the original image located at 0,0 in the new image. | ||
| 320 | * If a bgColor is supplied, composite the original image over that | ||
| 321 | * color with a SrcOver operation, otherwise make a SrcNoEa copy. | ||
| 322 | */ | ||
| 323 | BufferedImage makeBufferedImage(Image img, Color bgColor, int type, | ||
| 324 | int sx1, int sy1, int sx2, int sy2) | ||
| 325 | { | ||
| 326 | BufferedImage bimg = new BufferedImage(sx2-sx1, sy2-sy1, type); | ||
| 327 | Graphics2D g2d = bimg.createGraphics(); | ||
| 328 | g2d.setComposite(AlphaComposite.Src); | ||
| 329 | if (bgColor != null) { | ||
| 330 | g2d.setColor(bgColor); | ||
| 331 | g2d.fillRect(0, 0, sx2-sx1, sy2-sy1); | ||
| 332 | g2d.setComposite(AlphaComposite.SrcOver); | ||
| 333 | } | ||
| 334 | g2d.drawImage(img, -sx1, -sy1, null); | ||
| 335 | g2d.dispose(); | ||
| 336 | return bimg; | ||
| 337 | } | ||
| 338 | |||
| 339 | protected void renderImageXform(SunGraphics2D sg, Image img, | ||
| 340 | AffineTransform tx, int interpType, | ||
| 341 | int sx1, int sy1, int sx2, int sy2, | ||
| 342 | Color bgColor) | ||
| 343 | { | ||
| 344 | Region clip = sg.getCompClip(); | ||
| 345 | SurfaceData dstData = sg.surfaceData; | ||
| 346 | SurfaceData srcData = dstData.getSourceSurfaceData(img, | ||
| 347 | sg.TRANSFORM_GENERIC, | ||
| 348 | sg.imageComp, | ||
| 349 | bgColor); | ||
| 350 | |||
| 351 | if (srcData == null) { | ||
| 352 | img = getBufferedImage(img); | ||
| 353 | srcData = dstData.getSourceSurfaceData(img, | ||
| 354 | sg.TRANSFORM_GENERIC, | ||
| 355 | sg.imageComp, | ||
| 356 | bgColor); | ||
| 357 | if (srcData == null) { | ||
| 358 | // REMIND: Is this correct? Can this happen? | ||
| 359 | return; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | if (isBgOperation(srcData, bgColor)) { | ||
| 364 | // We cannot perform bg operations during transform so make | ||
| 365 | // an opaque temp image with the appropriate background | ||
| 366 | // and work from there. | ||
| 367 | img = makeBufferedImage(img, bgColor, BufferedImage.TYPE_INT_RGB, | ||
| 368 | sx1, sy1, sx2, sy2); | ||
| 369 | // Temp image has appropriate subimage at 0,0 now. | ||
| 370 | sx2 -= sx1; | ||
| 371 | sy2 -= sy1; | ||
| 372 | sx1 = sy1 = 0; | ||
| 373 | |||
| 374 | srcData = dstData.getSourceSurfaceData(img, | ||
| 375 | sg.TRANSFORM_GENERIC, | ||
| 376 | sg.imageComp, | ||
| 377 | bgColor); | ||
| 378 | } | ||
| 379 | |||
| 380 | SurfaceType srcType = srcData.getSurfaceType(); | ||
| 381 | TransformHelper helper = TransformHelper.getFromCache(srcType); | ||
| 382 | |||
| 383 | if (helper == null) { | ||
| 384 | /* We have no helper for this source image type. | ||
| 385 | * But we know that we do have helpers for both RGB and ARGB, | ||
| 386 | * so convert to one of those types depending on transparency. | ||
| 387 | * ARGB_PRE might be a better choice if the source image has | ||
| 388 | * alpha, but it may cause some recursion here since we only | ||
| 389 | * tend to have converters that convert to ARGB. | ||
| 390 | */ | ||
| 391 | int type = ((srcData.getTransparency() == Transparency.OPAQUE) | ||
| 392 | ? BufferedImage.TYPE_INT_RGB | ||
| 393 | : BufferedImage.TYPE_INT_ARGB); | ||
| 394 | img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2); | ||
| 395 | // Temp image has appropriate subimage at 0,0 now. | ||
| 396 | sx2 -= sx1; | ||
| 397 | sy2 -= sy1; | ||
| 398 | sx1 = sy1 = 0; | ||
| 399 | |||
| 400 | srcData = dstData.getSourceSurfaceData(img, | ||
| 401 | sg.TRANSFORM_GENERIC, | ||
| 402 | sg.imageComp, | ||
| 403 | null); | ||
| 404 | srcType = srcData.getSurfaceType(); | ||
| 405 | helper = TransformHelper.getFromCache(srcType); | ||
| 406 | // assert(helper != null); | ||
| 407 | } | ||
| 408 | |||
| 409 | AffineTransform itx; | ||
| 410 | try { | ||
| 411 | itx = tx.createInverse(); | ||
| 412 | } catch (NoninvertibleTransformException e) { | ||
| 413 | // Non-invertible transform means no output | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | |||
| 417 | /* | ||
| 418 | * Find the maximum bounds on the destination that will be | ||
| 419 | * affected by the transformed source. First, transform all | ||
| 420 | * four corners of the source and then min and max the resulting | ||
| 421 | * destination coordinates of the transformed corners. | ||
| 422 | * Note that tx already has the offset to sx1,sy1 accounted | ||
| 423 | * for so we use the box (0, 0, sx2-sx1, sy2-sy1) as the | ||
| 424 | * source coordinates. | ||
| 425 | */ | ||
| 426 | double coords[] = new double[8]; | ||
| 427 | /* corner: UL UR LL LR */ | ||
| 428 | /* index: 0 1 2 3 4 5 6 7 */ | ||
| 429 | /* coord: (0, 0), (w, 0), (0, h), (w, h) */ | ||
| 430 | coords[2] = coords[6] = sx2 - sx1; | ||
| 431 | coords[5] = coords[7] = sy2 - sy1; | ||
| 432 | tx.transform(coords, 0, coords, 0, 4); | ||
| 433 | double ddx1, ddy1, ddx2, ddy2; | ||
| 434 | ddx1 = ddx2 = coords[0]; | ||
| 435 | ddy1 = ddy2 = coords[1]; | ||
| 436 | for (int i = 2; i < coords.length; i += 2) { | ||
| 437 | double d = coords[i]; | ||
| 438 | if (ddx1 > d) ddx1 = d; | ||
| 439 | else if (ddx2 < d) ddx2 = d; | ||
| 440 | d = coords[i+1]; | ||
| 441 | if (ddy1 > d) ddy1 = d; | ||
| 442 | else if (ddy2 < d) ddy2 = d; | ||
| 443 | } | ||
| 444 | int dx1 = (int) Math.floor(ddx1); | ||
| 445 | int dy1 = (int) Math.floor(ddy1); | ||
| 446 | int dx2 = (int) Math.ceil(ddx2); | ||
| 447 | int dy2 = (int) Math.ceil(ddy2); | ||
| 448 | |||
| 449 | SurfaceType dstType = dstData.getSurfaceType(); | ||
| 450 | MaskBlit maskblit; | ||
| 451 | Blit blit; | ||
| 452 | if (sg.compositeState <= sg.COMP_ALPHA) { | ||
| 453 | /* NOTE: We either have, or we can make, | ||
| 454 | * a MaskBlit for any alpha composite type | ||
| 455 | */ | ||
| 456 | maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre, | ||
| 457 | sg.imageComp, | ||
| 458 | dstType); | ||
| 459 | |||
| 460 | /* NOTE: We can only use the native TransformHelper | ||
| 461 | * func to go directly to the dest if both the helper | ||
| 462 | * and the MaskBlit are native. | ||
| 463 | * All helpers are native at this point, but some MaskBlit | ||
| 464 | * objects are implemented in Java, so we need to check. | ||
| 465 | */ | ||
| 466 | if (maskblit.getNativePrim() != 0) { | ||
| 467 | // We can render directly. | ||
| 468 | helper.Transform(maskblit, srcData, dstData, | ||
| 469 | sg.composite, clip, | ||
| 470 | itx, interpType, | ||
| 471 | sx1, sy1, sx2, sy2, | ||
| 472 | dx1, dy1, dx2, dy2, | ||
| 473 | null, 0, 0); | ||
| 474 | return; | ||
| 475 | } | ||
| 476 | blit = null; | ||
| 477 | } else { | ||
| 478 | /* NOTE: We either have, or we can make, | ||
| 479 | * a Blit for any composite type, even Custom | ||
| 480 | */ | ||
| 481 | maskblit = null; | ||
| 482 | blit = Blit.getFromCache(SurfaceType.IntArgbPre, | ||
| 483 | sg.imageComp, | ||
| 484 | dstType); | ||
| 485 | } | ||
| 486 | |||
| 487 | // We need to transform to a temp image and then copy | ||
| 488 | // just the pieces that are valid data to the dest. | ||
| 489 | BufferedImage tmpimg = new BufferedImage(dx2-dx1, dy2-dy1, | ||
| 490 | BufferedImage.TYPE_INT_ARGB); | ||
| 491 | SurfaceData tmpData = SurfaceData.getPrimarySurfaceData(tmpimg); | ||
| 492 | SurfaceType tmpType = tmpData.getSurfaceType(); | ||
| 493 | MaskBlit tmpmaskblit = | ||
| 494 | MaskBlit.getFromCache(SurfaceType.IntArgbPre, | ||
| 495 | CompositeType.SrcNoEa, | ||
| 496 | tmpType); | ||
| 497 | /* | ||
| 498 | * The helper function fills a temporary edges buffer | ||
| 499 | * for us with the bounding coordinates of each scanline | ||
| 500 | * in the following format: | ||
| 501 | * | ||
| 502 | * edges[0, 1] = [top y, bottom y) | ||
| 503 | * edges[2, 3] = [left x, right x) of top row | ||
| 504 | * ... | ||
| 505 | * edges[h*2, h*2+1] = [left x, right x) of bottom row | ||
| 506 | * | ||
| 507 | * all coordinates in the edges array will be relative to dx1, dy1 | ||
| 508 | * | ||
| 509 | * edges thus has to be h*2+2 in length | ||
| 510 | */ | ||
| 511 | int edges[] = new int[(dy2-dy1)*2+2]; | ||
| 512 | // It is important that edges[0]=edges[1]=0 when we call | ||
| 513 | // Transform in case it must return early and we would | ||
| 514 | // not want to render anything on an error condition. | ||
| 515 | helper.Transform(tmpmaskblit, srcData, tmpData, | ||
| 516 | AlphaComposite.Src, null, | ||
| 517 | itx, interpType, | ||
| 518 | sx1, sy1, sx2, sy2, | ||
| 519 | 0, 0, dx2-dx1, dy2-dy1, | ||
| 520 | edges, dx1, dy1); | ||
| 521 | |||
| 522 | /* | ||
| 523 | * Now copy the results, scanline by scanline, into the dest. | ||
| 524 | * The edges array helps us minimize the work. | ||
| 525 | */ | ||
| 526 | int index = 2; | ||
| 527 | for (int y = edges[0]; y < edges[1]; y++) { | ||
| 528 | int relx1 = edges[index++]; | ||
| 529 | int relx2 = edges[index++]; | ||
| 530 | if (relx1 >= relx2) { | ||
| 531 | continue; | ||
| 532 | } | ||
| 533 | if (maskblit != null) { | ||
| 534 | maskblit.MaskBlit(tmpData, dstData, | ||
| 535 | sg.composite, clip, | ||
| 536 | relx1, y, | ||
| 537 | dx1+relx1, dy1+y, | ||
| 538 | relx2 - relx1, 1, | ||
| 539 | null, 0, 0); | ||
| 540 | } else { | ||
| 541 | blit.Blit(tmpData, dstData, | ||
| 542 | sg.composite, clip, | ||
| 543 | relx1, y, | ||
| 544 | dx1+relx1, dy1+y, | ||
| 545 | relx2 - relx1, 1); | ||
| 546 | } | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 550 | // Render an image using only integer translation | ||
| 551 | // (no scale or transform or sub-pixel interpolated translations). | ||
| 552 | protected boolean renderImageCopy(SunGraphics2D sg, Image img, | ||
| 553 | Color bgColor, | ||
| 554 | int dx, int dy, | ||
| 555 | int sx, int sy, | ||
| 556 | int w, int h) | ||
| 557 | { | ||
| 558 | Region clip = sg.getCompClip(); | ||
| 559 | SurfaceData dstData = sg.surfaceData; | ||
| 560 | |||
| 561 | int attempts = 0; | ||
| 562 | // Loop up to twice through; this gives us a chance to | ||
| 563 | // revalidate the surfaceData objects in case of an exception | ||
| 564 | // and try it once more | ||
| 565 | while (true) { | ||
| 566 | SurfaceData srcData = | ||
| 567 | dstData.getSourceSurfaceData(img, | ||
| 568 | sg.TRANSFORM_ISIDENT, | ||
| 569 | sg.imageComp, | ||
| 570 | bgColor); | ||
| 571 | if (srcData == null) { | ||
| 572 | return false; | ||
| 573 | } | ||
| 574 | |||
| 575 | try { | ||
| 576 | SurfaceType srcType = srcData.getSurfaceType(); | ||
| 577 | SurfaceType dstType = dstData.getSurfaceType(); | ||
| 578 | blitSurfaceData(sg, clip, | ||
| 579 | srcData, dstData, srcType, dstType, | ||
| 580 | sx, sy, dx, dy, w, h, bgColor); | ||
| 581 | return true; | ||
| 582 | } catch (NullPointerException e) { | ||
| 583 | if (!(SurfaceData.isNull(dstData) || | ||
| 584 | SurfaceData.isNull(srcData))) | ||
| 585 | { | ||
| 586 | // Something else caused the exception, throw it... | ||
| 587 | throw e; | ||
| 588 | } | ||
| 589 | return false; | ||
| 590 | // NOP if we have been disposed | ||
| 591 | } catch (InvalidPipeException e) { | ||
| 592 | // Always catch the exception; try this a couple of times | ||
| 593 | // and fail silently if the system is not yet ready to | ||
| 594 | // revalidate the source or dest surfaceData objects. | ||
| 595 | ++attempts; | ||
| 596 | clip = sg.getCompClip(); // ensures sg.surfaceData is valid | ||
| 597 | dstData = sg.surfaceData; | ||
| 598 | if (SurfaceData.isNull(dstData) || | ||
| 599 | SurfaceData.isNull(srcData) || (attempts > 1)) | ||
| 600 | { | ||
| 601 | return false; | ||
| 602 | } | ||
| 603 | } | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | // Render an image using only integer scaling (no transform). | ||
| 608 | protected boolean renderImageScale(SunGraphics2D sg, Image img, | ||
| 609 | Color bgColor, int interpType, | ||
| 610 | int sx1, int sy1, | ||
| 611 | int sx2, int sy2, | ||
| 612 | double dx1, double dy1, | ||
| 613 | double dx2, double dy2) | ||
| 614 | { | ||
| 615 | // Currently only NEAREST_NEIGHBOR interpolation is implemented | ||
| 616 | // for ScaledBlit operations. | ||
| 617 | if (interpType != AffineTransformOp.TYPE_NEAREST_NEIGHBOR) { | ||
| 618 | return false; | ||
| 619 | } | ||
| 620 | |||
| 621 | Region clip = sg.getCompClip(); | ||
| 622 | SurfaceData dstData = sg.surfaceData; | ||
| 623 | |||
| 624 | int attempts = 0; | ||
| 625 | // Loop up to twice through; this gives us a chance to | ||
| 626 | // revalidate the surfaceData objects in case of an exception | ||
| 627 | // and try it once more | ||
| 628 | while (true) { | ||
| 629 | SurfaceData srcData = | ||
| 630 | dstData.getSourceSurfaceData(img, | ||
| 631 | sg.TRANSFORM_TRANSLATESCALE, | ||
| 632 | sg.imageComp, | ||
| 633 | bgColor); | ||
| 634 | |||
| 635 | if (srcData == null || isBgOperation(srcData, bgColor)) { | ||
| 636 | return false; | ||
| 637 | } | ||
| 638 | |||
| 639 | try { | ||
| 640 | SurfaceType srcType = srcData.getSurfaceType(); | ||
| 641 | SurfaceType dstType = dstData.getSurfaceType(); | ||
| 642 | return scaleSurfaceData(sg, clip, | ||
| 643 | srcData, dstData, srcType, dstType, | ||
| 644 | sx1, sy1, sx2, sy2, | ||
| 645 | dx1, dy1, dx2, dy2); | ||
| 646 | } catch (NullPointerException e) { | ||
| 647 | if (!SurfaceData.isNull(dstData)) { | ||
| 648 | // Something else caused the exception, throw it... | ||
| 649 | throw e; | ||
| 650 | } | ||
| 651 | return false; | ||
| 652 | // NOP if we have been disposed | ||
| 653 | } catch (InvalidPipeException e) { | ||
| 654 | // Always catch the exception; try this a couple of times | ||
| 655 | // and fail silently if the system is not yet ready to | ||
| 656 | // revalidate the source or dest surfaceData objects. | ||
| 657 | ++attempts; | ||
| 658 | clip = sg.getCompClip(); // ensures sg.surfaceData is valid | ||
| 659 | dstData = sg.surfaceData; | ||
| 660 | if (SurfaceData.isNull(dstData) || | ||
| 661 | SurfaceData.isNull(srcData) || (attempts > 1)) | ||
| 662 | { | ||
| 663 | return false; | ||
| 664 | } | ||
| 665 | } | ||
| 666 | } | ||
| 667 | } | ||
| 668 | |||
| 669 | public boolean scaleImage(SunGraphics2D sg, Image img, | ||
| 670 | int dx1, int dy1, int dx2, int dy2, | ||
| 671 | int sx1, int sy1, int sx2, int sy2, | ||
| 672 | Color bgColor) | ||
| 673 | { | ||
| 674 | int srcW, srcH, dstW, dstH; | ||
| 675 | int srcX, srcY, dstX, dstY; | ||
| 676 | boolean srcWidthFlip = false; | ||
| 677 | boolean srcHeightFlip = false; | ||
| 678 | boolean dstWidthFlip = false; | ||
| 679 | boolean dstHeightFlip = false; | ||
| 680 | |||
| 681 | if (sx2 > sx1) { | ||
| 682 | srcW = sx2 - sx1; | ||
| 683 | srcX = sx1; | ||
| 684 | } else { | ||
| 685 | srcWidthFlip = true; | ||
| 686 | srcW = sx1 - sx2; | ||
| 687 | srcX = sx2; | ||
| 688 | } | ||
| 689 | if (sy2 > sy1) { | ||
| 690 | srcH = sy2-sy1; | ||
| 691 | srcY = sy1; | ||
| 692 | } else { | ||
| 693 | srcHeightFlip = true; | ||
| 694 | srcH = sy1-sy2; | ||
| 695 | srcY = sy2; | ||
| 696 | } | ||
| 697 | if (dx2 > dx1) { | ||
| 698 | dstW = dx2 - dx1; | ||
| 699 | dstX = dx1; | ||
| 700 | } else { | ||
| 701 | dstW = dx1 - dx2; | ||
| 702 | dstWidthFlip = true; | ||
| 703 | dstX = dx2; | ||
| 704 | } | ||
| 705 | if (dy2 > dy1) { | ||
| 706 | dstH = dy2 - dy1; | ||
| 707 | dstY = dy1; | ||
| 708 | } else { | ||
| 709 | dstH = dy1 - dy2; | ||
| 710 | dstHeightFlip = true; | ||
| 711 | dstY = dy2; | ||
| 712 | } | ||
| 713 | if (srcW <= 0 || srcH <= 0) { | ||
| 714 | return true; | ||
| 715 | } | ||
| 716 | // Only accelerate scale if it does not involve a flip or transform | ||
| 717 | if ((srcWidthFlip == dstWidthFlip) && | ||
| 718 | (srcHeightFlip == dstHeightFlip) && | ||
| 719 | isSimpleTranslate(sg)) | ||
| 720 | { | ||
| 721 | double ddx1 = dstX + sg.transX; | ||
| 722 | double ddy1 = dstY + sg.transY; | ||
| 723 | double ddx2 = ddx1 + dstW; | ||
| 724 | double ddy2 = ddy1 + dstH; | ||
| 725 | if (renderImageScale(sg, img, bgColor, sg.interpolationType, | ||
| 726 | srcX, srcY, srcX+srcW, srcY+srcH, | ||
| 727 | ddx1, ddy1, ddx2, ddy2)) | ||
| 728 | { | ||
| 729 | return true; | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | AffineTransform atfm = new AffineTransform(sg.transform); | ||
| 734 | atfm.translate(dx1, dy1); | ||
| 735 | double m00 = (double)(dx2-dx1)/(sx2-sx1); | ||
| 736 | double m11 = (double)(dy2-dy1)/(sy2-sy1); | ||
| 737 | atfm.scale(m00, m11); | ||
| 738 | atfm.translate(srcX-sx1, srcY-sy1); | ||
| 739 | |||
| 740 | int imgW = img.getWidth(null); | ||
| 741 | int imgH = img.getHeight(null); | ||
| 742 | srcW += srcX; | ||
| 743 | srcH += srcY; | ||
| 744 | // Make sure we are not out of bounds | ||
| 745 | if (srcW > imgW) { | ||
| 746 | srcW = imgW; | ||
| 747 | } | ||
| 748 | if (srcH > imgH) { | ||
| 749 | srcH = imgH; | ||
| 750 | } | ||
| 751 | if (srcX < 0) { | ||
| 752 | atfm.translate(-srcX, 0); | ||
| 753 | srcX = 0; | ||
| 754 | } | ||
| 755 | if (srcY < 0) { | ||
| 756 | atfm.translate(0, -srcY); | ||
| 757 | srcY = 0; | ||
| 758 | } | ||
| 759 | if (srcX >= srcW || srcY >= srcH) { | ||
| 760 | return true; | ||
| 761 | } | ||
| 762 | // Note: src[WH] are currently the right and bottom coordinates. | ||
| 763 | // The following two lines would adjust src[WH] back to being | ||
| 764 | // dimensions. | ||
| 765 | // srcW -= srcX; | ||
| 766 | // srcH -= srcY; | ||
| 767 | // Since transformImage needs right and bottom coords we will | ||
| 768 | // omit this adjustment. | ||
| 769 | |||
| 770 | transformImage(sg, img, atfm, sg.interpolationType, | ||
| 771 | srcX, srcY, srcW, srcH, bgColor); | ||
| 772 | return true; | ||
| 773 | } | ||
| 774 | |||
| 775 | /** | ||
| 776 | ** Utilities | ||
| 777 | ** The following methods are used by the public methods above | ||
| 778 | ** for performing various operations | ||
| 779 | **/ | ||
| 780 | |||
| 781 | /* | ||
| 782 | * This constant represents a tradeoff between the | ||
| 783 | * need to make sure that image transformations are | ||
| 784 | * "very close" to integer device coordinates before | ||
| 785 | * we decide to use an integer scale or copy operation | ||
| 786 | * as a substitute and the fact that roundoff errors | ||
| 787 | * in AffineTransforms are frequently introduced by | ||
| 788 | * performing multiple sequential operations on them. | ||
| 789 | * | ||
| 790 | * The evaluation of bug 4990624 details the potential | ||
| 791 | * for this error cutoff to result in display anomalies | ||
| 792 | * in different types of image operations and how this | ||
| 793 | * value represents a good compromise here. | ||
| 794 | */ | ||
| 795 | private static final double MAX_TX_ERROR = .0001; | ||
| 796 | |||
| 797 | public static boolean closeToInteger(int i, double d) { | ||
| 798 | return (Math.abs(d-i) < MAX_TX_ERROR); | ||
| 799 | } | ||
| 800 | |||
| 801 | public static boolean isSimpleTranslate(SunGraphics2D sg) { | ||
| 802 | int ts = sg.transformState; | ||
| 803 | if (ts <= sg.TRANSFORM_INT_TRANSLATE) { | ||
| 804 | // Integer translates are always "simple" | ||
| 805 | return true; | ||
| 806 | } | ||
| 807 | if (ts >= sg.TRANSFORM_TRANSLATESCALE) { | ||
| 808 | // Scales and beyond are always "not simple" | ||
| 809 | return false; | ||
| 810 | } | ||
| 811 | // non-integer translates are only simple when not interpolating | ||
| 812 | if (sg.interpolationType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR) { | ||
| 813 | return true; | ||
| 814 | } | ||
| 815 | return false; | ||
| 816 | } | ||
| 817 | |||
| 818 | protected static boolean isBgOperation(SurfaceData srcData, Color bgColor) { | ||
| 819 | // If we cannot get the srcData, then cannot assume anything about | ||
| 820 | // the image | ||
| 821 | return ((srcData == null) || | ||
| 822 | ((bgColor != null) && | ||
| 823 | (srcData.getTransparency() != Transparency.OPAQUE))); | ||
| 824 | } | ||
| 825 | |||
| 826 | protected BufferedImage getBufferedImage(Image img) { | ||
| 827 | if (img instanceof BufferedImage) { | ||
| 828 | return (BufferedImage)img; | ||
| 829 | } | ||
| 830 | // Must be VolatileImage; get BufferedImage representation | ||
| 831 | return ((VolatileImage)img).getSnapshot(); | ||
| 832 | } | ||
| 833 | |||
| 834 | /* | ||
| 835 | * Return the color model to be used with this BufferedImage and | ||
| 836 | * transform. | ||
| 837 | */ | ||
| 838 | private ColorModel getTransformColorModel(SunGraphics2D sg, | ||
| 839 | BufferedImage bImg, | ||
| 840 | AffineTransform tx) { | ||
| 841 | ColorModel cm = bImg.getColorModel(); | ||
| 842 | ColorModel dstCM = cm; | ||
| 843 | |||
| 844 | if (tx.isIdentity()) { | ||
| 845 | return dstCM; | ||
| 846 | } | ||
| 847 | int type = tx.getType(); | ||
| 848 | boolean needTrans = | ||
| 849 | ((type&(tx.TYPE_MASK_ROTATION|tx.TYPE_GENERAL_TRANSFORM)) != 0); | ||
| 850 | if (! needTrans && type != tx.TYPE_TRANSLATION && type != tx.TYPE_IDENTITY) | ||
| 851 | { | ||
| 852 | double[] mtx = new double[4]; | ||
| 853 | tx.getMatrix(mtx); | ||
| 854 | // Check out the matrix. A non-integral scale will force ARGB | ||
| 855 | // since the edge conditions cannot be guaranteed. | ||
| 856 | needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]); | ||
| 857 | } | ||
| 858 | |||
| 859 | if (sg.renderHint != SunHints.INTVAL_RENDER_QUALITY) { | ||
| 860 | if (cm instanceof IndexColorModel) { | ||
| 861 | Raster raster = bImg.getRaster(); | ||
| 862 | IndexColorModel icm = (IndexColorModel) cm; | ||
| 863 | // Just need to make sure that we have a transparent pixel | ||
| 864 | if (needTrans && cm.getTransparency() == cm.OPAQUE) { | ||
| 865 | // Fix 4221407 | ||
| 866 | if (raster instanceof sun.awt.image.BytePackedRaster) { | ||
| 867 | dstCM = ColorModel.getRGBdefault(); | ||
| 868 | } | ||
| 869 | else { | ||
| 870 | double[] matrix = new double[6]; | ||
| 871 | tx.getMatrix(matrix); | ||
| 872 | if (matrix[1] == 0. && matrix[2] ==0. | ||
| 873 | && matrix[4] == 0. && matrix[5] == 0.) { | ||
| 874 | // Only scaling so do not need to create | ||
| 875 | } | ||
| 876 | else { | ||
| 877 | int mapSize = icm.getMapSize(); | ||
| 878 | if (mapSize < 256) { | ||
| 879 | int[] cmap = new int[mapSize+1]; | ||
| 880 | icm.getRGBs(cmap); | ||
| 881 | cmap[mapSize] = 0x0000; | ||
| 882 | dstCM = new | ||
| 883 | IndexColorModel(icm.getPixelSize(), | ||
| 884 | mapSize+1, | ||
| 885 | cmap, 0, true, mapSize, | ||
| 886 | DataBuffer.TYPE_BYTE); | ||
| 887 | } | ||
| 888 | else { | ||
| 889 | dstCM = ColorModel.getRGBdefault(); | ||
| 890 | } | ||
| 891 | } /* if (matrix[0] < 1.f ...) */ | ||
| 892 | } /* raster instanceof sun.awt.image.BytePackedRaster */ | ||
| 893 | } /* if (cm.getTransparency() == cm.OPAQUE) */ | ||
| 894 | } /* if (cm instanceof IndexColorModel) */ | ||
| 895 | else if (needTrans && cm.getTransparency() == cm.OPAQUE) { | ||
| 896 | // Need a bitmask transparency | ||
| 897 | // REMIND: for now, use full transparency since no loops | ||
| 898 | // for bitmask | ||
| 899 | dstCM = ColorModel.getRGBdefault(); | ||
| 900 | } | ||
| 901 | } /* if (sg.renderHint == RENDER_QUALITY) */ | ||
| 902 | else { | ||
| 903 | |||
| 904 | if (cm instanceof IndexColorModel || | ||
| 905 | (needTrans && cm.getTransparency() == cm.OPAQUE)) | ||
| 906 | { | ||
| 907 | // Need a bitmask transparency | ||
| 908 | // REMIND: for now, use full transparency since no loops | ||
| 909 | // for bitmask | ||
| 910 | dstCM = ColorModel.getRGBdefault(); | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | return dstCM; | ||
| 915 | } | ||
| 916 | |||
| 917 | protected void blitSurfaceData(SunGraphics2D sg, | ||
| 918 | Region clipRegion, | ||
| 919 | SurfaceData srcData, | ||
| 920 | SurfaceData dstData, | ||
| 921 | SurfaceType srcType, | ||
| 922 | SurfaceType dstType, | ||
| 923 | int sx, int sy, int dx, int dy, | ||
| 924 | int w, int h, | ||
| 925 | Color bgColor) | ||
| 926 | { | ||
| 927 | if (w <= 0 || h <= 0) { | ||
| 928 | /* | ||
| 929 | * Fix for bugid 4783274 - BlitBg throws an exception for | ||
| 930 | * a particular set of anomalous parameters. | ||
| 931 | * REMIND: The native loops do proper clipping and would | ||
| 932 | * detect this situation themselves, but the Java loops | ||
| 933 | * all seem to trust their parameters a little too well | ||
| 934 | * to the point where they will try to process a negative | ||
| 935 | * area of pixels and throw exceptions. The real fix is | ||
| 936 | * to modify the Java loops to do proper clipping so that | ||
| 937 | * they can deal with negative dimensions as well as | ||
| 938 | * improperly large dimensions, but that fix is too risky | ||
| 939 | * to integrate for Mantis at this point. In the meantime | ||
| 940 | * eliminating the negative or zero dimensions here is | ||
| 941 | * "correct" and saves them from some nasty exceptional | ||
| 942 | * conditions, one of which is the test case of 4783274. | ||
| 943 | */ | ||
| 944 | return; | ||
| 945 | } | ||
| 946 | CompositeType comp = sg.imageComp; | ||
| 947 | if (CompositeType.SrcOverNoEa.equals(comp) && | ||
| 948 | (srcData.getTransparency() == Transparency.OPAQUE || | ||
| 949 | (bgColor != null && | ||
| 950 | bgColor.getTransparency() == Transparency.OPAQUE))) | ||
| 951 | { | ||
| 952 | comp = CompositeType.SrcNoEa; | ||
| 953 | } | ||
| 954 | if (!isBgOperation(srcData, bgColor)) { | ||
| 955 | Blit blit = Blit.getFromCache(srcType, comp, dstType); | ||
| 956 | blit.Blit(srcData, dstData, sg.composite, clipRegion, | ||
| 957 | sx, sy, dx, dy, w, h); | ||
| 958 | } else { | ||
| 959 | BlitBg blit = BlitBg.getFromCache(srcType, comp, dstType); | ||
| 960 | blit.BlitBg(srcData, dstData, sg.composite, clipRegion, | ||
| 961 | bgColor.getRGB(), sx, sy, dx, dy, w, h); | ||
| 962 | } | ||
| 963 | } | ||
| 964 | |||
| 965 | protected boolean scaleSurfaceData(SunGraphics2D sg, | ||
| 966 | Region clipRegion, | ||
| 967 | SurfaceData srcData, | ||
| 968 | SurfaceData dstData, | ||
| 969 | SurfaceType srcType, | ||
| 970 | SurfaceType dstType, | ||
| 971 | int sx1, int sy1, | ||
| 972 | int sx2, int sy2, | ||
| 973 | double dx1, double dy1, | ||
| 974 | double dx2, double dy2) | ||
| 975 | { | ||
| 976 | CompositeType comp = sg.imageComp; | ||
| 977 | if (CompositeType.SrcOverNoEa.equals(comp) && | ||
| 978 | (srcData.getTransparency() == Transparency.OPAQUE)) | ||
| 979 | { | ||
| 980 | comp = CompositeType.SrcNoEa; | ||
| 981 | } | ||
| 982 | |||
| 983 | ScaledBlit blit = ScaledBlit.getFromCache(srcType, comp, dstType); | ||
| 984 | if (blit != null) { | ||
| 985 | blit.Scale(srcData, dstData, sg.composite, clipRegion, | ||
| 986 | sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2); | ||
| 987 | return true; | ||
| 988 | } | ||
| 989 | return false; | ||
| 990 | } | ||
| 991 | |||
| 992 | protected static boolean imageReady(ToolkitImage sunimg, | ||
| 993 | ImageObserver observer) | ||
| 994 | { | ||
| 995 | if (sunimg.hasError()) { | ||
| 996 | if (observer != null) { | ||
| 997 | observer.imageUpdate(sunimg, | ||
| 998 | ImageObserver.ERROR|ImageObserver.ABORT, | ||
| 999 | -1, -1, -1, -1); | ||
| 1000 | } | ||
| 1001 | return false; | ||
| 1002 | } | ||
| 1003 | return true; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 1007 | int x, int y, | ||
| 1008 | Color bgColor, | ||
| 1009 | ImageObserver observer) { | ||
| 1010 | if (!(img instanceof ToolkitImage)) { | ||
| 1011 | return copyImage(sg, img, x, y, bgColor); | ||
| 1012 | } else { | ||
| 1013 | ToolkitImage sunimg = (ToolkitImage)img; | ||
| 1014 | if (!imageReady(sunimg, observer)) { | ||
| 1015 | return false; | ||
| 1016 | } | ||
| 1017 | ImageRepresentation ir = sunimg.getImageRep(); | ||
| 1018 | return ir.drawToBufImage(sg, sunimg, x, y, bgColor, observer); | ||
| 1019 | } | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 1023 | int dx, int dy, int sx, int sy, int w, int h, | ||
| 1024 | Color bgColor, | ||
| 1025 | ImageObserver observer) { | ||
| 1026 | if (!(img instanceof ToolkitImage)) { | ||
| 1027 | return copyImage(sg, img, dx, dy, sx, sy, w, h, bgColor); | ||
| 1028 | } else { | ||
| 1029 | ToolkitImage sunimg = (ToolkitImage)img; | ||
| 1030 | if (!imageReady(sunimg, observer)) { | ||
| 1031 | return false; | ||
| 1032 | } | ||
| 1033 | ImageRepresentation ir = sunimg.getImageRep(); | ||
| 1034 | return ir.drawToBufImage(sg, sunimg, | ||
| 1035 | dx, dy, (dx + w), (dy + h), | ||
| 1036 | sx, sy, (sx + w), (sy + h), | ||
| 1037 | bgColor, observer); | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | public boolean scaleImage(SunGraphics2D sg, Image img, | ||
| 1042 | int x, int y, | ||
| 1043 | int width, int height, | ||
| 1044 | Color bgColor, | ||
| 1045 | ImageObserver observer) { | ||
| 1046 | if (!(img instanceof ToolkitImage)) { | ||
| 1047 | return scaleImage(sg, img, x, y, width, height, bgColor); | ||
| 1048 | } else { | ||
| 1049 | ToolkitImage sunimg = (ToolkitImage)img; | ||
| 1050 | if (!imageReady(sunimg, observer)) { | ||
| 1051 | return false; | ||
| 1052 | } | ||
| 1053 | ImageRepresentation ir = sunimg.getImageRep(); | ||
| 1054 | return ir.drawToBufImage(sg, sunimg, x, y, width, height, bgColor, | ||
| 1055 | observer); | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | public boolean scaleImage(SunGraphics2D sg, Image img, | ||
| 1060 | int dx1, int dy1, int dx2, int dy2, | ||
| 1061 | int sx1, int sy1, int sx2, int sy2, | ||
| 1062 | Color bgColor, | ||
| 1063 | ImageObserver observer) { | ||
| 1064 | if (!(img instanceof ToolkitImage)) { | ||
| 1065 | return scaleImage(sg, img, dx1, dy1, dx2, dy2, | ||
| 1066 | sx1, sy1, sx2, sy2, bgColor); | ||
| 1067 | } else { | ||
| 1068 | ToolkitImage sunimg = (ToolkitImage)img; | ||
| 1069 | if (!imageReady(sunimg, observer)) { | ||
| 1070 | return false; | ||
| 1071 | } | ||
| 1072 | ImageRepresentation ir = sunimg.getImageRep(); | ||
| 1073 | return ir.drawToBufImage(sg, sunimg, dx1, dy1, dx2, dy2, | ||
| 1074 | sx1, sy1, sx2, sy2, bgColor, observer); | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | public boolean transformImage(SunGraphics2D sg, Image img, | ||
| 1079 | AffineTransform atfm, | ||
| 1080 | ImageObserver observer) { | ||
| 1081 | if (!(img instanceof ToolkitImage)) { | ||
| 1082 | transformImage(sg, img, 0, 0, atfm, sg.interpolationType); | ||
| 1083 | return true; | ||
| 1084 | } else { | ||
| 1085 | ToolkitImage sunimg = (ToolkitImage)img; | ||
| 1086 | if (!imageReady(sunimg, observer)) { | ||
| 1087 | return false; | ||
| 1088 | } | ||
| 1089 | ImageRepresentation ir = sunimg.getImageRep(); | ||
| 1090 | return ir.drawToBufImage(sg, sunimg, atfm, observer); | ||
| 1091 | } | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | public void transformImage(SunGraphics2D sg, BufferedImage img, | ||
| 1095 | BufferedImageOp op, int x, int y) | ||
| 1096 | { | ||
| 1097 | if (op != null) { | ||
| 1098 | if (op instanceof AffineTransformOp) { | ||
| 1099 | AffineTransformOp atop = (AffineTransformOp) op; | ||
| 1100 | transformImage(sg, img, x, y, | ||
| 1101 | atop.getTransform(), | ||
| 1102 | atop.getInterpolationType()); | ||
| 1103 | return; | ||
| 1104 | } else { | ||
| 1105 | img = op.filter(img, null); | ||
| 1106 | } | ||
| 1107 | } | ||
| 1108 | copyImage(sg, img, x, y, null); | ||
| 1109 | } | ||
| 1110 | } | ||
Binary file not shown.
| @@ -0,0 +1,86 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2001, 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.Color; | ||
| 29 | import java.awt.Image; | ||
| 30 | import java.awt.image.BufferedImage; | ||
| 31 | import java.awt.image.BufferedImageOp; | ||
| 32 | import java.awt.image.ImageObserver; | ||
| 33 | import java.awt.geom.AffineTransform; | ||
| 34 | import sun.java2d.SunGraphics2D; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * This interface defines the set of calls that pipeline objects | ||
| 38 | * can use to pass on responsibility for performing various | ||
| 39 | * image copy commands. | ||
| 40 | * There are 3 types of image copies handled by this class: | ||
| 41 | * - copyImage: These methods simply copy the pixels | ||
| 42 | * from the src to dest, either from (0, 0) (implicit) | ||
| 43 | * or from a given (sx, sy) location. | ||
| 44 | * - scaleImage: These methods copy from src to dest while | ||
| 45 | * scaling the source image. The src and dest rectangles | ||
| 46 | * are used to specify the scale. | ||
| 47 | * - copyImageBg: These methods behave the same as the | ||
| 48 | * copyImage methods except they substitute the given | ||
| 49 | * background color for any transparent pixels. | ||
| 50 | * - scaleImageBg: These methods behave the same as the | ||
| 51 | * scaleImage methods except they substitute the given | ||
| 52 | * background color for any transparent pixels. | ||
| 53 | * - transformImage.... | ||
| 54 | */ | ||
| 55 | public interface DrawImagePipe { | ||
| 56 | |||
| 57 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 58 | int x, int y, | ||
| 59 | Color bgColor, | ||
| 60 | ImageObserver observer); | ||
| 61 | |||
| 62 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 63 | int dx, int dy, int sx, int sy, int w, int h, | ||
| 64 | Color bgColor, | ||
| 65 | ImageObserver observer); | ||
| 66 | |||
| 67 | public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y, | ||
| 68 | int width, int height, | ||
| 69 | Color bgColor, | ||
| 70 | ImageObserver observer); | ||
| 71 | |||
| 72 | public boolean scaleImage(SunGraphics2D sg, Image img, | ||
| 73 | int dx1, int dy1, int dx2, int dy2, | ||
| 74 | int sx1, int sy1, int sx2, int sy2, | ||
| 75 | Color bgColor, | ||
| 76 | ImageObserver observer); | ||
| 77 | |||
| 78 | public boolean transformImage(SunGraphics2D sg, Image img, | ||
| 79 | AffineTransform atfm, | ||
| 80 | ImageObserver observer); | ||
| 81 | |||
| 82 | public void transformImage(SunGraphics2D sg, BufferedImage img, | ||
| 83 | BufferedImageOp op, int x, int y); | ||
| 84 | |||
| 85 | |||
| 86 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,154 @@ | |||
| 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.awt.AlphaComposite; | ||
| 29 | import java.awt.CompositeContext; | ||
| 30 | import java.awt.PaintContext; | ||
| 31 | import java.awt.Rectangle; | ||
| 32 | import java.awt.Shape; | ||
| 33 | import java.awt.RenderingHints; | ||
| 34 | import java.awt.image.ColorModel; | ||
| 35 | import java.awt.image.BufferedImage; | ||
| 36 | import java.awt.image.Raster; | ||
| 37 | import java.awt.image.WritableRaster; | ||
| 38 | import sun.awt.image.BufImgSurfaceData; | ||
| 39 | import sun.java2d.SunGraphics2D; | ||
| 40 | import sun.java2d.SurfaceData; | ||
| 41 | import sun.java2d.loops.Blit; | ||
| 42 | import sun.java2d.loops.MaskBlit; | ||
| 43 | import sun.java2d.loops.CompositeType; | ||
| 44 | |||
| 45 | public class GeneralCompositePipe implements CompositePipe { | ||
| 46 | class TileContext { | ||
| 47 | SunGraphics2D sunG2D; | ||
| 48 | PaintContext paintCtxt; | ||
| 49 | CompositeContext compCtxt; | ||
| 50 | ColorModel compModel; | ||
| 51 | Object pipeState; | ||
| 52 | |||
| 53 | public TileContext(SunGraphics2D sg, PaintContext pCtx, | ||
| 54 | CompositeContext cCtx, ColorModel cModel) { | ||
| 55 | sunG2D = sg; | ||
| 56 | paintCtxt = pCtx; | ||
| 57 | compCtxt = cCtx; | ||
| 58 | compModel = cModel; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR, | ||
| 63 | int[] abox) { | ||
| 64 | RenderingHints hints = sg.getRenderingHints(); | ||
| 65 | ColorModel model = sg.getDeviceColorModel(); | ||
| 66 | PaintContext paintContext = | ||
| 67 | sg.paint.createContext(model, devR, s.getBounds2D(), | ||
| 68 | sg.cloneTransform(), | ||
| 69 | hints); | ||
| 70 | CompositeContext compositeContext = | ||
| 71 | sg.composite.createContext(paintContext.getColorModel(), model, | ||
| 72 | hints); | ||
| 73 | return new TileContext(sg, paintContext, compositeContext, model); | ||
| 74 | } | ||
| 75 | |||
| 76 | public boolean needTile(Object ctx, int x, int y, int w, int h) { | ||
| 77 | return true; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * GeneralCompositePipe.renderPathTile works with custom composite operator | ||
| 82 | * provided by an application | ||
| 83 | */ | ||
| 84 | public void renderPathTile(Object ctx, | ||
| 85 | byte[] atile, int offset, int tilesize, | ||
| 86 | int x, int y, int w, int h) { | ||
| 87 | TileContext context = (TileContext) ctx; | ||
| 88 | PaintContext paintCtxt = context.paintCtxt; | ||
| 89 | CompositeContext compCtxt = context.compCtxt; | ||
| 90 | SunGraphics2D sg = context.sunG2D; | ||
| 91 | |||
| 92 | Raster srcRaster = paintCtxt.getRaster(x, y, w, h); | ||
| 93 | ColorModel paintModel = paintCtxt.getColorModel(); | ||
| 94 | |||
| 95 | Raster dstRaster; | ||
| 96 | Raster dstIn; | ||
| 97 | WritableRaster dstOut; | ||
| 98 | |||
| 99 | SurfaceData sd = sg.getSurfaceData(); | ||
| 100 | dstRaster = sd.getRaster(x, y, w, h); | ||
| 101 | if (dstRaster instanceof WritableRaster && atile == null) { | ||
| 102 | dstOut = (WritableRaster) dstRaster; | ||
| 103 | dstOut = dstOut.createWritableChild(x, y, w, h, 0, 0, null); | ||
| 104 | dstIn = dstOut; | ||
| 105 | } else { | ||
| 106 | dstIn = dstRaster.createChild(x, y, w, h, 0, 0, null); | ||
| 107 | dstOut = dstIn.createCompatibleWritableRaster(); | ||
| 108 | } | ||
| 109 | |||
| 110 | compCtxt.compose(srcRaster, dstIn, dstOut); | ||
| 111 | |||
| 112 | if (dstRaster != dstOut && dstOut.getParent() != dstRaster) { | ||
| 113 | if (dstRaster instanceof WritableRaster && atile == null) { | ||
| 114 | ((WritableRaster) dstRaster).setDataElements(x, y, dstOut); | ||
| 115 | } else { | ||
| 116 | ColorModel cm = sg.getDeviceColorModel(); | ||
| 117 | BufferedImage resImg = | ||
| 118 | new BufferedImage(cm, dstOut, | ||
| 119 | cm.isAlphaPremultiplied(), | ||
| 120 | null); | ||
| 121 | SurfaceData resData = BufImgSurfaceData.createData(resImg); | ||
| 122 | if (atile == null) { | ||
| 123 | Blit blit = Blit.getFromCache(resData.getSurfaceType(), | ||
| 124 | CompositeType.SrcNoEa, | ||
| 125 | sd.getSurfaceType()); | ||
| 126 | blit.Blit(resData, sd, AlphaComposite.Src, null, | ||
| 127 | 0, 0, x, y, w, h); | ||
| 128 | } else { | ||
| 129 | MaskBlit blit = MaskBlit.getFromCache(resData.getSurfaceType(), | ||
| 130 | CompositeType.SrcNoEa, | ||
| 131 | sd.getSurfaceType()); | ||
| 132 | blit.MaskBlit(resData, sd, AlphaComposite.Src, null, | ||
| 133 | 0, 0, x, y, w, h, | ||
| 134 | atile, offset, tilesize); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | public void skipTile(Object ctx, int x, int y) { | ||
| 141 | return; | ||
| 142 | } | ||
| 143 | |||
| 144 | public void endSequence(Object ctx) { | ||
| 145 | TileContext context = (TileContext) ctx; | ||
| 146 | if (context.paintCtxt != null) { | ||
| 147 | context.paintCtxt.dispose(); | ||
| 148 | } | ||
| 149 | if (context.compCtxt != null) { | ||
| 150 | context.compCtxt.dispose(); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | } | ||
Binary file not shown.
| @@ -0,0 +1,60 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 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.font.GlyphVector; | ||
| 29 | import sun.awt.SunHints; | ||
| 30 | import sun.java2d.SunGraphics2D; | ||
| 31 | import sun.font.GlyphList; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * A delegate pipe of SG2D which implements redispatching of | ||
| 35 | * for the src mode loops in the drawGlyphVector case where | ||
| 36 | * the installed loop may not match the glyphvector. | ||
| 37 | */ | ||
| 38 | |||
| 39 | public abstract class GlyphListLoopPipe extends GlyphListPipe | ||
| 40 | implements LoopBasedPipe | ||
| 41 | { | ||
| 42 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl, | ||
| 43 | int aaHint) { | ||
| 44 | switch (aaHint) { | ||
| 45 | case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: | ||
| 46 | sg2d.loops.drawGlyphListLoop. | ||
| 47 | DrawGlyphList(sg2d, sg2d.surfaceData, gl); | ||
| 48 | return; | ||
| 49 | case SunHints.INTVAL_TEXT_ANTIALIAS_ON: | ||
| 50 | sg2d.loops.drawGlyphListAALoop. | ||
| 51 | DrawGlyphListAA(sg2d, sg2d.surfaceData, gl); | ||
| 52 | return; | ||
| 53 | case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB: | ||
| 54 | case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB: | ||
| 55 | sg2d.loops.drawGlyphListLCDLoop. | ||
| 56 | DrawGlyphListLCD(sg2d,sg2d.surfaceData, gl); | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
Binary file not shown.
| @@ -0,0 +1,147 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2005, 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.Font; | ||
| 29 | import java.awt.Rectangle; | ||
| 30 | import java.awt.Shape; | ||
| 31 | import java.awt.font.FontRenderContext; | ||
| 32 | import java.awt.font.GlyphVector; | ||
| 33 | import java.awt.font.TextLayout; | ||
| 34 | |||
| 35 | import sun.awt.SunHints; | ||
| 36 | import sun.java2d.SunGraphics2D; | ||
| 37 | import sun.java2d.SurfaceData; | ||
| 38 | import sun.font.GlyphList; | ||
| 39 | import sun.java2d.loops.FontInfo; | ||
| 40 | |||
| 41 | /** | ||
| 42 | * A delegate pipe of SG2D for drawing text. | ||
| 43 | */ | ||
| 44 | |||
| 45 | public abstract class GlyphListPipe implements TextPipe { | ||
| 46 | |||
| 47 | public void drawString(SunGraphics2D sg2d, String s, | ||
| 48 | double x, double y) | ||
| 49 | { | ||
| 50 | FontInfo info = sg2d.getFontInfo(); | ||
| 51 | if (info.pixelHeight > OutlineTextRenderer.THRESHHOLD) { | ||
| 52 | SurfaceData.outlineTextRenderer.drawString(sg2d, s, x, y); | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 56 | float devx, devy; | ||
| 57 | if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { | ||
| 58 | double origin[] = {x + info.originX, y + info.originY}; | ||
| 59 | sg2d.transform.transform(origin, 0, origin, 0, 1); | ||
| 60 | devx = (float)origin[0]; | ||
| 61 | devy = (float)origin[1]; | ||
| 62 | } else { | ||
| 63 | devx = (float)(x + info.originX + sg2d.transX); | ||
| 64 | devy = (float)(y + info.originY + sg2d.transY); | ||
| 65 | } | ||
| 66 | /* setFromString returns false if shaping is needed, and we then back | ||
| 67 | * off to a TextLayout. Such text may benefit slightly from a lower | ||
| 68 | * overhead in this approach over the approach in previous releases. | ||
| 69 | */ | ||
| 70 | GlyphList gl = GlyphList.getInstance(); | ||
| 71 | if (gl.setFromString(info, s, devx, devy)) { | ||
| 72 | drawGlyphList(sg2d, gl); | ||
| 73 | gl.dispose(); | ||
| 74 | } else { | ||
| 75 | gl.dispose(); // release this asap. | ||
| 76 | TextLayout tl = new TextLayout(s, sg2d.getFont(), | ||
| 77 | sg2d.getFontRenderContext()); | ||
| 78 | tl.draw(sg2d, (float)x, (float)y); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | public void drawChars(SunGraphics2D sg2d, | ||
| 83 | char data[], int offset, int length, | ||
| 84 | int ix, int iy) | ||
| 85 | { | ||
| 86 | FontInfo info = sg2d.getFontInfo(); | ||
| 87 | float x, y; | ||
| 88 | if (info.pixelHeight > OutlineTextRenderer.THRESHHOLD) { | ||
| 89 | SurfaceData.outlineTextRenderer.drawChars( | ||
| 90 | sg2d, data, offset, length, ix, iy); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { | ||
| 94 | double origin[] = {ix + info.originX, iy + info.originY}; | ||
| 95 | sg2d.transform.transform(origin, 0, origin, 0, 1); | ||
| 96 | x = (float) origin[0]; | ||
| 97 | y = (float) origin[1]; | ||
| 98 | } else { | ||
| 99 | x = ix + info.originX + sg2d.transX; | ||
| 100 | y = iy + info.originY + sg2d.transY; | ||
| 101 | } | ||
| 102 | GlyphList gl = GlyphList.getInstance(); | ||
| 103 | if (gl.setFromChars(info, data, offset, length, x, y)) { | ||
| 104 | drawGlyphList(sg2d, gl); | ||
| 105 | gl.dispose(); | ||
| 106 | } else { | ||
| 107 | gl.dispose(); // release this asap. | ||
| 108 | TextLayout tl = new TextLayout(new String(data, offset, length), | ||
| 109 | sg2d.getFont(), | ||
| 110 | sg2d.getFontRenderContext()); | ||
| 111 | tl.draw(sg2d, ix, iy); | ||
| 112 | |||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | public void drawGlyphVector(SunGraphics2D sg2d, GlyphVector gv, | ||
| 117 | float x, float y) | ||
| 118 | { | ||
| 119 | FontRenderContext frc = gv.getFontRenderContext(); | ||
| 120 | FontInfo info = sg2d.getGVFontInfo(gv.getFont(), frc); | ||
| 121 | if (info.pixelHeight > OutlineTextRenderer.THRESHHOLD) { | ||
| 122 | SurfaceData.outlineTextRenderer.drawGlyphVector(sg2d, gv, x, y); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) { | ||
| 126 | double origin[] = {x, y}; | ||
| 127 | sg2d.transform.transform(origin, 0, origin, 0, 1); | ||
| 128 | x = (float) origin[0]; | ||
| 129 | y = (float) origin[1]; | ||
| 130 | } else { | ||
| 131 | x += sg2d.transX; // don't use the glyph info origin, already in gv. | ||
| 132 | y += sg2d.transY; | ||
| 133 | } | ||
| 134 | |||
| 135 | GlyphList gl = GlyphList.getInstance(); | ||
| 136 | gl.setFromGlyphVector(info, gv, x, y); | ||
| 137 | drawGlyphList(sg2d, gl, info.aaHint); | ||
| 138 | gl.dispose(); | ||
| 139 | } | ||
| 140 | |||
| 141 | protected abstract void drawGlyphList(SunGraphics2D sg2d, GlyphList gl); | ||
| 142 | |||
| 143 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl, | ||
| 144 | int aaHint) { | ||
| 145 | drawGlyphList(sg2d, gl); | ||
| 146 | } | ||
| 147 | } | ||
Binary file not shown.
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 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.font.GlyphVector; | ||
| 29 | import sun.java2d.SunGraphics2D; | ||
| 30 | import sun.font.GlyphList; | ||
| 31 | import static sun.awt.SunHints.*; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * A delegate pipe of SG2D for drawing LCD text with | ||
| 35 | * a solid source colour to an opaque destination. | ||
| 36 | */ | ||
| 37 | |||
| 38 | public class LCDTextRenderer extends GlyphListLoopPipe { | ||
| 39 | |||
| 40 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { | ||
| 41 | sg2d.loops.drawGlyphListLCDLoop. | ||
| 42 | DrawGlyphListLCD(sg2d, sg2d.surfaceData, gl); | ||
| 43 | } | ||
| 44 | } | ||
Binary file not shown.
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2009, 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 | /** | ||
| 29 | * This is a marker interface used by Pipes that need RenderLoops. | ||
| 30 | * RenderLoops are validated in SurfaceData when a pipe is recognised to | ||
| 31 | * implement this interface. | ||
| 32 | * | ||
| 33 | * @author Mario Torre <neugens@aicas.com> | ||
| 34 | */ | ||
| 35 | public interface LoopBasedPipe { | ||
| 36 | |||
| 37 | } | ||
Binary file not shown.
| @@ -0,0 +1,378 @@ | |||
| 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.pipe; | ||
| 27 | |||
| 28 | import java.awt.Font; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import java.awt.BasicStroke; | ||
| 31 | import java.awt.Polygon; | ||
| 32 | import java.awt.geom.AffineTransform; | ||
| 33 | import java.awt.geom.PathIterator; | ||
| 34 | import java.awt.geom.RoundRectangle2D; | ||
| 35 | import java.awt.geom.Ellipse2D; | ||
| 36 | import java.awt.geom.Arc2D; | ||
| 37 | import java.awt.geom.IllegalPathStateException; | ||
| 38 | import java.awt.geom.Path2D; | ||
| 39 | import java.awt.font.GlyphVector; | ||
| 40 | import sun.java2d.SunGraphics2D; | ||
| 41 | import sun.java2d.SurfaceData; | ||
| 42 | import sun.java2d.loops.FontInfo; | ||
| 43 | import sun.java2d.loops.DrawPolygons; | ||
| 44 | import sun.java2d.loops.FillParallelogram; | ||
| 45 | import sun.java2d.loops.DrawParallelogram; | ||
| 46 | import sun.awt.SunHints; | ||
| 47 | |||
| 48 | public class LoopPipe | ||
| 49 | implements PixelDrawPipe, | ||
| 50 | PixelFillPipe, | ||
| 51 | ParallelogramPipe, | ||
| 52 | ShapeDrawPipe, | ||
| 53 | LoopBasedPipe | ||
| 54 | { | ||
| 55 | final static RenderingEngine RenderEngine = RenderingEngine.getInstance(); | ||
| 56 | |||
| 57 | public void drawLine(SunGraphics2D sg2d, | ||
| 58 | int x1, int y1, int x2, int y2) | ||
| 59 | { | ||
| 60 | int tX = sg2d.transX; | ||
| 61 | int tY = sg2d.transY; | ||
| 62 | sg2d.loops.drawLineLoop.DrawLine(sg2d, sg2d.getSurfaceData(), | ||
| 63 | x1 + tX, y1 + tY, | ||
| 64 | x2 + tX, y2 + tY); | ||
| 65 | } | ||
| 66 | |||
| 67 | public void drawRect(SunGraphics2D sg2d, | ||
| 68 | int x, int y, int width, int height) | ||
| 69 | { | ||
| 70 | sg2d.loops.drawRectLoop.DrawRect(sg2d, sg2d.getSurfaceData(), | ||
| 71 | x + sg2d.transX, | ||
| 72 | y + sg2d.transY, | ||
| 73 | width, height); | ||
| 74 | } | ||
| 75 | |||
| 76 | public void drawRoundRect(SunGraphics2D sg2d, | ||
| 77 | int x, int y, int width, int height, | ||
| 78 | int arcWidth, int arcHeight) | ||
| 79 | { | ||
| 80 | sg2d.shapepipe.draw(sg2d, | ||
| 81 | new RoundRectangle2D.Float(x, y, width, height, | ||
| 82 | arcWidth, arcHeight)); | ||
| 83 | } | ||
| 84 | |||
| 85 | public void drawOval(SunGraphics2D sg2d, | ||
| 86 | int x, int y, int width, int height) | ||
| 87 | { | ||
| 88 | sg2d.shapepipe.draw(sg2d, new Ellipse2D.Float(x, y, width, height)); | ||
| 89 | } | ||
| 90 | |||
| 91 | public void drawArc(SunGraphics2D sg2d, | ||
| 92 | int x, int y, int width, int height, | ||
| 93 | int startAngle, int arcAngle) | ||
| 94 | { | ||
| 95 | sg2d.shapepipe.draw(sg2d, new Arc2D.Float(x, y, width, height, | ||
| 96 | startAngle, arcAngle, | ||
| 97 | Arc2D.OPEN)); | ||
| 98 | } | ||
| 99 | |||
| 100 | public void drawPolyline(SunGraphics2D sg2d, | ||
| 101 | int xPoints[], int yPoints[], | ||
| 102 | int nPoints) | ||
| 103 | { | ||
| 104 | int nPointsArray[] = { nPoints }; | ||
| 105 | sg2d.loops.drawPolygonsLoop.DrawPolygons(sg2d, sg2d.getSurfaceData(), | ||
| 106 | xPoints, yPoints, | ||
| 107 | nPointsArray, 1, | ||
| 108 | sg2d.transX, sg2d.transY, | ||
| 109 | false); | ||
| 110 | } | ||
| 111 | |||
| 112 | public void drawPolygon(SunGraphics2D sg2d, | ||
| 113 | int xPoints[], int yPoints[], | ||
| 114 | int nPoints) | ||
| 115 | { | ||
| 116 | int nPointsArray[] = { nPoints }; | ||
| 117 | sg2d.loops.drawPolygonsLoop.DrawPolygons(sg2d, sg2d.getSurfaceData(), | ||
| 118 | xPoints, yPoints, | ||
| 119 | nPointsArray, 1, | ||
| 120 | sg2d.transX, sg2d.transY, | ||
| 121 | true); | ||
| 122 | } | ||
| 123 | |||
| 124 | public void fillRect(SunGraphics2D sg2d, | ||
| 125 | int x, int y, int width, int height) | ||
| 126 | { | ||
| 127 | sg2d.loops.fillRectLoop.FillRect(sg2d, sg2d.getSurfaceData(), | ||
| 128 | x + sg2d.transX, | ||
| 129 | y + sg2d.transY, | ||
| 130 | width, height); | ||
| 131 | } | ||
| 132 | |||
| 133 | public void fillRoundRect(SunGraphics2D sg2d, | ||
| 134 | int x, int y, int width, int height, | ||
| 135 | int arcWidth, int arcHeight) | ||
| 136 | { | ||
| 137 | sg2d.shapepipe.fill(sg2d, | ||
| 138 | new RoundRectangle2D.Float(x, y, width, height, | ||
| 139 | arcWidth, arcHeight)); | ||
| 140 | } | ||
| 141 | |||
| 142 | public void fillOval(SunGraphics2D sg2d, | ||
| 143 | int x, int y, int width, int height) | ||
| 144 | { | ||
| 145 | sg2d.shapepipe.fill(sg2d, new Ellipse2D.Float(x, y, width, height)); | ||
| 146 | } | ||
| 147 | |||
| 148 | public void fillArc(SunGraphics2D sg2d, | ||
| 149 | int x, int y, int width, int height, | ||
| 150 | int startAngle, int arcAngle) | ||
| 151 | { | ||
| 152 | sg2d.shapepipe.fill(sg2d, new Arc2D.Float(x, y, width, height, | ||
| 153 | startAngle, arcAngle, | ||
| 154 | Arc2D.PIE)); | ||
| 155 | } | ||
| 156 | |||
| 157 | public void fillPolygon(SunGraphics2D sg2d, | ||
| 158 | int xPoints[], int yPoints[], | ||
| 159 | int nPoints) | ||
| 160 | { | ||
| 161 | ShapeSpanIterator sr = getFillSSI(sg2d); | ||
| 162 | |||
| 163 | try { | ||
| 164 | sr.setOutputArea(sg2d.getCompClip()); | ||
| 165 | sr.appendPoly(xPoints, yPoints, nPoints, sg2d.transX, sg2d.transY); | ||
| 166 | fillSpans(sg2d, sr); | ||
| 167 | } finally { | ||
| 168 | sr.dispose(); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | |||
| 173 | public void draw(SunGraphics2D sg2d, Shape s) { | ||
| 174 | if (sg2d.strokeState == sg2d.STROKE_THIN) { | ||
| 175 | Path2D.Float p2df; | ||
| 176 | int transX; | ||
| 177 | int transY; | ||
| 178 | if (sg2d.transformState <= sg2d.TRANSFORM_INT_TRANSLATE) { | ||
| 179 | if (s instanceof Path2D.Float) { | ||
| 180 | p2df = (Path2D.Float)s; | ||
| 181 | } else { | ||
| 182 | p2df = new Path2D.Float(s); | ||
| 183 | } | ||
| 184 | transX = sg2d.transX; | ||
| 185 | transY = sg2d.transY; | ||
| 186 | } else { | ||
| 187 | p2df = new Path2D.Float(s, sg2d.transform); | ||
| 188 | transX = 0; | ||
| 189 | transY = 0; | ||
| 190 | } | ||
| 191 | sg2d.loops.drawPathLoop.DrawPath(sg2d, sg2d.getSurfaceData(), | ||
| 192 | transX, transY, p2df); | ||
| 193 | return; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (sg2d.strokeState == sg2d.STROKE_CUSTOM) { | ||
| 197 | fill(sg2d, sg2d.stroke.createStrokedShape(s)); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | |||
| 201 | ShapeSpanIterator sr = getStrokeSpans(sg2d, s); | ||
| 202 | |||
| 203 | try { | ||
| 204 | fillSpans(sg2d, sr); | ||
| 205 | } finally { | ||
| 206 | sr.dispose(); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | /** | ||
| 211 | * Return a ShapeSpanIterator instance that normalizes as | ||
| 212 | * appropriate for a fill operation as per the settings in | ||
| 213 | * the specified SunGraphics2D object. | ||
| 214 | * | ||
| 215 | * The ShapeSpanIterator will be newly constructed and ready | ||
| 216 | * to start taking in geometry. | ||
| 217 | * | ||
| 218 | * Note that the caller is responsible for calling dispose() | ||
| 219 | * on the returned ShapeSpanIterator inside a try/finally block: | ||
| 220 | * <pre> | ||
| 221 | * ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d); | ||
| 222 | * try { | ||
| 223 | * ssi.setOutputArea(clip); | ||
| 224 | * ssi.appendPath(...); // or appendPoly | ||
| 225 | * // iterate the spans from ssi and operate on them | ||
| 226 | * } finally { | ||
| 227 | * ssi.dispose(); | ||
| 228 | * } | ||
| 229 | * </pre> | ||
| 230 | */ | ||
| 231 | public static ShapeSpanIterator getFillSSI(SunGraphics2D sg2d) { | ||
| 232 | boolean adjust = ((sg2d.stroke instanceof BasicStroke) && | ||
| 233 | sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE); | ||
| 234 | return new ShapeSpanIterator(adjust); | ||
| 235 | } | ||
| 236 | |||
| 237 | /* | ||
| 238 | * Return a ShapeSpanIterator ready to iterate the spans of the wide | ||
| 239 | * outline of Shape s using the attributes of the SunGraphics2D | ||
| 240 | * object. | ||
| 241 | * | ||
| 242 | * The ShapeSpanIterator returned will be fully constructed | ||
| 243 | * and filled with the geometry from the Shape widened by the | ||
| 244 | * appropriate BasicStroke and normalization parameters taken | ||
| 245 | * from the SunGraphics2D object and be ready to start returning | ||
| 246 | * spans. | ||
| 247 | * | ||
| 248 | * Note that the caller is responsible for calling dispose() | ||
| 249 | * on the returned ShapeSpanIterator inside a try/finally block. | ||
| 250 | * <pre> | ||
| 251 | * ShapeSpanIterator ssi = LoopPipe.getStrokeSpans(sg2d, s); | ||
| 252 | * try { | ||
| 253 | * // iterate the spans from ssi and operate on them | ||
| 254 | * } finally { | ||
| 255 | * ssi.dispose(); | ||
| 256 | * } | ||
| 257 | * </pre> | ||
| 258 | * | ||
| 259 | * REMIND: This should return a SpanIterator interface object | ||
| 260 | * but the caller needs to dispose() the object and that method | ||
| 261 | * is only on ShapeSpanIterator. | ||
| 262 | * TODO: Add a dispose() method to the SpanIterator interface. | ||
| 263 | */ | ||
| 264 | public static ShapeSpanIterator getStrokeSpans(SunGraphics2D sg2d, | ||
| 265 | Shape s) | ||
| 266 | { | ||
| 267 | ShapeSpanIterator sr = new ShapeSpanIterator(false); | ||
| 268 | |||
| 269 | try { | ||
| 270 | sr.setOutputArea(sg2d.getCompClip()); | ||
| 271 | sr.setRule(PathIterator.WIND_NON_ZERO); | ||
| 272 | |||
| 273 | BasicStroke bs = (BasicStroke) sg2d.stroke; | ||
| 274 | boolean thin = (sg2d.strokeState <= sg2d.STROKE_THINDASHED); | ||
| 275 | boolean normalize = | ||
| 276 | (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE); | ||
| 277 | |||
| 278 | RenderEngine.strokeTo(s, | ||
| 279 | sg2d.transform, bs, | ||
| 280 | thin, normalize, false, sr); | ||
| 281 | } catch (Throwable t) { | ||
| 282 | sr.dispose(); | ||
| 283 | sr = null; | ||
| 284 | t.printStackTrace(); | ||
| 285 | throw new InternalError("Unable to Stroke shape ("+ | ||
| 286 | t.getMessage()+")"); | ||
| 287 | } | ||
| 288 | return sr; | ||
| 289 | } | ||
| 290 | |||
| 291 | public void fill(SunGraphics2D sg2d, Shape s) { | ||
| 292 | if (sg2d.strokeState == sg2d.STROKE_THIN) { | ||
| 293 | Path2D.Float p2df; | ||
| 294 | int transX; | ||
| 295 | int transY; | ||
| 296 | if (sg2d.transformState <= sg2d.TRANSFORM_INT_TRANSLATE) { | ||
| 297 | if (s instanceof Path2D.Float) { | ||
| 298 | p2df = (Path2D.Float)s; | ||
| 299 | } else { | ||
| 300 | p2df = new Path2D.Float(s); | ||
| 301 | } | ||
| 302 | transX = sg2d.transX; | ||
| 303 | transY = sg2d.transY; | ||
| 304 | } else { | ||
| 305 | p2df = new Path2D.Float(s, sg2d.transform); | ||
| 306 | transX = 0; | ||
| 307 | transY = 0; | ||
| 308 | } | ||
| 309 | sg2d.loops.fillPathLoop.FillPath(sg2d, sg2d.getSurfaceData(), | ||
| 310 | transX, transY, p2df); | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | ShapeSpanIterator sr = getFillSSI(sg2d); | ||
| 315 | try { | ||
| 316 | sr.setOutputArea(sg2d.getCompClip()); | ||
| 317 | AffineTransform at = | ||
| 318 | ((sg2d.transformState == sg2d.TRANSFORM_ISIDENT) | ||
| 319 | ? null | ||
| 320 | : sg2d.transform); | ||
| 321 | sr.appendPath(s.getPathIterator(at)); | ||
| 322 | fillSpans(sg2d, sr); | ||
| 323 | } finally { | ||
| 324 | sr.dispose(); | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 328 | private static void fillSpans(SunGraphics2D sg2d, SpanIterator si) { | ||
| 329 | // REMIND: Eventually, the plan is that it will not be possible for | ||
| 330 | // fs to be null since the FillSpans loop will be the fundamental | ||
| 331 | // loop implemented for any destination type... | ||
| 332 | if (sg2d.clipState == sg2d.CLIP_SHAPE) { | ||
| 333 | si = sg2d.clipRegion.filter(si); | ||
| 334 | // REMIND: Region.filter produces a Java-only iterator | ||
| 335 | // with no native counterpart... | ||
| 336 | } else { | ||
| 337 | sun.java2d.loops.FillSpans fs = sg2d.loops.fillSpansLoop; | ||
| 338 | if (fs != null) { | ||
| 339 | fs.FillSpans(sg2d, sg2d.getSurfaceData(), si); | ||
| 340 | return; | ||
| 341 | } | ||
| 342 | } | ||
| 343 | int spanbox[] = new int[4]; | ||
| 344 | SurfaceData sd = sg2d.getSurfaceData(); | ||
| 345 | while (si.nextSpan(spanbox)) { | ||
| 346 | int x = spanbox[0]; | ||
| 347 | int y = spanbox[1]; | ||
| 348 | int w = spanbox[2] - x; | ||
| 349 | int h = spanbox[3] - y; | ||
| 350 | sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | public void fillParallelogram(SunGraphics2D sg2d, | ||
| 355 | double ux1, double uy1, | ||
| 356 | double ux2, double uy2, | ||
| 357 | double x, double y, | ||
| 358 | double dx1, double dy1, | ||
| 359 | double dx2, double dy2) | ||
| 360 | { | ||
| 361 | FillParallelogram fp = sg2d.loops.fillParallelogramLoop; | ||
| 362 | fp.FillParallelogram(sg2d, sg2d.getSurfaceData(), | ||
| 363 | x, y, dx1, dy1, dx2, dy2); | ||
| 364 | } | ||
| 365 | |||
| 366 | public void drawParallelogram(SunGraphics2D sg2d, | ||
| 367 | double ux1, double uy1, | ||
| 368 | double ux2, double uy2, | ||
| 369 | double x, double y, | ||
| 370 | double dx1, double dy1, | ||
| 371 | double dx2, double dy2, | ||
| 372 | double lw1, double lw2) | ||
| 373 | { | ||
| 374 | DrawParallelogram dp = sg2d.loops.drawParallelogramLoop; | ||
| 375 | dp.DrawParallelogram(sg2d, sg2d.getSurfaceData(), | ||
| 376 | x, y, dx1, dy1, dx2, dy2, lw1, lw2); | ||
| 377 | } | ||
| 378 | } | ||
Binary file not shown.
| @@ -0,0 +1,155 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2003, 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.Color; | ||
| 29 | import java.awt.Image; | ||
| 30 | import java.awt.Shape; | ||
| 31 | import java.awt.geom.AffineTransform; | ||
| 32 | import java.awt.image.BufferedImage; | ||
| 33 | import java.awt.image.BufferedImageOp; | ||
| 34 | import java.awt.image.ImageObserver; | ||
| 35 | import java.awt.font.GlyphVector; | ||
| 36 | import sun.java2d.SunGraphics2D; | ||
| 37 | |||
| 38 | /** | ||
| 39 | * This is a class that implements all of the basic pixel rendering | ||
| 40 | * methods as NOPs. | ||
| 41 | * This class is useful for installing as the pipeline when the | ||
| 42 | * clip is determined to be empty or when the composite operation is | ||
| 43 | * determined to have no effect (i.e. rule == SRC_OVER, extraAlpha == 0.0). | ||
| 44 | */ | ||
| 45 | public class NullPipe | ||
| 46 | implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, TextPipe, | ||
| 47 | DrawImagePipe | ||
| 48 | { | ||
| 49 | public void drawLine(SunGraphics2D sg, | ||
| 50 | int x1, int y1, int x2, int y2) { | ||
| 51 | } | ||
| 52 | |||
| 53 | public void drawRect(SunGraphics2D sg, | ||
| 54 | int x, int y, int width, int height) { | ||
| 55 | } | ||
| 56 | |||
| 57 | public void fillRect(SunGraphics2D sg, | ||
| 58 | int x, int y, int width, int height) { | ||
| 59 | } | ||
| 60 | |||
| 61 | public void drawRoundRect(SunGraphics2D sg, | ||
| 62 | int x, int y, int width, int height, | ||
| 63 | int arcWidth, int arcHeight) { | ||
| 64 | } | ||
| 65 | |||
| 66 | public void fillRoundRect(SunGraphics2D sg, | ||
| 67 | int x, int y, int width, int height, | ||
| 68 | int arcWidth, int arcHeight) { | ||
| 69 | } | ||
| 70 | |||
| 71 | public void drawOval(SunGraphics2D sg, | ||
| 72 | int x, int y, int width, int height) { | ||
| 73 | } | ||
| 74 | |||
| 75 | public void fillOval(SunGraphics2D sg, | ||
| 76 | int x, int y, int width, int height) { | ||
| 77 | } | ||
| 78 | |||
| 79 | public void drawArc(SunGraphics2D sg, | ||
| 80 | int x, int y, int width, int height, | ||
| 81 | int startAngle, int arcAngle) { | ||
| 82 | } | ||
| 83 | |||
| 84 | public void fillArc(SunGraphics2D sg, | ||
| 85 | int x, int y, int width, int height, | ||
| 86 | int startAngle, int arcAngle) { | ||
| 87 | } | ||
| 88 | |||
| 89 | public void drawPolyline(SunGraphics2D sg, | ||
| 90 | int xPoints[], int yPoints[], | ||
| 91 | int nPoints) { | ||
| 92 | } | ||
| 93 | |||
| 94 | public void drawPolygon(SunGraphics2D sg, | ||
| 95 | int xPoints[], int yPoints[], | ||
| 96 | int nPoints) { | ||
| 97 | } | ||
| 98 | |||
| 99 | public void fillPolygon(SunGraphics2D sg, | ||
| 100 | int xPoints[], int yPoints[], | ||
| 101 | int nPoints) { | ||
| 102 | } | ||
| 103 | |||
| 104 | public void draw(SunGraphics2D sg, Shape s) { | ||
| 105 | } | ||
| 106 | |||
| 107 | public void fill(SunGraphics2D sg, Shape s) { | ||
| 108 | } | ||
| 109 | |||
| 110 | public void drawString(SunGraphics2D sg, String s, double x, double y) { | ||
| 111 | } | ||
| 112 | |||
| 113 | public void drawGlyphVector(SunGraphics2D sg, GlyphVector g, | ||
| 114 | float x, float y) { | ||
| 115 | } | ||
| 116 | |||
| 117 | public void drawChars(SunGraphics2D sg, | ||
| 118 | char data[], int offset, int length, | ||
| 119 | int x, int y) { | ||
| 120 | } | ||
| 121 | |||
| 122 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 123 | int x, int y, | ||
| 124 | Color bgColor, | ||
| 125 | ImageObserver observer) { | ||
| 126 | return false; | ||
| 127 | } | ||
| 128 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 129 | int dx, int dy, int sx, int sy, int w, int h, | ||
| 130 | Color bgColor, | ||
| 131 | ImageObserver observer) { | ||
| 132 | return false; | ||
| 133 | } | ||
| 134 | public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y, | ||
| 135 | int w, int h, | ||
| 136 | Color bgColor, | ||
| 137 | ImageObserver observer) { | ||
| 138 | return false; | ||
| 139 | } | ||
| 140 | public boolean scaleImage(SunGraphics2D sg, Image img, | ||
| 141 | int dx1, int dy1, int dx2, int dy2, | ||
| 142 | int sx1, int sy1, int sx2, int sy2, | ||
| 143 | Color bgColor, | ||
| 144 | ImageObserver observer) { | ||
| 145 | return false; | ||
| 146 | } | ||
| 147 | public boolean transformImage(SunGraphics2D sg, Image img, | ||
| 148 | AffineTransform atfm, | ||
| 149 | ImageObserver observer) { | ||
| 150 | return false; | ||
| 151 | } | ||
| 152 | public void transformImage(SunGraphics2D sg, BufferedImage img, | ||
| 153 | BufferedImageOp op, int x, int y) { | ||
| 154 | } | ||
| 155 | } | ||
Binary file not shown.
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2005, 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.font.FontRenderContext; | ||
| 29 | import java.awt.font.GlyphVector; | ||
| 30 | import java.awt.font.TextLayout; | ||
| 31 | import sun.java2d.SunGraphics2D; | ||
| 32 | import sun.font.GlyphList; | ||
| 33 | import sun.awt.SunHints; | ||
| 34 | |||
| 35 | import java.awt.Shape; | ||
| 36 | import java.awt.geom.AffineTransform; | ||
| 37 | import java.awt.font.TextLayout; | ||
| 38 | |||
| 39 | /** | ||
| 40 | * A delegate pipe of SG2D for drawing "large" text with | ||
| 41 | * a solid source colour to an opaque destination. | ||
| 42 | * The text is drawn as a filled outline. | ||
| 43 | * Since the developer is not explicitly requesting this way of | ||
| 44 | * rendering, this should not be used if the current paint is not | ||
| 45 | * a solid colour. | ||
| 46 | * | ||
| 47 | * If text anti-aliasing is requested by the application, and | ||
| 48 | * filling path, an anti-aliasing fill pipe needs to | ||
| 49 | * be invoked. | ||
| 50 | * This involves making some of the same decisions as in the | ||
| 51 | * validatePipe call, which may be in a SurfaceData subclass, so | ||
| 52 | * its awkward to always ensure that the correct pipe is used. | ||
| 53 | * The easiest thing, rather than reproducing much of that logic | ||
| 54 | * is to call validatePipe() which works but is expensive, although | ||
| 55 | * probably not compared to the cost of filling the path. | ||
| 56 | * Note if AA hint is ON but text-AA hint is OFF this logic will | ||
| 57 | * produce AA text which perhaps isn't what the user expected. | ||
| 58 | * Note that the glyphvector obeys its FRC, not the G2D. | ||
| 59 | */ | ||
| 60 | |||
| 61 | public class OutlineTextRenderer implements TextPipe { | ||
| 62 | |||
| 63 | // Text with a height greater than the threshhold will be | ||
| 64 | // drawn via this pipe. | ||
| 65 | public static final int THRESHHOLD = 100; | ||
| 66 | |||
| 67 | public void drawChars(SunGraphics2D g2d, | ||
| 68 | char data[], int offset, int length, | ||
| 69 | int x, int y) { | ||
| 70 | |||
| 71 | String s = new String(data, offset, length); | ||
| 72 | drawString(g2d, s, x, y); | ||
| 73 | } | ||
| 74 | |||
| 75 | public void drawString(SunGraphics2D g2d, String str, double x, double y) { | ||
| 76 | |||
| 77 | if ("".equals(str)) { | ||
| 78 | return; // TextLayout constructor throws IAE on "". | ||
| 79 | } | ||
| 80 | TextLayout tl = new TextLayout(str, g2d.getFont(), | ||
| 81 | g2d.getFontRenderContext()); | ||
| 82 | Shape s = tl.getOutline(AffineTransform.getTranslateInstance(x, y)); | ||
| 83 | |||
| 84 | int textAAHint = g2d.getFontInfo().aaHint; | ||
| 85 | |||
| 86 | int prevaaHint = - 1; | ||
| 87 | if (textAAHint != SunHints.INTVAL_TEXT_ANTIALIAS_OFF && | ||
| 88 | g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { | ||
| 89 | prevaaHint = g2d.antialiasHint; | ||
| 90 | g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_ON; | ||
| 91 | g2d.validatePipe(); | ||
| 92 | } else if (textAAHint == SunHints.INTVAL_TEXT_ANTIALIAS_OFF | ||
| 93 | && g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_OFF) { | ||
| 94 | prevaaHint = g2d.antialiasHint; | ||
| 95 | g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF; | ||
| 96 | g2d.validatePipe(); | ||
| 97 | } | ||
| 98 | |||
| 99 | g2d.fill(s); | ||
| 100 | |||
| 101 | if (prevaaHint != -1) { | ||
| 102 | g2d.antialiasHint = prevaaHint; | ||
| 103 | g2d.validatePipe(); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | public void drawGlyphVector(SunGraphics2D g2d, GlyphVector gv, | ||
| 108 | float x, float y) { | ||
| 109 | |||
| 110 | |||
| 111 | Shape s = gv.getOutline(x, y); | ||
| 112 | int prevaaHint = - 1; | ||
| 113 | FontRenderContext frc = gv.getFontRenderContext(); | ||
| 114 | boolean aa = frc.isAntiAliased(); | ||
| 115 | |||
| 116 | /* aa will be true if any AA mode has been specified. | ||
| 117 | * ie for LCD and 'gasp' modes too. | ||
| 118 | * We will check if 'gasp' has resolved AA to be "OFF", and | ||
| 119 | * in all other cases (ie AA ON and all LCD modes) use AA outlines. | ||
| 120 | */ | ||
| 121 | if (aa) { | ||
| 122 | if (g2d.getGVFontInfo(gv.getFont(), frc).aaHint == | ||
| 123 | SunHints.INTVAL_TEXT_ANTIALIAS_OFF) { | ||
| 124 | aa = false; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | if (aa && g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { | ||
| 129 | prevaaHint = g2d.antialiasHint; | ||
| 130 | g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_ON; | ||
| 131 | g2d.validatePipe(); | ||
| 132 | } else if (!aa && g2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_OFF) { | ||
| 133 | prevaaHint = g2d.antialiasHint; | ||
| 134 | g2d.antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF; | ||
| 135 | g2d.validatePipe(); | ||
| 136 | } | ||
| 137 | |||
| 138 | g2d.fill(s); | ||
| 139 | |||
| 140 | if (prevaaHint != -1) { | ||
| 141 | g2d.antialiasHint = prevaaHint; | ||
| 142 | g2d.validatePipe(); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
Binary file not shown.
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008, 2011 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 sun.java2d.SunGraphics2D; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This interface defines the set of calls that pipeline objects | ||
| 32 | * can use to pass on responsibility for drawing arbitrary | ||
| 33 | * parallelogram shapes. | ||
| 34 | * Six floating point numbers are provided and the parallelogram | ||
| 35 | * is defined as the quadrilateral with the following vertices: | ||
| 36 | * <pre> | ||
| 37 | * origin: (x, y) | ||
| 38 | * => (x+dx1, y+dy1) | ||
| 39 | * => (x+dx1+dx2, y+dy1+dy2) | ||
| 40 | * => (x+dx2, y+dy2) | ||
| 41 | * => origin | ||
| 42 | * </pre> | ||
| 43 | * The four u[xy][12] parameters are the unsorted extreme coordinates | ||
| 44 | * of the primitive in user space. They may have been generated by a | ||
| 45 | * line or a rectangle so they could have u[xy]2 < u[xy]1 in some cases. | ||
| 46 | * They should be sorted before calculating the bounds of the original | ||
| 47 | * primitive (such as for calculating the user space bounds for the | ||
| 48 | * Paint.createContext() method). | ||
| 49 | */ | ||
| 50 | public interface ParallelogramPipe { | ||
| 51 | public void fillParallelogram(SunGraphics2D sg, | ||
| 52 | double ux1, double uy1, | ||
| 53 | double ux2, double uy2, | ||
| 54 | double x, double y, | ||
| 55 | double dx1, double dy1, | ||
| 56 | double dx2, double dy2); | ||
| 57 | |||
| 58 | /** | ||
| 59 | * Draw a Parallelogram with the indicated line widths | ||
| 60 | * assuming a standard BasicStroke with MITER joins. | ||
| 61 | * lw1 specifies the width of the stroke along the dx1,dy1 | ||
| 62 | * vector and lw2 specifies the width of the stroke along | ||
| 63 | * the dx2,dy2 vector. | ||
| 64 | * This is equivalent to outsetting the indicated | ||
| 65 | * parallelogram by lw/2 pixels, then insetting the | ||
| 66 | * same parallelogram by lw/2 pixels and filling the | ||
| 67 | * difference between the outer and inner parallelograms. | ||
| 68 | */ | ||
| 69 | public void drawParallelogram(SunGraphics2D sg, | ||
| 70 | double ux1, double uy1, | ||
| 71 | double ux2, double uy2, | ||
| 72 | double x, double y, | ||
| 73 | double dx1, double dy1, | ||
| 74 | double dx2, double dy2, | ||
| 75 | double lw1, double lw2); | ||
| 76 | } | ||
Binary file not shown.
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 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 sun.java2d.SunGraphics2D; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This interface defines the set of calls that pipeline objects | ||
| 32 | * can use to pass on responsibility for drawing various basic | ||
| 33 | * geometric figures defined by explicit integer coordinates. | ||
| 34 | * Typically this interface will be used for communication when | ||
| 35 | * the coordinates of the rendering have been narrowed down to | ||
| 36 | * actual device pixels, or for communication of untransformed | ||
| 37 | * coordinates when the coordinates were specified using integers. | ||
| 38 | * This interface does not cover all of the rendering calls that | ||
| 39 | * are possible in Graphics since many of the rendering calls can | ||
| 40 | * be transformed into one or more variants of these calls. | ||
| 41 | */ | ||
| 42 | public interface PixelDrawPipe { | ||
| 43 | public void drawLine(SunGraphics2D sg, | ||
| 44 | int x1, int y1, int x2, int y2); | ||
| 45 | |||
| 46 | public void drawRect(SunGraphics2D sg, | ||
| 47 | int x, int y, int width, int height); | ||
| 48 | |||
| 49 | public void drawRoundRect(SunGraphics2D sg, | ||
| 50 | int x, int y, int width, int height, | ||
| 51 | int arcWidth, int arcHeight); | ||
| 52 | |||
| 53 | public void drawOval(SunGraphics2D sg, | ||
| 54 | int x, int y, int width, int height); | ||
| 55 | |||
| 56 | public void drawArc(SunGraphics2D sg, | ||
| 57 | int x, int y, int width, int height, | ||
| 58 | int startAngle, int arcAngle); | ||
| 59 | |||
| 60 | public void drawPolyline(SunGraphics2D sg, | ||
| 61 | int xPoints[], int yPoints[], | ||
| 62 | int nPoints); | ||
| 63 | |||
| 64 | public void drawPolygon(SunGraphics2D sg, | ||
| 65 | int xPoints[], int yPoints[], | ||
| 66 | int nPoints); | ||
| 67 | } | ||
Binary file not shown.
| @@ -0,0 +1,61 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 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 sun.java2d.SunGraphics2D; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This interface defines the set of calls that pipeline objects | ||
| 32 | * can use to pass on responsibility for filling various basic | ||
| 33 | * geometric figures defined by explicit integer coordinates. | ||
| 34 | * Typically this interface will be used for communication when | ||
| 35 | * the coordinates of the rendering have been narrowed down to | ||
| 36 | * actual device pixels, or for communication of untransformed | ||
| 37 | * coordinates when the coordinates were specified using integers. | ||
| 38 | * This interface does not cover all of the rendering calls that | ||
| 39 | * are possible in Graphics since many of the rendering calls can | ||
| 40 | * be transformed into one or more variants of these calls. | ||
| 41 | */ | ||
| 42 | public interface PixelFillPipe { | ||
| 43 | public void fillRect(SunGraphics2D sg, | ||
| 44 | int x, int y, int width, int height); | ||
| 45 | |||
| 46 | |||
| 47 | public void fillRoundRect(SunGraphics2D sg, | ||
| 48 | int x, int y, int width, int height, | ||
| 49 | int arcWidth, int arcHeight); | ||
| 50 | |||
| 51 | public void fillOval(SunGraphics2D sg, | ||
| 52 | int x, int y, int width, int height); | ||
| 53 | |||
| 54 | public void fillArc(SunGraphics2D sg, | ||
| 55 | int x, int y, int width, int height, | ||
| 56 | int startAngle, int arcAngle); | ||
| 57 | |||
| 58 | public void fillPolygon(SunGraphics2D sg, | ||
| 59 | int xPoints[], int yPoints[], | ||
| 60 | int nPoints); | ||
| 61 | } | ||
Binary file not shown.
| @@ -0,0 +1,429 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008, 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.Shape; | ||
| 29 | import java.awt.BasicStroke; | ||
| 30 | import java.awt.geom.Line2D; | ||
| 31 | import java.awt.geom.Rectangle2D; | ||
| 32 | import java.awt.geom.AffineTransform; | ||
| 33 | import sun.java2d.SunGraphics2D; | ||
| 34 | import sun.awt.SunHints; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * This class converts calls to the basic pixel rendering methods | ||
| 38 | * into calls to the methods on a ParallelogramPipe. | ||
| 39 | * Most calls are transformed into calls to the fill(Shape) method | ||
| 40 | * by the parent PixelToShapeConverter class, but some calls are | ||
| 41 | * transformed into calls to fill/drawParallelogram(). | ||
| 42 | */ | ||
| 43 | public class PixelToParallelogramConverter extends PixelToShapeConverter | ||
| 44 | implements ShapeDrawPipe | ||
| 45 | { | ||
| 46 | ParallelogramPipe outrenderer; | ||
| 47 | double minPenSize; | ||
| 48 | double normPosition; | ||
| 49 | double normRoundingBias; | ||
| 50 | boolean adjustfill; | ||
| 51 | |||
| 52 | /** | ||
| 53 | * @param shapepipe pipeline to forward shape calls to | ||
| 54 | * @param pgrampipe pipeline to forward parallelogram calls to | ||
| 55 | * (and drawLine calls if possible) | ||
| 56 | * @param minPenSize minimum pen size for dropout control | ||
| 57 | * @param normPosition sub-pixel location to normalize endpoints | ||
| 58 | * for STROKE_NORMALIZE cases | ||
| 59 | * @param adjustFill boolean to control whethere normalization | ||
| 60 | * constants are also applied to fill operations | ||
| 61 | * (normally true for non-AA, false for AA) | ||
| 62 | */ | ||
| 63 | public PixelToParallelogramConverter(ShapeDrawPipe shapepipe, | ||
| 64 | ParallelogramPipe pgrampipe, | ||
| 65 | double minPenSize, | ||
| 66 | double normPosition, | ||
| 67 | boolean adjustfill) | ||
| 68 | { | ||
| 69 | super(shapepipe); | ||
| 70 | outrenderer = pgrampipe; | ||
| 71 | this.minPenSize = minPenSize; | ||
| 72 | this.normPosition = normPosition; | ||
| 73 | this.normRoundingBias = 0.5 - normPosition; | ||
| 74 | this.adjustfill = adjustfill; | ||
| 75 | } | ||
| 76 | |||
| 77 | public void drawLine(SunGraphics2D sg2d, | ||
| 78 | int x1, int y1, int x2, int y2) | ||
| 79 | { | ||
| 80 | if (!drawGeneralLine(sg2d, x1, y1, x2, y2)) { | ||
| 81 | super.drawLine(sg2d, x1, y1, x2, y2); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | public void drawRect(SunGraphics2D sg2d, | ||
| 86 | int x, int y, int w, int h) | ||
| 87 | { | ||
| 88 | if (w >= 0 && h >= 0) { | ||
| 89 | if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { | ||
| 90 | BasicStroke bs = ((BasicStroke) sg2d.stroke); | ||
| 91 | if (w > 0 && h > 0) { | ||
| 92 | if (bs.getLineJoin() == BasicStroke.JOIN_MITER && | ||
| 93 | bs.getDashArray() == null) | ||
| 94 | { | ||
| 95 | double lw = bs.getLineWidth(); | ||
| 96 | drawRectangle(sg2d, x, y, w, h, lw); | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | } else { | ||
| 100 | // Note: This calls the integer version which | ||
| 101 | // will verify that the local drawLine optimizations | ||
| 102 | // work and call super.drawLine(), if not. | ||
| 103 | drawLine(sg2d, x, y, x+w, y+h); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | super.drawRect(sg2d, x, y, w, h); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | public void fillRect(SunGraphics2D sg2d, | ||
| 112 | int x, int y, int w, int h) | ||
| 113 | { | ||
| 114 | if (w > 0 && h > 0) { | ||
| 115 | fillRectangle(sg2d, x, y, w, h); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | public void draw(SunGraphics2D sg2d, Shape s) { | ||
| 120 | if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { | ||
| 121 | BasicStroke bs = ((BasicStroke) sg2d.stroke); | ||
| 122 | if (s instanceof Rectangle2D) { | ||
| 123 | if (bs.getLineJoin() == BasicStroke.JOIN_MITER && | ||
| 124 | bs.getDashArray() == null) | ||
| 125 | { | ||
| 126 | Rectangle2D r2d = (Rectangle2D) s; | ||
| 127 | double w = r2d.getWidth(); | ||
| 128 | double h = r2d.getHeight(); | ||
| 129 | double x = r2d.getX(); | ||
| 130 | double y = r2d.getY(); | ||
| 131 | if (w >= 0 && h >= 0) { | ||
| 132 | double lw = bs.getLineWidth(); | ||
| 133 | drawRectangle(sg2d, x, y, w, h, lw); | ||
| 134 | } | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | } else if (s instanceof Line2D) { | ||
| 138 | Line2D l2d = (Line2D) s; | ||
| 139 | if (drawGeneralLine(sg2d, | ||
| 140 | l2d.getX1(), l2d.getY1(), | ||
| 141 | l2d.getX2(), l2d.getY2())) | ||
| 142 | { | ||
| 143 | return; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | outpipe.draw(sg2d, s); | ||
| 149 | } | ||
| 150 | |||
| 151 | public void fill(SunGraphics2D sg2d, Shape s) { | ||
| 152 | if (s instanceof Rectangle2D) { | ||
| 153 | Rectangle2D r2d = (Rectangle2D) s; | ||
| 154 | double w = r2d.getWidth(); | ||
| 155 | double h = r2d.getHeight(); | ||
| 156 | if (w > 0 && h > 0) { | ||
| 157 | double x = r2d.getX(); | ||
| 158 | double y = r2d.getY(); | ||
| 159 | fillRectangle(sg2d, x, y, w, h); | ||
| 160 | } | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | outpipe.fill(sg2d, s); | ||
| 165 | } | ||
| 166 | |||
| 167 | static double len(double x, double y) { | ||
| 168 | return ((x == 0) ? Math.abs(y) | ||
| 169 | : ((y == 0) ? Math.abs(x) | ||
| 170 | : Math.sqrt(x * x + y * y))); | ||
| 171 | } | ||
| 172 | |||
| 173 | double normalize(double v) { | ||
| 174 | return Math.floor(v + normRoundingBias) + normPosition; | ||
| 175 | } | ||
| 176 | |||
| 177 | public boolean drawGeneralLine(SunGraphics2D sg2d, | ||
| 178 | double ux1, double uy1, | ||
| 179 | double ux2, double uy2) | ||
| 180 | { | ||
| 181 | if (sg2d.strokeState == SunGraphics2D.STROKE_CUSTOM || | ||
| 182 | sg2d.strokeState == SunGraphics2D.STROKE_THINDASHED) | ||
| 183 | { | ||
| 184 | return false; | ||
| 185 | } | ||
| 186 | BasicStroke bs = (BasicStroke) sg2d.stroke; | ||
| 187 | int cap = bs.getEndCap(); | ||
| 188 | if (cap == BasicStroke.CAP_ROUND || bs.getDashArray() != null) { | ||
| 189 | // TODO: we could construct the GeneralPath directly | ||
| 190 | // for CAP_ROUND and save a lot of processing in that case... | ||
| 191 | // And again, we would need to deal with dropout control... | ||
| 192 | return false; | ||
| 193 | } | ||
| 194 | double lw = bs.getLineWidth(); | ||
| 195 | // Save the original dx, dy in case we need it to transform | ||
| 196 | // the linewidth as a perpendicular vector below | ||
| 197 | double dx = ux2 - ux1; | ||
| 198 | double dy = uy2 - uy1; | ||
| 199 | double x1, y1, x2, y2; | ||
| 200 | switch (sg2d.transformState) { | ||
| 201 | case SunGraphics2D.TRANSFORM_GENERIC: | ||
| 202 | case SunGraphics2D.TRANSFORM_TRANSLATESCALE: | ||
| 203 | { | ||
| 204 | double coords[] = {ux1, uy1, ux2, uy2}; | ||
| 205 | sg2d.transform.transform(coords, 0, coords, 0, 2); | ||
| 206 | x1 = coords[0]; | ||
| 207 | y1 = coords[1]; | ||
| 208 | x2 = coords[2]; | ||
| 209 | y2 = coords[3]; | ||
| 210 | } | ||
| 211 | break; | ||
| 212 | case SunGraphics2D.TRANSFORM_ANY_TRANSLATE: | ||
| 213 | case SunGraphics2D.TRANSFORM_INT_TRANSLATE: | ||
| 214 | { | ||
| 215 | double tx = sg2d.transform.getTranslateX(); | ||
| 216 | double ty = sg2d.transform.getTranslateY(); | ||
| 217 | x1 = ux1 + tx; | ||
| 218 | y1 = uy1 + ty; | ||
| 219 | x2 = ux2 + tx; | ||
| 220 | y2 = uy2 + ty; | ||
| 221 | } | ||
| 222 | break; | ||
| 223 | case SunGraphics2D.TRANSFORM_ISIDENT: | ||
| 224 | x1 = ux1; | ||
| 225 | y1 = uy1; | ||
| 226 | x2 = ux2; | ||
| 227 | y2 = uy2; | ||
| 228 | break; | ||
| 229 | default: | ||
| 230 | throw new InternalError("unknown TRANSFORM state..."); | ||
| 231 | } | ||
| 232 | if (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) { | ||
| 233 | if (sg2d.strokeState == SunGraphics2D.STROKE_THIN && | ||
| 234 | outrenderer instanceof PixelDrawPipe) | ||
| 235 | { | ||
| 236 | // PixelDrawPipes will add sg2d.transXY so we need to factor | ||
| 237 | // that out... | ||
| 238 | int ix1 = (int) Math.floor(x1 - sg2d.transX); | ||
| 239 | int iy1 = (int) Math.floor(y1 - sg2d.transY); | ||
| 240 | int ix2 = (int) Math.floor(x2 - sg2d.transX); | ||
| 241 | int iy2 = (int) Math.floor(y2 - sg2d.transY); | ||
| 242 | ((PixelDrawPipe)outrenderer).drawLine(sg2d, ix1, iy1, ix2, iy2); | ||
| 243 | return true; | ||
| 244 | } | ||
| 245 | x1 = normalize(x1); | ||
| 246 | y1 = normalize(y1); | ||
| 247 | x2 = normalize(x2); | ||
| 248 | y2 = normalize(y2); | ||
| 249 | } | ||
| 250 | if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { | ||
| 251 | // Transform the linewidth... | ||
| 252 | // calculate the scaling factor for a unit vector | ||
| 253 | // perpendicular to the original user space line. | ||
| 254 | double len = len(dx, dy); | ||
| 255 | if (len == 0) { | ||
| 256 | dx = len = 1; | ||
| 257 | // dy = 0; already | ||
| 258 | } | ||
| 259 | // delta transform the transposed (90 degree rotated) unit vector | ||
| 260 | double unitvector[] = {dy/len, -dx/len}; | ||
| 261 | sg2d.transform.deltaTransform(unitvector, 0, unitvector, 0, 1); | ||
| 262 | lw *= len(unitvector[0], unitvector[1]); | ||
| 263 | } | ||
| 264 | lw = Math.max(lw, minPenSize); | ||
| 265 | dx = x2 - x1; | ||
| 266 | dy = y2 - y1; | ||
| 267 | double len = len(dx, dy); | ||
| 268 | double udx, udy; | ||
| 269 | if (len == 0) { | ||
| 270 | if (cap == BasicStroke.CAP_BUTT) { | ||
| 271 | return true; | ||
| 272 | } | ||
| 273 | udx = lw; | ||
| 274 | udy = 0; | ||
| 275 | } else { | ||
| 276 | udx = lw * dx / len; | ||
| 277 | udy = lw * dy / len; | ||
| 278 | } | ||
| 279 | double px = x1 + udy / 2.0; | ||
| 280 | double py = y1 - udx / 2.0; | ||
| 281 | if (cap == BasicStroke.CAP_SQUARE) { | ||
| 282 | px -= udx / 2.0; | ||
| 283 | py -= udy / 2.0; | ||
| 284 | dx += udx; | ||
| 285 | dy += udy; | ||
| 286 | } | ||
| 287 | outrenderer.fillParallelogram(sg2d, ux1, uy1, ux2, uy2, | ||
| 288 | px, py, -udy, udx, dx, dy); | ||
| 289 | return true; | ||
| 290 | } | ||
| 291 | |||
| 292 | public void fillRectangle(SunGraphics2D sg2d, | ||
| 293 | double rx, double ry, | ||
| 294 | double rw, double rh) | ||
| 295 | { | ||
| 296 | double px, py; | ||
| 297 | double dx1, dy1, dx2, dy2; | ||
| 298 | AffineTransform txform = sg2d.transform; | ||
| 299 | dx1 = txform.getScaleX(); | ||
| 300 | dy1 = txform.getShearY(); | ||
| 301 | dx2 = txform.getShearX(); | ||
| 302 | dy2 = txform.getScaleY(); | ||
| 303 | px = rx * dx1 + ry * dx2 + txform.getTranslateX(); | ||
| 304 | py = rx * dy1 + ry * dy2 + txform.getTranslateY(); | ||
| 305 | dx1 *= rw; | ||
| 306 | dy1 *= rw; | ||
| 307 | dx2 *= rh; | ||
| 308 | dy2 *= rh; | ||
| 309 | if (adjustfill && | ||
| 310 | sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM && | ||
| 311 | sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) | ||
| 312 | { | ||
| 313 | double newx = normalize(px); | ||
| 314 | double newy = normalize(py); | ||
| 315 | dx1 = normalize(px + dx1) - newx; | ||
| 316 | dy1 = normalize(py + dy1) - newy; | ||
| 317 | dx2 = normalize(px + dx2) - newx; | ||
| 318 | dy2 = normalize(py + dy2) - newy; | ||
| 319 | px = newx; | ||
| 320 | py = newy; | ||
| 321 | } | ||
| 322 | outrenderer.fillParallelogram(sg2d, rx, ry, rx+rw, ry+rh, | ||
| 323 | px, py, dx1, dy1, dx2, dy2); | ||
| 324 | } | ||
| 325 | |||
| 326 | public void drawRectangle(SunGraphics2D sg2d, | ||
| 327 | double rx, double ry, | ||
| 328 | double rw, double rh, | ||
| 329 | double lw) | ||
| 330 | { | ||
| 331 | double px, py; | ||
| 332 | double dx1, dy1, dx2, dy2; | ||
| 333 | double lw1, lw2; | ||
| 334 | AffineTransform txform = sg2d.transform; | ||
| 335 | dx1 = txform.getScaleX(); | ||
| 336 | dy1 = txform.getShearY(); | ||
| 337 | dx2 = txform.getShearX(); | ||
| 338 | dy2 = txform.getScaleY(); | ||
| 339 | px = rx * dx1 + ry * dx2 + txform.getTranslateX(); | ||
| 340 | py = rx * dy1 + ry * dy2 + txform.getTranslateY(); | ||
| 341 | // lw along dx1,dy1 scale by transformed length of dx2,dy2 vectors | ||
| 342 | // and vice versa | ||
| 343 | lw1 = len(dx1, dy1) * lw; | ||
| 344 | lw2 = len(dx2, dy2) * lw; | ||
| 345 | dx1 *= rw; | ||
| 346 | dy1 *= rw; | ||
| 347 | dx2 *= rh; | ||
| 348 | dy2 *= rh; | ||
| 349 | if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM && | ||
| 350 | sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE) | ||
| 351 | { | ||
| 352 | double newx = normalize(px); | ||
| 353 | double newy = normalize(py); | ||
| 354 | dx1 = normalize(px + dx1) - newx; | ||
| 355 | dy1 = normalize(py + dy1) - newy; | ||
| 356 | dx2 = normalize(px + dx2) - newx; | ||
| 357 | dy2 = normalize(py + dy2) - newy; | ||
| 358 | px = newx; | ||
| 359 | py = newy; | ||
| 360 | } | ||
| 361 | lw1 = Math.max(lw1, minPenSize); | ||
| 362 | lw2 = Math.max(lw2, minPenSize); | ||
| 363 | double len1 = len(dx1, dy1); | ||
| 364 | double len2 = len(dx2, dy2); | ||
| 365 | if (lw1 >= len1 || lw2 >= len2) { | ||
| 366 | // The line widths are large enough to consume the | ||
| 367 | // entire hole in the middle of the parallelogram | ||
| 368 | // so we can just fill the outer parallelogram. | ||
| 369 | fillOuterParallelogram(sg2d, | ||
| 370 | rx, ry, rx+rw, ry+rh, | ||
| 371 | px, py, dx1, dy1, dx2, dy2, | ||
| 372 | len1, len2, lw1, lw2); | ||
| 373 | } else { | ||
| 374 | outrenderer.drawParallelogram(sg2d, | ||
| 375 | rx, ry, rx+rw, ry+rh, | ||
| 376 | px, py, dx1, dy1, dx2, dy2, | ||
| 377 | lw1 / len1, lw2 / len2); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | /** | ||
| 382 | * This utility function handles the case where a drawRectangle | ||
| 383 | * operation discovered that the interior hole in the rectangle | ||
| 384 | * or parallelogram has been completely filled in by the stroke | ||
| 385 | * width. It calculates the outer parallelogram of the stroke | ||
| 386 | * and issues a single fillParallelogram request to fill it. | ||
| 387 | */ | ||
| 388 | public void fillOuterParallelogram(SunGraphics2D sg2d, | ||
| 389 | double ux1, double uy1, | ||
| 390 | double ux2, double uy2, | ||
| 391 | double px, double py, | ||
| 392 | double dx1, double dy1, | ||
| 393 | double dx2, double dy2, | ||
| 394 | double len1, double len2, | ||
| 395 | double lw1, double lw2) | ||
| 396 | { | ||
| 397 | double udx1 = dx1 / len1; | ||
| 398 | double udy1 = dy1 / len1; | ||
| 399 | double udx2 = dx2 / len2; | ||
| 400 | double udy2 = dy2 / len2; | ||
| 401 | if (len1 == 0) { | ||
| 402 | // len1 is 0, replace udxy1 with perpendicular of udxy2 | ||
| 403 | if (len2 == 0) { | ||
| 404 | // both are 0, use a unit Y vector for udxy2 | ||
| 405 | udx2 = 0; | ||
| 406 | udy2 = 1; | ||
| 407 | } | ||
| 408 | udx1 = udy2; | ||
| 409 | udy1 = -udx2; | ||
| 410 | } else if (len2 == 0) { | ||
| 411 | // len2 is 0, replace udxy2 with perpendicular of udxy1 | ||
| 412 | udx2 = udy1; | ||
| 413 | udy2 = -udx1; | ||
| 414 | } | ||
| 415 | udx1 *= lw1; | ||
| 416 | udy1 *= lw1; | ||
| 417 | udx2 *= lw2; | ||
| 418 | udy2 *= lw2; | ||
| 419 | px -= (udx1 + udx2) / 2; | ||
| 420 | py -= (udy1 + udy2) / 2; | ||
| 421 | dx1 += udx1; | ||
| 422 | dy1 += udy1; | ||
| 423 | dx2 += udx2; | ||
| 424 | dy2 += udy2; | ||
| 425 | |||
| 426 | outrenderer.fillParallelogram(sg2d, ux1, uy1, ux2, uy2, | ||
| 427 | px, py, dx1, dy1, dx2, dy2); | ||
| 428 | } | ||
| 429 | } | ||
Binary file not shown.
| @@ -0,0 +1,133 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 1998, 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.Rectangle; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import java.awt.geom.Arc2D; | ||
| 31 | import java.awt.geom.Ellipse2D; | ||
| 32 | import java.awt.geom.Line2D; | ||
| 33 | import java.awt.geom.RoundRectangle2D; | ||
| 34 | import java.awt.geom.GeneralPath; | ||
| 35 | import sun.java2d.SunGraphics2D; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * This class converts calls to the basic pixel rendering methods | ||
| 39 | * into calls to a generic Shape rendering pipeline. | ||
| 40 | */ | ||
| 41 | public class PixelToShapeConverter | ||
| 42 | implements PixelDrawPipe, PixelFillPipe | ||
| 43 | { | ||
| 44 | ShapeDrawPipe outpipe; | ||
| 45 | |||
| 46 | public PixelToShapeConverter(ShapeDrawPipe pipe) { | ||
| 47 | outpipe = pipe; | ||
| 48 | } | ||
| 49 | |||
| 50 | public void drawLine(SunGraphics2D sg, | ||
| 51 | int x1, int y1, int x2, int y2) { | ||
| 52 | outpipe.draw(sg, new Line2D.Float(x1, y1, x2, y2)); | ||
| 53 | } | ||
| 54 | |||
| 55 | public void drawRect(SunGraphics2D sg, | ||
| 56 | int x, int y, int w, int h) { | ||
| 57 | outpipe.draw(sg, new Rectangle(x, y, w, h)); | ||
| 58 | } | ||
| 59 | |||
| 60 | public void fillRect(SunGraphics2D sg, | ||
| 61 | int x, int y, int w, int h) { | ||
| 62 | outpipe.fill(sg, new Rectangle(x, y, w, h)); | ||
| 63 | } | ||
| 64 | |||
| 65 | public void drawRoundRect(SunGraphics2D sg, | ||
| 66 | int x, int y, int w, int h, | ||
| 67 | int aW, int aH) { | ||
| 68 | outpipe.draw(sg, new RoundRectangle2D.Float(x, y, w, h, aW, aH)); | ||
| 69 | } | ||
| 70 | |||
| 71 | public void fillRoundRect(SunGraphics2D sg, | ||
| 72 | int x, int y, int w, int h, | ||
| 73 | int aW, int aH) { | ||
| 74 | outpipe.fill(sg, new RoundRectangle2D.Float(x, y, w, h, aW, aH)); | ||
| 75 | } | ||
| 76 | |||
| 77 | public void drawOval(SunGraphics2D sg, | ||
| 78 | int x, int y, int w, int h) { | ||
| 79 | outpipe.draw(sg, new Ellipse2D.Float(x, y, w, h)); | ||
| 80 | } | ||
| 81 | |||
| 82 | public void fillOval(SunGraphics2D sg, | ||
| 83 | int x, int y, int w, int h) { | ||
| 84 | outpipe.fill(sg, new Ellipse2D.Float(x, y, w, h)); | ||
| 85 | } | ||
| 86 | |||
| 87 | public void drawArc(SunGraphics2D sg, | ||
| 88 | int x, int y, int w, int h, | ||
| 89 | int start, int extent) { | ||
| 90 | outpipe.draw(sg, new Arc2D.Float(x, y, w, h, | ||
| 91 | start, extent, Arc2D.OPEN)); | ||
| 92 | } | ||
| 93 | |||
| 94 | public void fillArc(SunGraphics2D sg, | ||
| 95 | int x, int y, int w, int h, | ||
| 96 | int start, int extent) { | ||
| 97 | outpipe.fill(sg, new Arc2D.Float(x, y, w, h, | ||
| 98 | start, extent, Arc2D.PIE)); | ||
| 99 | } | ||
| 100 | |||
| 101 | private Shape makePoly(int xPoints[], int yPoints[], | ||
| 102 | int nPoints, boolean close) { | ||
| 103 | GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD); | ||
| 104 | if (nPoints > 0) { | ||
| 105 | gp.moveTo(xPoints[0], yPoints[0]); | ||
| 106 | } | ||
| 107 | for (int i = 1; i < nPoints; i++) { | ||
| 108 | gp.lineTo(xPoints[i], yPoints[i]); | ||
| 109 | } | ||
| 110 | if (close) { | ||
| 111 | gp.closePath(); | ||
| 112 | } | ||
| 113 | return gp; | ||
| 114 | } | ||
| 115 | |||
| 116 | public void drawPolyline(SunGraphics2D sg, | ||
| 117 | int xPoints[], int yPoints[], | ||
| 118 | int nPoints) { | ||
| 119 | outpipe.draw(sg, makePoly(xPoints, yPoints, nPoints, false)); | ||
| 120 | } | ||
| 121 | |||
| 122 | public void drawPolygon(SunGraphics2D sg, | ||
| 123 | int xPoints[], int yPoints[], | ||
| 124 | int nPoints) { | ||
| 125 | outpipe.draw(sg, makePoly(xPoints, yPoints, nPoints, true)); | ||
| 126 | } | ||
| 127 | |||
| 128 | public void fillPolygon(SunGraphics2D sg, | ||
| 129 | int xPoints[], int yPoints[], | ||
| 130 | int nPoints) { | ||
| 131 | outpipe.fill(sg, makePoly(xPoints, yPoints, nPoints, true)); | ||
| 132 | } | ||
| 133 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1255 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 2006, 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.Rectangle; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import java.awt.geom.AffineTransform; | ||
| 31 | import java.awt.geom.RectangularShape; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * This class encapsulates a definition of a two dimensional region which | ||
| 35 | * consists of a number of Y ranges each containing multiple X bands. | ||
| 36 | * <p> | ||
| 37 | * A rectangular Region is allowed to have a null band list in which | ||
| 38 | * case the rectangular shape is defined by the bounding box parameters | ||
| 39 | * (lox, loy, hix, hiy). | ||
| 40 | * <p> | ||
| 41 | * The band list, if present, consists of a list of rows in ascending Y | ||
| 42 | * order, ending at endIndex which is the index beyond the end of the | ||
| 43 | * last row. Each row consists of at least 3 + 2n entries (n >= 1) | ||
| 44 | * where the first 3 entries specify the Y range as start, end, and | ||
| 45 | * the number of X ranges in that Y range. These 3 entries are | ||
| 46 | * followed by pairs of X coordinates in ascending order: | ||
| 47 | * <pre> | ||
| 48 | * bands[rowstart+0] = Y0; // starting Y coordinate | ||
| 49 | * bands[rowstart+1] = Y1; // ending Y coordinate - endY > startY | ||
| 50 | * bands[rowstart+2] = N; // number of X bands - N >= 1 | ||
| 51 | * | ||
| 52 | * bands[rowstart+3] = X10; // starting X coordinate of first band | ||
| 53 | * bands[rowstart+4] = X11; // ending X coordinate of first band | ||
| 54 | * bands[rowstart+5] = X20; // starting X coordinate of second band | ||
| 55 | * bands[rowstart+6] = X21; // ending X coordinate of second band | ||
| 56 | * ... | ||
| 57 | * bands[rowstart+3+N*2-2] = XN0; // starting X coord of last band | ||
| 58 | * bands[rowstart+3+N*2-1] = XN1; // ending X coord of last band | ||
| 59 | * | ||
| 60 | * bands[rowstart+3+N*2] = ... // start of next Y row | ||
| 61 | * </pre> | ||
| 62 | */ | ||
| 63 | public class Region { | ||
| 64 | static final int INIT_SIZE = 50; | ||
| 65 | static final int GROW_SIZE = 50; | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Immutable Region. | ||
| 69 | */ | ||
| 70 | private static final class ImmutableRegion extends Region { | ||
| 71 | protected ImmutableRegion(int lox, int loy, int hix, int hiy) { | ||
| 72 | super(lox, loy, hix, hiy); | ||
| 73 | } | ||
| 74 | |||
| 75 | // Override all the methods that mutate the object | ||
| 76 | public void appendSpans(sun.java2d.pipe.SpanIterator si) {} | ||
| 77 | public void setOutputArea(java.awt.Rectangle r) {} | ||
| 78 | public void setOutputAreaXYWH(int x, int y, int w, int h) {} | ||
| 79 | public void setOutputArea(int[] box) {} | ||
| 80 | public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) {} | ||
| 81 | } | ||
| 82 | |||
| 83 | public static final Region EMPTY_REGION = new ImmutableRegion(0, 0, 0, 0); | ||
| 84 | public static final Region WHOLE_REGION = new ImmutableRegion( | ||
| 85 | Integer.MIN_VALUE, | ||
| 86 | Integer.MIN_VALUE, | ||
| 87 | Integer.MAX_VALUE, | ||
| 88 | Integer.MAX_VALUE); | ||
| 89 | |||
| 90 | int lox; | ||
| 91 | int loy; | ||
| 92 | int hix; | ||
| 93 | int hiy; | ||
| 94 | |||
| 95 | int endIndex; | ||
| 96 | int[] bands; | ||
| 97 | |||
| 98 | private static native void initIDs(); | ||
| 99 | |||
| 100 | static { | ||
| 101 | initIDs(); | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Adds the dimension <code>dim</code> to the coordinate | ||
| 106 | * <code>start</code> with appropriate clipping. If | ||
| 107 | * <code>dim</code> is non-positive then the method returns | ||
| 108 | * the start coordinate. If the sum overflows an integer | ||
| 109 | * data type then the method returns <code>Integer.MAX_VALUE</code>. | ||
| 110 | */ | ||
| 111 | public static int dimAdd(int start, int dim) { | ||
| 112 | if (dim <= 0) return start; | ||
| 113 | if ((dim += start) < start) return Integer.MAX_VALUE; | ||
| 114 | return dim; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * Adds the delta {@code dv} to the value {@code v} with | ||
| 119 | * appropriate clipping to the bounds of Integer resolution. | ||
| 120 | * If the answer would be greater than {@code Integer.MAX_VALUE} | ||
| 121 | * then {@code Integer.MAX_VALUE} is returned. | ||
| 122 | * If the answer would be less than {@code Integer.MIN_VALUE} | ||
| 123 | * then {@code Integer.MIN_VALUE} is returned. | ||
| 124 | * Otherwise the sum is returned. | ||
| 125 | */ | ||
| 126 | public static int clipAdd(int v, int dv) { | ||
| 127 | int newv = v + dv; | ||
| 128 | if ((newv > v) != (dv > 0)) { | ||
| 129 | newv = (dv < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE; | ||
| 130 | } | ||
| 131 | return newv; | ||
| 132 | } | ||
| 133 | |||
| 134 | protected Region(int lox, int loy, int hix, int hiy) { | ||
| 135 | this.lox = lox; | ||
| 136 | this.loy = loy; | ||
| 137 | this.hix = hix; | ||
| 138 | this.hiy = hiy; | ||
| 139 | } | ||
| 140 | |||
| 141 | /** | ||
| 142 | * Returns a Region object covering the pixels which would be | ||
| 143 | * touched by a fill or clip operation on a Graphics implementation | ||
| 144 | * on the specified Shape object under the optionally specified | ||
| 145 | * AffineTransform object. | ||
| 146 | * | ||
| 147 | * @param s a non-null Shape object specifying the geometry enclosing | ||
| 148 | * the pixels of interest | ||
| 149 | * @param at an optional <code>AffineTransform</code> to be applied to the | ||
| 150 | * coordinates as they are returned in the iteration, or | ||
| 151 | * <code>null</code> if untransformed coordinates are desired | ||
| 152 | */ | ||
| 153 | public static Region getInstance(Shape s, AffineTransform at) { | ||
| 154 | return getInstance(WHOLE_REGION, false, s, at); | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Returns a Region object covering the pixels which would be | ||
| 159 | * touched by a fill or clip operation on a Graphics implementation | ||
| 160 | * on the specified Shape object under the optionally specified | ||
| 161 | * AffineTransform object further restricted by the specified | ||
| 162 | * device bounds. | ||
| 163 | * <p> | ||
| 164 | * Note that only the bounds of the specified Region are used to | ||
| 165 | * restrict the resulting Region. | ||
| 166 | * If devBounds is non-rectangular and clipping to the specific | ||
| 167 | * bands of devBounds is needed, then an intersection of the | ||
| 168 | * resulting Region with devBounds must be performed in a | ||
| 169 | * subsequent step. | ||
| 170 | * | ||
| 171 | * @param devBounds a non-null Region specifying some bounds to | ||
| 172 | * clip the geometry to | ||
| 173 | * @param s a non-null Shape object specifying the geometry enclosing | ||
| 174 | * the pixels of interest | ||
| 175 | * @param at an optional <code>AffineTransform</code> to be applied to the | ||
| 176 | * coordinates as they are returned in the iteration, or | ||
| 177 | * <code>null</code> if untransformed coordinates are desired | ||
| 178 | */ | ||
| 179 | public static Region getInstance(Region devBounds, | ||
| 180 | Shape s, AffineTransform at) | ||
| 181 | { | ||
| 182 | return getInstance(devBounds, false, s, at); | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 186 | * Returns a Region object covering the pixels which would be | ||
| 187 | * touched by a fill or clip operation on a Graphics implementation | ||
| 188 | * on the specified Shape object under the optionally specified | ||
| 189 | * AffineTransform object further restricted by the specified | ||
| 190 | * device bounds. | ||
| 191 | * If the normalize parameter is true then coordinate normalization | ||
| 192 | * is performed as per the 2D Graphics non-antialiasing implementation | ||
| 193 | * of the VALUE_STROKE_NORMALIZE hint. | ||
| 194 | * <p> | ||
| 195 | * Note that only the bounds of the specified Region are used to | ||
| 196 | * restrict the resulting Region. | ||
| 197 | * If devBounds is non-rectangular and clipping to the specific | ||
| 198 | * bands of devBounds is needed, then an intersection of the | ||
| 199 | * resulting Region with devBounds must be performed in a | ||
| 200 | * subsequent step. | ||
| 201 | * | ||
| 202 | * @param devBounds a non-null Region specifying some bounds to | ||
| 203 | * clip the geometry to | ||
| 204 | * @param normalize a boolean indicating whether or not to apply | ||
| 205 | * normalization | ||
| 206 | * @param s a non-null Shape object specifying the geometry enclosing | ||
| 207 | * the pixels of interest | ||
| 208 | * @param at an optional <code>AffineTransform</code> to be applied to the | ||
| 209 | * coordinates as they are returned in the iteration, or | ||
| 210 | * <code>null</code> if untransformed coordinates are desired | ||
| 211 | */ | ||
| 212 | public static Region getInstance(Region devBounds, boolean normalize, | ||
| 213 | Shape s, AffineTransform at) | ||
| 214 | { | ||
| 215 | // Optimize for empty shapes to avoid involving the SpanIterator | ||
| 216 | if (s instanceof RectangularShape && | ||
| 217 | ((RectangularShape)s).isEmpty()) | ||
| 218 | { | ||
| 219 | return EMPTY_REGION; | ||
| 220 | } | ||
| 221 | |||
| 222 | int box[] = new int[4]; | ||
| 223 | ShapeSpanIterator sr = new ShapeSpanIterator(normalize); | ||
| 224 | try { | ||
| 225 | sr.setOutputArea(devBounds); | ||
| 226 | sr.appendPath(s.getPathIterator(at)); | ||
| 227 | sr.getPathBox(box); | ||
| 228 | Region r = Region.getInstance(box); | ||
| 229 | r.appendSpans(sr); | ||
| 230 | return r; | ||
| 231 | } finally { | ||
| 232 | sr.dispose(); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * Returns a Region object with a rectangle of interest specified | ||
| 238 | * by the indicated Rectangle object. | ||
| 239 | * <p> | ||
| 240 | * This method can also be used to create a simple rectangular | ||
| 241 | * region. | ||
| 242 | */ | ||
| 243 | public static Region getInstance(Rectangle r) { | ||
| 244 | return Region.getInstanceXYWH(r.x, r.y, r.width, r.height); | ||
| 245 | } | ||
| 246 | |||
| 247 | /** | ||
| 248 | * Returns a Region object with a rectangle of interest specified | ||
| 249 | * by the indicated rectangular area in x, y, width, height format. | ||
| 250 | * <p> | ||
| 251 | * This method can also be used to create a simple rectangular | ||
| 252 | * region. | ||
| 253 | */ | ||
| 254 | public static Region getInstanceXYWH(int x, int y, int w, int h) { | ||
| 255 | return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); | ||
| 256 | } | ||
| 257 | |||
| 258 | /** | ||
| 259 | * Returns a Region object with a rectangle of interest specified | ||
| 260 | * by the indicated span array. | ||
| 261 | * <p> | ||
| 262 | * This method can also be used to create a simple rectangular | ||
| 263 | * region. | ||
| 264 | */ | ||
| 265 | public static Region getInstance(int box[]) { | ||
| 266 | return new Region(box[0], box[1], box[2], box[3]); | ||
| 267 | } | ||
| 268 | |||
| 269 | /** | ||
| 270 | * Returns a Region object with a rectangle of interest specified | ||
| 271 | * by the indicated rectangular area in lox, loy, hix, hiy format. | ||
| 272 | * <p> | ||
| 273 | * This method can also be used to create a simple rectangular | ||
| 274 | * region. | ||
| 275 | */ | ||
| 276 | public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) { | ||
| 277 | return new Region(lox, loy, hix, hiy); | ||
| 278 | } | ||
| 279 | |||
| 280 | /** | ||
| 281 | * Sets the rectangle of interest for storing and returning | ||
| 282 | * region bands. | ||
| 283 | * <p> | ||
| 284 | * This method can also be used to initialize a simple rectangular | ||
| 285 | * region. | ||
| 286 | */ | ||
| 287 | public void setOutputArea(Rectangle r) { | ||
| 288 | setOutputAreaXYWH(r.x, r.y, r.width, r.height); | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * Sets the rectangle of interest for storing and returning | ||
| 293 | * region bands. The rectangle is specified in x, y, width, height | ||
| 294 | * format and appropriate clipping is performed as per the method | ||
| 295 | * <code>dimAdd</code>. | ||
| 296 | * <p> | ||
| 297 | * This method can also be used to initialize a simple rectangular | ||
| 298 | * region. | ||
| 299 | */ | ||
| 300 | public void setOutputAreaXYWH(int x, int y, int w, int h) { | ||
| 301 | setOutputAreaXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); | ||
| 302 | } | ||
| 303 | |||
| 304 | /** | ||
| 305 | * Sets the rectangle of interest for storing and returning | ||
| 306 | * region bands. The rectangle is specified as a span array. | ||
| 307 | * <p> | ||
| 308 | * This method can also be used to initialize a simple rectangular | ||
| 309 | * region. | ||
| 310 | */ | ||
| 311 | public void setOutputArea(int box[]) { | ||
| 312 | this.lox = box[0]; | ||
| 313 | this.loy = box[1]; | ||
| 314 | this.hix = box[2]; | ||
| 315 | this.hiy = box[3]; | ||
| 316 | } | ||
| 317 | |||
| 318 | /** | ||
| 319 | * Sets the rectangle of interest for storing and returning | ||
| 320 | * region bands. The rectangle is specified in lox, loy, | ||
| 321 | * hix, hiy format. | ||
| 322 | * <p> | ||
| 323 | * This method can also be used to initialize a simple rectangular | ||
| 324 | * region. | ||
| 325 | */ | ||
| 326 | public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) { | ||
| 327 | this.lox = lox; | ||
| 328 | this.loy = loy; | ||
| 329 | this.hix = hix; | ||
| 330 | this.hiy = hiy; | ||
| 331 | } | ||
| 332 | |||
| 333 | /** | ||
| 334 | * Appends the list of spans returned from the indicated | ||
| 335 | * SpanIterator. Each span must be at a higher starting | ||
| 336 | * Y coordinate than the previous data or it must have a | ||
| 337 | * Y range equal to the highest Y band in the region and a | ||
| 338 | * higher X coordinate than any of the spans in that band. | ||
| 339 | */ | ||
| 340 | public void appendSpans(SpanIterator si) { | ||
| 341 | int[] box = new int[6]; | ||
| 342 | |||
| 343 | while (si.nextSpan(box)) { | ||
| 344 | appendSpan(box); | ||
| 345 | } | ||
| 346 | |||
| 347 | endRow(box); | ||
| 348 | calcBBox(); | ||
| 349 | } | ||
| 350 | |||
| 351 | /** | ||
| 352 | * Returns a Region object that represents the same list of | ||
| 353 | * rectangles as the current Region object, translated by | ||
| 354 | * the specified dx, dy translation factors. | ||
| 355 | */ | ||
| 356 | public Region getTranslatedRegion(int dx, int dy) { | ||
| 357 | if ((dx | dy) == 0) { | ||
| 358 | return this; | ||
| 359 | } | ||
| 360 | int tlox = lox + dx; | ||
| 361 | int tloy = loy + dy; | ||
| 362 | int thix = hix + dx; | ||
| 363 | int thiy = hiy + dy; | ||
| 364 | if ((tlox > lox) != (dx > 0) || | ||
| 365 | (tloy > loy) != (dy > 0) || | ||
| 366 | (thix > hix) != (dx > 0) || | ||
| 367 | (thiy > hiy) != (dy > 0)) | ||
| 368 | { | ||
| 369 | return getSafeTranslatedRegion(dx, dy); | ||
| 370 | } | ||
| 371 | Region ret = new Region(tlox, tloy, thix, thiy); | ||
| 372 | int bands[] = this.bands; | ||
| 373 | if (bands != null) { | ||
| 374 | int end = endIndex; | ||
| 375 | ret.endIndex = end; | ||
| 376 | int newbands[] = new int[end]; | ||
| 377 | ret.bands = newbands; | ||
| 378 | int i = 0; | ||
| 379 | int ncol; | ||
| 380 | while (i < end) { | ||
| 381 | newbands[i] = bands[i] + dy; i++; | ||
| 382 | newbands[i] = bands[i] + dy; i++; | ||
| 383 | newbands[i] = ncol = bands[i]; i++; | ||
| 384 | while (--ncol >= 0) { | ||
| 385 | newbands[i] = bands[i] + dx; i++; | ||
| 386 | newbands[i] = bands[i] + dx; i++; | ||
| 387 | } | ||
| 388 | } | ||
| 389 | } | ||
| 390 | return ret; | ||
| 391 | } | ||
| 392 | |||
| 393 | private Region getSafeTranslatedRegion(int dx, int dy) { | ||
| 394 | int tlox = clipAdd(lox, dx); | ||
| 395 | int tloy = clipAdd(loy, dy); | ||
| 396 | int thix = clipAdd(hix, dx); | ||
| 397 | int thiy = clipAdd(hiy, dy); | ||
| 398 | Region ret = new Region(tlox, tloy, thix, thiy); | ||
| 399 | int bands[] = this.bands; | ||
| 400 | if (bands != null) { | ||
| 401 | int end = endIndex; | ||
| 402 | int newbands[] = new int[end]; | ||
| 403 | int i = 0; // index for source bands | ||
| 404 | int j = 0; // index for translated newbands | ||
| 405 | int ncol; | ||
| 406 | while (i < end) { | ||
| 407 | int y1, y2; | ||
| 408 | newbands[j++] = y1 = clipAdd(bands[i++], dy); | ||
| 409 | newbands[j++] = y2 = clipAdd(bands[i++], dy); | ||
| 410 | newbands[j++] = ncol = bands[i++]; | ||
| 411 | int savej = j; | ||
| 412 | if (y1 < y2) { | ||
| 413 | while (--ncol >= 0) { | ||
| 414 | int x1 = clipAdd(bands[i++], dx); | ||
| 415 | int x2 = clipAdd(bands[i++], dx); | ||
| 416 | if (x1 < x2) { | ||
| 417 | newbands[j++] = x1; | ||
| 418 | newbands[j++] = x2; | ||
| 419 | } | ||
| 420 | } | ||
| 421 | } else { | ||
| 422 | i += ncol * 2; | ||
| 423 | } | ||
| 424 | // Did we get any non-empty bands in this row? | ||
| 425 | if (j > savej) { | ||
| 426 | newbands[savej-1] = (j - savej) / 2; | ||
| 427 | } else { | ||
| 428 | j = savej - 3; | ||
| 429 | } | ||
| 430 | } | ||
| 431 | if (j <= 5) { | ||
| 432 | if (j < 5) { | ||
| 433 | // No rows or bands were generated... | ||
| 434 | ret.lox = ret.loy = ret.hix = ret.hiy = 0; | ||
| 435 | } else { | ||
| 436 | // Only generated one single rect in the end... | ||
| 437 | ret.loy = newbands[0]; | ||
| 438 | ret.hiy = newbands[1]; | ||
| 439 | ret.lox = newbands[3]; | ||
| 440 | ret.hix = newbands[4]; | ||
| 441 | } | ||
| 442 | // ret.endIndex and ret.bands were never initialized... | ||
| 443 | // ret.endIndex = 0; | ||
| 444 | // ret.newbands = null; | ||
| 445 | } else { | ||
| 446 | // Generated multiple bands and/or multiple rows... | ||
| 447 | ret.endIndex = j; | ||
| 448 | ret.bands = newbands; | ||
| 449 | } | ||
| 450 | } | ||
| 451 | return ret; | ||
| 452 | } | ||
| 453 | |||
| 454 | /** | ||
| 455 | * Returns a Region object that represents the intersection of | ||
| 456 | * this object with the specified Rectangle. The return value | ||
| 457 | * may be this same object if no clipping occurs. | ||
| 458 | */ | ||
| 459 | public Region getIntersection(Rectangle r) { | ||
| 460 | return getIntersectionXYWH(r.x, r.y, r.width, r.height); | ||
| 461 | } | ||
| 462 | |||
| 463 | /** | ||
| 464 | * Returns a Region object that represents the intersection of | ||
| 465 | * this object with the specified rectangular area. The return | ||
| 466 | * value may be this same object if no clipping occurs. | ||
| 467 | */ | ||
| 468 | public Region getIntersectionXYWH(int x, int y, int w, int h) { | ||
| 469 | return getIntersectionXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); | ||
| 470 | } | ||
| 471 | |||
| 472 | /** | ||
| 473 | * Returns a Region object that represents the intersection of | ||
| 474 | * this object with the specified rectangular area. The return | ||
| 475 | * value may be this same object if no clipping occurs. | ||
| 476 | */ | ||
| 477 | public Region getIntersectionXYXY(int lox, int loy, int hix, int hiy) { | ||
| 478 | if (isInsideXYXY(lox, loy, hix, hiy)) { | ||
| 479 | return this; | ||
| 480 | } | ||
| 481 | Region ret = new Region((lox < this.lox) ? this.lox : lox, | ||
| 482 | (loy < this.loy) ? this.loy : loy, | ||
| 483 | (hix > this.hix) ? this.hix : hix, | ||
| 484 | (hiy > this.hiy) ? this.hiy : hiy); | ||
| 485 | if (bands != null) { | ||
| 486 | ret.appendSpans(this.getSpanIterator()); | ||
| 487 | } | ||
| 488 | return ret; | ||
| 489 | } | ||
| 490 | |||
| 491 | /** | ||
| 492 | * Returns a Region object that represents the intersection of this | ||
| 493 | * object with the specified Region object. | ||
| 494 | * <p> | ||
| 495 | * If {@code A} and {@code B} are both Region Objects and | ||
| 496 | * <code>C = A.getIntersection(B);</code> then a point will | ||
| 497 | * be contained in {@code C} iff it is contained in both | ||
| 498 | * {@code A} and {@code B}. | ||
| 499 | * <p> | ||
| 500 | * The return value may be this same object or the argument | ||
| 501 | * Region object if no clipping occurs. | ||
| 502 | */ | ||
| 503 | public Region getIntersection(Region r) { | ||
| 504 | if (this.isInsideQuickCheck(r)) { | ||
| 505 | return this; | ||
| 506 | } | ||
| 507 | if (r.isInsideQuickCheck(this)) { | ||
| 508 | return r; | ||
| 509 | } | ||
| 510 | Region ret = new Region((r.lox < this.lox) ? this.lox : r.lox, | ||
| 511 | (r.loy < this.loy) ? this.loy : r.loy, | ||
| 512 | (r.hix > this.hix) ? this.hix : r.hix, | ||
| 513 | (r.hiy > this.hiy) ? this.hiy : r.hiy); | ||
| 514 | if (!ret.isEmpty()) { | ||
| 515 | ret.filterSpans(this, r, INCLUDE_COMMON); | ||
| 516 | } | ||
| 517 | return ret; | ||
| 518 | } | ||
| 519 | |||
| 520 | /** | ||
| 521 | * Returns a Region object that represents the union of this | ||
| 522 | * object with the specified Region object. | ||
| 523 | * <p> | ||
| 524 | * If {@code A} and {@code B} are both Region Objects and | ||
| 525 | * <code>C = A.getUnion(B);</code> then a point will | ||
| 526 | * be contained in {@code C} iff it is contained in either | ||
| 527 | * {@code A} or {@code B}. | ||
| 528 | * <p> | ||
| 529 | * The return value may be this same object or the argument | ||
| 530 | * Region object if no augmentation occurs. | ||
| 531 | */ | ||
| 532 | public Region getUnion(Region r) { | ||
| 533 | if (r.isEmpty() || r.isInsideQuickCheck(this)) { | ||
| 534 | return this; | ||
| 535 | } | ||
| 536 | if (this.isEmpty() || this.isInsideQuickCheck(r)) { | ||
| 537 | return r; | ||
| 538 | } | ||
| 539 | Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox, | ||
| 540 | (r.loy > this.loy) ? this.loy : r.loy, | ||
| 541 | (r.hix < this.hix) ? this.hix : r.hix, | ||
| 542 | (r.hiy < this.hiy) ? this.hiy : r.hiy); | ||
| 543 | ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B | INCLUDE_COMMON); | ||
| 544 | return ret; | ||
| 545 | } | ||
| 546 | |||
| 547 | /** | ||
| 548 | * Returns a Region object that represents the difference of the | ||
| 549 | * specified Region object subtracted from this object. | ||
| 550 | * <p> | ||
| 551 | * If {@code A} and {@code B} are both Region Objects and | ||
| 552 | * <code>C = A.getDifference(B);</code> then a point will | ||
| 553 | * be contained in {@code C} iff it is contained in | ||
| 554 | * {@code A} but not contained in {@code B}. | ||
| 555 | * <p> | ||
| 556 | * The return value may be this same object or the argument | ||
| 557 | * Region object if no clipping occurs. | ||
| 558 | */ | ||
| 559 | public Region getDifference(Region r) { | ||
| 560 | if (!r.intersectsQuickCheck(this)) { | ||
| 561 | return this; | ||
| 562 | } | ||
| 563 | if (this.isInsideQuickCheck(r)) { | ||
| 564 | return EMPTY_REGION; | ||
| 565 | } | ||
| 566 | Region ret = new Region(this.lox, this.loy, this.hix, this.hiy); | ||
| 567 | ret.filterSpans(this, r, INCLUDE_A); | ||
| 568 | return ret; | ||
| 569 | } | ||
| 570 | |||
| 571 | /** | ||
| 572 | * Returns a Region object that represents the exclusive or of this | ||
| 573 | * object with the specified Region object. | ||
| 574 | * <p> | ||
| 575 | * If {@code A} and {@code B} are both Region Objects and | ||
| 576 | * <code>C = A.getExclusiveOr(B);</code> then a point will | ||
| 577 | * be contained in {@code C} iff it is contained in either | ||
| 578 | * {@code A} or {@code B}, but not if it is contained in both. | ||
| 579 | * <p> | ||
| 580 | * The return value may be this same object or the argument | ||
| 581 | * Region object if either is empty. | ||
| 582 | */ | ||
| 583 | public Region getExclusiveOr(Region r) { | ||
| 584 | if (r.isEmpty()) { | ||
| 585 | return this; | ||
| 586 | } | ||
| 587 | if (this.isEmpty()) { | ||
| 588 | return r; | ||
| 589 | } | ||
| 590 | Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox, | ||
| 591 | (r.loy > this.loy) ? this.loy : r.loy, | ||
| 592 | (r.hix < this.hix) ? this.hix : r.hix, | ||
| 593 | (r.hiy < this.hiy) ? this.hiy : r.hiy); | ||
| 594 | ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B); | ||
| 595 | return ret; | ||
| 596 | } | ||
| 597 | |||
| 598 | static final int INCLUDE_A = 1; | ||
| 599 | static final int INCLUDE_B = 2; | ||
| 600 | static final int INCLUDE_COMMON = 4; | ||
| 601 | |||
| 602 | private void filterSpans(Region ra, Region rb, int flags) { | ||
| 603 | int abands[] = ra.bands; | ||
| 604 | int bbands[] = rb.bands; | ||
| 605 | if (abands == null) { | ||
| 606 | abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix}; | ||
| 607 | } | ||
| 608 | if (bbands == null) { | ||
| 609 | bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix}; | ||
| 610 | } | ||
| 611 | int box[] = new int[6]; | ||
| 612 | int acolstart = 0; | ||
| 613 | int ay1 = abands[acolstart++]; | ||
| 614 | int ay2 = abands[acolstart++]; | ||
| 615 | int acolend = abands[acolstart++]; | ||
| 616 | acolend = acolstart + 2 * acolend; | ||
| 617 | int bcolstart = 0; | ||
| 618 | int by1 = bbands[bcolstart++]; | ||
| 619 | int by2 = bbands[bcolstart++]; | ||
| 620 | int bcolend = bbands[bcolstart++]; | ||
| 621 | bcolend = bcolstart + 2 * bcolend; | ||
| 622 | int y = loy; | ||
| 623 | while (y < hiy) { | ||
| 624 | if (y >= ay2) { | ||
| 625 | if (acolend < ra.endIndex) { | ||
| 626 | acolstart = acolend; | ||
| 627 | ay1 = abands[acolstart++]; | ||
| 628 | ay2 = abands[acolstart++]; | ||
| 629 | acolend = abands[acolstart++]; | ||
| 630 | acolend = acolstart + 2 * acolend; | ||
| 631 | } else { | ||
| 632 | if ((flags & INCLUDE_B) == 0) break; | ||
| 633 | ay1 = ay2 = hiy; | ||
| 634 | } | ||
| 635 | continue; | ||
| 636 | } | ||
| 637 | if (y >= by2) { | ||
| 638 | if (bcolend < rb.endIndex) { | ||
| 639 | bcolstart = bcolend; | ||
| 640 | by1 = bbands[bcolstart++]; | ||
| 641 | by2 = bbands[bcolstart++]; | ||
| 642 | bcolend = bbands[bcolstart++]; | ||
| 643 | bcolend = bcolstart + 2 * bcolend; | ||
| 644 | } else { | ||
| 645 | if ((flags & INCLUDE_A) == 0) break; | ||
| 646 | by1 = by2 = hiy; | ||
| 647 | } | ||
| 648 | continue; | ||
| 649 | } | ||
| 650 | int yend; | ||
| 651 | if (y < by1) { | ||
| 652 | if (y < ay1) { | ||
| 653 | y = Math.min(ay1, by1); | ||
| 654 | continue; | ||
| 655 | } | ||
| 656 | // We are in a set of rows that belong only to A | ||
| 657 | yend = Math.min(ay2, by1); | ||
| 658 | if ((flags & INCLUDE_A) != 0) { | ||
| 659 | box[1] = y; | ||
| 660 | box[3] = yend; | ||
| 661 | int acol = acolstart; | ||
| 662 | while (acol < acolend) { | ||
| 663 | box[0] = abands[acol++]; | ||
| 664 | box[2] = abands[acol++]; | ||
| 665 | appendSpan(box); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } else if (y < ay1) { | ||
| 669 | // We are in a set of rows that belong only to B | ||
| 670 | yend = Math.min(by2, ay1); | ||
| 671 | if ((flags & INCLUDE_B) != 0) { | ||
| 672 | box[1] = y; | ||
| 673 | box[3] = yend; | ||
| 674 | int bcol = bcolstart; | ||
| 675 | while (bcol < bcolend) { | ||
| 676 | box[0] = bbands[bcol++]; | ||
| 677 | box[2] = bbands[bcol++]; | ||
| 678 | appendSpan(box); | ||
| 679 | } | ||
| 680 | } | ||
| 681 | } else { | ||
| 682 | // We are in a set of rows that belong to both A and B | ||
| 683 | yend = Math.min(ay2, by2); | ||
| 684 | box[1] = y; | ||
| 685 | box[3] = yend; | ||
| 686 | int acol = acolstart; | ||
| 687 | int bcol = bcolstart; | ||
| 688 | int ax1 = abands[acol++]; | ||
| 689 | int ax2 = abands[acol++]; | ||
| 690 | int bx1 = bbands[bcol++]; | ||
| 691 | int bx2 = bbands[bcol++]; | ||
| 692 | int x = Math.min(ax1, bx1); | ||
| 693 | if (x < lox) x = lox; | ||
| 694 | while (x < hix) { | ||
| 695 | if (x >= ax2) { | ||
| 696 | if (acol < acolend) { | ||
| 697 | ax1 = abands[acol++]; | ||
| 698 | ax2 = abands[acol++]; | ||
| 699 | } else { | ||
| 700 | if ((flags & INCLUDE_B) == 0) break; | ||
| 701 | ax1 = ax2 = hix; | ||
| 702 | } | ||
| 703 | continue; | ||
| 704 | } | ||
| 705 | if (x >= bx2) { | ||
| 706 | if (bcol < bcolend) { | ||
| 707 | bx1 = bbands[bcol++]; | ||
| 708 | bx2 = bbands[bcol++]; | ||
| 709 | } else { | ||
| 710 | if ((flags & INCLUDE_A) == 0) break; | ||
| 711 | bx1 = bx2 = hix; | ||
| 712 | } | ||
| 713 | continue; | ||
| 714 | } | ||
| 715 | int xend; | ||
| 716 | boolean appendit; | ||
| 717 | if (x < bx1) { | ||
| 718 | if (x < ax1) { | ||
| 719 | xend = Math.min(ax1, bx1); | ||
| 720 | appendit = false; | ||
| 721 | } else { | ||
| 722 | xend = Math.min(ax2, bx1); | ||
| 723 | appendit = ((flags & INCLUDE_A) != 0); | ||
| 724 | } | ||
| 725 | } else if (x < ax1) { | ||
| 726 | xend = Math.min(ax1, bx2); | ||
| 727 | appendit = ((flags & INCLUDE_B) != 0); | ||
| 728 | } else { | ||
| 729 | xend = Math.min(ax2, bx2); | ||
| 730 | appendit = ((flags & INCLUDE_COMMON) != 0); | ||
| 731 | } | ||
| 732 | if (appendit) { | ||
| 733 | box[0] = x; | ||
| 734 | box[2] = xend; | ||
| 735 | appendSpan(box); | ||
| 736 | } | ||
| 737 | x = xend; | ||
| 738 | } | ||
| 739 | } | ||
| 740 | y = yend; | ||
| 741 | } | ||
| 742 | endRow(box); | ||
| 743 | calcBBox(); | ||
| 744 | } | ||
| 745 | |||
| 746 | /** | ||
| 747 | * Returns a Region object that represents the bounds of the | ||
| 748 | * intersection of this object with the bounds of the specified | ||
| 749 | * Region object. | ||
| 750 | * <p> | ||
| 751 | * The return value may be this same object if no clipping occurs | ||
| 752 | * and this Region is rectangular. | ||
| 753 | */ | ||
| 754 | public Region getBoundsIntersection(Rectangle r) { | ||
| 755 | return getBoundsIntersectionXYWH(r.x, r.y, r.width, r.height); | ||
| 756 | } | ||
| 757 | |||
| 758 | /** | ||
| 759 | * Returns a Region object that represents the bounds of the | ||
| 760 | * intersection of this object with the bounds of the specified | ||
| 761 | * rectangular area in x, y, width, height format. | ||
| 762 | * <p> | ||
| 763 | * The return value may be this same object if no clipping occurs | ||
| 764 | * and this Region is rectangular. | ||
| 765 | */ | ||
| 766 | public Region getBoundsIntersectionXYWH(int x, int y, int w, int h) { | ||
| 767 | return getBoundsIntersectionXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); | ||
| 768 | } | ||
| 769 | |||
| 770 | /** | ||
| 771 | * Returns a Region object that represents the bounds of the | ||
| 772 | * intersection of this object with the bounds of the specified | ||
| 773 | * rectangular area in lox, loy, hix, hiy format. | ||
| 774 | * <p> | ||
| 775 | * The return value may be this same object if no clipping occurs | ||
| 776 | * and this Region is rectangular. | ||
| 777 | */ | ||
| 778 | public Region getBoundsIntersectionXYXY(int lox, int loy, | ||
| 779 | int hix, int hiy) | ||
| 780 | { | ||
| 781 | if (this.bands == null && | ||
| 782 | this.lox >= lox && this.loy >= loy && | ||
| 783 | this.hix <= hix && this.hiy <= hiy) | ||
| 784 | { | ||
| 785 | return this; | ||
| 786 | } | ||
| 787 | return new Region((lox < this.lox) ? this.lox : lox, | ||
| 788 | (loy < this.loy) ? this.loy : loy, | ||
| 789 | (hix > this.hix) ? this.hix : hix, | ||
| 790 | (hiy > this.hiy) ? this.hiy : hiy); | ||
| 791 | } | ||
| 792 | |||
| 793 | /** | ||
| 794 | * Returns a Region object that represents the intersection of | ||
| 795 | * this object with the bounds of the specified Region object. | ||
| 796 | * <p> | ||
| 797 | * The return value may be this same object or the argument | ||
| 798 | * Region object if no clipping occurs and the Regions are | ||
| 799 | * rectangular. | ||
| 800 | */ | ||
| 801 | public Region getBoundsIntersection(Region r) { | ||
| 802 | if (this.encompasses(r)) { | ||
| 803 | return r; | ||
| 804 | } | ||
| 805 | if (r.encompasses(this)) { | ||
| 806 | return this; | ||
| 807 | } | ||
| 808 | return new Region((r.lox < this.lox) ? this.lox : r.lox, | ||
| 809 | (r.loy < this.loy) ? this.loy : r.loy, | ||
| 810 | (r.hix > this.hix) ? this.hix : r.hix, | ||
| 811 | (r.hiy > this.hiy) ? this.hiy : r.hiy); | ||
| 812 | } | ||
| 813 | |||
| 814 | /** | ||
| 815 | * Appends a single span defined by the 4 parameters | ||
| 816 | * spanlox, spanloy, spanhix, spanhiy. | ||
| 817 | * This span must be at a higher starting Y coordinate than | ||
| 818 | * the previous data or it must have a Y range equal to the | ||
| 819 | * highest Y band in the region and a higher X coordinate | ||
| 820 | * than any of the spans in that band. | ||
| 821 | */ | ||
| 822 | private void appendSpan(int box[]) { | ||
| 823 | int spanlox, spanloy, spanhix, spanhiy; | ||
| 824 | if ((spanlox = box[0]) < lox) spanlox = lox; | ||
| 825 | if ((spanloy = box[1]) < loy) spanloy = loy; | ||
| 826 | if ((spanhix = box[2]) > hix) spanhix = hix; | ||
| 827 | if ((spanhiy = box[3]) > hiy) spanhiy = hiy; | ||
| 828 | if (spanhix <= spanlox || spanhiy <= spanloy) { | ||
| 829 | return; | ||
| 830 | } | ||
| 831 | |||
| 832 | int curYrow = box[4]; | ||
| 833 | if (endIndex == 0 || spanloy >= bands[curYrow + 1]) { | ||
| 834 | if (bands == null) { | ||
| 835 | bands = new int[INIT_SIZE]; | ||
| 836 | } else { | ||
| 837 | needSpace(5); | ||
| 838 | endRow(box); | ||
| 839 | curYrow = box[4]; | ||
| 840 | } | ||
| 841 | bands[endIndex++] = spanloy; | ||
| 842 | bands[endIndex++] = spanhiy; | ||
| 843 | bands[endIndex++] = 0; | ||
| 844 | } else if (spanloy == bands[curYrow] && | ||
| 845 | spanhiy == bands[curYrow + 1] && | ||
| 846 | spanlox >= bands[endIndex - 1]) { | ||
| 847 | if (spanlox == bands[endIndex - 1]) { | ||
| 848 | bands[endIndex - 1] = spanhix; | ||
| 849 | return; | ||
| 850 | } | ||
| 851 | needSpace(2); | ||
| 852 | } else { | ||
| 853 | throw new InternalError("bad span"); | ||
| 854 | } | ||
| 855 | bands[endIndex++] = spanlox; | ||
| 856 | bands[endIndex++] = spanhix; | ||
| 857 | bands[curYrow + 2]++; | ||
| 858 | } | ||
| 859 | |||
| 860 | private void needSpace(int num) { | ||
| 861 | if (endIndex + num >= bands.length) { | ||
| 862 | int[] newbands = new int[bands.length + GROW_SIZE]; | ||
| 863 | System.arraycopy(bands, 0, newbands, 0, endIndex); | ||
| 864 | bands = newbands; | ||
| 865 | } | ||
| 866 | } | ||
| 867 | |||
| 868 | private void endRow(int box[]) { | ||
| 869 | int cur = box[4]; | ||
| 870 | int prev = box[5]; | ||
| 871 | if (cur > prev) { | ||
| 872 | int[] bands = this.bands; | ||
| 873 | if (bands[prev + 1] == bands[cur] && | ||
| 874 | bands[prev + 2] == bands[cur + 2]) | ||
| 875 | { | ||
| 876 | int num = bands[cur + 2] * 2; | ||
| 877 | cur += 3; | ||
| 878 | prev += 3; | ||
| 879 | while (num > 0) { | ||
| 880 | if (bands[cur++] != bands[prev++]) { | ||
| 881 | break; | ||
| 882 | } | ||
| 883 | num--; | ||
| 884 | } | ||
| 885 | if (num == 0) { | ||
| 886 | // prev == box[4] | ||
| 887 | bands[box[5] + 1] = bands[prev + 1]; | ||
| 888 | endIndex = prev; | ||
| 889 | return; | ||
| 890 | } | ||
| 891 | } | ||
| 892 | } | ||
| 893 | box[5] = box[4]; | ||
| 894 | box[4] = endIndex; | ||
| 895 | } | ||
| 896 | |||
| 897 | private void calcBBox() { | ||
| 898 | int[] bands = this.bands; | ||
| 899 | if (endIndex <= 5) { | ||
| 900 | if (endIndex == 0) { | ||
| 901 | lox = loy = hix = hiy = 0; | ||
| 902 | } else { | ||
| 903 | loy = bands[0]; | ||
| 904 | hiy = bands[1]; | ||
| 905 | lox = bands[3]; | ||
| 906 | hix = bands[4]; | ||
| 907 | endIndex = 0; | ||
| 908 | } | ||
| 909 | this.bands = null; | ||
| 910 | return; | ||
| 911 | } | ||
| 912 | int lox = this.hix; | ||
| 913 | int hix = this.lox; | ||
| 914 | int hiyindex = 0; | ||
| 915 | |||
| 916 | int i = 0; | ||
| 917 | while (i < endIndex) { | ||
| 918 | hiyindex = i; | ||
| 919 | int numbands = bands[i + 2]; | ||
| 920 | i += 3; | ||
| 921 | if (lox > bands[i]) { | ||
| 922 | lox = bands[i]; | ||
| 923 | } | ||
| 924 | i += numbands * 2; | ||
| 925 | if (hix < bands[i - 1]) { | ||
| 926 | hix = bands[i - 1]; | ||
| 927 | } | ||
| 928 | } | ||
| 929 | |||
| 930 | this.lox = lox; | ||
| 931 | this.loy = bands[0]; | ||
| 932 | this.hix = hix; | ||
| 933 | this.hiy = bands[hiyindex + 1]; | ||
| 934 | } | ||
| 935 | |||
| 936 | /** | ||
| 937 | * Returns the lowest X coordinate in the Region. | ||
| 938 | */ | ||
| 939 | public final int getLoX() { | ||
| 940 | return lox; | ||
| 941 | } | ||
| 942 | |||
| 943 | /** | ||
| 944 | * Returns the lowest Y coordinate in the Region. | ||
| 945 | */ | ||
| 946 | public final int getLoY() { | ||
| 947 | return loy; | ||
| 948 | } | ||
| 949 | |||
| 950 | /** | ||
| 951 | * Returns the highest X coordinate in the Region. | ||
| 952 | */ | ||
| 953 | public final int getHiX() { | ||
| 954 | return hix; | ||
| 955 | } | ||
| 956 | |||
| 957 | /** | ||
| 958 | * Returns the highest Y coordinate in the Region. | ||
| 959 | */ | ||
| 960 | public final int getHiY() { | ||
| 961 | return hiy; | ||
| 962 | } | ||
| 963 | |||
| 964 | /** | ||
| 965 | * Returns the width of this Region clipped to the range (0 - MAX_INT). | ||
| 966 | */ | ||
| 967 | public final int getWidth() { | ||
| 968 | if (hix < lox) return 0; | ||
| 969 | int w; | ||
| 970 | if ((w = hix - lox) < 0) { | ||
| 971 | w = Integer.MAX_VALUE; | ||
| 972 | } | ||
| 973 | return w; | ||
| 974 | } | ||
| 975 | |||
| 976 | /** | ||
| 977 | * Returns the height of this Region clipped to the range (0 - MAX_INT). | ||
| 978 | */ | ||
| 979 | public final int getHeight() { | ||
| 980 | if (hiy < loy) return 0; | ||
| 981 | int h; | ||
| 982 | if ((h = hiy - loy) < 0) { | ||
| 983 | h = Integer.MAX_VALUE; | ||
| 984 | } | ||
| 985 | return h; | ||
| 986 | } | ||
| 987 | |||
| 988 | /** | ||
| 989 | * Returns true iff this Region encloses no area. | ||
| 990 | */ | ||
| 991 | public boolean isEmpty() { | ||
| 992 | return (hix <= lox || hiy <= loy); | ||
| 993 | } | ||
| 994 | |||
| 995 | /** | ||
| 996 | * Returns true iff this Region represents a single simple | ||
| 997 | * rectangular area. | ||
| 998 | */ | ||
| 999 | public boolean isRectangular() { | ||
| 1000 | return (bands == null); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | /** | ||
| 1004 | * Returns true iff this Region contains the specified coordinate. | ||
| 1005 | */ | ||
| 1006 | public boolean contains(int x, int y) { | ||
| 1007 | if (x < lox || x >= hix || y < loy || y >= hiy) return false; | ||
| 1008 | if (bands == null) return true; | ||
| 1009 | int i = 0; | ||
| 1010 | while (i < endIndex) { | ||
| 1011 | if (y < bands[i++]) { | ||
| 1012 | return false; | ||
| 1013 | } | ||
| 1014 | if (y >= bands[i++]) { | ||
| 1015 | int numspans = bands[i++]; | ||
| 1016 | i += numspans * 2; | ||
| 1017 | } else { | ||
| 1018 | int end = bands[i++]; | ||
| 1019 | end = i + end * 2; | ||
| 1020 | while (i < end) { | ||
| 1021 | if (x < bands[i++]) return false; | ||
| 1022 | if (x < bands[i++]) return true; | ||
| 1023 | } | ||
| 1024 | return false; | ||
| 1025 | } | ||
| 1026 | } | ||
| 1027 | return false; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | /** | ||
| 1031 | * Returns true iff this Region lies inside the indicated | ||
| 1032 | * rectangular area specified in x, y, width, height format | ||
| 1033 | * with appropriate clipping performed as per the dimAdd method. | ||
| 1034 | */ | ||
| 1035 | public boolean isInsideXYWH(int x, int y, int w, int h) { | ||
| 1036 | return isInsideXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | /** | ||
| 1040 | * Returns true iff this Region lies inside the indicated | ||
| 1041 | * rectangular area specified in lox, loy, hix, hiy format. | ||
| 1042 | */ | ||
| 1043 | public boolean isInsideXYXY(int lox, int loy, int hix, int hiy) { | ||
| 1044 | return (this.lox >= lox && this.loy >= loy && | ||
| 1045 | this.hix <= hix && this.hiy <= hiy); | ||
| 1046 | |||
| 1047 | } | ||
| 1048 | |||
| 1049 | /** | ||
| 1050 | * Quickly checks if this Region lies inside the specified | ||
| 1051 | * Region object. | ||
| 1052 | * <p> | ||
| 1053 | * This method will return false if the specified Region | ||
| 1054 | * object is not a simple rectangle. | ||
| 1055 | */ | ||
| 1056 | public boolean isInsideQuickCheck(Region r) { | ||
| 1057 | return (r.bands == null && | ||
| 1058 | r.lox <= this.lox && r.loy <= this.loy && | ||
| 1059 | r.hix >= this.hix && r.hiy >= this.hiy); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | /** | ||
| 1063 | * Quickly checks if this Region intersects the specified | ||
| 1064 | * rectangular area specified in lox, loy, hix, hiy format. | ||
| 1065 | * <p> | ||
| 1066 | * This method tests only against the bounds of this region | ||
| 1067 | * and does not bother to test if the rectangular region | ||
| 1068 | * actually intersects any bands. | ||
| 1069 | */ | ||
| 1070 | public boolean intersectsQuickCheckXYXY(int lox, int loy, | ||
| 1071 | int hix, int hiy) | ||
| 1072 | { | ||
| 1073 | return (hix > this.lox && lox < this.hix && | ||
| 1074 | hiy > this.loy && loy < this.hiy); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | /** | ||
| 1078 | * Quickly checks if this Region intersects the specified | ||
| 1079 | * Region object. | ||
| 1080 | * <p> | ||
| 1081 | * This method tests only against the bounds of this region | ||
| 1082 | * and does not bother to test if the rectangular region | ||
| 1083 | * actually intersects any bands. | ||
| 1084 | */ | ||
| 1085 | public boolean intersectsQuickCheck(Region r) { | ||
| 1086 | return (r.hix > this.lox && r.lox < this.hix && | ||
| 1087 | r.hiy > this.loy && r.loy < this.hiy); | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | /** | ||
| 1091 | * Quickly checks if this Region surrounds the specified | ||
| 1092 | * Region object. | ||
| 1093 | * <p> | ||
| 1094 | * This method will return false if this Region object is | ||
| 1095 | * not a simple rectangle. | ||
| 1096 | */ | ||
| 1097 | public boolean encompasses(Region r) { | ||
| 1098 | return (this.bands == null && | ||
| 1099 | this.lox <= r.lox && this.loy <= r.loy && | ||
| 1100 | this.hix >= r.hix && this.hiy >= r.hiy); | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | /** | ||
| 1104 | * Quickly checks if this Region surrounds the specified | ||
| 1105 | * rectangular area specified in x, y, width, height format. | ||
| 1106 | * <p> | ||
| 1107 | * This method will return false if this Region object is | ||
| 1108 | * not a simple rectangle. | ||
| 1109 | */ | ||
| 1110 | public boolean encompassesXYWH(int x, int y, int w, int h) { | ||
| 1111 | return encompassesXYXY(x, y, dimAdd(x, w), dimAdd(y, h)); | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | /** | ||
| 1115 | * Quickly checks if this Region surrounds the specified | ||
| 1116 | * rectangular area specified in lox, loy, hix, hiy format. | ||
| 1117 | * <p> | ||
| 1118 | * This method will return false if this Region object is | ||
| 1119 | * not a simple rectangle. | ||
| 1120 | */ | ||
| 1121 | public boolean encompassesXYXY(int lox, int loy, int hix, int hiy) { | ||
| 1122 | return (this.bands == null && | ||
| 1123 | this.lox <= lox && this.loy <= loy && | ||
| 1124 | this.hix >= hix && this.hiy >= hiy); | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | /** | ||
| 1128 | * Gets the bbox of the available spans, clipped to the OutputArea. | ||
| 1129 | */ | ||
| 1130 | public void getBounds(int pathbox[]) { | ||
| 1131 | pathbox[0] = lox; | ||
| 1132 | pathbox[1] = loy; | ||
| 1133 | pathbox[2] = hix; | ||
| 1134 | pathbox[3] = hiy; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | /** | ||
| 1138 | * Clips the indicated bbox array to the bounds of this Region. | ||
| 1139 | */ | ||
| 1140 | public void clipBoxToBounds(int bbox[]) { | ||
| 1141 | if (bbox[0] < lox) bbox[0] = lox; | ||
| 1142 | if (bbox[1] < loy) bbox[1] = loy; | ||
| 1143 | if (bbox[2] > hix) bbox[2] = hix; | ||
| 1144 | if (bbox[3] > hiy) bbox[3] = hiy; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /** | ||
| 1148 | * Gets an iterator object to iterate over the spans in this region. | ||
| 1149 | */ | ||
| 1150 | public RegionIterator getIterator() { | ||
| 1151 | return new RegionIterator(this); | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | /** | ||
| 1155 | * Gets a span iterator object that iterates over the spans in this region | ||
| 1156 | */ | ||
| 1157 | public SpanIterator getSpanIterator() { | ||
| 1158 | return new RegionSpanIterator(this); | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | /** | ||
| 1162 | * Gets a span iterator object that iterates over the spans in this region | ||
| 1163 | * but clipped to the bounds given in the argument (xlo, ylo, xhi, yhi). | ||
| 1164 | */ | ||
| 1165 | public SpanIterator getSpanIterator(int bbox[]) { | ||
| 1166 | SpanIterator result = getSpanIterator(); | ||
| 1167 | result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]); | ||
| 1168 | return result; | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | /** | ||
| 1172 | * Returns a SpanIterator that is the argument iterator filtered by | ||
| 1173 | * this region. | ||
| 1174 | */ | ||
| 1175 | public SpanIterator filter(SpanIterator si) { | ||
| 1176 | if (bands == null) { | ||
| 1177 | si.intersectClipBox(lox, loy, hix, hiy); | ||
| 1178 | } else { | ||
| 1179 | si = new RegionClipSpanIterator(this, si); | ||
| 1180 | } | ||
| 1181 | return si; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | public String toString() { | ||
| 1185 | StringBuffer sb = new StringBuffer(); | ||
| 1186 | sb.append("Region[["); | ||
| 1187 | sb.append(lox); | ||
| 1188 | sb.append(", "); | ||
| 1189 | sb.append(loy); | ||
| 1190 | sb.append(" => "); | ||
| 1191 | sb.append(hix); | ||
| 1192 | sb.append(", "); | ||
| 1193 | sb.append(hiy); | ||
| 1194 | sb.append("]"); | ||
| 1195 | if (bands != null) { | ||
| 1196 | int col = 0; | ||
| 1197 | while (col < endIndex) { | ||
| 1198 | sb.append("y{"); | ||
| 1199 | sb.append(bands[col++]); | ||
| 1200 | sb.append(","); | ||
| 1201 | sb.append(bands[col++]); | ||
| 1202 | sb.append("}["); | ||
| 1203 | int end = bands[col++]; | ||
| 1204 | end = col + end * 2; | ||
| 1205 | while (col < end) { | ||
| 1206 | sb.append("x("); | ||
| 1207 | sb.append(bands[col++]); | ||
| 1208 | sb.append(", "); | ||
| 1209 | sb.append(bands[col++]); | ||
| 1210 | sb.append(")"); | ||
| 1211 | } | ||
| 1212 | sb.append("]"); | ||
| 1213 | } | ||
| 1214 | } | ||
| 1215 | sb.append("]"); | ||
| 1216 | return sb.toString(); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | public int hashCode() { | ||
| 1220 | return (isEmpty() ? 0 : (lox * 3 + loy * 5 + hix * 7 + hiy * 9)); | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | public boolean equals(Object o) { | ||
| 1224 | if (!(o instanceof Region)) { | ||
| 1225 | return false; | ||
| 1226 | } | ||
| 1227 | Region r = (Region) o; | ||
| 1228 | if (this.isEmpty()) { | ||
| 1229 | return r.isEmpty(); | ||
| 1230 | } else if (r.isEmpty()) { | ||
| 1231 | return false; | ||
| 1232 | } | ||
| 1233 | if (r.lox != this.lox || r.loy != this.loy || | ||
| 1234 | r.hix != this.hix || r.hiy != this.hiy) | ||
| 1235 | { | ||
| 1236 | return false; | ||
| 1237 | } | ||
| 1238 | if (this.bands == null) { | ||
| 1239 | return (r.bands == null); | ||
| 1240 | } else if (r.bands == null) { | ||
| 1241 | return false; | ||
| 1242 | } | ||
| 1243 | if (this.endIndex != r.endIndex) { | ||
| 1244 | return false; | ||
| 1245 | } | ||
| 1246 | int abands[] = this.bands; | ||
| 1247 | int bbands[] = r.bands; | ||
| 1248 | for (int i = 0; i < endIndex; i++) { | ||
| 1249 | if (abands[i] != bbands[i]) { | ||
| 1250 | return false; | ||
| 1251 | } | ||
| 1252 | } | ||
| 1253 | return true; | ||
| 1254 | } | ||
| 1255 | } | ||
Binary file not shown.
| @@ -0,0 +1,392 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1999, 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.geom.PathIterator; | ||
| 29 | import java.awt.Rectangle; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * This class clips a SpanIterator to a Region and outputs the | ||
| 33 | * resulting spans as another SpanIterator. | ||
| 34 | * | ||
| 35 | * Spans are output in the usual y/x order, unless the input span | ||
| 36 | * iterator doesn't conform to this order, or the iterator's span | ||
| 37 | * straddle more than one band of the Region used for clipping. | ||
| 38 | * | ||
| 39 | * Principle of operation: | ||
| 40 | * | ||
| 41 | * The iterator maintains a several cursors onto the RegionIterator | ||
| 42 | * in order to avoid having to buffer spans from the SpanIterator. | ||
| 43 | * They are: | ||
| 44 | * resetState The initial state of the RegionIterator | ||
| 45 | * lwm Low Water Mark, a running start point for | ||
| 46 | * processing each band. Usually goes down, but | ||
| 47 | * can be reset to resetState if a span has a lower | ||
| 48 | * start coordinate than the previous one. | ||
| 49 | * row The start of the current band of the RegionIterator | ||
| 50 | * box The current span of the current row | ||
| 51 | * | ||
| 52 | * The main nextSpan() loop implements a coroutine like structure, with | ||
| 53 | * three producers to get the next span, row and box calling each other | ||
| 54 | * to iterate through the span iterator and region. | ||
| 55 | * | ||
| 56 | * REMIND: Needs a native implementation! | ||
| 57 | */ | ||
| 58 | public class RegionClipSpanIterator implements SpanIterator { | ||
| 59 | |||
| 60 | // The inputs to the filter | ||
| 61 | Region rgn; | ||
| 62 | SpanIterator spanIter; | ||
| 63 | |||
| 64 | // The cursors that track the progress through the region | ||
| 65 | RegionIterator resetState; | ||
| 66 | RegionIterator lwm; | ||
| 67 | RegionIterator row; | ||
| 68 | RegionIterator box; | ||
| 69 | |||
| 70 | // The bounds of the current span iterator span | ||
| 71 | int spanlox, spanhix, spanloy, spanhiy; | ||
| 72 | |||
| 73 | // The extent of the region band marking the low water mark | ||
| 74 | int lwmloy, lwmhiy; | ||
| 75 | |||
| 76 | // The bounds of the current region box | ||
| 77 | int rgnlox, rgnloy, rgnhix, rgnhiy; | ||
| 78 | |||
| 79 | // The bounding box of the input Region. Used for click | ||
| 80 | // rejection of iterator spans | ||
| 81 | int rgnbndslox, rgnbndsloy, rgnbndshix, rgnbndshiy; | ||
| 82 | |||
| 83 | // The array used to hold coordinates from the region iterator | ||
| 84 | int rgnbox[] = new int[4]; | ||
| 85 | |||
| 86 | // The array used to hold coordinates from the span iterator | ||
| 87 | int spanbox[] = new int[4]; | ||
| 88 | |||
| 89 | // True if the next iterator span should be read on the next | ||
| 90 | // iteration of the main nextSpan() loop | ||
| 91 | boolean doNextSpan; | ||
| 92 | |||
| 93 | // True if the next region box should be read on the next | ||
| 94 | // iteration of the main nextSpan() loop | ||
| 95 | boolean doNextBox; | ||
| 96 | |||
| 97 | // True if there are no more spans or the Region is empty | ||
| 98 | boolean done = false; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Creates an instance that filters the spans generated by | ||
| 102 | * spanIter through the region described by rgn. | ||
| 103 | */ | ||
| 104 | public RegionClipSpanIterator(Region rgn, SpanIterator spanIter) { | ||
| 105 | |||
| 106 | this.spanIter = spanIter; | ||
| 107 | |||
| 108 | resetState = rgn.getIterator(); | ||
| 109 | lwm = resetState.createCopy(); | ||
| 110 | |||
| 111 | if (!lwm.nextYRange(rgnbox)) { | ||
| 112 | done = true; | ||
| 113 | return; | ||
| 114 | } | ||
| 115 | |||
| 116 | rgnloy = lwmloy = rgnbox[1]; | ||
| 117 | rgnhiy = lwmhiy = rgnbox[3]; | ||
| 118 | |||
| 119 | rgn.getBounds(rgnbox); | ||
| 120 | rgnbndslox = rgnbox[0]; | ||
| 121 | rgnbndsloy = rgnbox[1]; | ||
| 122 | rgnbndshix = rgnbox[2]; | ||
| 123 | rgnbndshiy = rgnbox[3]; | ||
| 124 | if (rgnbndslox >= rgnbndshix || | ||
| 125 | rgnbndsloy >= rgnbndshiy) { | ||
| 126 | done = true; | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | |||
| 130 | this.rgn = rgn; | ||
| 131 | |||
| 132 | |||
| 133 | row = lwm.createCopy(); | ||
| 134 | box = row.createCopy(); | ||
| 135 | doNextSpan = true; | ||
| 136 | doNextBox = false; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Gets the bbox of the available path segments, clipped to the | ||
| 141 | * Region. | ||
| 142 | */ | ||
| 143 | public void getPathBox(int pathbox[]) { | ||
| 144 | int[] rgnbox = new int[4]; | ||
| 145 | rgn.getBounds(rgnbox); | ||
| 146 | spanIter.getPathBox(pathbox); | ||
| 147 | |||
| 148 | if (pathbox[0] < rgnbox[0]) { | ||
| 149 | pathbox[0] = rgnbox[0]; | ||
| 150 | } | ||
| 151 | |||
| 152 | if (pathbox[1] < rgnbox[1]) { | ||
| 153 | pathbox[1] = rgnbox[1]; | ||
| 154 | } | ||
| 155 | |||
| 156 | if (pathbox[2] > rgnbox[2]) { | ||
| 157 | pathbox[2] = rgnbox[2]; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (pathbox[3] > rgnbox[3]) { | ||
| 161 | pathbox[3] = rgnbox[3]; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | /* | ||
| 166 | * Intersects the path box with the given bbox. | ||
| 167 | * Returned spans are clipped to this region, or discarded | ||
| 168 | * altogether if they lie outside it. | ||
| 169 | */ | ||
| 170 | public void intersectClipBox(int lox, int loy, int hix, int hiy) { | ||
| 171 | spanIter.intersectClipBox(lox, loy, hix, hiy); | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | /* | ||
| 176 | * Fetches the next span that needs to be operated on. | ||
| 177 | * If the return value is false then there are no more spans. | ||
| 178 | */ | ||
| 179 | public boolean nextSpan(int resultbox[]) { | ||
| 180 | if (done) { | ||
| 181 | return false; | ||
| 182 | } | ||
| 183 | |||
| 184 | int resultlox, resultloy, resulthix, resulthiy; | ||
| 185 | boolean doNextRow = false; | ||
| 186 | |||
| 187 | // REMIND: Cache the coordinate inst vars used in this loop | ||
| 188 | // in locals vars. | ||
| 189 | while (true) { | ||
| 190 | // We've exhausted the current span so get the next one | ||
| 191 | if (doNextSpan) { | ||
| 192 | if (!spanIter.nextSpan(spanbox)) { | ||
| 193 | done = true; | ||
| 194 | return false; | ||
| 195 | } else { | ||
| 196 | spanlox = spanbox[0]; | ||
| 197 | // Clip out spans that lie outside of the rgn's bounds | ||
| 198 | if (spanlox >= rgnbndshix) { | ||
| 199 | continue; | ||
| 200 | } | ||
| 201 | |||
| 202 | spanloy = spanbox[1]; | ||
| 203 | if (spanloy >= rgnbndshiy) { | ||
| 204 | continue; | ||
| 205 | } | ||
| 206 | |||
| 207 | spanhix = spanbox[2]; | ||
| 208 | if (spanhix <= rgnbndslox) { | ||
| 209 | continue; | ||
| 210 | } | ||
| 211 | |||
| 212 | spanhiy = spanbox[3]; | ||
| 213 | if (spanhiy <= rgnbndsloy) { | ||
| 214 | continue; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | // If the span starts higher up than the low-water mark, | ||
| 218 | // reset the lwm. This can only happen if spans aren't | ||
| 219 | // returned in strict y/x order, or the first time through. | ||
| 220 | if (lwmloy > spanloy) { | ||
| 221 | lwm.copyStateFrom(resetState); | ||
| 222 | lwm.nextYRange(rgnbox); | ||
| 223 | lwmloy = rgnbox[1]; | ||
| 224 | lwmhiy = rgnbox[3]; | ||
| 225 | } | ||
| 226 | // Skip to the first rgn row whose bottom edge is | ||
| 227 | // below the top of the current span. This will only | ||
| 228 | // execute >0 times when the current span starts in a | ||
| 229 | // lower region row than the previous one, or possibly the | ||
| 230 | // first time through. | ||
| 231 | while (lwmhiy <= spanloy) { | ||
| 232 | if (!lwm.nextYRange(rgnbox)) | ||
| 233 | break; | ||
| 234 | lwmloy = rgnbox[1]; | ||
| 235 | lwmhiy = rgnbox[3]; | ||
| 236 | } | ||
| 237 | // If the row overlaps the span, process it, otherwise | ||
| 238 | // fetch another span | ||
| 239 | if (lwmhiy > spanloy && lwmloy < spanhiy) { | ||
| 240 | // Update the current row if it's different from the | ||
| 241 | // new lwm | ||
| 242 | if (rgnloy != lwmloy) { | ||
| 243 | row.copyStateFrom(lwm); | ||
| 244 | rgnloy = lwmloy; | ||
| 245 | rgnhiy = lwmhiy; | ||
| 246 | } | ||
| 247 | box.copyStateFrom(row); | ||
| 248 | doNextBox = true; | ||
| 249 | doNextSpan = false; | ||
| 250 | } | ||
| 251 | continue; | ||
| 252 | } | ||
| 253 | |||
| 254 | // The current row's spans are exhausted, do the next one | ||
| 255 | if (doNextRow) { | ||
| 256 | // Next time we either do the next span or the next box | ||
| 257 | doNextRow = false; | ||
| 258 | // Get the next row | ||
| 259 | boolean ok = row.nextYRange(rgnbox); | ||
| 260 | // If there was one, update the bounds | ||
| 261 | if (ok) { | ||
| 262 | rgnloy = rgnbox[1]; | ||
| 263 | rgnhiy = rgnbox[3]; | ||
| 264 | } | ||
| 265 | if (!ok || rgnloy >= spanhiy) { | ||
| 266 | // If we've exhausted the rows or this one is below the span, | ||
| 267 | // go onto the next span | ||
| 268 | doNextSpan = true; | ||
| 269 | } | ||
| 270 | else { | ||
| 271 | // Otherwise get the first box on this row | ||
| 272 | box.copyStateFrom(row); | ||
| 273 | doNextBox = true; | ||
| 274 | } | ||
| 275 | continue; | ||
| 276 | } | ||
| 277 | |||
| 278 | // Process the next box in the current row | ||
| 279 | if (doNextBox) { | ||
| 280 | boolean ok = box.nextXBand(rgnbox); | ||
| 281 | if (ok) { | ||
| 282 | rgnlox = rgnbox[0]; | ||
| 283 | rgnhix = rgnbox[2]; | ||
| 284 | } | ||
| 285 | if (!ok || rgnlox >= spanhix) { | ||
| 286 | // If there was no next rgn span or it's beyond the | ||
| 287 | // source span, go onto the next row or span | ||
| 288 | doNextBox = false; | ||
| 289 | if (rgnhiy >= spanhiy) { | ||
| 290 | // If the current row totally overlaps the span, | ||
| 291 | // go onto the next span | ||
| 292 | doNextSpan = true; | ||
| 293 | } else { | ||
| 294 | // otherwise go onto the next rgn row | ||
| 295 | doNextRow = true; | ||
| 296 | } | ||
| 297 | } else { | ||
| 298 | // Otherwise, if the new rgn span overlaps the | ||
| 299 | // spanbox, no need to get another box | ||
| 300 | doNextBox = rgnhix <= spanlox; | ||
| 301 | } | ||
| 302 | continue; | ||
| 303 | } | ||
| 304 | |||
| 305 | // Prepare to do the next box either on this call or | ||
| 306 | // or the subsequent one | ||
| 307 | doNextBox = true; | ||
| 308 | |||
| 309 | // Clip the current span against the current box | ||
| 310 | if (spanlox > rgnlox) { | ||
| 311 | resultlox = spanlox; | ||
| 312 | } | ||
| 313 | else { | ||
| 314 | resultlox = rgnlox; | ||
| 315 | } | ||
| 316 | |||
| 317 | if (spanloy > rgnloy) { | ||
| 318 | resultloy = spanloy; | ||
| 319 | } | ||
| 320 | else { | ||
| 321 | resultloy = rgnloy; | ||
| 322 | } | ||
| 323 | |||
| 324 | if (spanhix < rgnhix) { | ||
| 325 | resulthix = spanhix; | ||
| 326 | } | ||
| 327 | else { | ||
| 328 | resulthix = rgnhix; | ||
| 329 | } | ||
| 330 | |||
| 331 | if (spanhiy < rgnhiy) { | ||
| 332 | resulthiy = spanhiy; | ||
| 333 | } | ||
| 334 | else { | ||
| 335 | resulthiy = rgnhiy; | ||
| 336 | } | ||
| 337 | |||
| 338 | // If the result is empty, try then next box | ||
| 339 | // otherwise return the box. | ||
| 340 | // REMIND: I think by definition it's non-empty | ||
| 341 | // if we're here. Need to think about this some more. | ||
| 342 | if (resultlox >= resulthix || | ||
| 343 | resultloy >= resulthiy) { | ||
| 344 | continue; | ||
| 345 | } | ||
| 346 | else { | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | resultbox[0] = resultlox; | ||
| 352 | resultbox[1] = resultloy; | ||
| 353 | resultbox[2] = resulthix; | ||
| 354 | resultbox[3] = resulthiy; | ||
| 355 | return true; | ||
| 356 | |||
| 357 | } | ||
| 358 | |||
| 359 | |||
| 360 | /** | ||
| 361 | * This method tells the iterator that it may skip all spans | ||
| 362 | * whose Y range is completely above the indicated Y coordinate. | ||
| 363 | */ | ||
| 364 | public void skipDownTo(int y) { | ||
| 365 | spanIter.skipDownTo(y); | ||
| 366 | } | ||
| 367 | |||
| 368 | /** | ||
| 369 | * This method returns a native pointer to a function block that | ||
| 370 | * can be used by a native method to perform the same iteration | ||
| 371 | * cycle that the above methods provide while avoiding upcalls to | ||
| 372 | * the Java object. | ||
| 373 | * The definition of the structure whose pointer is returned by | ||
| 374 | * this method is defined in: | ||
| 375 | * <pre> | ||
| 376 | * src/share/native/sun/java2d/pipe/SpanIterator.h | ||
| 377 | * </pre> | ||
| 378 | */ | ||
| 379 | public long getNativeIterator() { | ||
| 380 | return 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | /* | ||
| 384 | * Cleans out all internal data structures. | ||
| 385 | */ | ||
| 386 | //public native void dispose(); | ||
| 387 | |||
| 388 | protected void finalize() { | ||
| 389 | //dispose(); | ||
| 390 | } | ||
| 391 | |||
| 392 | } | ||
Binary file not shown.
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 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.awt.Rectangle; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * This class defines the API for iterating through the bands | ||
| 32 | * of a region object. | ||
| 33 | */ | ||
| 34 | public class RegionIterator { | ||
| 35 | Region region; | ||
| 36 | int curIndex; | ||
| 37 | int numXbands; | ||
| 38 | |||
| 39 | RegionIterator(Region r) { | ||
| 40 | region = r; | ||
| 41 | } | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Returns a new RegionIterator object representing the same | ||
| 45 | * iteration state as this object to allow multiple iteration | ||
| 46 | * branches from the current position. | ||
| 47 | */ | ||
| 48 | public RegionIterator createCopy() { | ||
| 49 | RegionIterator r = new RegionIterator(region); | ||
| 50 | r.curIndex = this.curIndex; | ||
| 51 | r.numXbands = this.numXbands; | ||
| 52 | return r; | ||
| 53 | } | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Copies the iteration state from this RegionIterator object | ||
| 57 | * into another RegionIterator object to allow multiple iteration | ||
| 58 | * branches from the current position. | ||
| 59 | */ | ||
| 60 | public void copyStateFrom(RegionIterator ri) { | ||
| 61 | if (this.region != ri.region) { | ||
| 62 | throw new InternalError("region mismatch"); | ||
| 63 | } | ||
| 64 | this.curIndex = ri.curIndex; | ||
| 65 | this.numXbands = ri.numXbands; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Moves the iteration state to the beginning of the next | ||
| 70 | * Y range in the region returning true if one is found | ||
| 71 | * and recording the low and high Y coordinates of the | ||
| 72 | * range in the array at locations 1 and 3 respectively. | ||
| 73 | */ | ||
| 74 | public boolean nextYRange(int range[]) { | ||
| 75 | curIndex += numXbands * 2; | ||
| 76 | numXbands = 0; | ||
| 77 | if (curIndex >= region.endIndex) { | ||
| 78 | return false; | ||
| 79 | } | ||
| 80 | range[1] = region.bands[curIndex++]; | ||
| 81 | range[3] = region.bands[curIndex++]; | ||
| 82 | numXbands = region.bands[curIndex++]; | ||
| 83 | return true; | ||
| 84 | } | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Moves the iteration state to the beginning of the next | ||
| 88 | * X band in the current Y range returning true if one is | ||
| 89 | * found and recording the low and high X coordinates of | ||
| 90 | * the range in the array at locations 0 and 2 respectively. | ||
| 91 | */ | ||
| 92 | public boolean nextXBand(int range[]) { | ||
| 93 | if (numXbands <= 0) { | ||
| 94 | return false; | ||
| 95 | } | ||
| 96 | numXbands--; | ||
| 97 | range[0] = region.bands[curIndex++]; | ||
| 98 | range[2] = region.bands[curIndex++]; | ||
| 99 | return true; | ||
| 100 | } | ||
| 101 | } | ||
Binary file not shown.
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1999, 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 | /** | ||
| 29 | * This class implements the ShapeIterator interface for a Region. | ||
| 30 | * This is useful as the source iterator of a device clip region | ||
| 31 | * (in its native guise), and also as the result of clipping a | ||
| 32 | * Region to a rectangle. | ||
| 33 | */ | ||
| 34 | public class RegionSpanIterator implements SpanIterator { | ||
| 35 | // The RegionIterator that we use to do the work | ||
| 36 | RegionIterator ri; | ||
| 37 | |||
| 38 | // Clipping bounds | ||
| 39 | int lox, loy, hix, hiy; | ||
| 40 | |||
| 41 | // Current Y band limits | ||
| 42 | int curloy, curhiy; | ||
| 43 | |||
| 44 | // Are we done? | ||
| 45 | boolean done = false; | ||
| 46 | |||
| 47 | // Is the associated Region rectangular? | ||
| 48 | boolean isrect; | ||
| 49 | |||
| 50 | /* | ||
| 51 | REMIND: For native implementation | ||
| 52 | long pData; // Private storage of rect info | ||
| 53 | |||
| 54 | static { | ||
| 55 | initIDs(); | ||
| 56 | } | ||
| 57 | |||
| 58 | public static native void initIDs(); | ||
| 59 | */ | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Constructs an instance based on the given Region | ||
| 63 | */ | ||
| 64 | public RegionSpanIterator(Region r) { | ||
| 65 | int[] bounds = new int[4]; | ||
| 66 | |||
| 67 | r.getBounds(bounds); | ||
| 68 | lox = bounds[0]; | ||
| 69 | loy = bounds[1]; | ||
| 70 | hix = bounds[2]; | ||
| 71 | hiy = bounds[3]; | ||
| 72 | isrect = r.isRectangular(); | ||
| 73 | |||
| 74 | ri = r.getIterator(); | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Gets the bbox of the available region spans. | ||
| 79 | */ | ||
| 80 | public void getPathBox(int pathbox[]) { | ||
| 81 | pathbox[0] = lox; | ||
| 82 | pathbox[1] = loy; | ||
| 83 | pathbox[2] = hix; | ||
| 84 | pathbox[3] = hiy; | ||
| 85 | } | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Intersect the box used for clipping the output spans with the | ||
| 89 | * given box. | ||
| 90 | */ | ||
| 91 | public void intersectClipBox(int clox, int cloy, int chix, int chiy) { | ||
| 92 | if (clox > lox) { | ||
| 93 | lox = clox; | ||
| 94 | } | ||
| 95 | if (cloy > loy) { | ||
| 96 | loy = cloy; | ||
| 97 | } | ||
| 98 | if (chix < hix) { | ||
| 99 | hix = chix; | ||
| 100 | } | ||
| 101 | if (chiy < hiy) { | ||
| 102 | hiy = chiy; | ||
| 103 | } | ||
| 104 | done = lox >= hix || loy >= hiy; | ||
| 105 | } | ||
| 106 | |||
| 107 | /** | ||
| 108 | * Fetches the next span that needs to be operated on. | ||
| 109 | * If the return value is false then there are no more spans. | ||
| 110 | */ | ||
| 111 | public boolean nextSpan(int spanbox[]) { | ||
| 112 | |||
| 113 | // Quick test for end conditions | ||
| 114 | if (done) { | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | |||
| 118 | // If the Region is rectangular, we store our bounds (possibly | ||
| 119 | // clipped via intersectClipBox()) in spanbox and return true | ||
| 120 | // so that the caller will process the single span. We set done | ||
| 121 | // to true to ensure that this will be the last span processed. | ||
| 122 | if (isrect) { | ||
| 123 | getPathBox(spanbox); | ||
| 124 | done = true; | ||
| 125 | return true; | ||
| 126 | } | ||
| 127 | |||
| 128 | // Local cache of current span's bounds | ||
| 129 | int curlox, curhix; | ||
| 130 | int curloy = this.curloy; | ||
| 131 | int curhiy = this.curhiy; | ||
| 132 | |||
| 133 | while (true) { | ||
| 134 | if (!ri.nextXBand(spanbox)) { | ||
| 135 | if (!ri.nextYRange(spanbox)) { | ||
| 136 | done = true; | ||
| 137 | return false; | ||
| 138 | } | ||
| 139 | // Update the current y band and clip it | ||
| 140 | curloy = spanbox[1]; | ||
| 141 | curhiy = spanbox[3]; | ||
| 142 | if (curloy < loy) { | ||
| 143 | curloy = loy; | ||
| 144 | } | ||
| 145 | if (curhiy > hiy) { | ||
| 146 | curhiy = hiy; | ||
| 147 | } | ||
| 148 | // Check for moving below the clip rect | ||
| 149 | if (curloy >= hiy) { | ||
| 150 | done = true; | ||
| 151 | return false; | ||
| 152 | } | ||
| 153 | continue; | ||
| 154 | } | ||
| 155 | // Clip the x box | ||
| 156 | curlox = spanbox[0]; | ||
| 157 | curhix = spanbox[2]; | ||
| 158 | if (curlox < lox) { | ||
| 159 | curlox = lox; | ||
| 160 | } | ||
| 161 | if (curhix > hix) { | ||
| 162 | curhix = hix; | ||
| 163 | } | ||
| 164 | // If it's non- box, we're done | ||
| 165 | if (curlox < curhix && curloy < curhiy) { | ||
| 166 | break; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | // Update the result and the store y range | ||
| 171 | spanbox[0] = curlox; | ||
| 172 | spanbox[1] = this.curloy = curloy; | ||
| 173 | spanbox[2] = curhix; | ||
| 174 | spanbox[3] = this.curhiy = curhiy; | ||
| 175 | return true; | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * This method tells the iterator that it may skip all spans | ||
| 180 | * whose Y range is completely above the indicated Y coordinate. | ||
| 181 | */ | ||
| 182 | public void skipDownTo(int y) { | ||
| 183 | loy = y; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * This method returns a native pointer to a function block that | ||
| 188 | * can be used by a native method to perform the same iteration | ||
| 189 | * cycle that the above methods provide while avoiding upcalls to | ||
| 190 | * the Java object. | ||
| 191 | * The definition of the structure whose pointer is returned by | ||
| 192 | * this method is defined in: | ||
| 193 | * <pre> | ||
| 194 | * src/share/native/sun/java2d/pipe/SpanIterator.h | ||
| 195 | * </pre> | ||
| 196 | */ | ||
| 197 | public long getNativeIterator() { | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | /* | ||
| 202 | * Cleans out all internal data structures. | ||
| 203 | * REMIND: Native implementation | ||
| 204 | public native void dispose(); | ||
| 205 | |||
| 206 | protected void finalize() { | ||
| 207 | dispose(); | ||
| 208 | } | ||
| 209 | */ | ||
| 210 | } | ||
Binary file not shown.
| @@ -0,0 +1,294 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 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.pipe; | ||
| 27 | |||
| 28 | import sun.misc.Unsafe; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * The RenderBuffer class is a simplified, high-performance, Unsafe wrapper | ||
| 32 | * used for buffering rendering operations in a single-threaded rendering | ||
| 33 | * environment. It's functionality is similar to the ByteBuffer and related | ||
| 34 | * NIO classes. However, the methods in this class perform little to no | ||
| 35 | * alignment or bounds checks for performance reasons. Therefore, it is | ||
| 36 | * the caller's responsibility to ensure that all put() calls are properly | ||
| 37 | * aligned and within bounds: | ||
| 38 | * - int and float values must be aligned on 4-byte boundaries | ||
| 39 | * - long and double values must be aligned on 8-byte boundaries | ||
| 40 | * | ||
| 41 | * This class only includes the bare minimum of methods to support | ||
| 42 | * single-threaded rendering. For example, there is no put(double[]) method | ||
| 43 | * because we currently have no need for such a method in the STR classes. | ||
| 44 | */ | ||
| 45 | public class RenderBuffer { | ||
| 46 | |||
| 47 | /** | ||
| 48 | * These constants represent the size of various data types (in bytes). | ||
| 49 | */ | ||
| 50 | protected static final long SIZEOF_BYTE = 1L; | ||
| 51 | protected static final long SIZEOF_SHORT = 2L; | ||
| 52 | protected static final long SIZEOF_INT = 4L; | ||
| 53 | protected static final long SIZEOF_FLOAT = 4L; | ||
| 54 | protected static final long SIZEOF_LONG = 8L; | ||
| 55 | protected static final long SIZEOF_DOUBLE = 8L; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Represents the number of elements at which we have empirically | ||
| 59 | * determined that the average cost of a JNI call exceeds the expense | ||
| 60 | * of an element by element copy. In other words, if the number of | ||
| 61 | * elements in an array to be copied exceeds this value, then we should | ||
| 62 | * use the copyFromArray() method to complete the bulk put operation. | ||
| 63 | * (This value can be adjusted if the cost of JNI downcalls is reduced | ||
| 64 | * in a future release.) | ||
| 65 | */ | ||
| 66 | private static final int COPY_FROM_ARRAY_THRESHOLD = 6; | ||
| 67 | |||
| 68 | protected final Unsafe unsafe; | ||
| 69 | protected final long baseAddress; | ||
| 70 | protected final long endAddress; | ||
| 71 | protected long curAddress; | ||
| 72 | protected final int capacity; | ||
| 73 | |||
| 74 | protected RenderBuffer(int numBytes) { | ||
| 75 | unsafe = Unsafe.getUnsafe(); | ||
| 76 | curAddress = baseAddress = unsafe.allocateMemory(numBytes); | ||
| 77 | endAddress = baseAddress + numBytes; | ||
| 78 | capacity = numBytes; | ||
| 79 | } | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Allocates a fresh buffer using the machine endianness. | ||
| 83 | */ | ||
| 84 | public static RenderBuffer allocate(int numBytes) { | ||
| 85 | return new RenderBuffer(numBytes); | ||
| 86 | } | ||
| 87 | |||
| 88 | /** | ||
| 89 | * Returns the base address of the underlying memory buffer. | ||
| 90 | */ | ||
| 91 | public final long getAddress() { | ||
| 92 | return baseAddress; | ||
| 93 | } | ||
| 94 | |||
| 95 | /** | ||
| 96 | * The behavior (and names) of the following methods are nearly | ||
| 97 | * identical to their counterparts in the various NIO Buffer classes. | ||
| 98 | */ | ||
| 99 | |||
| 100 | public final int capacity() { | ||
| 101 | return capacity; | ||
| 102 | } | ||
| 103 | |||
| 104 | public final int remaining() { | ||
| 105 | return (int)(endAddress - curAddress); | ||
| 106 | } | ||
| 107 | |||
| 108 | public final int position() { | ||
| 109 | return (int)(curAddress - baseAddress); | ||
| 110 | } | ||
| 111 | |||
| 112 | public final void position(long numBytes) { | ||
| 113 | curAddress = baseAddress + numBytes; | ||
| 114 | } | ||
| 115 | |||
| 116 | public final void clear() { | ||
| 117 | curAddress = baseAddress; | ||
| 118 | } | ||
| 119 | |||
| 120 | public final RenderBuffer skip(long numBytes) { | ||
| 121 | curAddress += numBytes; | ||
| 122 | return this; | ||
| 123 | } | ||
| 124 | |||
| 125 | /** | ||
| 126 | * putByte() methods... | ||
| 127 | */ | ||
| 128 | |||
| 129 | public final RenderBuffer putByte(byte x) { | ||
| 130 | unsafe.putByte(curAddress, x); | ||
| 131 | curAddress += SIZEOF_BYTE; | ||
| 132 | return this; | ||
| 133 | } | ||
| 134 | |||
| 135 | public RenderBuffer put(byte[] x) { | ||
| 136 | return put(x, 0, x.length); | ||
| 137 | } | ||
| 138 | |||
| 139 | public RenderBuffer put(byte[] x, int offset, int length) { | ||
| 140 | if (length > COPY_FROM_ARRAY_THRESHOLD) { | ||
| 141 | long offsetInBytes = offset * SIZEOF_BYTE + Unsafe.ARRAY_BYTE_BASE_OFFSET; | ||
| 142 | long lengthInBytes = length * SIZEOF_BYTE; | ||
| 143 | unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); | ||
| 144 | position(position() + lengthInBytes); | ||
| 145 | } else { | ||
| 146 | int end = offset + length; | ||
| 147 | for (int i = offset; i < end; i++) { | ||
| 148 | putByte(x[i]); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | return this; | ||
| 152 | } | ||
| 153 | |||
| 154 | /** | ||
| 155 | * putShort() methods... | ||
| 156 | */ | ||
| 157 | |||
| 158 | public final RenderBuffer putShort(short x) { | ||
| 159 | // assert (position() % SIZEOF_SHORT == 0); | ||
| 160 | unsafe.putShort(curAddress, x); | ||
| 161 | curAddress += SIZEOF_SHORT; | ||
| 162 | return this; | ||
| 163 | } | ||
| 164 | |||
| 165 | public RenderBuffer put(short[] x) { | ||
| 166 | return put(x, 0, x.length); | ||
| 167 | } | ||
| 168 | |||
| 169 | public RenderBuffer put(short[] x, int offset, int length) { | ||
| 170 | // assert (position() % SIZEOF_SHORT == 0); | ||
| 171 | if (length > COPY_FROM_ARRAY_THRESHOLD) { | ||
| 172 | long offsetInBytes = offset * SIZEOF_SHORT + Unsafe.ARRAY_SHORT_BASE_OFFSET; | ||
| 173 | long lengthInBytes = length * SIZEOF_SHORT; | ||
| 174 | unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); | ||
| 175 | position(position() + lengthInBytes); | ||
| 176 | } else { | ||
| 177 | int end = offset + length; | ||
| 178 | for (int i = offset; i < end; i++) { | ||
| 179 | putShort(x[i]); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | return this; | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 186 | * putInt() methods... | ||
| 187 | */ | ||
| 188 | |||
| 189 | public final RenderBuffer putInt(int pos, int x) { | ||
| 190 | // assert (baseAddress + pos % SIZEOF_INT == 0); | ||
| 191 | unsafe.putInt(baseAddress + pos, x); | ||
| 192 | return this; | ||
| 193 | } | ||
| 194 | |||
| 195 | public final RenderBuffer putInt(int x) { | ||
| 196 | // assert (position() % SIZEOF_INT == 0); | ||
| 197 | unsafe.putInt(curAddress, x); | ||
| 198 | curAddress += SIZEOF_INT; | ||
| 199 | return this; | ||
| 200 | } | ||
| 201 | |||
| 202 | public RenderBuffer put(int[] x) { | ||
| 203 | return put(x, 0, x.length); | ||
| 204 | } | ||
| 205 | |||
| 206 | public RenderBuffer put(int[] x, int offset, int length) { | ||
| 207 | // assert (position() % SIZEOF_INT == 0); | ||
| 208 | if (length > COPY_FROM_ARRAY_THRESHOLD) { | ||
| 209 | long offsetInBytes = offset * SIZEOF_INT + Unsafe.ARRAY_INT_BASE_OFFSET; | ||
| 210 | long lengthInBytes = length * SIZEOF_INT; | ||
| 211 | unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); | ||
| 212 | position(position() + lengthInBytes); | ||
| 213 | } else { | ||
| 214 | int end = offset + length; | ||
| 215 | for (int i = offset; i < end; i++) { | ||
| 216 | putInt(x[i]); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | return this; | ||
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | * putFloat() methods... | ||
| 224 | */ | ||
| 225 | |||
| 226 | public final RenderBuffer putFloat(float x) { | ||
| 227 | // assert (position() % SIZEOF_FLOAT == 0); | ||
| 228 | unsafe.putFloat(curAddress, x); | ||
| 229 | curAddress += SIZEOF_FLOAT; | ||
| 230 | return this; | ||
| 231 | } | ||
| 232 | |||
| 233 | public RenderBuffer put(float[] x) { | ||
| 234 | return put(x, 0, x.length); | ||
| 235 | } | ||
| 236 | |||
| 237 | public RenderBuffer put(float[] x, int offset, int length) { | ||
| 238 | // assert (position() % SIZEOF_FLOAT == 0); | ||
| 239 | if (length > COPY_FROM_ARRAY_THRESHOLD) { | ||
| 240 | long offsetInBytes = offset * SIZEOF_FLOAT + Unsafe.ARRAY_FLOAT_BASE_OFFSET; | ||
| 241 | long lengthInBytes = length * SIZEOF_FLOAT; | ||
| 242 | unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); | ||
| 243 | position(position() + lengthInBytes); | ||
| 244 | } else { | ||
| 245 | int end = offset + length; | ||
| 246 | for (int i = offset; i < end; i++) { | ||
| 247 | putFloat(x[i]); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | return this; | ||
| 251 | } | ||
| 252 | |||
| 253 | /** | ||
| 254 | * putLong() methods... | ||
| 255 | */ | ||
| 256 | |||
| 257 | public final RenderBuffer putLong(long x) { | ||
| 258 | // assert (position() % SIZEOF_LONG == 0); | ||
| 259 | unsafe.putLong(curAddress, x); | ||
| 260 | curAddress += SIZEOF_LONG; | ||
| 261 | return this; | ||
| 262 | } | ||
| 263 | |||
| 264 | public RenderBuffer put(long[] x) { | ||
| 265 | return put(x, 0, x.length); | ||
| 266 | } | ||
| 267 | |||
| 268 | public RenderBuffer put(long[] x, int offset, int length) { | ||
| 269 | // assert (position() % SIZEOF_LONG == 0); | ||
| 270 | if (length > COPY_FROM_ARRAY_THRESHOLD) { | ||
| 271 | long offsetInBytes = offset * SIZEOF_LONG + Unsafe.ARRAY_LONG_BASE_OFFSET; | ||
| 272 | long lengthInBytes = length * SIZEOF_LONG; | ||
| 273 | unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); | ||
| 274 | position(position() + lengthInBytes); | ||
| 275 | } else { | ||
| 276 | int end = offset + length; | ||
| 277 | for (int i = offset; i < end; i++) { | ||
| 278 | putLong(x[i]); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | return this; | ||
| 282 | } | ||
| 283 | |||
| 284 | /** | ||
| 285 | * putDouble() method(s)... | ||
| 286 | */ | ||
| 287 | |||
| 288 | public final RenderBuffer putDouble(double x) { | ||
| 289 | // assert (position() % SIZEOF_DOUBLE == 0); | ||
| 290 | unsafe.putDouble(curAddress, x); | ||
| 291 | curAddress += SIZEOF_DOUBLE; | ||
| 292 | return this; | ||
| 293 | } | ||
| 294 | } | ||
Binary file not shown.
| @@ -0,0 +1,223 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 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.util.HashSet; | ||
| 29 | import java.util.Set; | ||
| 30 | import sun.awt.SunToolkit; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * The RenderQueue class encapsulates a RenderBuffer on which rendering | ||
| 34 | * operations are enqueued. Note that the RenderQueue lock must be acquired | ||
| 35 | * before performing any operations on the queue (e.g. enqueuing an operation | ||
| 36 | * or flushing the queue). A sample usage scenario follows: | ||
| 37 | * | ||
| 38 | * public void drawSomething(...) { | ||
| 39 | * rq.lock(); | ||
| 40 | * try { | ||
| 41 | * ctx.validate(...); | ||
| 42 | * rq.ensureCapacity(4); | ||
| 43 | * rq.getBuffer().putInt(DRAW_SOMETHING); | ||
| 44 | * ... | ||
| 45 | * } finally { | ||
| 46 | * rq.unlock(); | ||
| 47 | * } | ||
| 48 | * } | ||
| 49 | * | ||
| 50 | * If you are enqueuing an operation that involves 8-byte parameters (i.e. | ||
| 51 | * long or double values), it is imperative that you ensure proper | ||
| 52 | * alignment of the underlying RenderBuffer. This can be accomplished | ||
| 53 | * simply by providing an offset to the first 8-byte parameter in your | ||
| 54 | * operation to the ensureCapacityAndAlignment() method. For example: | ||
| 55 | * | ||
| 56 | * public void drawStuff(...) { | ||
| 57 | * rq.lock(); | ||
| 58 | * try { | ||
| 59 | * RenderBuffer buf = rq.getBuffer(); | ||
| 60 | * ctx.validate(...); | ||
| 61 | * // 28 total bytes in the operation, 12 bytes to the first long | ||
| 62 | * rq.ensureCapacityAndAlignment(28, 12); | ||
| 63 | * buf.putInt(DRAW_STUFF); | ||
| 64 | * buf.putInt(x).putInt(y); | ||
| 65 | * buf.putLong(addr1); | ||
| 66 | * buf.putLong(addr2); | ||
| 67 | * } finally { | ||
| 68 | * rq.unlock(); | ||
| 69 | * } | ||
| 70 | * } | ||
| 71 | */ | ||
| 72 | public abstract class RenderQueue { | ||
| 73 | |||
| 74 | /** The size of the underlying buffer, in bytes. */ | ||
| 75 | private static final int BUFFER_SIZE = 32000; | ||
| 76 | |||
| 77 | /** The underlying buffer for this queue. */ | ||
| 78 | protected RenderBuffer buf; | ||
| 79 | |||
| 80 | /** | ||
| 81 | * A Set containing hard references to Objects that must stay alive until | ||
| 82 | * the queue has been completely flushed. | ||
| 83 | */ | ||
| 84 | protected Set refSet; | ||
| 85 | |||
| 86 | protected RenderQueue() { | ||
| 87 | refSet = new HashSet(); | ||
| 88 | buf = RenderBuffer.allocate(BUFFER_SIZE); | ||
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Locks the queue for read/write access. | ||
| 93 | */ | ||
| 94 | public final void lock() { | ||
| 95 | /* | ||
| 96 | * Implementation note: In theory we should have two separate locks: | ||
| 97 | * one lock to synchronize access to the RenderQueue, and then a | ||
| 98 | * separate lock (the AWT lock) that only needs to be acquired when | ||
| 99 | * we are about to flush the queue (using native windowing system | ||
| 100 | * operations). In practice it has been difficult to enforce the | ||
| 101 | * correct lock ordering; sometimes AWT will have already acquired | ||
| 102 | * the AWT lock before grabbing the RQ lock (see 6253009), while the | ||
| 103 | * expected order should be RQ lock and then AWT lock. Due to this | ||
| 104 | * issue, using two separate locks is prone to deadlocks. Therefore, | ||
| 105 | * to solve this issue we have decided to eliminate the separate RQ | ||
| 106 | * lock and instead just acquire the AWT lock here. (Someday it might | ||
| 107 | * be nice to go back to the old two-lock system, but that would | ||
| 108 | * require potentially risky changes to AWT to ensure that it never | ||
| 109 | * acquires the AWT lock before calling into 2D code that wants to | ||
| 110 | * acquire the RQ lock.) | ||
| 111 | */ | ||
| 112 | SunToolkit.awtLock(); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Attempts to lock the queue. If successful, this method returns true, | ||
| 117 | * indicating that the caller is responsible for calling | ||
| 118 | * <code>unlock</code>; otherwise this method returns false. | ||
| 119 | */ | ||
| 120 | public final boolean tryLock() { | ||
| 121 | return SunToolkit.awtTryLock(); | ||
| 122 | } | ||
| 123 | |||
| 124 | /** | ||
| 125 | * Unlocks the queue. | ||
| 126 | */ | ||
| 127 | public final void unlock() { | ||
| 128 | SunToolkit.awtUnlock(); | ||
| 129 | } | ||
| 130 | |||
| 131 | /** | ||
| 132 | * Adds the given Object to the set of hard references, which will | ||
| 133 | * prevent that Object from being disposed until the queue has been | ||
| 134 | * flushed completely. This is useful in cases where some enqueued | ||
| 135 | * data could become invalid if the reference Object were garbage | ||
| 136 | * collected before the queue could be processed. (For example, keeping | ||
| 137 | * a hard reference to a FontStrike will prevent any enqueued glyph | ||
| 138 | * images associated with that strike from becoming invalid before the | ||
| 139 | * queue is flushed.) The reference set will be cleared immediately | ||
| 140 | * after the queue is flushed each time. | ||
| 141 | */ | ||
| 142 | public final void addReference(Object ref) { | ||
| 143 | refSet.add(ref); | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Returns the encapsulated RenderBuffer object. | ||
| 148 | */ | ||
| 149 | public final RenderBuffer getBuffer() { | ||
| 150 | return buf; | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * Ensures that there will be enough room on the underlying buffer | ||
| 155 | * for the following operation. If the operation will not fit given | ||
| 156 | * the remaining space, the buffer will be flushed immediately, leaving | ||
| 157 | * an empty buffer for the impending operation. | ||
| 158 | * | ||
| 159 | * @param opsize size (in bytes) of the following operation | ||
| 160 | */ | ||
| 161 | public final void ensureCapacity(int opsize) { | ||
| 162 | if (buf.remaining() < opsize) { | ||
| 163 | flushNow(); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * Convenience method that is equivalent to calling ensureCapacity() | ||
| 169 | * followed by ensureAlignment(). The ensureCapacity() call allows for an | ||
| 170 | * extra 4 bytes of space in case the ensureAlignment() method needs to | ||
| 171 | * insert a NOOP token on the buffer. | ||
| 172 | * | ||
| 173 | * @param opsize size (in bytes) of the following operation | ||
| 174 | * @param first8ByteValueOffset offset (in bytes) from the current | ||
| 175 | * position to the first 8-byte value used in the following operation | ||
| 176 | */ | ||
| 177 | public final void ensureCapacityAndAlignment(int opsize, | ||
| 178 | int first8ByteValueOffset) | ||
| 179 | { | ||
| 180 | ensureCapacity(opsize + 4); | ||
| 181 | ensureAlignment(first8ByteValueOffset); | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Inserts a 4-byte NOOP token when necessary to ensure that all 8-byte | ||
| 186 | * parameters for the following operation are added to the underlying | ||
| 187 | * buffer with an 8-byte memory alignment. | ||
| 188 | * | ||
| 189 | * @param first8ByteValueOffset offset (in bytes) from the current | ||
| 190 | * position to the first 8-byte value used in the following operation | ||
| 191 | */ | ||
| 192 | public final void ensureAlignment(int first8ByteValueOffset) { | ||
| 193 | int first8ByteValuePosition = buf.position() + first8ByteValueOffset; | ||
| 194 | if ((first8ByteValuePosition & 7) != 0) { | ||
| 195 | buf.putInt(BufferedOpCodes.NOOP); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | /** | ||
| 200 | * Immediately processes each operation currently pending on the buffer. | ||
| 201 | * This method will block until the entire buffer has been flushed. The | ||
| 202 | * queue lock must be acquired before calling this method. | ||
| 203 | */ | ||
| 204 | public abstract void flushNow(); | ||
| 205 | |||
| 206 | /** | ||
| 207 | * Immediately processes each operation currently pending on the buffer, | ||
| 208 | * and then invokes the provided task. This method will block until the | ||
| 209 | * entire buffer has been flushed and the provided task has been executed. | ||
| 210 | * The queue lock must be acquired before calling this method. | ||
| 211 | */ | ||
| 212 | public abstract void flushAndInvokeNow(Runnable task); | ||
| 213 | |||
| 214 | /** | ||
| 215 | * Updates the current position of the underlying buffer, and then | ||
| 216 | * flushes the queue immediately. This method is useful when native code | ||
| 217 | * has added data to the queue and needs to flush immediately. | ||
| 218 | */ | ||
| 219 | public void flushNow(int position) { | ||
| 220 | buf.position(position); | ||
| 221 | flushNow(); | ||
| 222 | } | ||
| 223 | } | ||
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,482 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 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.pipe; | ||
| 27 | |||
| 28 | import java.awt.Shape; | ||
| 29 | import java.awt.BasicStroke; | ||
| 30 | import java.awt.geom.PathIterator; | ||
| 31 | import java.awt.geom.AffineTransform; | ||
| 32 | |||
| 33 | import java.security.PrivilegedAction; | ||
| 34 | import java.security.AccessController; | ||
| 35 | import java.util.ServiceLoader; | ||
| 36 | import sun.security.action.GetPropertyAction; | ||
| 37 | |||
| 38 | import sun.awt.geom.PathConsumer2D; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * This class abstracts a number of features for which the Java 2D | ||
| 42 | * implementation relies on proprietary licensed software libraries. | ||
| 43 | * Access to those features is now achieved by retrieving the singleton | ||
| 44 | * instance of this class and calling the appropriate methods on it. | ||
| 45 | * The 3 primary features abstracted here include: | ||
| 46 | * <dl> | ||
| 47 | * <dt>Shape createStrokedShape(Shape, [BasicStroke attributes]); | ||
| 48 | * <dd>This method implements the functionality of the method of the | ||
| 49 | * same name on the {@link BasicStroke} class. | ||
| 50 | * <dt>void strokeTo(Shape, [rendering parameters], PathConsumer2D); | ||
| 51 | * <dd>This method performs widening of the source path on the fly | ||
| 52 | * and sends the results to the given {@link PathConsumer2D} object. | ||
| 53 | * This procedure avoids having to create an intermediate Shape | ||
| 54 | * object to hold the results of the {@code createStrokedShape} method. | ||
| 55 | * The main user of this method is the Java 2D non-antialiasing renderer. | ||
| 56 | * <dt>AATileGenerator getAATileGenerator(Shape, [rendering parameters]); | ||
| 57 | * <dd>This method returns an object which can iterate over the | ||
| 58 | * specified bounding box and produce tiles of coverage values for | ||
| 59 | * antialiased rendering. The details of the operation of the | ||
| 60 | * {@link AATileGenerator} object are explained in its class comments. | ||
| 61 | * </dl> | ||
| 62 | * Additionally, the following informational method supplies important | ||
| 63 | * data about the implementation. | ||
| 64 | * <dl> | ||
| 65 | * <dt>float getMinimumAAPenSize() | ||
| 66 | * <dd>This method provides information on how small the BasicStroke | ||
| 67 | * line width can get before dropouts occur. Rendering with a BasicStroke | ||
| 68 | * is defined to never allow the line to have breaks, gaps, or dropouts | ||
| 69 | * even if the width is set to 0.0f, so this information allows the | ||
| 70 | * {@link SunGraphics2D} class to detect the "thin line" case and set | ||
| 71 | * the rendering attributes accordingly. | ||
| 72 | * </dl> | ||
| 73 | * At startup the runtime will load a single instance of this class. | ||
| 74 | * It searches the classpath for a registered provider of this API | ||
| 75 | * and returns either the last one it finds, or the instance whose | ||
| 76 | * class name matches the value supplied in the System property | ||
| 77 | * {@code sun.java2d.renderer}. | ||
| 78 | * Additionally, a runtime System property flag can be set to trace | ||
| 79 | * all calls to methods on the {@code RenderingEngine} in use by | ||
| 80 | * setting the sun.java2d.renderer.trace property to any non-null value. | ||
| 81 | * <p> | ||
| 82 | * Parts of the system that need to use any of the above features should | ||
| 83 | * call {@code RenderingEngine.getInstance()} to obtain the properly | ||
| 84 | * registered (and possibly trace-enabled) version of the RenderingEngine. | ||
| 85 | */ | ||
| 86 | public abstract class RenderingEngine { | ||
| 87 | private static RenderingEngine reImpl; | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Returns an instance of {@code RenderingEngine} as determined | ||
| 91 | * by the installation environment and runtime flags. | ||
| 92 | * <p> | ||
| 93 | * A specific instance of the {@code RenderingEngine} can be | ||
| 94 | * chosen by specifying the runtime flag: | ||
| 95 | * <pre> | ||
| 96 | * java -Dsun.java2d.renderer=<classname> | ||
| 97 | * </pre> | ||
| 98 | * | ||
| 99 | * If no specific {@code RenderingEngine} is specified on the command | ||
| 100 | * or Ductus renderer is specified, it will attempt loading the | ||
| 101 | * sun.dc.DuctusRenderingEngine class using Class.forName as a fastpath; | ||
| 102 | * if not found, use the ServiceLoader. | ||
| 103 | * If no specific {@code RenderingEngine} is specified on the command | ||
| 104 | * line then the last one returned by enumerating all subclasses of | ||
| 105 | * {@code RenderingEngine} known to the ServiceLoader is used. | ||
| 106 | * <p> | ||
| 107 | * Runtime tracing of the actions of the {@code RenderingEngine} | ||
| 108 | * can be enabled by specifying the runtime flag: | ||
| 109 | * <pre> | ||
| 110 | * java -Dsun.java2d.renderer.trace=<any string> | ||
| 111 | * </pre> | ||
| 112 | * @return an instance of {@code RenderingEngine} | ||
| 113 | * @since 1.7 | ||
| 114 | */ | ||
| 115 | public static synchronized RenderingEngine getInstance() { | ||
| 116 | if (reImpl != null) { | ||
| 117 | return reImpl; | ||
| 118 | } | ||
| 119 | |||
| 120 | reImpl = (RenderingEngine) | ||
| 121 | AccessController.doPrivileged(new PrivilegedAction() { | ||
| 122 | public Object run() { | ||
| 123 | final String ductusREClass = "sun.dc.DuctusRenderingEngine"; | ||
| 124 | String reClass = | ||
| 125 | System.getProperty("sun.java2d.renderer", ductusREClass); | ||
| 126 | if (reClass.equals(ductusREClass)) { | ||
| 127 | try { | ||
| 128 | Class cls = Class.forName(ductusREClass); | ||
| 129 | return cls.newInstance(); | ||
| 130 | } catch (ClassNotFoundException x) { | ||
| 131 | // not found | ||
| 132 | } catch (IllegalAccessException x) { | ||
| 133 | // should not reach here | ||
| 134 | } catch (InstantiationException x) { | ||
| 135 | // should not reach here | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | ServiceLoader<RenderingEngine> reLoader = | ||
| 140 | ServiceLoader.loadInstalled(RenderingEngine.class); | ||
| 141 | |||
| 142 | RenderingEngine service = null; | ||
| 143 | |||
| 144 | for (RenderingEngine re : reLoader) { | ||
| 145 | service = re; | ||
| 146 | if (re.getClass().getName().equals(reClass)) { | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | return service; | ||
| 151 | } | ||
| 152 | }); | ||
| 153 | |||
| 154 | if (reImpl == null) { | ||
| 155 | throw new InternalError("No RenderingEngine module found"); | ||
| 156 | } | ||
| 157 | |||
| 158 | GetPropertyAction gpa = | ||
| 159 | new GetPropertyAction("sun.java2d.renderer.trace"); | ||
| 160 | String reTrace = (String) AccessController.doPrivileged(gpa); | ||
| 161 | if (reTrace != null) { | ||
| 162 | reImpl = new Tracer(reImpl); | ||
| 163 | } | ||
| 164 | |||
| 165 | return reImpl; | ||
| 166 | } | ||
| 167 | |||
| 168 | /** | ||
| 169 | * Create a widened path as specified by the parameters. | ||
| 170 | * <p> | ||
| 171 | * The specified {@code src} {@link Shape} is widened according | ||
| 172 | * to the specified attribute parameters as per the | ||
| 173 | * {@link BasicStroke} specification. | ||
| 174 | * | ||
| 175 | * @param src the source path to be widened | ||
| 176 | * @param width the width of the widened path as per {@code BasicStroke} | ||
| 177 | * @param caps the end cap decorations as per {@code BasicStroke} | ||
| 178 | * @param join the segment join decorations as per {@code BasicStroke} | ||
| 179 | * @param miterlimit the miter limit as per {@code BasicStroke} | ||
| 180 | * @param dashes the dash length array as per {@code BasicStroke} | ||
| 181 | * @param dashphase the initial dash phase as per {@code BasicStroke} | ||
| 182 | * @return the widened path stored in a new {@code Shape} object | ||
| 183 | * @since 1.7 | ||
| 184 | */ | ||
| 185 | public abstract Shape createStrokedShape(Shape src, | ||
| 186 | float width, | ||
| 187 | int caps, | ||
| 188 | int join, | ||
| 189 | float miterlimit, | ||
| 190 | float dashes[], | ||
| 191 | float dashphase); | ||
| 192 | |||
| 193 | /** | ||
| 194 | * Sends the geometry for a widened path as specified by the parameters | ||
| 195 | * to the specified consumer. | ||
| 196 | * <p> | ||
| 197 | * The specified {@code src} {@link Shape} is widened according | ||
| 198 | * to the parameters specified by the {@link BasicStroke} object. | ||
| 199 | * Adjustments are made to the path as appropriate for the | ||
| 200 | * {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize} | ||
| 201 | * boolean parameter is true. | ||
| 202 | * Adjustments are made to the path as appropriate for the | ||
| 203 | * {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias} | ||
| 204 | * boolean parameter is true. | ||
| 205 | * <p> | ||
| 206 | * The geometry of the widened path is forwarded to the indicated | ||
| 207 | * {@link PathConsumer2D} object as it is calculated. | ||
| 208 | * | ||
| 209 | * @param src the source path to be widened | ||
| 210 | * @param bs the {@code BasicSroke} object specifying the | ||
| 211 | * decorations to be applied to the widened path | ||
| 212 | * @param normalize indicates whether stroke normalization should | ||
| 213 | * be applied | ||
| 214 | * @param antialias indicates whether or not adjustments appropriate | ||
| 215 | * to antialiased rendering should be applied | ||
| 216 | * @param consumer the {@code PathConsumer2D} instance to forward | ||
| 217 | * the widened geometry to | ||
| 218 | * @since 1.7 | ||
| 219 | */ | ||
| 220 | public abstract void strokeTo(Shape src, | ||
| 221 | AffineTransform at, | ||
| 222 | BasicStroke bs, | ||
| 223 | boolean thin, | ||
| 224 | boolean normalize, | ||
| 225 | boolean antialias, | ||
| 226 | PathConsumer2D consumer); | ||
| 227 | |||
| 228 | /** | ||
| 229 | * Construct an antialiased tile generator for the given shape with | ||
| 230 | * the given rendering attributes and store the bounds of the tile | ||
| 231 | * iteration in the bbox parameter. | ||
| 232 | * The {@code at} parameter specifies a transform that should affect | ||
| 233 | * both the shape and the {@code BasicStroke} attributes. | ||
| 234 | * The {@code clip} parameter specifies the current clip in effect | ||
| 235 | * in device coordinates and can be used to prune the data for the | ||
| 236 | * operation, but the renderer is not required to perform any | ||
| 237 | * clipping. | ||
| 238 | * If the {@code BasicStroke} parameter is null then the shape | ||
| 239 | * should be filled as is, otherwise the attributes of the | ||
| 240 | * {@code BasicStroke} should be used to specify a draw operation. | ||
| 241 | * The {@code thin} parameter indicates whether or not the | ||
| 242 | * transformed {@code BasicStroke} represents coordinates smaller | ||
| 243 | * than the minimum resolution of the antialiasing rasterizer as | ||
| 244 | * specified by the {@code getMinimumAAPenWidth()} method. | ||
| 245 | * <p> | ||
| 246 | * Upon returning, this method will fill the {@code bbox} parameter | ||
| 247 | * with 4 values indicating the bounds of the iteration of the | ||
| 248 | * tile generator. | ||
| 249 | * The iteration order of the tiles will be as specified by the | ||
| 250 | * pseudo-code: | ||
| 251 | * <pre> | ||
| 252 | * for (y = bbox[1]; y < bbox[3]; y += tileheight) { | ||
| 253 | * for (x = bbox[0]; x < bbox[2]; x += tilewidth) { | ||
| 254 | * } | ||
| 255 | * } | ||
| 256 | * </pre> | ||
| 257 | * If there is no output to be rendered, this method may return | ||
| 258 | * null. | ||
| 259 | * | ||
| 260 | * @param s the shape to be rendered (fill or draw) | ||
| 261 | * @param at the transform to be applied to the shape and the | ||
| 262 | * stroke attributes | ||
| 263 | * @param clip the current clip in effect in device coordinates | ||
| 264 | * @param bs if non-null, a {@code BasicStroke} whose attributes | ||
| 265 | * should be applied to this operation | ||
| 266 | * @param thin true if the transformed stroke attributes are smaller | ||
| 267 | * than the minimum dropout pen width | ||
| 268 | * @param normalize true if the {@code VALUE_STROKE_NORMALIZE} | ||
| 269 | * {@code RenderingHint} is in effect | ||
| 270 | * @param bbox returns the bounds of the iteration | ||
| 271 | * @return the {@code AATileGenerator} instance to be consulted | ||
| 272 | * for tile coverages, or null if there is no output to render | ||
| 273 | * @since 1.7 | ||
| 274 | */ | ||
| 275 | public abstract AATileGenerator getAATileGenerator(Shape s, | ||
| 276 | AffineTransform at, | ||
| 277 | Region clip, | ||
| 278 | BasicStroke bs, | ||
| 279 | boolean thin, | ||
| 280 | boolean normalize, | ||
| 281 | int bbox[]); | ||
| 282 | |||
| 283 | /** | ||
| 284 | * Construct an antialiased tile generator for the given parallelogram | ||
| 285 | * store the bounds of the tile iteration in the bbox parameter. | ||
| 286 | * The parallelogram is specified as a starting point and 2 delta | ||
| 287 | * vectors that indicate the slopes of the 2 pairs of sides of the | ||
| 288 | * parallelogram. | ||
| 289 | * The 4 corners of the parallelogram are defined by the 4 points: | ||
| 290 | * <ul> | ||
| 291 | * <li> {@code x}, {@code y} | ||
| 292 | * <li> {@code x+dx1}, {@code y+dy1} | ||
| 293 | * <li> {@code x+dx1+dx2}, {@code y+dy1+dy2} | ||
| 294 | * <li> {@code x+dx2}, {@code y+dy2} | ||
| 295 | * </ul> | ||
| 296 | * The {@code lw1} and {@code lw2} parameters provide a specification | ||
| 297 | * for an optionally stroked parallelogram if they are positive numbers. | ||
| 298 | * The {@code lw1} parameter is the ratio of the length of the {@code dx1}, | ||
| 299 | * {@code dx2} delta vector to half of the line width in that same | ||
| 300 | * direction. | ||
| 301 | * The {@code lw2} parameter provides the same ratio for the other delta | ||
| 302 | * vector. | ||
| 303 | * If {@code lw1} and {@code lw2} are both greater than zero, then | ||
| 304 | * the parallelogram figure is doubled by both expanding and contracting | ||
| 305 | * each delta vector by its corresponding {@code lw} value. | ||
| 306 | * If either (@code lw1) or {@code lw2} are also greater than 1, then | ||
| 307 | * the inner (contracted) parallelogram disappears and the figure is | ||
| 308 | * simply a single expanded parallelogram. | ||
| 309 | * The {@code clip} parameter specifies the current clip in effect | ||
| 310 | * in device coordinates and can be used to prune the data for the | ||
| 311 | * operation, but the renderer is not required to perform any | ||
| 312 | * clipping. | ||
| 313 | * <p> | ||
| 314 | * Upon returning, this method will fill the {@code bbox} parameter | ||
| 315 | * with 4 values indicating the bounds of the iteration of the | ||
| 316 | * tile generator. | ||
| 317 | * The iteration order of the tiles will be as specified by the | ||
| 318 | * pseudo-code: | ||
| 319 | * <pre> | ||
| 320 | * for (y = bbox[1]; y < bbox[3]; y += tileheight) { | ||
| 321 | * for (x = bbox[0]; x < bbox[2]; x += tilewidth) { | ||
| 322 | * } | ||
| 323 | * } | ||
| 324 | * </pre> | ||
| 325 | * If there is no output to be rendered, this method may return | ||
| 326 | * null. | ||
| 327 | * | ||
| 328 | * @param x the X coordinate of the first corner of the parallelogram | ||
| 329 | * @param y the Y coordinate of the first corner of the parallelogram | ||
| 330 | * @param dx1 the X coordinate delta of the first leg of the parallelogram | ||
| 331 | * @param dy1 the Y coordinate delta of the first leg of the parallelogram | ||
| 332 | * @param dx2 the X coordinate delta of the second leg of the parallelogram | ||
| 333 | * @param dy2 the Y coordinate delta of the second leg of the parallelogram | ||
| 334 | * @param lw1 the line width ratio for the first leg of the parallelogram | ||
| 335 | * @param lw2 the line width ratio for the second leg of the parallelogram | ||
| 336 | * @param clip the current clip in effect in device coordinates | ||
| 337 | * @param bbox returns the bounds of the iteration | ||
| 338 | * @return the {@code AATileGenerator} instance to be consulted | ||
| 339 | * for tile coverages, or null if there is no output to render | ||
| 340 | * @since 1.7 | ||
| 341 | */ | ||
| 342 | public abstract AATileGenerator getAATileGenerator(double x, double y, | ||
| 343 | double dx1, double dy1, | ||
| 344 | double dx2, double dy2, | ||
| 345 | double lw1, double lw2, | ||
| 346 | Region clip, | ||
| 347 | int bbox[]); | ||
| 348 | |||
| 349 | /** | ||
| 350 | * Returns the minimum pen width that the antialiasing rasterizer | ||
| 351 | * can represent without dropouts occuring. | ||
| 352 | * @since 1.7 | ||
| 353 | */ | ||
| 354 | public abstract float getMinimumAAPenSize(); | ||
| 355 | |||
| 356 | /** | ||
| 357 | * Utility method to feed a {@link PathConsumer2D} object from a | ||
| 358 | * given {@link PathIterator}. | ||
| 359 | * This method deals with the details of running the iterator and | ||
| 360 | * feeding the consumer a segment at a time. | ||
| 361 | */ | ||
| 362 | public static void feedConsumer(PathIterator pi, PathConsumer2D consumer) { | ||
| 363 | float coords[] = new float[6]; | ||
| 364 | while (!pi.isDone()) { | ||
| 365 | switch (pi.currentSegment(coords)) { | ||
| 366 | case PathIterator.SEG_MOVETO: | ||
| 367 | consumer.moveTo(coords[0], coords[1]); | ||
| 368 | break; | ||
| 369 | case PathIterator.SEG_LINETO: | ||
| 370 | consumer.lineTo(coords[0], coords[1]); | ||
| 371 | break; | ||
| 372 | case PathIterator.SEG_QUADTO: | ||
| 373 | consumer.quadTo(coords[0], coords[1], | ||
| 374 | coords[2], coords[3]); | ||
| 375 | break; | ||
| 376 | case PathIterator.SEG_CUBICTO: | ||
| 377 | consumer.curveTo(coords[0], coords[1], | ||
| 378 | coords[2], coords[3], | ||
| 379 | coords[4], coords[5]); | ||
| 380 | break; | ||
| 381 | case PathIterator.SEG_CLOSE: | ||
| 382 | consumer.closePath(); | ||
| 383 | break; | ||
| 384 | } | ||
| 385 | pi.next(); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | static class Tracer extends RenderingEngine { | ||
| 390 | RenderingEngine target; | ||
| 391 | String name; | ||
| 392 | |||
| 393 | public Tracer(RenderingEngine target) { | ||
| 394 | this.target = target; | ||
| 395 | name = target.getClass().getName(); | ||
| 396 | } | ||
| 397 | |||
| 398 | public Shape createStrokedShape(Shape src, | ||
| 399 | float width, | ||
| 400 | int caps, | ||
| 401 | int join, | ||
| 402 | float miterlimit, | ||
| 403 | float dashes[], | ||
| 404 | float dashphase) | ||
| 405 | { | ||
| 406 | System.out.println(name+".createStrokedShape("+ | ||
| 407 | src.getClass().getName()+", "+ | ||
| 408 | "width = "+width+", "+ | ||
| 409 | "caps = "+caps+", "+ | ||
| 410 | "join = "+join+", "+ | ||
| 411 | "miter = "+miterlimit+", "+ | ||
| 412 | "dashes = "+dashes+", "+ | ||
| 413 | "dashphase = "+dashphase+")"); | ||
| 414 | return target.createStrokedShape(src, | ||
| 415 | width, caps, join, miterlimit, | ||
| 416 | dashes, dashphase); | ||
| 417 | } | ||
| 418 | |||
| 419 | public void strokeTo(Shape src, | ||
| 420 | AffineTransform at, | ||
| 421 | BasicStroke bs, | ||
| 422 | boolean thin, | ||
| 423 | boolean normalize, | ||
| 424 | boolean antialias, | ||
| 425 | PathConsumer2D consumer) | ||
| 426 | { | ||
| 427 | System.out.println(name+".strokeTo("+ | ||
| 428 | src.getClass().getName()+", "+ | ||
| 429 | at+", "+ | ||
| 430 | bs+", "+ | ||
| 431 | (thin ? "thin" : "wide")+", "+ | ||
| 432 | (normalize ? "normalized" : "pure")+", "+ | ||
| 433 | (antialias ? "AA" : "non-AA")+", "+ | ||
| 434 | consumer.getClass().getName()+")"); | ||
| 435 | target.strokeTo(src, at, bs, thin, normalize, antialias, consumer); | ||
| 436 | } | ||
| 437 | |||
| 438 | public float getMinimumAAPenSize() { | ||
| 439 | System.out.println(name+".getMinimumAAPenSize()"); | ||
| 440 | return target.getMinimumAAPenSize(); | ||
| 441 | } | ||
| 442 | |||
| 443 | public AATileGenerator getAATileGenerator(Shape s, | ||
| 444 | AffineTransform at, | ||
| 445 | Region clip, | ||
| 446 | BasicStroke bs, | ||
| 447 | boolean thin, | ||
| 448 | boolean normalize, | ||
| 449 | int bbox[]) | ||
| 450 | { | ||
| 451 | System.out.println(name+".getAATileGenerator("+ | ||
| 452 | s.getClass().getName()+", "+ | ||
| 453 | at+", "+ | ||
| 454 | clip+", "+ | ||
| 455 | bs+", "+ | ||
| 456 | (thin ? "thin" : "wide")+", "+ | ||
| 457 | (normalize ? "normalized" : "pure")+")"); | ||
| 458 | return target.getAATileGenerator(s, at, clip, | ||
| 459 | bs, thin, normalize, | ||
| 460 | bbox); | ||
| 461 | } | ||
| 462 | public AATileGenerator getAATileGenerator(double x, double y, | ||
| 463 | double dx1, double dy1, | ||
| 464 | double dx2, double dy2, | ||
| 465 | double lw1, double lw2, | ||
| 466 | Region clip, | ||
| 467 | int bbox[]) | ||
| 468 | { | ||
| 469 | System.out.println(name+".getAATileGenerator("+ | ||
| 470 | x+", "+y+", "+ | ||
| 471 | dx1+", "+dy1+", "+ | ||
| 472 | dx2+", "+dy2+", "+ | ||
| 473 | lw1+", "+lw2+", "+ | ||
| 474 | clip+")"); | ||
| 475 | return target.getAATileGenerator(x, y, | ||
| 476 | dx1, dy1, | ||
| 477 | dx2, dy2, | ||
| 478 | lw1, lw2, | ||
| 479 | clip, bbox); | ||
| 480 | } | ||
| 481 | } | ||
| 482 | } | ||
Binary file not shown.
| @@ -0,0 +1,40 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 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.Shape; | ||
| 29 | import sun.java2d.SunGraphics2D; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * This interface defines the set of calls that pipeline objects | ||
| 33 | * can use to pass on responsibility for drawing generic Shape | ||
| 34 | * objects. | ||
| 35 | */ | ||
| 36 | public interface ShapeDrawPipe { | ||
| 37 | public void draw(SunGraphics2D sg, Shape s); | ||
| 38 | |||
| 39 | public void fill(SunGraphics2D sg, Shape s); | ||
| 40 | } | ||
Binary file not shown.
| @@ -0,0 +1,201 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 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.geom.PathIterator; | ||
| 29 | import java.awt.Rectangle; | ||
| 30 | import sun.awt.geom.PathConsumer2D; | ||
| 31 | |||
| 32 | /** | ||
| 33 | * This class can iterate individual span elements generated by scan | ||
| 34 | * converting a Shape. | ||
| 35 | * This particular implementation flattens the incoming path and then | ||
| 36 | * performs simple polygon tracing to calculate the spans. | ||
| 37 | * | ||
| 38 | * Note that this class holds pointers to native data which must be | ||
| 39 | * disposed. It is not marked as finalizable since it is intended | ||
| 40 | * to be very lightweight and finalization is a comparitively expensive | ||
| 41 | * procedure. The caller must specifically use try{} finally{} to | ||
| 42 | * manually ensure that the object is disposed after use, otherwise | ||
| 43 | * native data structures might be leaked. | ||
| 44 | * | ||
| 45 | * Here is a code sample for using this class: | ||
| 46 | * | ||
| 47 | * public void fillShape(Shape s, Rectangle clipRect) { | ||
| 48 | * ShapeSpanIterator ssi = new ShapeSpanIterator(false); | ||
| 49 | * try { | ||
| 50 | * ssi.setOutputArea(clipRect); | ||
| 51 | * ssi.appendPath(s.getPathIterator(null)); | ||
| 52 | * int spanbox[] = new int[4]; | ||
| 53 | * while (ssi.nextSpan(spanbox)) { | ||
| 54 | * int x = spanbox[0]; | ||
| 55 | * int y = spanbox[1]; | ||
| 56 | * int w = spanbox[2] - x; | ||
| 57 | * int h = spanbox[3] - y; | ||
| 58 | * fillRect(x, y, w, h); | ||
| 59 | * } | ||
| 60 | * } finally { | ||
| 61 | * ssi.dispose(); | ||
| 62 | * } | ||
| 63 | * } | ||
| 64 | */ | ||
| 65 | public final class ShapeSpanIterator | ||
| 66 | implements SpanIterator, PathConsumer2D | ||
| 67 | { | ||
| 68 | long pData; | ||
| 69 | |||
| 70 | static { | ||
| 71 | initIDs(); | ||
| 72 | } | ||
| 73 | |||
| 74 | public static native void initIDs(); | ||
| 75 | |||
| 76 | public ShapeSpanIterator(boolean adjust) { | ||
| 77 | setNormalize(adjust); | ||
| 78 | } | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Appends the geometry and winding rule from the indicated | ||
| 82 | * path iterator. | ||
| 83 | */ | ||
| 84 | public void appendPath(PathIterator pi) { | ||
| 85 | float coords[] = new float[6]; | ||
| 86 | |||
| 87 | setRule(pi.getWindingRule()); | ||
| 88 | while (!pi.isDone()) { | ||
| 89 | addSegment(pi.currentSegment(coords), coords); | ||
| 90 | pi.next(); | ||
| 91 | } | ||
| 92 | pathDone(); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Appends the geometry from the indicated set of polygon points. | ||
| 97 | */ | ||
| 98 | public native void appendPoly(int xPoints[], int yPoints[], int nPoints, | ||
| 99 | int xoff, int yoff); | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Sets the normalization flag so that incoming data is | ||
| 103 | * adjusted to nearest (0.25, 0.25) subpixel position. | ||
| 104 | */ | ||
| 105 | private native void setNormalize(boolean adjust); | ||
| 106 | |||
| 107 | /* | ||
| 108 | * Sets the rectangle of interest for storing and returning | ||
| 109 | * span segments. | ||
| 110 | */ | ||
| 111 | public void setOutputAreaXYWH(int x, int y, int w, int h) { | ||
| 112 | setOutputAreaXYXY(x, y, Region.dimAdd(x, w), Region.dimAdd(y, h)); | ||
| 113 | } | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Sets the rectangle of interest for storing and returning | ||
| 117 | * span segments. | ||
| 118 | */ | ||
| 119 | public native void setOutputAreaXYXY(int lox, int loy, int hix, int hiy); | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Sets the rectangle of interest for storing and returning | ||
| 123 | * span segments to the specified Rectangle. | ||
| 124 | */ | ||
| 125 | public void setOutputArea(Rectangle r) { | ||
| 126 | setOutputAreaXYWH(r.x, r.y, r.width, r.height); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Sets the rectangle of interest for storing and returning | ||
| 131 | * span segments to the bounds of the specified Region. | ||
| 132 | */ | ||
| 133 | public void setOutputArea(Region r) { | ||
| 134 | setOutputAreaXYXY(r.lox, r.loy, r.hix, r.hiy); | ||
| 135 | } | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Sets the winding rule in the native data structures. | ||
| 139 | */ | ||
| 140 | public native void setRule(int rule); | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Adds a single PathIterator segment to the internal list of | ||
| 144 | * path element structures. | ||
| 145 | */ | ||
| 146 | public native void addSegment(int type, float coords[]); | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Gets the bbox of the available path segments, clipped to the | ||
| 150 | * OutputArea. | ||
| 151 | */ | ||
| 152 | public native void getPathBox(int pathbox[]); | ||
| 153 | |||
| 154 | /* | ||
| 155 | * Intersects the path box with the given bbox. | ||
| 156 | * Returned spans are clipped to this region, or discarded | ||
| 157 | * altogether if they lie outside it. | ||
| 158 | */ | ||
| 159 | public native void intersectClipBox(int lox, int loy, int hix, int hiy); | ||
| 160 | |||
| 161 | /* | ||
| 162 | * Fetches the next span that needs to be operated on. | ||
| 163 | * If the return value is false then there are no more spans. | ||
| 164 | */ | ||
| 165 | public native boolean nextSpan(int spanbox[]); | ||
| 166 | |||
| 167 | /** | ||
| 168 | * This method tells the iterator that it may skip all spans | ||
| 169 | * whose Y range is completely above the indicated Y coordinate. | ||
| 170 | */ | ||
| 171 | public native void skipDownTo(int y); | ||
| 172 | |||
| 173 | /** | ||
| 174 | * This method returns a native pointer to a function block that | ||
| 175 | * can be used by a native method to perform the same iteration | ||
| 176 | * cycle that the above methods provide while avoiding upcalls to | ||
| 177 | * the Java object. | ||
| 178 | * The definition of the structure whose pointer is returned by | ||
| 179 | * this method is defined in: | ||
| 180 | * <pre> | ||
| 181 | * src/share/native/sun/java2d/pipe/SpanIterator.h | ||
| 182 | * </pre> | ||
| 183 | */ | ||
| 184 | public native long getNativeIterator(); | ||
| 185 | |||
| 186 | /* | ||
| 187 | * Cleans out all internal data structures. | ||
| 188 | */ | ||
| 189 | public native void dispose(); | ||
| 190 | |||
| 191 | public native void moveTo(float x, float y); | ||
| 192 | public native void lineTo(float x, float y); | ||
| 193 | public native void quadTo(float x1, float y1, | ||
| 194 | float x2, float y2); | ||
| 195 | public native void curveTo(float x1, float y1, | ||
| 196 | float x2, float y2, | ||
| 197 | float x3, float y3); | ||
| 198 | public native void closePath(); | ||
| 199 | public native void pathDone(); | ||
| 200 | public native long getNativeConsumer(); | ||
| 201 | } | ||
Binary file not shown.
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2005, 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.font.GlyphVector; | ||
| 29 | import sun.awt.SunHints; | ||
| 30 | import sun.java2d.SunGraphics2D; | ||
| 31 | import sun.font.GlyphList; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * A delegate pipe of SG2D for drawing text with | ||
| 35 | * a solid source colour to an opaque destination. | ||
| 36 | */ | ||
| 37 | |||
| 38 | public class SolidTextRenderer extends GlyphListLoopPipe | ||
| 39 | implements LoopBasedPipe | ||
| 40 | { | ||
| 41 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { | ||
| 42 | sg2d.loops.drawGlyphListLoop.DrawGlyphList(sg2d, sg2d.surfaceData, gl); | ||
| 43 | } | ||
| 44 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,141 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 1999, 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.Rectangle; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import java.awt.geom.PathIterator; | ||
| 31 | import sun.java2d.SunGraphics2D; | ||
| 32 | |||
| 33 | /** | ||
| 34 | * This class uses a Region iterator to modify the extents of alpha | ||
| 35 | * tiles created during Shape rendering based upon a non-rectangular | ||
| 36 | * clipping path. | ||
| 37 | */ | ||
| 38 | public class SpanClipRenderer implements CompositePipe | ||
| 39 | { | ||
| 40 | CompositePipe outpipe; | ||
| 41 | |||
| 42 | static Class RegionClass = Region.class; | ||
| 43 | static Class RegionIteratorClass = RegionIterator.class; | ||
| 44 | |||
| 45 | static { | ||
| 46 | initIDs(RegionClass, RegionIteratorClass); | ||
| 47 | } | ||
| 48 | |||
| 49 | static native void initIDs(Class rc, Class ric); | ||
| 50 | |||
| 51 | public SpanClipRenderer(CompositePipe pipe) { | ||
| 52 | outpipe = pipe; | ||
| 53 | } | ||
| 54 | |||
| 55 | class SCRcontext { | ||
| 56 | RegionIterator iterator; | ||
| 57 | Object outcontext; | ||
| 58 | int band[]; | ||
| 59 | byte tile[]; | ||
| 60 | |||
| 61 | public SCRcontext(RegionIterator ri, Object outctx) { | ||
| 62 | iterator = ri; | ||
| 63 | outcontext = outctx; | ||
| 64 | band = new int[4]; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | public Object startSequence(SunGraphics2D sg, Shape s, Rectangle devR, | ||
| 69 | int[] abox) { | ||
| 70 | RegionIterator ri = sg.clipRegion.getIterator(); | ||
| 71 | |||
| 72 | return new SCRcontext(ri, outpipe.startSequence(sg, s, devR, abox)); | ||
| 73 | } | ||
| 74 | |||
| 75 | public boolean needTile(Object ctx, int x, int y, int w, int h) { | ||
| 76 | SCRcontext context = (SCRcontext) ctx; | ||
| 77 | return (outpipe.needTile(context.outcontext, x, y, w, h)); | ||
| 78 | } | ||
| 79 | |||
| 80 | public void renderPathTile(Object ctx, | ||
| 81 | byte[] atile, int offset, int tsize, | ||
| 82 | int x, int y, int w, int h, | ||
| 83 | ShapeSpanIterator sr) { | ||
| 84 | renderPathTile(ctx, atile, offset, tsize, x, y, w, h); | ||
| 85 | } | ||
| 86 | |||
| 87 | public void renderPathTile(Object ctx, | ||
| 88 | byte[] atile, int offset, int tsize, | ||
| 89 | int x, int y, int w, int h) { | ||
| 90 | SCRcontext context = (SCRcontext) ctx; | ||
| 91 | RegionIterator ri = context.iterator.createCopy(); | ||
| 92 | int[] band = context.band; | ||
| 93 | band[0] = x; | ||
| 94 | band[1] = y; | ||
| 95 | band[2] = x + w; | ||
| 96 | band[3] = y + h; | ||
| 97 | if (atile == null) { | ||
| 98 | int size = w * h; | ||
| 99 | atile = context.tile; | ||
| 100 | if (atile != null && atile.length < size) { | ||
| 101 | atile = null; | ||
| 102 | } | ||
| 103 | if (atile == null) { | ||
| 104 | atile = new byte[size]; | ||
| 105 | context.tile = atile; | ||
| 106 | } | ||
| 107 | offset = 0; | ||
| 108 | tsize = w; | ||
| 109 | fillTile(ri, atile, offset, tsize, band); | ||
| 110 | } else { | ||
| 111 | eraseTile(ri, atile, offset, tsize, band); | ||
| 112 | } | ||
| 113 | |||
| 114 | if (band[2] > band[0] && band[3] > band[1]) { | ||
| 115 | offset += (band[1] - y) * tsize + (band[0] - x); | ||
| 116 | outpipe.renderPathTile(context.outcontext, | ||
| 117 | atile, offset, tsize, | ||
| 118 | band[0], band[1], | ||
| 119 | band[2] - band[0], | ||
| 120 | band[3] - band[1]); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | public native void fillTile(RegionIterator ri, | ||
| 125 | byte[] alpha, int offset, int tsize, | ||
| 126 | int[] band); | ||
| 127 | |||
| 128 | public native void eraseTile(RegionIterator ri, | ||
| 129 | byte[] alpha, int offset, int tsize, | ||
| 130 | int[] band); | ||
| 131 | |||
| 132 | public void skipTile(Object ctx, int x, int y) { | ||
| 133 | SCRcontext context = (SCRcontext) ctx; | ||
| 134 | outpipe.skipTile(context.outcontext, x, y); | ||
| 135 | } | ||
| 136 | |||
| 137 | public void endSequence(Object ctx) { | ||
| 138 | SCRcontext context = (SCRcontext) ctx; | ||
| 139 | outpipe.endSequence(context.outcontext); | ||
| 140 | } | ||
| 141 | } | ||
Binary file not shown.
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 1999, 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 | /** | ||
| 29 | * This interface defines a general method for iterating through the | ||
| 30 | * rectangular "spans" that represent the interior of a filled path. | ||
| 31 | * <p> | ||
| 32 | * There can be many kinds of span iterators used in the rendering | ||
| 33 | * pipeline, the most basic being an iterator that scan converts a | ||
| 34 | * path defined by any PathIterator, or an nested iterator which | ||
| 35 | * intersects another iterator's spans with a clip region. | ||
| 36 | * Other iterators can be created for scan converting some of the | ||
| 37 | * primitive shapes more explicitly for speed or quality. | ||
| 38 | * | ||
| 39 | * @author Jim Graham | ||
| 40 | */ | ||
| 41 | public interface SpanIterator { | ||
| 42 | /** | ||
| 43 | * This method returns the bounding box of the spans that the | ||
| 44 | * iterator will be returning. | ||
| 45 | * The array must be of length at least 4 and upon return, it | ||
| 46 | * will be filled with the values: | ||
| 47 | * <pre> | ||
| 48 | * {PathMinX, PathMinY, PathMaxX, PathMaxY}. | ||
| 49 | * </pre> | ||
| 50 | */ | ||
| 51 | public void getPathBox(int pathbox[]); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * This method constrains the spans returned by nextSpan() to the | ||
| 55 | * rectangle whose bounds are given. | ||
| 56 | */ | ||
| 57 | public void intersectClipBox(int lox, int loy, int hix, int hiy); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * This method returns the next span in the shape being iterated. | ||
| 61 | * The array must be of length at least 4 and upon return, it | ||
| 62 | * will be filled with the values: | ||
| 63 | * <pre> | ||
| 64 | * {SpanMinX, SpanMinY, SpanMaxX, SpanMaxY}. | ||
| 65 | * </pre> | ||
| 66 | */ | ||
| 67 | public boolean nextSpan(int spanbox[]); | ||
| 68 | |||
| 69 | /** | ||
| 70 | * This method tells the iterator that it may skip all spans | ||
| 71 | * whose Y range is completely above the indicated Y coordinate. | ||
| 72 | * This method is used to provide feedback from the caller when | ||
| 73 | * clipping prevents the display of any data in a given Y range. | ||
| 74 | * Typically it will only be called when this iterator has returned | ||
| 75 | * a span whose MaxY coordinate is less than the indicated Y and | ||
| 76 | * the calling mechanism wants to avoid unnecessary iteration work. | ||
| 77 | * While this request could technically be ignored (i.e. a NOP), | ||
| 78 | * doing so could potentially cause the caller to make this callback | ||
| 79 | * for each span that is being skipped. | ||
| 80 | */ | ||
| 81 | public void skipDownTo(int y); | ||
| 82 | |||
| 83 | /** | ||
| 84 | * This method returns a native pointer to a function block that | ||
| 85 | * can be used by a native method to perform the same iteration | ||
| 86 | * cycle that the above methods provide while avoiding upcalls to | ||
| 87 | * the Java object. | ||
| 88 | * The definition of the structure whose pointer is returned by | ||
| 89 | * this method is defined in: | ||
| 90 | * <pre> | ||
| 91 | * src/share/native/sun/java2d/pipe/SpanIterator.h | ||
| 92 | * </pre> | ||
| 93 | */ | ||
| 94 | public long getNativeIterator(); | ||
| 95 | } | ||
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,216 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 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 sun.java2d.SunGraphics2D; | ||
| 29 | import sun.java2d.SurfaceData; | ||
| 30 | import java.awt.Rectangle; | ||
| 31 | import java.awt.Shape; | ||
| 32 | import java.awt.BasicStroke; | ||
| 33 | import java.awt.geom.PathIterator; | ||
| 34 | import java.awt.geom.AffineTransform; | ||
| 35 | import java.awt.geom.Rectangle2D; | ||
| 36 | import sun.awt.SunHints; | ||
| 37 | |||
| 38 | /** | ||
| 39 | * This class is used to convert raw geometry into a span iterator | ||
| 40 | * object using a simple flattening polygon scan converter. | ||
| 41 | * The iterator can be passed on to special SpanFiller loops to | ||
| 42 | * perform the actual rendering. | ||
| 43 | */ | ||
| 44 | public abstract class SpanShapeRenderer implements ShapeDrawPipe { | ||
| 45 | final static RenderingEngine RenderEngine = RenderingEngine.getInstance(); | ||
| 46 | |||
| 47 | public static class Composite extends SpanShapeRenderer { | ||
| 48 | CompositePipe comppipe; | ||
| 49 | |||
| 50 | public Composite(CompositePipe pipe) { | ||
| 51 | comppipe = pipe; | ||
| 52 | } | ||
| 53 | |||
| 54 | public Object startSequence(SunGraphics2D sg, Shape s, | ||
| 55 | Rectangle devR, int[] bbox) { | ||
| 56 | return comppipe.startSequence(sg, s, devR, bbox); | ||
| 57 | } | ||
| 58 | |||
| 59 | public void renderBox(Object ctx, int x, int y, int w, int h) { | ||
| 60 | comppipe.renderPathTile(ctx, null, 0, w, x, y, w, h); | ||
| 61 | } | ||
| 62 | |||
| 63 | public void endSequence(Object ctx) { | ||
| 64 | comppipe.endSequence(ctx); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | public static class Simple extends SpanShapeRenderer | ||
| 69 | implements LoopBasedPipe | ||
| 70 | { | ||
| 71 | public Object startSequence(SunGraphics2D sg, Shape s, | ||
| 72 | Rectangle devR, int[] bbox) { | ||
| 73 | return sg; | ||
| 74 | } | ||
| 75 | |||
| 76 | public void renderBox(Object ctx, int x, int y, int w, int h) { | ||
| 77 | SunGraphics2D sg2d = (SunGraphics2D) ctx; | ||
| 78 | SurfaceData sd = sg2d.getSurfaceData(); | ||
| 79 | sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h); | ||
| 80 | } | ||
| 81 | |||
| 82 | public void endSequence(Object ctx) { | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | public void draw(SunGraphics2D sg, Shape s) { | ||
| 87 | if (sg.stroke instanceof BasicStroke) { | ||
| 88 | ShapeSpanIterator sr = LoopPipe.getStrokeSpans(sg, s); | ||
| 89 | try { | ||
| 90 | renderSpans(sg, sg.getCompClip(), s, sr); | ||
| 91 | } finally { | ||
| 92 | sr.dispose(); | ||
| 93 | } | ||
| 94 | } else { | ||
| 95 | fill(sg, sg.stroke.createStrokedShape(s)); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | public static final int NON_RECTILINEAR_TRANSFORM_MASK = | ||
| 100 | (AffineTransform.TYPE_GENERAL_TRANSFORM | | ||
| 101 | AffineTransform.TYPE_GENERAL_ROTATION); | ||
| 102 | |||
| 103 | public void fill(SunGraphics2D sg, Shape s) { | ||
| 104 | if (s instanceof Rectangle2D && | ||
| 105 | (sg.transform.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0) | ||
| 106 | { | ||
| 107 | renderRect(sg, (Rectangle2D) s); | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | |||
| 111 | Region clipRegion = sg.getCompClip(); | ||
| 112 | ShapeSpanIterator sr = LoopPipe.getFillSSI(sg); | ||
| 113 | try { | ||
| 114 | sr.setOutputArea(clipRegion); | ||
| 115 | sr.appendPath(s.getPathIterator(sg.transform)); | ||
| 116 | renderSpans(sg, clipRegion, s, sr); | ||
| 117 | } finally { | ||
| 118 | sr.dispose(); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | public abstract Object startSequence(SunGraphics2D sg, Shape s, | ||
| 123 | Rectangle devR, int[] bbox); | ||
| 124 | |||
| 125 | public abstract void renderBox(Object ctx, int x, int y, int w, int h); | ||
| 126 | |||
| 127 | public abstract void endSequence(Object ctx); | ||
| 128 | |||
| 129 | public void renderRect(SunGraphics2D sg, Rectangle2D r) { | ||
| 130 | double corners[] = { | ||
| 131 | r.getX(), r.getY(), r.getWidth(), r.getHeight(), | ||
| 132 | }; | ||
| 133 | corners[2] += corners[0]; | ||
| 134 | corners[3] += corners[1]; | ||
| 135 | if (corners[2] <= corners[0] || corners[3] <= corners[1]) { | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | sg.transform.transform(corners, 0, corners, 0, 2); | ||
| 139 | if (corners[2] < corners[0]) { | ||
| 140 | double t = corners[2]; | ||
| 141 | corners[2] = corners[0]; | ||
| 142 | corners[0] = t; | ||
| 143 | } | ||
| 144 | if (corners[3] < corners[1]) { | ||
| 145 | double t = corners[3]; | ||
| 146 | corners[3] = corners[1]; | ||
| 147 | corners[1] = t; | ||
| 148 | } | ||
| 149 | int abox[] = { | ||
| 150 | (int) corners[0], | ||
| 151 | (int) corners[1], | ||
| 152 | (int) corners[2], | ||
| 153 | (int) corners[3], | ||
| 154 | }; | ||
| 155 | Rectangle devR = new Rectangle(abox[0], abox[1], | ||
| 156 | abox[2] - abox[0], | ||
| 157 | abox[3] - abox[1]); | ||
| 158 | Region clipRegion = sg.getCompClip(); | ||
| 159 | clipRegion.clipBoxToBounds(abox); | ||
| 160 | if (abox[0] >= abox[2] || abox[1] >= abox[3]) { | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | Object context = startSequence(sg, r, devR, abox); | ||
| 164 | if (clipRegion.isRectangular()) { | ||
| 165 | renderBox(context, abox[0], abox[1], | ||
| 166 | abox[2] - abox[0], | ||
| 167 | abox[3] - abox[1]); | ||
| 168 | } else { | ||
| 169 | SpanIterator sr = clipRegion.getSpanIterator(abox); | ||
| 170 | while (sr.nextSpan(abox)) { | ||
| 171 | renderBox(context, abox[0], abox[1], | ||
| 172 | abox[2] - abox[0], | ||
| 173 | abox[3] - abox[1]); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | endSequence(context); | ||
| 177 | } | ||
| 178 | |||
| 179 | public void renderSpans(SunGraphics2D sg, Region clipRegion, Shape s, | ||
| 180 | ShapeSpanIterator sr) | ||
| 181 | { | ||
| 182 | Object context = null; | ||
| 183 | int abox[] = new int[4]; | ||
| 184 | try { | ||
| 185 | sr.getPathBox(abox); | ||
| 186 | Rectangle devR = new Rectangle(abox[0], abox[1], | ||
| 187 | abox[2] - abox[0], | ||
| 188 | abox[3] - abox[1]); | ||
| 189 | clipRegion.clipBoxToBounds(abox); | ||
| 190 | if (abox[0] >= abox[2] || abox[1] >= abox[3]) { | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | sr.intersectClipBox(abox[0], abox[1], abox[2], abox[3]); | ||
| 194 | context = startSequence(sg, s, devR, abox); | ||
| 195 | |||
| 196 | spanClipLoop(context, sr, clipRegion, abox); | ||
| 197 | |||
| 198 | } finally { | ||
| 199 | if (context != null) { | ||
| 200 | endSequence(context); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | public void spanClipLoop(Object ctx, SpanIterator sr, | ||
| 206 | Region r, int[] abox) { | ||
| 207 | if (!r.isRectangular()) { | ||
| 208 | sr = r.filter(sr); | ||
| 209 | } | ||
| 210 | while (sr.nextSpan(abox)) { | ||
| 211 | int x = abox[0]; | ||
| 212 | int y = abox[1]; | ||
| 213 | renderBox(ctx, x, y, abox[2] - x, abox[3] - y); | ||
| 214 | } | ||
| 215 | } | ||
| 216 | } | ||
Binary file not shown.
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1998, 2003, 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 | /* | ||
| 27 | * @author Charlton Innovations, Inc. | ||
| 28 | */ | ||
| 29 | |||
| 30 | package sun.java2d.pipe; | ||
| 31 | |||
| 32 | import sun.java2d.SunGraphics2D; | ||
| 33 | import java.awt.font.GlyphVector; | ||
| 34 | import java.awt.font.TextLayout; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * This interface defines the set of calls that pipeline objects | ||
| 38 | * can use to pass on responsibility for drawing various text | ||
| 39 | * representations. | ||
| 40 | */ | ||
| 41 | public interface TextPipe { | ||
| 42 | public void drawString(SunGraphics2D g2d, String s, | ||
| 43 | double x, double y); | ||
| 44 | public void drawGlyphVector(SunGraphics2D g2d, GlyphVector g, | ||
| 45 | float x, float y); | ||
| 46 | public void drawChars(SunGraphics2D g2d, | ||
| 47 | char data[], int offset, int length, | ||
| 48 | int x, int y); | ||
| 49 | } | ||
Binary file not shown.
| @@ -0,0 +1,98 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000, 2003, 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.Rectangle; | ||
| 29 | import java.awt.Shape; | ||
| 30 | import java.awt.Font; | ||
| 31 | import java.awt.font.GlyphVector; | ||
| 32 | import sun.java2d.SunGraphics2D; | ||
| 33 | import sun.java2d.loops.FontInfo; | ||
| 34 | import sun.font.GlyphList; | ||
| 35 | |||
| 36 | /* | ||
| 37 | * This class uses the alpha graybits arrays from a GlyphList object to | ||
| 38 | * drive a CompositePipe in much the same way as the antialiasing renderer. | ||
| 39 | */ | ||
| 40 | public class TextRenderer extends GlyphListPipe { | ||
| 41 | |||
| 42 | CompositePipe outpipe; | ||
| 43 | |||
| 44 | public TextRenderer(CompositePipe pipe) { | ||
| 45 | outpipe = pipe; | ||
| 46 | } | ||
| 47 | |||
| 48 | protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) { | ||
| 49 | int num = gl.getNumGlyphs(); | ||
| 50 | Region clipRegion = sg2d.getCompClip(); | ||
| 51 | int cx1 = clipRegion.getLoX(); | ||
| 52 | int cy1 = clipRegion.getLoY(); | ||
| 53 | int cx2 = clipRegion.getHiX(); | ||
| 54 | int cy2 = clipRegion.getHiY(); | ||
| 55 | Object ctx = null; | ||
| 56 | try { | ||
| 57 | int[] bounds = gl.getBounds(); | ||
| 58 | Rectangle r = new Rectangle(bounds[0], bounds[1], | ||
| 59 | bounds[2] - bounds[0], | ||
| 60 | bounds[3] - bounds[1]); | ||
| 61 | Shape s = sg2d.untransformShape(r); | ||
| 62 | ctx = outpipe.startSequence(sg2d, s, r, bounds); | ||
| 63 | for (int i = 0; i < num; i++) { | ||
| 64 | gl.setGlyphIndex(i); | ||
| 65 | int metrics[] = gl.getMetrics(); | ||
| 66 | int gx1 = metrics[0]; | ||
| 67 | int gy1 = metrics[1]; | ||
| 68 | int w = metrics[2]; | ||
| 69 | int gx2 = gx1 + w; | ||
| 70 | int gy2 = gy1 + metrics[3]; | ||
| 71 | int off = 0; | ||
| 72 | if (gx1 < cx1) { | ||
| 73 | off = cx1 - gx1; | ||
| 74 | gx1 = cx1; | ||
| 75 | } | ||
| 76 | if (gy1 < cy1) { | ||
| 77 | off += (cy1 - gy1) * w; | ||
| 78 | gy1 = cy1; | ||
| 79 | } | ||
| 80 | if (gx2 > cx2) gx2 = cx2; | ||
| 81 | if (gy2 > cy2) gy2 = cy2; | ||
| 82 | if (gx2 > gx1 && gy2 > gy1 && | ||
| 83 | outpipe.needTile(ctx, gx1, gy1, gx2 - gx1, gy2 - gy1)) | ||
| 84 | { | ||
| 85 | byte alpha[] = gl.getGrayBits(); | ||
| 86 | outpipe.renderPathTile(ctx, alpha, off, w, | ||
| 87 | gx1, gy1, gx2 - gx1, gy2 - gy1); | ||
| 88 | } else { | ||
| 89 | outpipe.skipTile(ctx, gx1, gy1); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } finally { | ||
| 93 | if (ctx != null) { | ||
| 94 | outpipe.endSequence(ctx); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
Binary file not shown.
| @@ -0,0 +1,241 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 1997, 2003, 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.Color; | ||
| 29 | import java.awt.Image; | ||
| 30 | import java.awt.Shape; | ||
| 31 | import java.awt.geom.AffineTransform; | ||
| 32 | import java.awt.image.BufferedImage; | ||
| 33 | import java.awt.image.BufferedImageOp; | ||
| 34 | import java.awt.image.ImageObserver; | ||
| 35 | import sun.java2d.SunGraphics2D; | ||
| 36 | import java.awt.font.GlyphVector; | ||
| 37 | |||
| 38 | /** | ||
| 39 | * This class is used to force a revalidation of the pipelines of | ||
| 40 | * the indicated SunGraphics2D object before a draw command. | ||
| 41 | * After calling SunGraphics2D.validatePipe() to force the pipeline | ||
| 42 | * to be revalidated, this object redispatches the draw command to | ||
| 43 | * the new valid pipe object. | ||
| 44 | */ | ||
| 45 | public class ValidatePipe | ||
| 46 | implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, TextPipe, | ||
| 47 | DrawImagePipe | ||
| 48 | { | ||
| 49 | /* | ||
| 50 | * Different subclasses may override this to do various | ||
| 51 | * other forms of validation and return a return code | ||
| 52 | * indicating whether or not the validation was successful. | ||
| 53 | */ | ||
| 54 | public boolean validate(SunGraphics2D sg) { | ||
| 55 | sg.validatePipe(); | ||
| 56 | return true; | ||
| 57 | } | ||
| 58 | |||
| 59 | public void drawLine(SunGraphics2D sg, | ||
| 60 | int x1, int y1, int x2, int y2) { | ||
| 61 | if (validate(sg)) { | ||
| 62 | sg.drawpipe.drawLine(sg, x1, y1, x2, y2); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | public void drawRect(SunGraphics2D sg, | ||
| 67 | int x, int y, int width, int height) { | ||
| 68 | if (validate(sg)) { | ||
| 69 | sg.drawpipe.drawRect(sg, x, y, width, height); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | public void fillRect(SunGraphics2D sg, | ||
| 74 | int x, int y, int width, int height) { | ||
| 75 | if (validate(sg)) { | ||
| 76 | sg.fillpipe.fillRect(sg, x, y, width, height); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | public void drawRoundRect(SunGraphics2D sg, | ||
| 81 | int x, int y, int width, int height, | ||
| 82 | int arcWidth, int arcHeight) { | ||
| 83 | if (validate(sg)) { | ||
| 84 | sg.drawpipe.drawRoundRect(sg, x, y, width, height, | ||
| 85 | arcWidth, arcHeight); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | public void fillRoundRect(SunGraphics2D sg, | ||
| 90 | int x, int y, int width, int height, | ||
| 91 | int arcWidth, int arcHeight) { | ||
| 92 | if (validate(sg)) { | ||
| 93 | sg.fillpipe.fillRoundRect(sg, x, y, width, height, | ||
| 94 | arcWidth, arcHeight); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | public void drawOval(SunGraphics2D sg, | ||
| 99 | int x, int y, int width, int height) { | ||
| 100 | if (validate(sg)) { | ||
| 101 | sg.drawpipe.drawOval(sg, x, y, width, height); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | public void fillOval(SunGraphics2D sg, | ||
| 106 | int x, int y, int width, int height) { | ||
| 107 | if (validate(sg)) { | ||
| 108 | sg.fillpipe.fillOval(sg, x, y, width, height); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | public void drawArc(SunGraphics2D sg, | ||
| 113 | int x, int y, int width, int height, | ||
| 114 | int startAngle, int arcAngle) { | ||
| 115 | if (validate(sg)) { | ||
| 116 | sg.drawpipe.drawArc(sg, x, y, width, height, startAngle, arcAngle); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | public void fillArc(SunGraphics2D sg, | ||
| 121 | int x, int y, int width, int height, | ||
| 122 | int startAngle, int arcAngle) { | ||
| 123 | if (validate(sg)) { | ||
| 124 | sg.fillpipe.fillArc(sg, x, y, width, height, startAngle, arcAngle); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | public void drawPolyline(SunGraphics2D sg, | ||
| 129 | int xPoints[], int yPoints[], | ||
| 130 | int nPoints) { | ||
| 131 | if (validate(sg)) { | ||
| 132 | sg.drawpipe.drawPolyline(sg, xPoints, yPoints, nPoints); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | public void drawPolygon(SunGraphics2D sg, | ||
| 137 | int xPoints[], int yPoints[], | ||
| 138 | int nPoints) { | ||
| 139 | if (validate(sg)) { | ||
| 140 | sg.drawpipe.drawPolygon(sg, xPoints, yPoints, nPoints); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | public void fillPolygon(SunGraphics2D sg, | ||
| 145 | int xPoints[], int yPoints[], | ||
| 146 | int nPoints) { | ||
| 147 | if (validate(sg)) { | ||
| 148 | sg.fillpipe.fillPolygon(sg, xPoints, yPoints, nPoints); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | public void draw(SunGraphics2D sg, Shape s) { | ||
| 153 | if (validate(sg)) { | ||
| 154 | sg.shapepipe.draw(sg, s); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | public void fill(SunGraphics2D sg, Shape s) { | ||
| 159 | if (validate(sg)) { | ||
| 160 | sg.shapepipe.fill(sg, s); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | public void drawString(SunGraphics2D sg, String s, double x, double y) { | ||
| 164 | if (validate(sg)) { | ||
| 165 | sg.textpipe.drawString(sg, s, x, y); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | public void drawGlyphVector(SunGraphics2D sg, GlyphVector g, | ||
| 169 | float x, float y) { | ||
| 170 | if (validate(sg)) { | ||
| 171 | sg.textpipe.drawGlyphVector(sg, g, x, y); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | public void drawChars(SunGraphics2D sg, | ||
| 175 | char data[], int offset, int length, | ||
| 176 | int x, int y) { | ||
| 177 | if (validate(sg)) { | ||
| 178 | sg.textpipe.drawChars(sg, data, offset, length, x, y); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 182 | int x, int y, | ||
| 183 | Color bgColor, | ||
| 184 | ImageObserver observer) { | ||
| 185 | if (validate(sg)) { | ||
| 186 | return sg.imagepipe.copyImage(sg, img, x, y, bgColor, observer); | ||
| 187 | } else { | ||
| 188 | return false; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | public boolean copyImage(SunGraphics2D sg, Image img, | ||
| 192 | int dx, int dy, int sx, int sy, int w, int h, | ||
| 193 | Color bgColor, | ||
| 194 | ImageObserver observer) { | ||
| 195 | if (validate(sg)) { | ||
| 196 | return sg.imagepipe.copyImage(sg, img, dx, dy, sx, sy, w, h, | ||
| 197 | bgColor, observer); | ||
| 198 | } else { | ||
| 199 | return false; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | public boolean scaleImage(SunGraphics2D sg, Image img, int x, int y, | ||
| 203 | int w, int h, | ||
| 204 | Color bgColor, | ||
| 205 | ImageObserver observer) { | ||
| 206 | if (validate(sg)) { | ||
| 207 | return sg.imagepipe.scaleImage(sg, img, x, y, w, h, bgColor, | ||
| 208 | observer); | ||
| 209 | } else { | ||
| 210 | return false; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | public boolean scaleImage(SunGraphics2D sg, Image img, | ||
| 214 | int dx1, int dy1, int dx2, int dy2, | ||
| 215 | int sx1, int sy1, int sx2, int sy2, | ||
| 216 | Color bgColor, | ||
| 217 | ImageObserver observer) { | ||
| 218 | if (validate(sg)) { | ||
| 219 | return sg.imagepipe.scaleImage(sg, img, dx1, dy1, dx2, dy2, | ||
| 220 | sx1, sy1, sx2, sy2, bgColor, | ||
| 221 | observer); | ||
| 222 | } else { | ||
| 223 | return false; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | public boolean transformImage(SunGraphics2D sg, Image img, | ||
| 227 | AffineTransform atfm, | ||
| 228 | ImageObserver observer) { | ||
| 229 | if (validate(sg)) { | ||
| 230 | return sg.imagepipe.transformImage(sg, img, atfm, observer); | ||
| 231 | } else { | ||
| 232 | return false; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | public void transformImage(SunGraphics2D sg, BufferedImage img, | ||
| 236 | BufferedImageOp op, int x, int y) { | ||
| 237 | if (validate(sg)) { | ||
| 238 | sg.imagepipe.transformImage(sg, img, op, x, y); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | } | ||
Binary file not shown.
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | /** | ||
| 29 | * An interface for receiving notifications about imminent accelerated device's | ||
| 30 | * events. Upon receiving such event appropriate actions can be taken (for | ||
| 31 | * example, resources associated with the device can be freed). | ||
| 32 | */ | ||
| 33 | public interface AccelDeviceEventListener { | ||
| 34 | /** | ||
| 35 | * Called when the device is about to be reset. | ||
| 36 | * | ||
| 37 | * One must release all native resources associated with the device which | ||
| 38 | * prevent the device from being reset (such as Default Pool resources for | ||
| 39 | * the D3D pipeline). | ||
| 40 | * | ||
| 41 | * It is safe to remove the listener while in the call back. | ||
| 42 | * | ||
| 43 | * Note: this method is called on the rendering thread, | ||
| 44 | * do not call into user code, do not take RQ lock! | ||
| 45 | */ | ||
| 46 | public void onDeviceReset(); | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Called when the device is about to be disposed of. | ||
| 50 | * | ||
| 51 | * One must release all native resources associated with the device. | ||
| 52 | * | ||
| 53 | * It is safe to remove the listener while in the call back. | ||
| 54 | * | ||
| 55 | * Note: this method is called on the rendering thread, | ||
| 56 | * do not call into user code, do not take RQ lock! | ||
| 57 | */ | ||
| 58 | public void onDeviceDispose(); | ||
| 59 | } | ||
| @@ -0,0 +1,167 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | import java.util.Collections; | ||
| 29 | import java.util.HashMap; | ||
| 30 | import java.util.Iterator; | ||
| 31 | import java.util.Map; | ||
| 32 | import java.util.Set; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * This class is used to notify listeners about accelerated device's | ||
| 36 | * events such as device reset or dispose that are about to occur. | ||
| 37 | */ | ||
| 38 | public class AccelDeviceEventNotifier { | ||
| 39 | |||
| 40 | private static AccelDeviceEventNotifier theInstance; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * A device is about to be reset. The listeners have to release all | ||
| 44 | * resources associated with the device which are required for the device | ||
| 45 | * to be reset. | ||
| 46 | */ | ||
| 47 | public static final int DEVICE_RESET = 0; | ||
| 48 | |||
| 49 | /** | ||
| 50 | * A device is about to be disposed. The listeners have to release all | ||
| 51 | * resources associated with the device. | ||
| 52 | */ | ||
| 53 | public static final int DEVICE_DISPOSED = 1; | ||
| 54 | |||
| 55 | private final Map<AccelDeviceEventListener, Integer> listeners; | ||
| 56 | |||
| 57 | private AccelDeviceEventNotifier() { | ||
| 58 | listeners = Collections.synchronizedMap( | ||
| 59 | new HashMap<AccelDeviceEventListener, Integer>(1)); | ||
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * Returns a singleton of AccelDeviceEventNotifier if it exists. If the | ||
| 64 | * passed boolean is false and singleton doesn't exist yet, null is | ||
| 65 | * returned. If the passed boolean is {@code true} and singleton doesn't | ||
| 66 | * exist it will be created and returned. | ||
| 67 | * | ||
| 68 | * @param create whether to create a singleton instance if doesn't yet | ||
| 69 | * exist | ||
| 70 | * @return a singleton instance or null | ||
| 71 | */ | ||
| 72 | private static synchronized | ||
| 73 | AccelDeviceEventNotifier getInstance(boolean create) | ||
| 74 | { | ||
| 75 | if (theInstance == null && create) { | ||
| 76 | theInstance = new AccelDeviceEventNotifier(); | ||
| 77 | } | ||
| 78 | return theInstance; | ||
| 79 | } | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Called to indicate that a device event had occured. | ||
| 83 | * If a singleton exists, the listeners (those associated with | ||
| 84 | * the device) will be notified. | ||
| 85 | * | ||
| 86 | * @param screen a screen number of the device which is a source of | ||
| 87 | * the event | ||
| 88 | * @param eventType a type of the event | ||
| 89 | * @see #DEVICE_DISPOSED | ||
| 90 | * @see #DEVICE_RESET | ||
| 91 | */ | ||
| 92 | public static final void eventOccured(int screen, int eventType) { | ||
| 93 | AccelDeviceEventNotifier notifier = getInstance(false); | ||
| 94 | if (notifier != null) { | ||
| 95 | notifier.notifyListeners(eventType, screen); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Adds the listener associated with a device on particular screen. | ||
| 101 | * | ||
| 102 | * Note: the listener must be removed as otherwise it will forever | ||
| 103 | * be referenced by the notifier. | ||
| 104 | * | ||
| 105 | * @param l the listener | ||
| 106 | * @param screen the screen number indicating which device the listener is | ||
| 107 | * interested in. | ||
| 108 | */ | ||
| 109 | public static final void addListener(AccelDeviceEventListener l,int screen){ | ||
| 110 | getInstance(true).add(l, screen); | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Removes the listener. | ||
| 115 | * | ||
| 116 | * @param l the listener | ||
| 117 | */ | ||
| 118 | public static final void removeListener(AccelDeviceEventListener l) { | ||
| 119 | getInstance(true).remove(l); | ||
| 120 | } | ||
| 121 | |||
| 122 | private final void add(AccelDeviceEventListener theListener, int screen) { | ||
| 123 | listeners.put(theListener, screen); | ||
| 124 | } | ||
| 125 | private final void remove(AccelDeviceEventListener theListener) { | ||
| 126 | listeners.remove(theListener); | ||
| 127 | } | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Notifies the listeners associated with the screen's device about the | ||
| 131 | * event. | ||
| 132 | * | ||
| 133 | * Implementation note: the current list of listeners is first duplicated | ||
| 134 | * which allows the listeners to remove themselves during the iteration. | ||
| 135 | * | ||
| 136 | * @param screen a screen number with which the device which is a source of | ||
| 137 | * the event is associated with | ||
| 138 | * @param eventType a type of the event | ||
| 139 | * @see #DEVICE_DISPOSED | ||
| 140 | * @see #DEVICE_RESET | ||
| 141 | */ | ||
| 142 | private final void notifyListeners(int deviceEventType, int screen) { | ||
| 143 | HashMap<AccelDeviceEventListener, Integer> listClone; | ||
| 144 | Set<AccelDeviceEventListener> cloneSet; | ||
| 145 | |||
| 146 | synchronized(listeners) { | ||
| 147 | listClone = | ||
| 148 | new HashMap<AccelDeviceEventListener, Integer>(listeners); | ||
| 149 | } | ||
| 150 | |||
| 151 | cloneSet = listClone.keySet(); | ||
| 152 | Iterator<AccelDeviceEventListener> itr = cloneSet.iterator(); | ||
| 153 | while (itr.hasNext()) { | ||
| 154 | AccelDeviceEventListener current = itr.next(); | ||
| 155 | Integer i = listClone.get(current); | ||
| 156 | // only notify listeners which are interested in this device | ||
| 157 | if (i != null && i.intValue() != screen) { | ||
| 158 | continue; | ||
| 159 | } | ||
| 160 | if (deviceEventType == DEVICE_RESET) { | ||
| 161 | current.onDeviceReset(); | ||
| 162 | } else if (deviceEventType == DEVICE_DISPOSED) { | ||
| 163 | current.onDeviceDispose(); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
Binary file not shown.
| @@ -0,0 +1,95 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | import java.awt.image.VolatileImage; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Implementors of this interface provida a way to create a | ||
| 32 | * {@code VolatileImage} whose destination surface is an | ||
| 33 | * {@link AccelSurface} of specified type. | ||
| 34 | * | ||
| 35 | * @see AccelSurface | ||
| 36 | */ | ||
| 37 | public interface AccelGraphicsConfig extends BufferedContextProvider { | ||
| 38 | /** | ||
| 39 | * Returns a VolatileImage with specified width, height, transparency | ||
| 40 | * and guaranteed accelerated surface type. If such image can not be created | ||
| 41 | * (out of vram error, specific surface type is not supported) null | ||
| 42 | * is returned. | ||
| 43 | * | ||
| 44 | * Note: if {@link AccelSurface#TEXTURE} type is requested, rendering | ||
| 45 | * to the image will be denied by throwing | ||
| 46 | * {@code UnsupportedOperationException } | ||
| 47 | * from {@link java.awt.image.VolatileImage#getGraphics} and | ||
| 48 | * {@link java.awt.image.VolatileImage#createGraphics} | ||
| 49 | * | ||
| 50 | * @param width the width of the returned {@code VolatileImage} | ||
| 51 | * @param height the height of the returned {@code VolatileImage} | ||
| 52 | * @param transparency the specified transparency mode | ||
| 53 | * @param type requested accelerated surface type as specified by constants | ||
| 54 | * in AccelSurface interface | ||
| 55 | * @return a {@code VolatileImage} backed up by requested accelerated | ||
| 56 | * surface type or null | ||
| 57 | * @throws IllegalArgumentException if the transparency is not a valid value | ||
| 58 | * @see AccelSurface#TEXTURE | ||
| 59 | * @see AccelSurface#RT_PLAIN | ||
| 60 | * @see AccelSurface#RT_TEXTURE | ||
| 61 | */ | ||
| 62 | public VolatileImage createCompatibleVolatileImage(int width, int height, | ||
| 63 | int transparency, | ||
| 64 | int type); | ||
| 65 | /** | ||
| 66 | * Returns object representing capabilities of the context associated | ||
| 67 | * with this {@code AccelGraphicsConfig}. | ||
| 68 | * | ||
| 69 | * @return ContextCapabilities object representing caps | ||
| 70 | * @see ContextCapabilities | ||
| 71 | */ | ||
| 72 | public ContextCapabilities getContextCapabilities(); | ||
| 73 | |||
| 74 | /** | ||
| 75 | * Adds an {@code AccelDeviceEventListener} to listen to accelerated | ||
| 76 | * device's (which is associated with this {@code AccelGraphicsConfig}) | ||
| 77 | * events. | ||
| 78 | * | ||
| 79 | * Note: a hard link to the listener may be kept so it must be explicitly | ||
| 80 | * removed via {@link #removeDeviceEventListener()}. | ||
| 81 | * | ||
| 82 | * @param l the listener | ||
| 83 | * @see AccelDeviceEventListener | ||
| 84 | */ | ||
| 85 | public void addDeviceEventListener(AccelDeviceEventListener l); | ||
| 86 | |||
| 87 | /** | ||
| 88 | * Removes an {@code AccelDeviceEventListener} from the list of listeners | ||
| 89 | * for this device's events. | ||
| 90 | * | ||
| 91 | * @param l the listener | ||
| 92 | * @see AccelDeviceEventListener | ||
| 93 | */ | ||
| 94 | public void removeDeviceEventListener(AccelDeviceEventListener l); | ||
| 95 | } | ||
Binary file not shown.
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | import java.awt.Rectangle; | ||
| 29 | import sun.java2d.Surface; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Abstraction for a hardware accelerated surface. | ||
| 33 | */ | ||
| 34 | public interface AccelSurface extends BufferedContextProvider, Surface { | ||
| 35 | /** | ||
| 36 | * Undefined | ||
| 37 | */ | ||
| 38 | public static final int UNDEFINED = 0; | ||
| 39 | /** | ||
| 40 | * Window (or window substitute) surface | ||
| 41 | */ | ||
| 42 | public static final int WINDOW = 1; | ||
| 43 | /** | ||
| 44 | * Render-To Plain surface (pbuffer for OpenGL, Render Target surface | ||
| 45 | * for Direct3D) | ||
| 46 | */ | ||
| 47 | public static final int RT_PLAIN = 2; | ||
| 48 | /** | ||
| 49 | * Texture surface | ||
| 50 | */ | ||
| 51 | public static final int TEXTURE = 3; | ||
| 52 | /** | ||
| 53 | * A back-buffer surface (SwapChain surface for Direct3D, backbuffer for | ||
| 54 | * OpenGL) | ||
| 55 | */ | ||
| 56 | public static final int FLIP_BACKBUFFER = 4; | ||
| 57 | /** | ||
| 58 | * Render-To Texture surface (fbobject for OpenGL, texture with render-to | ||
| 59 | * attribute for Direct3D) | ||
| 60 | */ | ||
| 61 | public static final int RT_TEXTURE = 5; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * Returns {@code int} representing surface's type as defined by constants | ||
| 65 | * in this interface. | ||
| 66 | * | ||
| 67 | * @return an integer representing this surface's type | ||
| 68 | * @see AccelSurface#UNDEFINED | ||
| 69 | * @see AccelSurface#WINDOW | ||
| 70 | * @see AccelSurface#RT_PLAIN | ||
| 71 | * @see AccelSurface#TEXTURE | ||
| 72 | * @see AccelSurface#FLIP_BACKBUFFER | ||
| 73 | * @see AccelSurface#RT_TEXTURE | ||
| 74 | */ | ||
| 75 | public int getType(); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Returns a pointer to the native surface data associated with this | ||
| 79 | * surface. | ||
| 80 | * Note: this pointer is only valid on the rendering thread. | ||
| 81 | * | ||
| 82 | * @return pointer to the native surface's data | ||
| 83 | */ | ||
| 84 | public long getNativeOps(); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Returns a pointer to the real native resource | ||
| 88 | * of the specified type associated with this AccelSurface. | ||
| 89 | * Note: this pointer is only valid on the rendering thread. | ||
| 90 | * | ||
| 91 | * @param resType the type of the requested resource | ||
| 92 | * @return a long containing a pointer to the native resource of the | ||
| 93 | * specified type or 0L if such resource doesn't exist for this surface | ||
| 94 | */ | ||
| 95 | public long getNativeResource(int resType); | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Marks this surface dirty. | ||
| 99 | */ | ||
| 100 | public void markDirty(); | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Returns whether the pipeline considers this surface valid. A surface | ||
| 104 | * may become invalid if it is disposed of, or resized. | ||
| 105 | * | ||
| 106 | * @return true if valid, false otherwise | ||
| 107 | */ | ||
| 108 | public boolean isValid(); | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Returns whether this surface is lost. The return value is only valid | ||
| 112 | * on the render thread, meaning that even if this method returns | ||
| 113 | * {@code true} it could be lost in the next moment unless it is called | ||
| 114 | * on the rendering thread. | ||
| 115 | * | ||
| 116 | * @return true if the surface is known to be lost, false otherwise | ||
| 117 | */ | ||
| 118 | public boolean isSurfaceLost(); | ||
| 119 | |||
| 120 | /** | ||
| 121 | * Returns the requested bounds of the destination surface. The real bounds | ||
| 122 | * of the native accelerated surface may differ. Use | ||
| 123 | * {@link #getNativeBounds} to get the bounds of the native surface. | ||
| 124 | * | ||
| 125 | * @return Rectangle representing java surface's bounds | ||
| 126 | */ | ||
| 127 | public Rectangle getBounds(); | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Returns real bounds of the native surface, which may differ from those | ||
| 131 | * returned by {@link #getBounds}. | ||
| 132 | * | ||
| 133 | * @return Rectangle representing native surface's bounds | ||
| 134 | */ | ||
| 135 | public Rectangle getNativeBounds(); | ||
| 136 | } | ||
| @@ -0,0 +1,74 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | import java.awt.Graphics; | ||
| 29 | import java.awt.Graphics2D; | ||
| 30 | import java.awt.GraphicsConfiguration; | ||
| 31 | import sun.awt.image.SunVolatileImage; | ||
| 32 | import static sun.java2d.pipe.hw.AccelSurface.*; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * This is an image with forced type of the accelerated surface. | ||
| 36 | */ | ||
| 37 | public class AccelTypedVolatileImage extends SunVolatileImage { | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Creates a volatile image with specified type of accelerated surface. | ||
| 41 | * | ||
| 42 | * @param graphicsConfig a GraphicsConfiguration for which this image should | ||
| 43 | * be created. | ||
| 44 | * @param width width | ||
| 45 | * @param height width | ||
| 46 | * @param transparency type of {@link java.awt.Transparency transparency} | ||
| 47 | * requested for the image | ||
| 48 | * @param accType type of the desired accelerated surface as defined in | ||
| 49 | * AccelSurface interface | ||
| 50 | * @see sun.java2d.pipe.hw.AccelSurface | ||
| 51 | */ | ||
| 52 | public AccelTypedVolatileImage(GraphicsConfiguration graphicsConfig, | ||
| 53 | int width, int height, int transparency, | ||
| 54 | int accType) | ||
| 55 | { | ||
| 56 | super(null, graphicsConfig, width, height, null, transparency, | ||
| 57 | null, accType); | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * {@inheritDoc} | ||
| 62 | * | ||
| 63 | * This method will throw {@code UnsupportedOperationException} if it this | ||
| 64 | * image's destination surface can not be rendered to. | ||
| 65 | */ | ||
| 66 | @Override | ||
| 67 | public Graphics2D createGraphics() { | ||
| 68 | if (getForcedAccelSurfaceType() == TEXTURE) { | ||
| 69 | throw new UnsupportedOperationException("Can't render " + | ||
| 70 | "to a non-RT Texture"); | ||
| 71 | } | ||
| 72 | return super.createGraphics(); | ||
| 73 | } | ||
| 74 | } | ||
Binary file not shown.
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | import sun.java2d.pipe.BufferedContext; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Classes implementing this interface can provide the {@code BufferedContext} | ||
| 32 | * associated with or used by them. | ||
| 33 | * | ||
| 34 | * @see sun.java2d.pipe.BufferedContext | ||
| 35 | */ | ||
| 36 | public interface BufferedContextProvider { | ||
| 37 | /** | ||
| 38 | * Retrieves a context associated with object implementing this | ||
| 39 | * interface. | ||
| 40 | * | ||
| 41 | * @return associated context | ||
| 42 | * @see sun.java2d.pipe.BufferedContext | ||
| 43 | */ | ||
| 44 | public BufferedContext getContext(); | ||
| 45 | } | ||
Binary file not shown.
| @@ -0,0 +1,128 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Represents a set of capabilities of a BufferedContext and associated | ||
| 30 | * AccelGraphicsConfig. | ||
| 31 | * | ||
| 32 | * @see AccelGraphicsConfig | ||
| 33 | */ | ||
| 34 | public class ContextCapabilities { | ||
| 35 | /** Indicates that the context has no capabilities. */ | ||
| 36 | public static final int CAPS_EMPTY = (0 << 0); | ||
| 37 | /** Indicates that the context supports RT surfaces with alpha channel. */ | ||
| 38 | public static final int CAPS_RT_PLAIN_ALPHA = (1 << 1); | ||
| 39 | /** Indicates that the context supports RT textures with alpha channel. */ | ||
| 40 | public static final int CAPS_RT_TEXTURE_ALPHA = (1 << 2); | ||
| 41 | /** Indicates that the context supports opaque RT textures. */ | ||
| 42 | public static final int CAPS_RT_TEXTURE_OPAQUE = (1 << 3); | ||
| 43 | /** Indicates that the context supports multitexturing. */ | ||
| 44 | public static final int CAPS_MULTITEXTURE = (1 << 4); | ||
| 45 | /** Indicates that the context supports non-pow2 texture dimensions. */ | ||
| 46 | public static final int CAPS_TEXNONPOW2 = (1 << 5); | ||
| 47 | /** Indicates that the context supports non-square textures. */ | ||
| 48 | public static final int CAPS_TEXNONSQUARE = (1 << 6); | ||
| 49 | /** Indicates that the context supports pixel shader 2.0 or better. */ | ||
| 50 | public static final int CAPS_PS20 = (1 << 7); | ||
| 51 | /** Indicates that the context supports pixel shader 3.0 or better. */ | ||
| 52 | public static final int CAPS_PS30 = (1 << 8); | ||
| 53 | /* | ||
| 54 | * Pipeline contexts should use this for defining pipeline-specific | ||
| 55 | * capabilities, for example: | ||
| 56 | * int CAPS_D3D_1 = (FIRST_PRIVATE_CAP << 0); | ||
| 57 | * int CAPS_D3D_2 = (FIRST_PRIVATE_CAP << 1); | ||
| 58 | */ | ||
| 59 | protected static final int FIRST_PRIVATE_CAP = (1 << 16); | ||
| 60 | |||
| 61 | protected final int caps; | ||
| 62 | protected final String adapterId; | ||
| 63 | |||
| 64 | /** | ||
| 65 | * Constructs a {@code ContextCapabilities} object. | ||
| 66 | * @param caps an {@code int} representing the capabilities | ||
| 67 | * @param a {@code String} representing the name of the adapter, or null, | ||
| 68 | * in which case the adapterId will be set to "unknown adapter". | ||
| 69 | */ | ||
| 70 | protected ContextCapabilities(int caps, String adapterId) { | ||
| 71 | this.caps = caps; | ||
| 72 | this.adapterId = adapterId != null ? adapterId : "unknown adapter"; | ||
| 73 | } | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Returns a string representing the name of the graphics adapter if such | ||
| 77 | * could be determined. It is guaranteed to never return {@code null}. | ||
| 78 | * @return string representing adapter id | ||
| 79 | */ | ||
| 80 | public String getAdapterId() { | ||
| 81 | return adapterId; | ||
| 82 | } | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Returns an {@code int} with capabilities (OR-ed constants defined in | ||
| 86 | * this class and its pipeline-specific subclasses). | ||
| 87 | * @return capabilities as {@code int} | ||
| 88 | */ | ||
| 89 | public int getCaps() { | ||
| 90 | return caps; | ||
| 91 | } | ||
| 92 | |||
| 93 | @Override | ||
| 94 | public String toString() { | ||
| 95 | StringBuffer buf = | ||
| 96 | new StringBuffer("ContextCapabilities: adapter=" + | ||
| 97 | adapterId+", caps="); | ||
| 98 | if (caps == CAPS_EMPTY) { | ||
| 99 | buf.append("CAPS_EMPTY"); | ||
| 100 | } else { | ||
| 101 | if ((caps & CAPS_RT_PLAIN_ALPHA) != 0) { | ||
| 102 | buf.append("CAPS_RT_PLAIN_ALPHA|"); | ||
| 103 | } | ||
| 104 | if ((caps & CAPS_RT_TEXTURE_ALPHA) != 0) { | ||
| 105 | buf.append("CAPS_RT_TEXTURE_ALPHA|"); | ||
| 106 | } | ||
| 107 | if ((caps & CAPS_RT_TEXTURE_OPAQUE) != 0) { | ||
| 108 | buf.append("CAPS_RT_TEXTURE_OPAQUE|"); | ||
| 109 | } | ||
| 110 | if ((caps & CAPS_MULTITEXTURE) != 0) { | ||
| 111 | buf.append("CAPS_MULTITEXTURE|"); | ||
| 112 | } | ||
| 113 | if ((caps & CAPS_TEXNONPOW2) != 0) { | ||
| 114 | buf.append("CAPS_TEXNONPOW2|"); | ||
| 115 | } | ||
| 116 | if ((caps & CAPS_TEXNONSQUARE) != 0) { | ||
| 117 | buf.append("CAPS_TEXNONSQUARE|"); | ||
| 118 | } | ||
| 119 | if ((caps & CAPS_PS20) != 0) { | ||
| 120 | buf.append("CAPS_PS20|"); | ||
| 121 | } | ||
| 122 | if ((caps & CAPS_PS30) != 0) { | ||
| 123 | buf.append("CAPS_PS30|"); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | return buf.toString(); | ||
| 127 | } | ||
| 128 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,154 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2007, 2008, 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.hw; | ||
| 27 | |||
| 28 | import java.awt.BufferCapabilities; | ||
| 29 | import java.awt.ImageCapabilities; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Provides extended BufferStrategy capabilities, allowing to specify | ||
| 33 | * the type of vertical refresh synchronization for a buffer strategy. | ||
| 34 | * | ||
| 35 | * This BS capability is always page flipping because v-sync is only relevant | ||
| 36 | * to flipping buffer strategies. | ||
| 37 | * | ||
| 38 | * Note that asking for a v-synced BS doesn't necessarily guarantee that it will | ||
| 39 | * be v-synced since the vsync capability may be disabled in the driver, or | ||
| 40 | * there may be other restriction (like a number of v-synced buffer strategies | ||
| 41 | * allowed per vm). Because of this {@code createBufferStrategy} doesn't | ||
| 42 | * throw {@code AWTException} when a v-synced BS could not be created when | ||
| 43 | * requested. | ||
| 44 | * | ||
| 45 | * @see java.awt.Canvas#createBufferStrategy(int, BufferCapabilities) | ||
| 46 | * @see java.awt.Window#createBufferStrategy(int, BufferCapabilities) | ||
| 47 | */ | ||
| 48 | public class ExtendedBufferCapabilities extends BufferCapabilities { | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Type of synchronization on vertical retrace. | ||
| 52 | */ | ||
| 53 | public static enum VSyncType { | ||
| 54 | /** | ||
| 55 | * Use the default v-sync mode appropriate for given BufferStrategy | ||
| 56 | * and situation. | ||
| 57 | */ | ||
| 58 | VSYNC_DEFAULT(0), | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Synchronize flip on vertical retrace. | ||
| 62 | */ | ||
| 63 | VSYNC_ON(1), | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Do not synchronize flip on vertical retrace. | ||
| 67 | */ | ||
| 68 | VSYNC_OFF(2); | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Used to identify the v-sync type (independent of the constants | ||
| 72 | * order as opposed to {@code ordinal()}). | ||
| 73 | */ | ||
| 74 | public int id() { | ||
| 75 | return id; | ||
| 76 | } | ||
| 77 | |||
| 78 | private VSyncType(int id) { | ||
| 79 | this.id = id; | ||
| 80 | } | ||
| 81 | private int id; | ||
| 82 | } | ||
| 83 | |||
| 84 | private VSyncType vsync; | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Creates an ExtendedBufferCapabilities object with front/back/flip caps | ||
| 88 | * from the passed cap, and VSYNC_DEFAULT v-sync mode. | ||
| 89 | */ | ||
| 90 | public ExtendedBufferCapabilities(BufferCapabilities caps) { | ||
| 91 | super(caps.getFrontBufferCapabilities(), | ||
| 92 | caps.getBackBufferCapabilities(), | ||
| 93 | caps.getFlipContents()); | ||
| 94 | |||
| 95 | this.vsync = VSyncType.VSYNC_DEFAULT; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Creates an ExtendedBufferCapabilities instance with front/back/flip caps | ||
| 100 | * from the passed caps, and VSYNC_DEFAULT v-sync mode. | ||
| 101 | */ | ||
| 102 | public ExtendedBufferCapabilities(ImageCapabilities front, | ||
| 103 | ImageCapabilities back, FlipContents flip) | ||
| 104 | { | ||
| 105 | super(front, back, flip); | ||
| 106 | |||
| 107 | this.vsync = VSyncType.VSYNC_DEFAULT; | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Creates an ExtendedBufferCapabilities instance with front/back/flip caps | ||
| 112 | * from the passed image/flip caps, and the v-sync type. | ||
| 113 | */ | ||
| 114 | public ExtendedBufferCapabilities(ImageCapabilities front, | ||
| 115 | ImageCapabilities back, FlipContents flip, | ||
| 116 | VSyncType t) | ||
| 117 | { | ||
| 118 | super(front, back, flip); | ||
| 119 | |||
| 120 | this.vsync = t; | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * Creates an ExtendedBufferCapabilities instance with front/back/flip caps | ||
| 125 | * from the passed cap, and the passed v-sync mode. | ||
| 126 | */ | ||
| 127 | public ExtendedBufferCapabilities(BufferCapabilities caps, VSyncType t) { | ||
| 128 | super(caps.getFrontBufferCapabilities(), | ||
| 129 | caps.getBackBufferCapabilities(), | ||
| 130 | caps.getFlipContents()); | ||
| 131 | |||
| 132 | this.vsync = t; | ||
| 133 | } | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Creates an ExtendedBufferCapabilities instance with front/back/flip caps | ||
| 137 | * from the object, and passed v-sync mode. | ||
| 138 | */ | ||
| 139 | public ExtendedBufferCapabilities derive(VSyncType t) { | ||
| 140 | return new ExtendedBufferCapabilities(this, t); | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Returns the type of v-sync requested by this capabilities instance. | ||
| 145 | */ | ||
| 146 | public VSyncType getVSync() { | ||
| 147 | return vsync; | ||
| 148 | } | ||
| 149 | |||
| 150 | @Override | ||
| 151 | public final boolean isPageFlipping() { | ||
| 152 | return true; | ||
| 153 | } | ||
| 154 | } | ||
| @@ -0,0 +1,15 @@ | |||
| 1 | <../../../../../../mkconfig | ||
| 2 | |||
| 3 | TARG=\ | ||
| 4 | AccelDeviceEventListener.dis\ | ||
| 5 | AccelDeviceEventNotifier.dis\ | ||
| 6 | AccelGraphicsConfig.dis\ | ||
| 7 | AccelSurface.dis\ | ||
| 8 | AccelTypedVolatileImage.dis\ | ||
| 9 | BufferedContextProvider.dis\ | ||
| 10 | ContextCapabilities.dis\ | ||
| 11 | ExtendedBufferCapabilities.dis\ | ||
| 12 | |||
| 13 | DISBIN=$ROOT/java/dis/java/java/sun/java2d/pipe/hw | ||
| 14 | |||
| 15 | <$ROOT/mkfiles/mkjava | ||
| @@ -0,0 +1,56 @@ | |||
| 1 | <../../../../../mkconfig | ||
| 2 | |||
| 3 | DIRS=\ | ||
| 4 | hw\ | ||
| 5 | |||
| 6 | TARG=\ | ||
| 7 | AAShapePipe.dis\ | ||
| 8 | AATextRenderer.dis\ | ||
| 9 | AATileGenerator.dis\ | ||
| 10 | AlphaColorPipe.dis\ | ||
| 11 | AlphaPaintPipe.dis\ | ||
| 12 | BufferedBufImgOps.dis\ | ||
| 13 | BufferedContext.dis\ | ||
| 14 | BufferedMaskBlit.dis\ | ||
| 15 | BufferedMaskFill.dis\ | ||
| 16 | BufferedOpCodes.dis\ | ||
| 17 | BufferedPaints.dis\ | ||
| 18 | BufferedRenderPipe.dis\ | ||
| 19 | BufferedTextPipe.dis\ | ||
| 20 | CompositePipe.dis\ | ||
| 21 | DrawImage.dis\ | ||
| 22 | DrawImagePipe.dis\ | ||
| 23 | GeneralCompositePipe.dis\ | ||
| 24 | GlyphListLoopPipe.dis\ | ||
| 25 | GlyphListPipe.dis\ | ||
| 26 | LCDTextRenderer.dis\ | ||
| 27 | LoopBasedPipe.dis\ | ||
| 28 | LoopPipe.dis\ | ||
| 29 | NullPipe.dis\ | ||
| 30 | OutlineTextRenderer.dis\ | ||
| 31 | ParallelogramPipe.dis\ | ||
| 32 | PixelDrawPipe.dis\ | ||
| 33 | PixelFillPipe.dis\ | ||
| 34 | PixelToParallelogramConverter.dis\ | ||
| 35 | PixelToShapeConverter.dis\ | ||
| 36 | Region.dis\ | ||
| 37 | RegionClipSpanIterator.dis\ | ||
| 38 | RegionIterator.dis\ | ||
| 39 | RegionSpanIterator.dis\ | ||
| 40 | RenderBuffer.dis\ | ||
| 41 | RenderingEngine.dis\ | ||
| 42 | RenderQueue.dis\ | ||
| 43 | ShapeDrawPipe.dis\ | ||
| 44 | ShapeSpanIterator.dis\ | ||
| 45 | SolidTextRenderer.dis\ | ||
| 46 | SpanClipRenderer.dis\ | ||
| 47 | SpanIterator.dis\ | ||
| 48 | SpanShapeRenderer.dis\ | ||
| 49 | TextPipe.dis\ | ||
| 50 | TextRenderer.dis\ | ||
| 51 | ValidatePipe.dis\ | ||
| 52 | |||
| 53 | DISBIN=$ROOT/java/dis/java/java/sun/java2d/pipe | ||
| 54 | |||
| 55 | <$ROOT/mkfiles/mkjava | ||
| 56 | <$ROOT/mkfiles/mksubdirs | ||