1/*
2 * Copyright (c) 2000, 2011, 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
26package sun.java2d.x11;
27
28import java.awt.Polygon;
29import java.awt.Shape;
30import java.awt.geom.AffineTransform;
31import java.awt.geom.PathIterator;
32import java.awt.geom.Path2D;
33import java.awt.geom.IllegalPathStateException;
34import sun.awt.SunToolkit;
35import sun.java2d.SunGraphics2D;
36import sun.java2d.SurfaceData;
37import sun.java2d.loops.GraphicsPrimitive;
38import sun.java2d.pipe.Region;
39import sun.java2d.pipe.PixelDrawPipe;
40import sun.java2d.pipe.PixelFillPipe;
41import sun.java2d.pipe.ShapeDrawPipe;
42import sun.java2d.pipe.SpanIterator;
43import sun.java2d.pipe.ShapeSpanIterator;
44import sun.java2d.pipe.LoopPipe;
45
46public 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 final 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}
526