1 /*
   2  * Copyright (c) 2000, 2017, 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 }