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