1 /* 2 * Copyright (c) 2000, 2018, 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.x11; 27 28 import java.awt.Polygon; 29 import java.awt.Shape; 30 import java.awt.geom.AffineTransform; 31 import java.awt.geom.PathIterator; 32 import java.awt.geom.Path2D; 33 import java.awt.geom.IllegalPathStateException; 34 import sun.awt.SunToolkit; 35 import sun.java2d.SunGraphics2D; 36 import sun.java2d.SurfaceData; 37 import sun.java2d.loops.GraphicsPrimitive; 38 import sun.java2d.pipe.Region; 39 import sun.java2d.pipe.PixelDrawPipe; 40 import sun.java2d.pipe.PixelFillPipe; 41 import sun.java2d.pipe.ShapeDrawPipe; 42 import sun.java2d.pipe.SpanIterator; 43 import sun.java2d.pipe.ShapeSpanIterator; 44 import sun.java2d.pipe.LoopPipe; 45 46 public class X11Renderer implements 47 PixelDrawPipe, 48 PixelFillPipe, 49 ShapeDrawPipe 50 { 51 public static X11Renderer getInstance() { 52 return (GraphicsPrimitive.tracingEnabled() 53 ? new X11TracingRenderer() 54 : new X11Renderer()); 55 } 56 57 private long validate(SunGraphics2D sg2d) { 58 // NOTE: getCompClip() will revalidateAll() if the 59 // surfaceData is invalid. This should ensure that 60 // the clip and pixel that we are validating against 61 // are the most current. 62 // 63 // The assumption is that the pipeline after that 64 // revalidation will either be another X11 pipe 65 // (because the drawable format never changes on X11) 66 // or a null pipeline if the surface is disposed. 67 // 68 // Since we do not get the ops structure of the SurfaceData 69 // until the actual call down to the native level we will 70 // pick up the most recently validated copy. 71 // Note that if the surface is disposed, a NullSurfaceData 72 // (with null native data structure) will be set in 73 // sg2d, so we have to protect against it in native code. 74 75 X11SurfaceData x11sd = (X11SurfaceData)sg2d.surfaceData; 76 return x11sd.getRenderGC(sg2d.getCompClip(), 77 sg2d.compositeState, sg2d.composite, 78 sg2d.pixel); 79 } 80 81 native void XDrawLine(long pXSData, long xgc, 82 int x1, int y1, int x2, int y2); 83 84 public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) { 85 SunToolkit.awtLock(); 86 try { 87 long xgc = validate(sg2d); 88 int transx = sg2d.transX; 89 int transy = sg2d.transY; 90 XDrawLine(sg2d.surfaceData.getNativeOps(), xgc, 91 x1+transx, y1+transy, x2+transx, y2+transy); 92 } finally { 93 SunToolkit.awtUnlock(); 94 } 95 } 96 97 native void XDrawRect(long pXSData, long xgc, 98 int x, int y, int w, int h); 99 100 public void drawRect(SunGraphics2D sg2d, 101 int x, int y, int width, int height) 102 { 103 SunToolkit.awtLock(); 104 try { 105 long xgc = validate(sg2d); 106 XDrawRect(sg2d.surfaceData.getNativeOps(), xgc, 107 x+sg2d.transX, y+sg2d.transY, width, height); 108 } finally { 109 SunToolkit.awtUnlock(); 110 } 111 } 112 113 native void XDrawRoundRect(long pXSData, long xgc, 114 int x, int y, int w, int h, 115 int arcW, int arcH); 116 117 public void drawRoundRect(SunGraphics2D sg2d, 118 int x, int y, int width, int height, 119 int arcWidth, int arcHeight) 120 { 121 SunToolkit.awtLock(); 122 try { 123 long xgc = validate(sg2d); 124 XDrawRoundRect(sg2d.surfaceData.getNativeOps(), xgc, 125 x+sg2d.transX, y+sg2d.transY, width, height, 126 arcWidth, arcHeight); 127 } finally { 128 SunToolkit.awtUnlock(); 129 } 130 } 131 132 native void XDrawOval(long pXSData, long xgc, 133 int x, int y, int w, int h); 134 135 public void drawOval(SunGraphics2D sg2d, 136 int x, int y, int width, int height) 137 { 138 SunToolkit.awtLock(); 139 try { 140 long xgc = validate(sg2d); 141 XDrawOval(sg2d.surfaceData.getNativeOps(), xgc, 142 x+sg2d.transX, y+sg2d.transY, width, height); 143 } finally { 144 SunToolkit.awtUnlock(); 145 } 146 } 147 148 native void XDrawArc(long pXSData, long xgc, 149 int x, int y, int w, int h, 150 int angleStart, int angleExtent); 151 152 public void drawArc(SunGraphics2D sg2d, 153 int x, int y, int width, int height, 154 int startAngle, int arcAngle) 155 { 156 SunToolkit.awtLock(); 157 try { 158 long xgc = validate(sg2d); 159 XDrawArc(sg2d.surfaceData.getNativeOps(), xgc, 160 x+sg2d.transX, y+sg2d.transY, width, height, 161 startAngle, arcAngle); 162 } finally { 163 SunToolkit.awtUnlock(); 164 } 165 } 166 167 native void XDrawPoly(long pXSData, long xgc, 168 int transx, int transy, 169 int[] xpoints, int[] ypoints, 170 int npoints, boolean isclosed); 171 172 public void drawPolyline(SunGraphics2D sg2d, 173 int[] xpoints, int[] ypoints, 174 int npoints) 175 { 176 SunToolkit.awtLock(); 177 try { 178 long xgc = validate(sg2d); 179 XDrawPoly(sg2d.surfaceData.getNativeOps(), xgc, 180 sg2d.transX, sg2d.transY, 181 xpoints, ypoints, npoints, false); 182 } finally { 183 SunToolkit.awtUnlock(); 184 } 185 } 186 187 public void drawPolygon(SunGraphics2D sg2d, 188 int[] xpoints, int[] ypoints, 189 int npoints) 190 { 191 SunToolkit.awtLock(); 192 try { 193 long xgc = validate(sg2d); 194 XDrawPoly(sg2d.surfaceData.getNativeOps(), xgc, 195 sg2d.transX, sg2d.transY, 196 xpoints, ypoints, npoints, true); 197 } finally { 198 SunToolkit.awtUnlock(); 199 } 200 } 201 202 native void XFillRect(long pXSData, long xgc, 203 int x, int y, int w, int h); 204 205 public void fillRect(SunGraphics2D sg2d, 206 int x, int y, int width, int height) 207 { 208 SunToolkit.awtLock(); 209 try { 210 long xgc = validate(sg2d); 211 XFillRect(sg2d.surfaceData.getNativeOps(), xgc, 212 x+sg2d.transX, y+sg2d.transY, width, height); 213 } finally { 214 SunToolkit.awtUnlock(); 215 } 216 } 217 218 native void XFillRoundRect(long pXSData, long xgc, 219 int x, int y, int w, int h, 220 int arcW, int arcH); 221 222 public void fillRoundRect(SunGraphics2D sg2d, 223 int x, int y, int width, int height, 224 int arcWidth, int arcHeight) 225 { 226 SunToolkit.awtLock(); 227 try { 228 long xgc = validate(sg2d); 229 XFillRoundRect(sg2d.surfaceData.getNativeOps(), xgc, 230 x+sg2d.transX, y+sg2d.transY, width, height, 231 arcWidth, arcHeight); 232 } finally { 233 SunToolkit.awtUnlock(); 234 } 235 } 236 237 native void XFillOval(long pXSData, long xgc, 238 int x, int y, int w, int h); 239 240 public void fillOval(SunGraphics2D sg2d, 241 int x, int y, int width, int height) 242 { 243 SunToolkit.awtLock(); 244 try { 245 long xgc = validate(sg2d); 246 XFillOval(sg2d.surfaceData.getNativeOps(), xgc, 247 x+sg2d.transX, y+sg2d.transY, width, height); 248 } finally { 249 SunToolkit.awtUnlock(); 250 } 251 } 252 253 native void XFillArc(long pXSData, long xgc, 254 int x, int y, int w, int h, 255 int angleStart, int angleExtent); 256 257 public void fillArc(SunGraphics2D sg2d, 258 int x, int y, int width, int height, 259 int startAngle, int arcAngle) 260 { 261 SunToolkit.awtLock(); 262 try { 263 long xgc = validate(sg2d); 264 XFillArc(sg2d.surfaceData.getNativeOps(), xgc, 265 x+sg2d.transX, y+sg2d.transY, width, height, 266 startAngle, arcAngle); 267 } finally { 268 SunToolkit.awtUnlock(); 269 } 270 } 271 272 native void XFillPoly(long pXSData, long xgc, 273 int transx, int transy, 274 int[] xpoints, int[] ypoints, 275 int npoints); 276 277 public void fillPolygon(SunGraphics2D sg2d, 278 int[] xpoints, int[] ypoints, 279 int npoints) 280 { 281 SunToolkit.awtLock(); 282 try { 283 long xgc = validate(sg2d); 284 XFillPoly(sg2d.surfaceData.getNativeOps(), xgc, 285 sg2d.transX, sg2d.transY, xpoints, ypoints, npoints); 286 } finally { 287 SunToolkit.awtUnlock(); 288 } 289 } 290 291 native void XFillSpans(long pXSData, long xgc, 292 SpanIterator si, long iterator, 293 int transx, int transy); 294 295 native void XDoPath(SunGraphics2D sg2d, long pXSData, long xgc, 296 int transX, int transY, Path2D.Float p2df, 297 boolean isFill); 298 299 private void doPath(SunGraphics2D sg2d, Shape s, boolean isFill) { 300 Path2D.Float p2df; 301 int transx, transy; 302 if (sg2d.transformState <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) { 303 if (s instanceof Path2D.Float) { 304 p2df = (Path2D.Float)s; 305 } else { 306 p2df = new Path2D.Float(s); 307 } 308 transx = sg2d.transX; 309 transy = sg2d.transY; 310 } else { 311 p2df = new Path2D.Float(s, sg2d.transform); 312 transx = 0; 313 transy = 0; 314 } 315 SunToolkit.awtLock(); 316 try { 317 long xgc = validate(sg2d); 318 XDoPath(sg2d, sg2d.surfaceData.getNativeOps(), xgc, 319 transx, transy, p2df, isFill); 320 } finally { 321 SunToolkit.awtUnlock(); 322 } 323 } 324 325 public void draw(SunGraphics2D sg2d, Shape s) { 326 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 327 // Delegate to drawPolygon() if possible... 328 if (s instanceof Polygon && 329 sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) 330 { 331 Polygon p = (Polygon) s; 332 drawPolygon(sg2d, p.xpoints, p.ypoints, p.npoints); 333 return; 334 } 335 336 // Otherwise we will use drawPath() for 337 // high-quality thin paths. 338 doPath(sg2d, s, false); 339 } else if (sg2d.strokeState < SunGraphics2D.STROKE_CUSTOM) { 340 // REMIND: X11 can handle uniform scaled wide lines 341 // and dashed lines itself if we set the appropriate 342 // XGC attributes (TBD). 343 ShapeSpanIterator si = LoopPipe.getStrokeSpans(sg2d, s); 344 try { 345 SunToolkit.awtLock(); 346 try { 347 long xgc = validate(sg2d); 348 XFillSpans(sg2d.surfaceData.getNativeOps(), xgc, 349 si, si.getNativeIterator(), 350 0, 0); 351 } finally { 352 SunToolkit.awtUnlock(); 353 } 354 } finally { 355 si.dispose(); 356 } 357 } else { 358 fill(sg2d, sg2d.stroke.createStrokedShape(s)); 359 } 360 } 361 362 public void fill(SunGraphics2D sg2d, Shape s) { 363 if (sg2d.strokeState == SunGraphics2D.STROKE_THIN) { 364 // Delegate to fillPolygon() if possible... 365 if (s instanceof Polygon && 366 sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) 367 { 368 Polygon p = (Polygon) s; 369 fillPolygon(sg2d, p.xpoints, p.ypoints, p.npoints); 370 return; 371 } 372 373 // Otherwise we will use fillPath() for 374 // high-quality fills. 375 doPath(sg2d, s, true); 376 return; 377 } 378 379 AffineTransform at; 380 int transx, transy; 381 if (sg2d.transformState < SunGraphics2D.TRANSFORM_TRANSLATESCALE) { 382 // Transform (translation) will be done by XFillSpans 383 at = null; 384 transx = sg2d.transX; 385 transy = sg2d.transY; 386 } else { 387 // Transform will be done by the PathIterator 388 at = sg2d.transform; 389 transx = transy = 0; 390 } 391 392 ShapeSpanIterator ssi = LoopPipe.getFillSSI(sg2d); 393 try { 394 // Subtract transx/y from the SSI clip to match the 395 // (potentially untranslated) geometry fed to it 396 Region clip = sg2d.getCompClip(); 397 ssi.setOutputAreaXYXY(clip.getLoX() - transx, 398 clip.getLoY() - transy, 399 clip.getHiX() - transx, 400 clip.getHiY() - transy); 401 ssi.appendPath(s.getPathIterator(at)); 402 SunToolkit.awtLock(); 403 try { 404 long xgc = validate(sg2d); 405 XFillSpans(sg2d.surfaceData.getNativeOps(), xgc, 406 ssi, ssi.getNativeIterator(), 407 transx, transy); 408 } finally { 409 SunToolkit.awtUnlock(); 410 } 411 } finally { 412 ssi.dispose(); 413 } 414 } 415 416 native void devCopyArea(long sdOps, long xgc, 417 int srcx, int srcy, 418 int dstx, int dsty, 419 int w, int h); 420 421 public static class X11TracingRenderer extends X11Renderer { 422 void XDrawLine(long pXSData, long xgc, 423 int x1, int y1, int x2, int y2) 424 { 425 GraphicsPrimitive.tracePrimitive("X11DrawLine"); 426 super.XDrawLine(pXSData, xgc, x1, y1, x2, y2); 427 } 428 void XDrawRect(long pXSData, long xgc, 429 int x, int y, int w, int h) 430 { 431 GraphicsPrimitive.tracePrimitive("X11DrawRect"); 432 super.XDrawRect(pXSData, xgc, x, y, w, h); 433 } 434 void XDrawRoundRect(long pXSData, long xgc, 435 int x, int y, int w, int h, 436 int arcW, int arcH) 437 { 438 GraphicsPrimitive.tracePrimitive("X11DrawRoundRect"); 439 super.XDrawRoundRect(pXSData, xgc, x, y, w, h, arcW, arcH); 440 } 441 void XDrawOval(long pXSData, long xgc, 442 int x, int y, int w, int h) 443 { 444 GraphicsPrimitive.tracePrimitive("X11DrawOval"); 445 super.XDrawOval(pXSData, xgc, x, y, w, h); 446 } 447 void XDrawArc(long pXSData, long xgc, 448 int x, int y, int w, int h, 449 int angleStart, int angleExtent) 450 { 451 GraphicsPrimitive.tracePrimitive("X11DrawArc"); 452 super.XDrawArc(pXSData, xgc, 453 x, y, w, h, angleStart, angleExtent); 454 } 455 void XDrawPoly(long pXSData, long xgc, 456 int transx, int transy, 457 int[] xpoints, int[] ypoints, 458 int npoints, boolean isclosed) 459 { 460 GraphicsPrimitive.tracePrimitive("X11DrawPoly"); 461 super.XDrawPoly(pXSData, xgc, transx, transy, 462 xpoints, ypoints, npoints, isclosed); 463 } 464 void XDoPath(SunGraphics2D sg2d, long pXSData, long xgc, 465 int transX, int transY, Path2D.Float p2df, 466 boolean isFill) 467 { 468 GraphicsPrimitive.tracePrimitive(isFill ? 469 "X11FillPath" : 470 "X11DrawPath"); 471 super.XDoPath(sg2d, pXSData, xgc, transX, transY, p2df, isFill); 472 } 473 void XFillRect(long pXSData, long xgc, 474 int x, int y, int w, int h) 475 { 476 GraphicsPrimitive.tracePrimitive("X11FillRect"); 477 super.XFillRect(pXSData, xgc, x, y, w, h); 478 } 479 void XFillRoundRect(long pXSData, long xgc, 480 int x, int y, int w, int h, 481 int arcW, int arcH) 482 { 483 GraphicsPrimitive.tracePrimitive("X11FillRoundRect"); 484 super.XFillRoundRect(pXSData, xgc, x, y, w, h, arcW, arcH); 485 } 486 void XFillOval(long pXSData, long xgc, 487 int x, int y, int w, int h) 488 { 489 GraphicsPrimitive.tracePrimitive("X11FillOval"); 490 super.XFillOval(pXSData, xgc, x, y, w, h); 491 } 492 void XFillArc(long pXSData, long xgc, 493 int x, int y, int w, int h, 494 int angleStart, int angleExtent) 495 { 496 GraphicsPrimitive.tracePrimitive("X11FillArc"); 497 super.XFillArc(pXSData, xgc, 498 x, y, w, h, angleStart, angleExtent); 499 } 500 void XFillPoly(long pXSData, long xgc, 501 int transx, int transy, 502 int[] xpoints, int[] ypoints, 503 int npoints) 504 { 505 GraphicsPrimitive.tracePrimitive("X11FillPoly"); 506 super.XFillPoly(pXSData, xgc, 507 transx, transy, xpoints, ypoints, npoints); 508 } 509 void XFillSpans(long pXSData, long xgc, 510 SpanIterator si, long iterator, int transx, int transy) 511 { 512 GraphicsPrimitive.tracePrimitive("X11FillSpans"); 513 super.XFillSpans(pXSData, xgc, 514 si, iterator, transx, transy); 515 } 516 void devCopyArea(long sdOps, long xgc, 517 int srcx, int srcy, 518 int dstx, int dsty, 519 int w, int h) 520 { 521 GraphicsPrimitive.tracePrimitive("X11CopyArea"); 522 super.devCopyArea(sdOps, xgc, srcx, srcy, dstx, dsty, w, h); 523 } 524 } 525 }