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