1 /* 2 * Copyright (c) 1999, 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.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 == SunGraphics2D.STROKE_THIN) { 175 Path2D.Float p2df; 176 int transX; 177 int transY; 178 if (sg2d.transformState <= SunGraphics2D.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 == SunGraphics2D.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 <= SunGraphics2D.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 throw new InternalError("Unable to Stroke shape ("+ 285 t.getMessage()+")", t); 286 } 287 return sr; 288 } 289 290 public void fill(SunGraphics2D sg2d, Shape s) { 291 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 292 Path2D.Float p2df; 293 int transX; 294 int transY; 295 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 296 if (s instanceof Path2D.Float) { 297 p2df = (Path2D.Float)s; 298 } else { 299 p2df = new Path2D.Float(s); 300 } 301 transX = sg2d.transX; 302 transY = sg2d.transY; 303 } else { 304 p2df = new Path2D.Float(s, sg2d.transform); 305 transX = 0; 306 transY = 0; 307 } 308 sg2d.loops.fillPathLoop.FillPath(sg2d, sg2d.getSurfaceData(), 309 transX, transY, p2df); 310 return; 311 } 312 313 ShapeSpanIterator sr = getFillSSI(sg2d); 314 try { 315 sr.setOutputArea(sg2d.getCompClip()); 316 AffineTransform at = 317 ((sg2d.transformState == SunGraphics2D.TRANSFORM_ISIDENT) 318 ? null 319 : sg2d.transform); 320 sr.appendPath(s.getPathIterator(at)); 321 fillSpans(sg2d, sr); 322 } finally { 323 sr.dispose(); 324 } 325 } 326 327 private static void fillSpans(SunGraphics2D sg2d, SpanIterator si) { 328 // REMIND: Eventually, the plan is that it will not be possible for 329 // fs to be null since the FillSpans loop will be the fundamental 330 // loop implemented for any destination type... 331 if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { 332 si = sg2d.clipRegion.filter(si); 333 // REMIND: Region.filter produces a Java-only iterator 334 // with no native counterpart... 335 } else { 336 sun.java2d.loops.FillSpans fs = sg2d.loops.fillSpansLoop; 337 if (fs != null) { 338 fs.FillSpans(sg2d, sg2d.getSurfaceData(), si); 339 return; 340 } 341 } 342 int spanbox[] = new int[4]; 343 SurfaceData sd = sg2d.getSurfaceData(); 344 while (si.nextSpan(spanbox)) { 345 int x = spanbox[0]; 346 int y = spanbox[1]; 347 int w = spanbox[2] - x; 348 int h = spanbox[3] - y; 349 sg2d.loops.fillRectLoop.FillRect(sg2d, sd, x, y, w, h); 350 } 351 } 352 353 public void fillParallelogram(SunGraphics2D sg2d, 354 double ux1, double uy1, 355 double ux2, double uy2, 356 double x, double y, 357 double dx1, double dy1, 358 double dx2, double dy2) 359 { 360 FillParallelogram fp = sg2d.loops.fillParallelogramLoop; 361 fp.FillParallelogram(sg2d, sg2d.getSurfaceData(), 362 x, y, dx1, dy1, dx2, dy2); 363 } 364 365 public void drawParallelogram(SunGraphics2D sg2d, 366 double ux1, double uy1, 367 double ux2, double uy2, 368 double x, double y, 369 double dx1, double dy1, 370 double dx2, double dy2, 371 double lw1, double lw2) 372 { 373 DrawParallelogram dp = sg2d.loops.drawParallelogramLoop; 374 dp.DrawParallelogram(sg2d, sg2d.getSurfaceData(), 375 x, y, dx1, dy1, dx2, dy2, lw1, lw2); 376 } 377 }