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.BasicStroke; 29 import java.awt.Shape; 30 import java.awt.geom.AffineTransform; 31 import java.awt.geom.Arc2D; 32 import java.awt.geom.Ellipse2D; 33 import java.awt.geom.Path2D; 34 import java.awt.geom.PathIterator; 35 import java.awt.geom.RoundRectangle2D; 36 37 import sun.awt.SunHints; 38 import sun.java2d.SunGraphics2D; 39 import sun.java2d.SurfaceData; 40 import sun.java2d.loops.DrawParallelogram; 41 import sun.java2d.loops.FillParallelogram; 42 43 public class LoopPipe 44 implements PixelDrawPipe, 45 PixelFillPipe, 46 ParallelogramPipe, 47 ShapeDrawPipe, 48 LoopBasedPipe 49 { 50 final static RenderingEngine RenderEngine = RenderingEngine.getInstance(); 51 52 public void drawLine(SunGraphics2D sg2d, 53 int x1, int y1, int x2, int y2) 54 { 55 int tX = sg2d.transX; 56 int tY = sg2d.transY; 57 sg2d.loops.drawLineLoop.DrawLine(sg2d, sg2d.getSurfaceData(), 58 x1 + tX, y1 + tY, 59 x2 + tX, y2 + tY); 60 } 61 62 public void drawRect(SunGraphics2D sg2d, 63 int x, int y, int width, int height) 64 { 65 sg2d.loops.drawRectLoop.DrawRect(sg2d, sg2d.getSurfaceData(), 66 x + sg2d.transX, 67 y + sg2d.transY, 68 width, height); 69 } 70 71 public void drawRoundRect(SunGraphics2D sg2d, 72 int x, int y, int width, int height, 73 int arcWidth, int arcHeight) 74 { 75 sg2d.shapepipe.draw(sg2d, 76 new RoundRectangle2D.Float(x, y, width, height, 77 arcWidth, arcHeight)); 78 } 79 80 public void drawOval(SunGraphics2D sg2d, 81 int x, int y, int width, int height) 82 { 83 sg2d.shapepipe.draw(sg2d, new Ellipse2D.Float(x, y, width, height)); 84 } 85 86 public void drawArc(SunGraphics2D sg2d, 87 int x, int y, int width, int height, 88 int startAngle, int arcAngle) 89 { 90 sg2d.shapepipe.draw(sg2d, new Arc2D.Float(x, y, width, height, 91 startAngle, arcAngle, 92 Arc2D.OPEN)); 93 } 94 95 public void drawPolyline(SunGraphics2D sg2d, 96 int xPoints[], int yPoints[], 97 int nPoints) 98 { 99 int nPointsArray[] = { nPoints }; 100 sg2d.loops.drawPolygonsLoop.DrawPolygons(sg2d, sg2d.getSurfaceData(), 101 xPoints, yPoints, 102 nPointsArray, 1, 103 sg2d.transX, sg2d.transY, 104 false); 105 } 106 107 public void drawPolygon(SunGraphics2D sg2d, 108 int xPoints[], int yPoints[], 109 int nPoints) 110 { 111 int nPointsArray[] = { nPoints }; 112 sg2d.loops.drawPolygonsLoop.DrawPolygons(sg2d, sg2d.getSurfaceData(), 113 xPoints, yPoints, 114 nPointsArray, 1, 115 sg2d.transX, sg2d.transY, 116 true); 117 } 118 119 public void fillRect(SunGraphics2D sg2d, 120 int x, int y, int width, int height) 121 { 122 sg2d.loops.fillRectLoop.FillRect(sg2d, sg2d.getSurfaceData(), 123 x + sg2d.transX, 124 y + sg2d.transY, 125 width, height); 126 } 127 128 public void fillRoundRect(SunGraphics2D sg2d, 129 int x, int y, int width, int height, 130 int arcWidth, int arcHeight) 131 { 132 sg2d.shapepipe.fill(sg2d, 133 new RoundRectangle2D.Float(x, y, width, height, 134 arcWidth, arcHeight)); 135 } 136 137 public void fillOval(SunGraphics2D sg2d, 138 int x, int y, int width, int height) 139 { 140 sg2d.shapepipe.fill(sg2d, new Ellipse2D.Float(x, y, width, height)); 141 } 142 143 public void fillArc(SunGraphics2D sg2d, 144 int x, int y, int width, int height, 145 int startAngle, int arcAngle) 146 { 147 sg2d.shapepipe.fill(sg2d, new Arc2D.Float(x, y, width, height, 148 startAngle, arcAngle, 149 Arc2D.PIE)); 150 } 151 152 public void fillPolygon(SunGraphics2D sg2d, 153 int xPoints[], int yPoints[], 154 int nPoints) 155 { 156 ShapeSpanIterator sr = getFillSSI(sg2d); 157 158 try { 159 sr.setOutputArea(sg2d.getCompClip()); 160 sr.appendPoly(xPoints, yPoints, nPoints, sg2d.transX, sg2d.transY); 161 fillSpans(sg2d, sr); 162 } finally { 163 sr.dispose(); 164 } 165 } 166 167 168 public void draw(SunGraphics2D sg2d, Shape s) { 169 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 170 Path2D.Float p2df; 171 int transX; 172 int transY; 173 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 174 if (s instanceof Path2D.Float) { 175 p2df = (Path2D.Float)s; 176 } else { 177 p2df = new Path2D.Float(s); 178 } 179 transX = sg2d.transX; 180 transY = sg2d.transY; 181 } else { 182 p2df = new Path2D.Float(s, sg2d.transform); 183 transX = 0; 184 transY = 0; 185 } 186 sg2d.loops.drawPathLoop.DrawPath(sg2d, sg2d.getSurfaceData(), 187 transX, transY, p2df); 188 return; 189 } 190 191 if (sg2d.strokeState == SunGraphics2D.STROKE_CUSTOM) { 192 fill(sg2d, sg2d.stroke.createStrokedShape(s)); 193 return; 194 } 195 196 ShapeSpanIterator sr = getStrokeSpans(sg2d, s); 197 198 try { 199 fillSpans(sg2d, sr); 200 } finally { 201 sr.dispose(); 202 } 203 } 204 205 /** 206 * Return a ShapeSpanIterator instance that normalizes as 207 * appropriate for a fill operation as per the settings in 208 * the specified SunGraphics2D object. 209 * 210 * The ShapeSpanIterator will be newly constructed and ready 211 * to start taking in geometry. 212 * 213 * Note that the caller is responsible for calling dispose() 214 * on the returned ShapeSpanIterator inside a try/finally block: 215 * <pre> 216 * ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d); 217 * try { 218 * ssi.setOutputArea(clip); 219 * ssi.appendPath(...); // or appendPoly 220 * // iterate the spans from ssi and operate on them 221 * } finally { 222 * ssi.dispose(); 223 * } 224 * </pre> 225 */ 226 public static ShapeSpanIterator getFillSSI(SunGraphics2D sg2d) { 227 boolean adjust = ((sg2d.stroke instanceof BasicStroke) && 228 sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE); 229 return new ShapeSpanIterator(adjust); 230 } 231 232 /* 233 * Return a ShapeSpanIterator ready to iterate the spans of the wide 234 * outline of Shape s using the attributes of the SunGraphics2D 235 * object. 236 * 237 * The ShapeSpanIterator returned will be fully constructed 238 * and filled with the geometry from the Shape widened by the 239 * appropriate BasicStroke and normalization parameters taken 240 * from the SunGraphics2D object and be ready to start returning 241 * spans. 242 * 243 * Note that the caller is responsible for calling dispose() 244 * on the returned ShapeSpanIterator inside a try/finally block. 245 * <pre> 246 * ShapeSpanIterator ssi = LoopPipe.getStrokeSpans(sg2d, s); 247 * try { 248 * // iterate the spans from ssi and operate on them 249 * } finally { 250 * ssi.dispose(); 251 * } 252 * </pre> 253 * 254 * REMIND: This should return a SpanIterator interface object 255 * but the caller needs to dispose() the object and that method 256 * is only on ShapeSpanIterator. 257 * TODO: Add a dispose() method to the SpanIterator interface. 258 */ 259 public static ShapeSpanIterator getStrokeSpans(SunGraphics2D sg2d, 260 Shape s) 261 { 262 ShapeSpanIterator sr = new ShapeSpanIterator(false); 263 264 try { 265 sr.setOutputArea(sg2d.getCompClip()); 266 sr.setRule(PathIterator.WIND_NON_ZERO); 267 268 BasicStroke bs = (BasicStroke) sg2d.stroke; 269 boolean thin = (sg2d.strokeState <= SunGraphics2D.STROKE_THINDASHED); 270 boolean normalize = 271 (sg2d.strokeHint != SunHints.INTVAL_STROKE_PURE); 272 273 RenderEngine.strokeTo(s, 274 sg2d.transform, bs, 275 thin, normalize, false, sr); 276 } catch (Throwable t) { 277 sr.dispose(); 278 sr = null; 279 throw new InternalError("Unable to Stroke shape ("+ 280 t.getMessage()+")", t); 281 } 282 return sr; 283 } 284 285 public void fill(SunGraphics2D sg2d, Shape s) { 286 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 287 Path2D.Float p2df; 288 int transX; 289 int transY; 290 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 291 if (s instanceof Path2D.Float) { 292 p2df = (Path2D.Float)s; 293 } else { 294 p2df = new Path2D.Float(s); 295 } 296 transX = sg2d.transX; 297 transY = sg2d.transY; 298 } else { 299 p2df = new Path2D.Float(s, sg2d.transform); 300 transX = 0; 301 transY = 0; 302 } 303 sg2d.loops.fillPathLoop.FillPath(sg2d, sg2d.getSurfaceData(), 304 transX, transY, p2df); 305 return; 306 } 307 308 ShapeSpanIterator sr = getFillSSI(sg2d); 309 try { 310 sr.setOutputArea(sg2d.getCompClip()); 311 AffineTransform at = 312 ((sg2d.transformState == SunGraphics2D.TRANSFORM_ISIDENT) 313 ? null 314 : sg2d.transform); 315 sr.appendPath(s.getPathIterator(at)); 316 fillSpans(sg2d, sr); 317 } finally { 318 sr.dispose(); 319 } 320 } 321 322 private static void fillSpans(SunGraphics2D sg2d, SpanIterator si) { 323 // REMIND: Eventually, the plan is that it will not be possible for 324 // fs to be null since the FillSpans loop will be the fundamental 325 // loop implemented for any destination type... 326 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 327 si = sg2d.clipRegion.filter(si); 328 // REMIND: Region.filter produces a Java-only iterator 329 // with no native counterpart... 330 } else { 331 sun.java2d.loops.FillSpans fs = sg2d.loops.fillSpansLoop; 332 if (fs != null) { 333 fs.FillSpans(sg2d, sg2d.getSurfaceData(), si); 334 return; 335 } 336 } 337 int spanbox[] = new int[4]; 338 SurfaceData sd = sg2d.getSurfaceData(); 339 while (si.nextSpan(spanbox)) { 340 int x = spanbox[0]; 341 int y = spanbox[1]; 342 int w = spanbox[2] - x; 343 int h = spanbox[3] - y; 344 sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h); 345 } 346 } 347 348 public void fillParallelogram(SunGraphics2D sg2d, 349 double ux1, double uy1, 350 double ux2, double uy2, 351 double x, double y, 352 double dx1, double dy1, 353 double dx2, double dy2) 354 { 355 FillParallelogram fp = sg2d.loops.fillParallelogramLoop; 356 fp.FillParallelogram(sg2d, sg2d.getSurfaceData(), 357 x, y, dx1, dy1, dx2, dy2); 358 } 359 360 public void drawParallelogram(SunGraphics2D sg2d, 361 double ux1, double uy1, 362 double ux2, double uy2, 363 double x, double y, 364 double dx1, double dy1, 365 double dx2, double dy2, 366 double lw1, double lw2) 367 { 368 DrawParallelogram dp = sg2d.loops.drawParallelogramLoop; 369 dp.DrawParallelogram(sg2d, sg2d.getSurfaceData(), 370 x, y, dx1, dy1, dx2, dy2, lw1, lw2); 371 } 372 }