1 /* 2 * Copyright (c) 1999, 2021, 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 drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2)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 drawRect(SunGraphics2D sg2d, int x, int y, int width, int height)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 drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight)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 drawOval(SunGraphics2D sg2d, int x, int y, int width, int height)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 drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle)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 drawPolyline(SunGraphics2D sg2d, int[] xPoints, int[] yPoints, int nPoints)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 drawPolygon(SunGraphics2D sg2d, int[] xPoints, int[] yPoints, int nPoints)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 fillRect(SunGraphics2D sg2d, int x, int y, int width, int height)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 fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight)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 fillOval(SunGraphics2D sg2d, int x, int y, int width, int height)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 fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle)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 fillPolygon(SunGraphics2D sg2d, int[] xPoints, int[] yPoints, int nPoints)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 draw(SunGraphics2D sg2d, Shape s)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 */ getFillSSI(SunGraphics2D sg2d)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 */ getStrokeSpans(SunGraphics2D sg2d, Shape s)258 public static ShapeSpanIterator getStrokeSpans(SunGraphics2D sg2d, 259 Shape s) 260 { 261 ShapeSpanIterator sr = new ShapeSpanIterator(false); 262 263 try { 264 final Region clip = sg2d.getCompClip(); 265 sr.setOutputArea(clip); 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, clip, 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 fill(SunGraphics2D sg2d, Shape s)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 fillSpans(SunGraphics2D sg2d, SpanIterator si)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 fillParallelogram(SunGraphics2D sg2d, double ux1, double uy1, double ux2, double uy2, double x, double y, double dx1, double dy1, double dx2, double dy2)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 drawParallelogram(SunGraphics2D sg2d, double ux1, double uy1, double ux2, double uy2, double x, double y, double dx1, double dy1, double dx2, double dy2, double lw1, double lw2)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 } 373