1 /* 2 * Copyright (c) 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.xr; 27 28 import java.awt.*; 29 import java.awt.geom.*; 30 31 import sun.awt.SunToolkit; 32 import sun.java2d.SunGraphics2D; 33 import sun.java2d.loops.*; 34 import sun.java2d.pipe.Region; 35 import sun.java2d.pipe.PixelDrawPipe; 36 import sun.java2d.pipe.PixelFillPipe; 37 import sun.java2d.pipe.ShapeDrawPipe; 38 import sun.java2d.pipe.SpanIterator; 39 import sun.java2d.pipe.ShapeSpanIterator; 40 import sun.java2d.pipe.LoopPipe; 41 42 /** 43 * XRender provides only accalerated rectangles. To emulate higher "order" 44 * geometry we have to pass everything else to DoPath/FillSpans. 45 * 46 * TODO: DrawRect could be instrified 47 * 48 * @author Clemens Eisserer 49 */ 50 51 public class XRRenderer implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe { 52 XRDrawHandler drawHandler; 53 MaskTileManager tileManager; 54 55 public XRRenderer(MaskTileManager tileManager) { 56 this.tileManager = tileManager; 57 this.drawHandler = new XRDrawHandler(); 58 } 59 60 /** 61 * Common validate method, used by all XRRender functions to validate the 62 * destination context. 63 */ 64 private final void validateSurface(SunGraphics2D sg2d) { 65 XRSurfaceData xrsd = (XRSurfaceData) sg2d.surfaceData; 66 xrsd.validateAsDestination(sg2d, sg2d.getCompClip()); 67 xrsd.maskBuffer.validateCompositeState(sg2d.composite, sg2d.transform, 68 sg2d.paint, sg2d); 69 } 70 71 public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) { 72 Region compClip = sg2d.getCompClip(); 73 int transX1 = x1 + sg2d.transX; 74 int transY1 = y1 + sg2d.transY; 75 int transX2 = x2 + sg2d.transX; 76 int transY2 = y2 + sg2d.transY; 77 78 // Non clipped fast path 79 if (compClip.contains(transX1, transY1) 80 && compClip.contains(transX2, transY2)) { 81 try { 82 SunToolkit.awtLock(); 83 84 validateSurface(sg2d); 85 tileManager.addLine(transX1, transY1, transX2, transY2); 86 tileManager.fillMask((XRSurfaceData) sg2d.surfaceData); 87 } finally { 88 SunToolkit.awtUnlock(); 89 } 90 } else { 91 draw(sg2d, new Line2D.Float(x1, y1, x2, y2)); 92 } 93 } 94 95 public void drawRect(SunGraphics2D sg2d, 96 int x, int y, int width, int height) { 97 draw(sg2d, new Rectangle2D.Float(x, y, width, height)); 98 } 99 100 public void drawPolyline(SunGraphics2D sg2d, 101 int xpoints[], int ypoints[], int npoints) { 102 Path2D.Float p2d = new Path2D.Float(); 103 if (npoints > 1) { 104 p2d.moveTo(xpoints[0], ypoints[0]); 105 for (int i = 1; i < npoints; i++) { 106 p2d.lineTo(xpoints[i], ypoints[i]); 107 } 108 } 109 110 draw(sg2d, p2d); 111 } 112 113 public void drawPolygon(SunGraphics2D sg2d, 114 int xpoints[], int ypoints[], int npoints) { 115 draw(sg2d, new Polygon(xpoints, ypoints, npoints)); 116 } 117 118 public synchronized void fillRect(SunGraphics2D sg2d, 119 int x, int y, int width, int height) { 120 SunToolkit.awtLock(); 121 try { 122 validateSurface(sg2d); 123 124 XRSurfaceData xrsd = (XRSurfaceData) sg2d.surfaceData; 125 126 x += sg2d.transform.getTranslateX(); 127 y += sg2d.transform.getTranslateY(); 128 129 tileManager.addRect(x, y, width, height); 130 tileManager.fillMask(xrsd); 131 132 } finally { 133 SunToolkit.awtUnlock(); 134 } 135 } 136 137 public void fillPolygon(SunGraphics2D sg2d, 138 int xpoints[], int ypoints[], int npoints) { 139 fill(sg2d, new Polygon(xpoints, ypoints, npoints)); 140 } 141 142 public void drawRoundRect(SunGraphics2D sg2d, 143 int x, int y, int width, int height, 144 int arcWidth, int arcHeight) { 145 draw(sg2d, new RoundRectangle2D.Float(x, y, width, height, 146 arcWidth, arcHeight)); 147 } 148 149 public void fillRoundRect(SunGraphics2D sg2d, int x, int y, 150 int width, int height, 151 int arcWidth, int arcHeight) { 152 fill(sg2d, new RoundRectangle2D.Float(x, y, width, height, 153 arcWidth, arcHeight)); 154 } 155 156 public void drawOval(SunGraphics2D sg2d, 157 int x, int y, int width, int height) { 158 draw(sg2d, new Ellipse2D.Float(x, y, width, height)); 159 } 160 161 public void fillOval(SunGraphics2D sg2d, 162 int x, int y, int width, int height) { 163 fill(sg2d, new Ellipse2D.Float(x, y, width, height)); 164 } 165 166 public void drawArc(SunGraphics2D sg2d, 167 int x, int y, int width, int height, 168 int startAngle, int arcAngle) { 169 draw(sg2d, new Arc2D.Float(x, y, width, height, 170 startAngle, arcAngle, Arc2D.OPEN)); 171 } 172 173 public void fillArc(SunGraphics2D sg2d, 174 int x, int y, int width, int height, 175 int startAngle, int arcAngle) { 176 fill(sg2d, new Arc2D.Float(x, y, width, height, 177 startAngle, arcAngle, Arc2D.PIE)); 178 } 179 180 private class XRDrawHandler extends ProcessPath.DrawHandler { 181 182 XRDrawHandler() { 183 // these are bogus values; the caller will use validate() 184 // to ensure that they are set properly prior to each usage 185 super(0, 0, 0, 0); 186 } 187 188 /** 189 * This method needs to be called prior to each draw/fillPath() 190 * operation to ensure the clip bounds are up to date. 191 */ 192 void validate(SunGraphics2D sg2d) { 193 Region clip = sg2d.getCompClip(); 194 setBounds(clip.getLoX(), clip.getLoY(), 195 clip.getHiX(), clip.getHiY(), sg2d.strokeHint); 196 validateSurface(sg2d); 197 } 198 199 public void drawLine(int x1, int y1, int x2, int y2) { 200 tileManager.addLine(x1, y1, x2, y2); 201 } 202 203 public void drawPixel(int x, int y) { 204 tileManager.addRect(x, y, 1, 1); 205 } 206 207 public void drawScanline(int x1, int x2, int y) { 208 tileManager.addRect(x1, y, x2 - x1 + 1, 1); 209 } 210 } 211 212 protected void drawPath(SunGraphics2D sg2d, Path2D.Float p2df, 213 int transx, int transy) { 214 SunToolkit.awtLock(); 215 try { 216 validateSurface(sg2d); 217 drawHandler.validate(sg2d); 218 ProcessPath.drawPath(drawHandler, p2df, transx, transy); 219 tileManager.fillMask(((XRSurfaceData) sg2d.surfaceData)); 220 } finally { 221 SunToolkit.awtUnlock(); 222 } 223 } 224 225 protected void fillPath(SunGraphics2D sg2d, Path2D.Float p2df, 226 int transx, int transy) { 227 SunToolkit.awtLock(); 228 try { 229 validateSurface(sg2d); 230 drawHandler.validate(sg2d); 231 ProcessPath.fillPath(drawHandler, p2df, transx, transy); 232 tileManager.fillMask(((XRSurfaceData) sg2d.surfaceData)); 233 } finally { 234 SunToolkit.awtUnlock(); 235 } 236 } 237 238 protected void fillSpans(SunGraphics2D sg2d, SpanIterator si, 239 int transx, int transy) { 240 SunToolkit.awtLock(); 241 try { 242 validateSurface(sg2d); 243 int[] spanBox = new int[4]; 244 while (si.nextSpan(spanBox)) { 245 tileManager.addRect(spanBox[0] + transx, 246 spanBox[1] + transy, 247 spanBox[2] - spanBox[0], 248 spanBox[3] - spanBox[1]); 249 } 250 tileManager.fillMask(((XRSurfaceData) sg2d.surfaceData)); 251 } finally { 252 SunToolkit.awtUnlock(); 253 } 254 } 255 256 public void draw(SunGraphics2D sg2d, Shape s) { 257 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 258 Path2D.Float p2df; 259 int transx, transy; 260 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 261 if (s instanceof Path2D.Float) { 262 p2df = (Path2D.Float) s; 263 } else { 264 p2df = new Path2D.Float(s); 265 } 266 transx = sg2d.transX; 267 transy = sg2d.transY; 268 } else { 269 p2df = new Path2D.Float(s, sg2d.transform); 270 transx = 0; 271 transy = 0; 272 } 273 drawPath(sg2d, p2df, transx, transy); 274 } else if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { 275 ShapeSpanIterator si = LoopPipe.getStrokeSpans(sg2d, s); 276 try { 277 fillSpans(sg2d, si, 0, 0); 278 } finally { 279 si.dispose(); 280 } 281 } else { 282 fill(sg2d, sg2d.stroke.createStrokedShape(s)); 283 } 284 } 285 286 public void fill(SunGraphics2D sg2d, Shape s) { 287 int transx, transy; 288 289 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 290 // Here we are able to use fillPath() for 291 // high-quality fills. 292 Path2D.Float p2df; 293 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 294 if (s instanceof Path2D.Float) { 295 p2df = (Path2D.Float) s; 296 } else { 297 p2df = new Path2D.Float(s); 298 } 299 transx = sg2d.transX; 300 transy = sg2d.transY; 301 } else { 302 p2df = new Path2D.Float(s, sg2d.transform); 303 transx = 0; 304 transy = 0; 305 } 306 fillPath(sg2d, p2df, transx, transy); 307 return; 308 } 309 310 AffineTransform at; 311 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 312 // Transform (translation) will be done by FillSpans 313 at = null; 314 transx = sg2d.transX; 315 transy = sg2d.transY; 316 } else { 317 // Transform will be done by the PathIterator 318 at = sg2d.transform; 319 transx = transy = 0; 320 } 321 322 ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d); 323 try { 324 // Subtract transx/y from the SSI clip to match the 325 // (potentially untranslated) geometry fed to it 326 Region clip = sg2d.getCompClip(); 327 ssi.setOutputAreaXYXY(clip.getLoX() - transx, 328 clip.getLoY() - transy, 329 clip.getHiX() - transx, 330 clip.getHiY() - transy); 331 ssi.appendPath(s.getPathIterator(at)); 332 fillSpans(sg2d, ssi, transx, transy); 333 } finally { 334 ssi.dispose(); 335 } 336 } 337 }