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 | |