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 {
getInstance()51     public static X11Renderer getInstance() {
52         return (GraphicsPrimitive.tracingEnabled()
53                 ? new X11TracingRenderer()
54                 : new X11Renderer());
55     }
56 
validate(SunGraphics2D sg2d)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 
XDrawLine(long pXSData, long xgc, int x1, int y1, int x2, int y2)81     native void XDrawLine(long pXSData, long xgc,
82                           int x1, int y1, int x2, int y2);
83 
drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2)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 
XDrawRect(long pXSData, long xgc, int x, int y, int w, int h)97     native void XDrawRect(long pXSData, long xgc,
98                           int x, int y, int w, int h);
99 
drawRect(SunGraphics2D sg2d, int x, int y, int width, int height)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 
XDrawRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH)113     native void XDrawRoundRect(long pXSData, long xgc,
114                                int x, int y, int w, int h,
115                                int arcW, int arcH);
116 
drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight)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 
XDrawOval(long pXSData, long xgc, int x, int y, int w, int h)132     native void XDrawOval(long pXSData, long xgc,
133                           int x, int y, int w, int h);
134 
drawOval(SunGraphics2D sg2d, int x, int y, int width, int height)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 
XDrawArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent)148     native void XDrawArc(long pXSData, long xgc,
149                          int x, int y, int w, int h,
150                          int angleStart, int angleExtent);
151 
drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle)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 
XDrawPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints, boolean isclosed)167     native void XDrawPoly(long pXSData, long xgc,
168                           int transx, int transy,
169                           int[] xpoints, int[] ypoints,
170                           int npoints, boolean isclosed);
171 
drawPolyline(SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints)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 
drawPolygon(SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints)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 
XFillRect(long pXSData, long xgc, int x, int y, int w, int h)202     native void XFillRect(long pXSData, long xgc,
203                           int x, int y, int w, int h);
204 
fillRect(SunGraphics2D sg2d, int x, int y, int width, int height)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 
XFillRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH)218     native void XFillRoundRect(long pXSData, long xgc,
219                                int x, int y, int w, int h,
220                                int arcW, int arcH);
221 
fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight)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 
XFillOval(long pXSData, long xgc, int x, int y, int w, int h)237     native void XFillOval(long pXSData, long xgc,
238                           int x, int y, int w, int h);
239 
fillOval(SunGraphics2D sg2d, int x, int y, int width, int height)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 
XFillArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent)253     native void XFillArc(long pXSData, long xgc,
254                          int x, int y, int w, int h,
255                          int angleStart, int angleExtent);
256 
fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle)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 
XFillPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints)272     native void XFillPoly(long pXSData, long xgc,
273                           int transx, int transy,
274                           int[] xpoints, int[] ypoints,
275                           int npoints);
276 
fillPolygon(SunGraphics2D sg2d, int[] xpoints, int[] ypoints, int npoints)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 
XFillSpans(long pXSData, long xgc, SpanIterator si, long iterator, int transx, int transy)291     native void XFillSpans(long pXSData, long xgc,
292                            SpanIterator si, long iterator,
293                            int transx, int transy);
294 
XDoPath(SunGraphics2D sg2d, long pXSData, long xgc, int transX, int transY, Path2D.Float p2df, boolean isFill)295     native void XDoPath(SunGraphics2D sg2d, long pXSData, long xgc,
296                         int transX, int transY, Path2D.Float p2df,
297                         boolean isFill);
298 
doPath(SunGraphics2D sg2d, Shape s, boolean isFill)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 
draw(SunGraphics2D sg2d, Shape s)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 
fill(SunGraphics2D sg2d, Shape s)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 
devCopyArea(long sdOps, long xgc, int srcx, int srcy, int dstx, int dsty, int w, int h)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 {
XDrawLine(long pXSData, long xgc, int x1, int y1, int x2, int y2)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         }
XDrawRect(long pXSData, long xgc, int x, int y, int w, int h)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         }
XDrawRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH)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         }
XDrawOval(long pXSData, long xgc, int x, int y, int w, int h)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         }
XDrawArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent)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         }
XDrawPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints, boolean isclosed)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         }
XDoPath(SunGraphics2D sg2d, long pXSData, long xgc, int transX, int transY, Path2D.Float p2df, boolean isFill)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         }
XFillRect(long pXSData, long xgc, int x, int y, int w, int h)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         }
XFillRoundRect(long pXSData, long xgc, int x, int y, int w, int h, int arcW, int arcH)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         }
XFillOval(long pXSData, long xgc, int x, int y, int w, int h)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         }
XFillArc(long pXSData, long xgc, int x, int y, int w, int h, int angleStart, int angleExtent)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         }
XFillPoly(long pXSData, long xgc, int transx, int transy, int[] xpoints, int[] ypoints, int npoints)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         }
XFillSpans(long pXSData, long xgc, SpanIterator si, long iterator, int transx, int transy)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         }
devCopyArea(long sdOps, long xgc, int srcx, int srcy, int dstx, int dsty, int w, int h)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 }
526