1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
6  *
7  * Project Info:  http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
22  * USA.
23  *
24  * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
25  * Other names may be trademarks of their respective owners.]
26  *
27  * ------------------
28  * SWTGraphics2D.java
29  * ------------------
30  * (C) Copyright 2006-2013, by Henry Proudhon and Contributors.
31  *
32  * Original Author:  Henry Proudhon (henry.proudhon AT ensmp.fr);
33  * Contributor(s):   Cedric Chabanois (cchabanois AT no-log.org);
34  *                   David Gilbert (for Object Refinery Limited);
35  *                   Ronnie Duan (see bug report 2583891);
36  *                   Kevin Xu (parts of patch 3506228);
37  *
38  * Changes
39  * -------
40  * 14-Jun-2006 : New class (HP);
41  * 29-Jan-2007 : Fixed the fillRect method (HP);
42  * 31-Jan-2007 : Moved the dummy JPanel to SWTUtils.java,
43  *               implemented the drawLine method (HP);
44  * 07-Apr-2007 : Dispose some of the swt ressources,
45  *               thanks to silent for pointing this out (HP);
46  * 23-May-2007 : Removed resource leaks by adding a resource pool (CC);
47  * 15-Jun-2007 : Fixed compile error for JDK 1.4 (DG);
48  * 22-Oct-2007 : Implemented clipping (HP);
49  * 22-Oct-2007 : Implemented some AlphaComposite support (HP);
50  * 23-Oct-2007 : Added mechanism for storing RenderingHints (which are
51  *               still ignored at this point) (DG);
52  * 23-Oct-2007 : Implemented drawPolygon(), drawPolyline(), drawOval(),
53  *               fillOval(), drawArc() and fillArc() (DG);
54  * 27-Nov-2007 : Implemented a couple of drawImage() methods (DG);
55  * 18-Nov-2008 : Check for GradientPaint in setPaint() method (DG);
56  * 27-Feb-2009 : Implemented fillPolygon() - see bug 2583891 (DG);
57  * 04-Jul-2012 : Fixed get/setStroke() - see bug 3514487 (DG);
58  * 18-Sep-2012 : Fixed missing text - see bug 3482106 and patch 3506228 (DG);
59  * 03-Jul-2013 : Use ParamChecks (DG);
60  *
61  */
62 
63 package org.jfree.experimental.swt;
64 
65 import java.awt.AlphaComposite;
66 import java.awt.BasicStroke;
67 import java.awt.Color;
68 import java.awt.Composite;
69 import java.awt.Font;
70 import java.awt.FontMetrics;
71 import java.awt.GradientPaint;
72 import java.awt.Graphics;
73 import java.awt.Graphics2D;
74 import java.awt.GraphicsConfiguration;
75 import java.awt.Image;
76 import java.awt.Paint;
77 import java.awt.Rectangle;
78 import java.awt.RenderingHints;
79 import java.awt.RenderingHints.Key;
80 import java.awt.Shape;
81 import java.awt.Stroke;
82 import java.awt.font.FontRenderContext;
83 import java.awt.font.GlyphVector;
84 import java.awt.geom.AffineTransform;
85 import java.awt.geom.Area;
86 import java.awt.geom.PathIterator;
87 import java.awt.geom.Rectangle2D;
88 import java.awt.image.BufferedImage;
89 import java.awt.image.BufferedImageOp;
90 import java.awt.image.ImageObserver;
91 import java.awt.image.RenderedImage;
92 import java.awt.image.renderable.RenderableImage;
93 import java.text.AttributedCharacterIterator;
94 import java.util.ArrayList;
95 import java.util.HashMap;
96 import java.util.Iterator;
97 import java.util.List;
98 import java.util.Map;
99 
100 import org.eclipse.swt.SWT;
101 import org.eclipse.swt.graphics.FontData;
102 import org.eclipse.swt.graphics.GC;
103 import org.eclipse.swt.graphics.ImageData;
104 import org.eclipse.swt.graphics.Path;
105 import org.eclipse.swt.graphics.Resource;
106 import org.eclipse.swt.graphics.Transform;
107 import org.jfree.chart.util.ParamChecks;
108 
109 /**
110  * This is a class utility to draw Graphics2D stuff on a swt composite.
111  * It is presently developed to use JFreeChart with the Standard
112  * Widget Toolkit but may be of a wider use later.
113  */
114 public class SWTGraphics2D extends Graphics2D {
115 
116     /** The swt graphic composite */
117     private GC gc;
118 
119     /**
120      * The rendering hints.  For now, these are not used, but at least the
121      * basic mechanism is present.
122      */
123     private RenderingHints hints;
124 
125     /** A reference to the compositing rule to apply. This is necessary
126      * due to the poor compositing interface of the SWT toolkit. */
127     private java.awt.Composite composite;
128 
129     /** A HashMap to store the Swt color resources. */
130     private Map colorsPool = new HashMap();
131 
132     /** A HashMap to store the Swt font resources. */
133     private Map fontsPool = new HashMap();
134 
135     /** A HashMap to store the Swt transform resources. */
136     private Map transformsPool = new HashMap();
137 
138     /** A List to store the Swt resources. */
139     private List resourcePool = new ArrayList();
140 
141     /**
142      * Creates a new instance.
143      *
144      * @param gc  the graphics context.
145      */
SWTGraphics2D(GC gc)146     public SWTGraphics2D(GC gc) {
147         super();
148         this.gc = gc;
149         this.hints = new RenderingHints(null);
150         this.composite = AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f);
151         setStroke(new BasicStroke());
152     }
153 
154     /**
155      * Not implemented yet - see {@link Graphics#create()}.
156      *
157      * @return <code>null</code>.
158      */
create()159     public Graphics create() {
160         // TODO Auto-generated method stub
161         return null;
162     }
163 
164     /**
165      * Not implemented yet - see {@link Graphics2D#getDeviceConfiguration()}.
166      *
167      * @return <code>null</code>.
168      */
getDeviceConfiguration()169     public GraphicsConfiguration getDeviceConfiguration() {
170         // TODO Auto-generated method stub
171         return null;
172     }
173 
174     /**
175      * Returns the current value for the specified hint key, or
176      * <code>null</code> if no value is set.
177      *
178      * @param hintKey  the hint key (<code>null</code> permitted).
179      *
180      * @return The hint value, or <code>null</code>.
181      *
182      * @see #setRenderingHint(RenderingHints.Key, Object)
183      */
getRenderingHint(Key hintKey)184     public Object getRenderingHint(Key hintKey) {
185         return this.hints.get(hintKey);
186     }
187 
188     /**
189      * Sets the value for a rendering hint.  For now, this graphics context
190      * ignores all hints.
191      *
192      * @param hintKey  the key (<code>null</code> not permitted).
193      * @param hintValue  the value (must be compatible with the specified key).
194      *
195      * @throws IllegalArgumentException if <code>hintValue</code> is not
196      *         compatible with the <code>hintKey</code>.
197      *
198      * @see #getRenderingHint(RenderingHints.Key)
199      */
setRenderingHint(Key hintKey, Object hintValue)200     public void setRenderingHint(Key hintKey, Object hintValue) {
201         this.hints.put(hintKey, hintValue);
202     }
203 
204     /**
205      * Returns a copy of the hints collection for this graphics context.
206      *
207      * @return A copy of the hints collection.
208      */
getRenderingHints()209     public RenderingHints getRenderingHints() {
210         return (RenderingHints) this.hints.clone();
211     }
212 
213     /**
214      * Adds the hints in the specified map to the graphics context, replacing
215      * any existing hints.  For now, this graphics context ignores all hints.
216      *
217      * @param hints  the hints (<code>null</code> not permitted).
218      *
219      * @see #setRenderingHints(Map)
220      */
addRenderingHints(Map hints)221     public void addRenderingHints(Map hints) {
222         this.hints.putAll(hints);
223     }
224 
225     /**
226      * Replaces the existing hints with those contained in the specified
227      * map.  Note that, for now, this graphics context ignores all hints.
228      *
229      * @param hints  the hints (<code>null</code> not permitted).
230      *
231      * @see #addRenderingHints(Map)
232      */
setRenderingHints(Map hints)233     public void setRenderingHints(Map hints) {
234         if (hints == null) {
235             throw new NullPointerException("Null 'hints' argument.");
236         }
237         this.hints = new RenderingHints(hints);
238     }
239 
240     /**
241      * Returns the current paint for this graphics context.
242      *
243      * @return The current paint.
244      *
245      * @see #setPaint(Paint)
246      */
getPaint()247     public Paint getPaint() {
248         // TODO: it might be a good idea to keep a reference to the color
249         // specified in setPaint() or setColor(), rather than creating a
250         // new object every time getPaint() is called.
251         return SWTUtils.toAwtColor(this.gc.getForeground());
252     }
253 
254     /**
255      * Sets the paint for this graphics context.  For now, this graphics
256      * context only supports instances of {@link Color} or
257      * {@link GradientPaint} (in the latter case there is no real gradient
258      * support, the paint used is the <code>Color</code> returned by
259      * <code>getColor1()</code>).
260      *
261      * @param paint  the paint (<code>null</code> permitted, ignored).
262      *
263      * @see #getPaint()
264      * @see #setColor(Color)
265      */
setPaint(Paint paint)266     public void setPaint(Paint paint) {
267         if (paint == null) {
268             return;  // to be consistent with other Graphics2D implementations
269         }
270         if (paint instanceof Color) {
271             setColor((Color) paint);
272         }
273         else if (paint instanceof GradientPaint) {
274             GradientPaint gp = (GradientPaint) paint;
275             setColor(gp.getColor1());
276         }
277         else {
278             throw new RuntimeException("Can only handle 'Color' at present.");
279         }
280     }
281 
282     /**
283      * Returns the current color for this graphics context.
284      *
285      * @return The current color.
286      *
287      * @see #setColor(Color)
288      */
getColor()289     public Color getColor() {
290         // TODO: it might be a good idea to keep a reference to the color
291         // specified in setPaint() or setColor(), rather than creating a
292         // new object every time getPaint() is called.
293         return SWTUtils.toAwtColor(this.gc.getForeground());
294     }
295 
296     /**
297      * Sets the current color for this graphics context.
298      *
299      * @param color  the color (<code>null</code> permitted but ignored).
300      *
301      * @see #getColor()
302      */
setColor(Color color)303     public void setColor(Color color) {
304         if (color == null) {
305             return;
306         }
307         org.eclipse.swt.graphics.Color swtColor = getSwtColorFromPool(color);
308         this.gc.setForeground(swtColor);
309         // handle transparency and compositing.
310         if (this.composite instanceof AlphaComposite) {
311             AlphaComposite acomp = (AlphaComposite) this.composite;
312             switch (acomp.getRule()) {
313             case AlphaComposite.SRC_OVER:
314                 this.gc.setAlpha((int) (color.getAlpha() * acomp.getAlpha()));
315                 break;
316             default:
317                 this.gc.setAlpha(color.getAlpha());
318                 break;
319             }
320         }
321     }
322 
323     private Color backgroundColor;
324 
325     /**
326      * Sets the background colour.
327      *
328      * @param color  the colour.
329      */
setBackground(Color color)330     public void setBackground(Color color) {
331         // since this is only used by clearRect(), we don't update the GC yet
332         this.backgroundColor = color;
333     }
334 
335     /**
336      * Returns the background colour.
337      *
338      * @return The background colour (possibly <code>null</code>)..
339      */
getBackground()340     public Color getBackground() {
341         return this.backgroundColor;
342     }
343 
344     /**
345      * Not implemented - see {@link Graphics#setPaintMode()}.
346      */
setPaintMode()347     public void setPaintMode() {
348         // TODO Auto-generated method stub
349     }
350 
351     /**
352      * Not implemented - see {@link Graphics#setXORMode(Color)}.
353      *
354      * @param color  the colour.
355      */
setXORMode(Color color)356     public void setXORMode(Color color) {
357         // TODO Auto-generated method stub
358     }
359 
360     /**
361      * Returns the current composite.
362      *
363      * @return The current composite.
364      *
365      * @see #setComposite(Composite)
366      */
getComposite()367     public Composite getComposite() {
368         return this.composite;
369     }
370 
371     /**
372      * Sets the current composite.  This implementation currently supports
373      * only the {@link AlphaComposite} class.
374      *
375      * @param comp  the composite (<code>null</code> not permitted).
376      */
setComposite(Composite comp)377     public void setComposite(Composite comp) {
378         if (comp == null) {
379             throw new IllegalArgumentException("Null 'comp' argument.");
380         }
381         this.composite = comp;
382         if (comp instanceof AlphaComposite) {
383             AlphaComposite acomp = (AlphaComposite) comp;
384             int alpha = (int) (acomp.getAlpha() * 0xFF);
385             this.gc.setAlpha(alpha);
386         }
387     }
388 
389     /**
390      * Returns the current stroke for this graphics context.
391      *
392      * @return The current stroke.
393      *
394      * @see #setStroke(Stroke)
395      */
getStroke()396     public Stroke getStroke() {
397         return new BasicStroke(this.gc.getLineWidth(),
398                 toAwtLineCap(this.gc.getLineCap()),
399                 toAwtLineJoin(this.gc.getLineJoin()));
400     }
401 
402     /**
403      * Sets the stroke for this graphics context.  For now, this implementation
404      * only recognises the {@link BasicStroke} class.
405      *
406      * @param stroke  the stroke (<code>null</code> not permitted).
407      *
408      * @see #getStroke()
409      */
setStroke(Stroke stroke)410     public void setStroke(Stroke stroke) {
411         if (stroke == null) {
412             throw new IllegalArgumentException("Null 'stroke' argument.");
413         }
414         if (stroke instanceof BasicStroke) {
415             BasicStroke bs = (BasicStroke) stroke;
416             this.gc.setLineWidth((int) bs.getLineWidth());
417             this.gc.setLineJoin(toSwtLineJoin(bs.getLineJoin()));
418             this.gc.setLineCap(toSwtLineCap(bs.getEndCap()));
419 
420             // set the line style to solid by default
421             this.gc.setLineStyle(SWT.LINE_SOLID);
422 
423             // apply dash style if any
424             float[] dashes = bs.getDashArray();
425             if (dashes != null) {
426                 int[] swtDashes = new int[dashes.length];
427                 for (int i = 0; i < swtDashes.length; i++) {
428                     swtDashes[i] = (int) dashes[i];
429                 }
430                 this.gc.setLineDash(swtDashes);
431             }
432         }
433         else {
434             throw new RuntimeException(
435                     "Can only handle 'Basic Stroke' at present.");
436         }
437     }
438 
439     /**
440      * Applies the specified clip.
441      *
442      * @param s  the shape for the clip.
443      */
clip(Shape s)444     public void clip(Shape s) {
445         Path path = toSwtPath(s);
446         this.gc.setClipping(path);
447         path.dispose();
448     }
449 
450     /**
451      * Returns the clip bounds.
452      *
453      * @return The clip bounds.
454      */
getClipBounds()455     public Rectangle getClipBounds() {
456         org.eclipse.swt.graphics.Rectangle clip = this.gc.getClipping();
457         return new Rectangle(clip.x, clip.y, clip.width, clip.height);
458     }
459 
460     /**
461      * Sets the clipping to the intersection of the current clip region and
462      * the specified rectangle.
463      *
464      * @param x  the x-coordinate.
465      * @param y  the y-coordinate.
466      * @param width  the width.
467      * @param height  the height.
468      */
clipRect(int x, int y, int width, int height)469     public void clipRect(int x, int y, int width, int height) {
470         org.eclipse.swt.graphics.Rectangle clip = this.gc.getClipping();
471         org.eclipse.swt.graphics.Rectangle r
472                 = new org.eclipse.swt.graphics.Rectangle(x, y, width, height);
473         clip.intersect(r);
474         this.gc.setClipping(clip);
475     }
476 
477     /**
478      * Returns the current clip.
479      *
480      * @return The current clip.
481      */
getClip()482     public Shape getClip() {
483         return SWTUtils.toAwtRectangle(this.gc.getClipping());
484     }
485 
486     /**
487      * Sets the clip region.
488      *
489      * @param clip  the clip.
490      */
setClip(Shape clip)491     public void setClip(Shape clip) {
492         if (clip == null) {
493             return;
494         }
495         Path clipPath = toSwtPath(clip);
496         this.gc.setClipping(clipPath);
497         clipPath.dispose();
498     }
499 
500     /**
501      * Sets the clip region to the specified rectangle.
502      *
503      * @param x  the x-coordinate.
504      * @param y  the y-coordinate.
505      * @param width  the width.
506      * @param height  the height.
507      */
setClip(int x, int y, int width, int height)508     public void setClip(int x, int y, int width, int height) {
509         this.gc.setClipping(x, y, width, height);
510     }
511 
512     /**
513      * Returns the current transform.
514      *
515      * @return The current transform.
516      */
getTransform()517     public AffineTransform getTransform() {
518         Transform swtTransform = new Transform(this.gc.getDevice());
519         this.gc.getTransform(swtTransform);
520         AffineTransform awtTransform = toAwtTransform(swtTransform);
521         swtTransform.dispose();
522         return awtTransform;
523     }
524 
525     /**
526      * Sets the current transform.
527      *
528      * @param t  the transform.
529      */
setTransform(AffineTransform t)530     public void setTransform(AffineTransform t) {
531         Transform transform = getSwtTransformFromPool(t);
532         this.gc.setTransform(transform);
533     }
534 
535     /**
536      * Concatenates the specified transform to the existing transform.
537      *
538      * @param t  the transform.
539      */
transform(AffineTransform t)540     public void transform(AffineTransform t) {
541         Transform swtTransform = new Transform(this.gc.getDevice());
542         this.gc.getTransform(swtTransform);
543         swtTransform.multiply(getSwtTransformFromPool(t));
544         this.gc.setTransform(swtTransform);
545         swtTransform.dispose();
546     }
547 
548     /**
549      * Applies a translation.
550      *
551      * @param x  the translation along the x-axis.
552      * @param y  the translation along the y-axis.
553      */
translate(int x, int y)554     public void translate(int x, int y) {
555         Transform swtTransform = new Transform(this.gc.getDevice());
556         this.gc.getTransform(swtTransform);
557         swtTransform.translate(x, y);
558         this.gc.setTransform(swtTransform);
559         swtTransform.dispose();
560     }
561 
562     /**
563      * Applies a translation.
564      *
565      * @param tx  the translation along the x-axis.
566      * @param ty  the translation along the y-axis.
567      */
translate(double tx, double ty)568     public void translate(double tx, double ty) {
569         translate((int) tx, (int) ty);
570     }
571 
572     /**
573      * Applies a rotation transform.
574      *
575      * @param theta  the angle of rotation.
576      */
rotate(double theta)577     public void rotate(double theta) {
578         AffineTransform t = getTransform();
579         t.rotate(theta);
580         setTransform(t);
581     }
582 
583     /**
584      * Not implemented - see {@link Graphics2D#rotate(double, double, double)}.
585      *
586      * @see java.awt.Graphics2D#rotate(double, double, double)
587      */
rotate(double theta, double x, double y)588     public void rotate(double theta, double x, double y) {
589         translate(x, y);
590         rotate(theta);
591         translate(-x, -y);
592     }
593 
594     /**
595      * Applies a scale transform.
596      *
597      * @param scaleX  the scale factor along the x-axis.
598      * @param scaleY  the scale factor along the y-axis.
599      */
scale(double scaleX, double scaleY)600     public void scale(double scaleX, double scaleY) {
601         Transform swtTransform = new Transform(this.gc.getDevice());
602         this.gc.getTransform(swtTransform);
603         swtTransform.scale((float) scaleX, (float) scaleY);
604         this.gc.setTransform(swtTransform);
605         swtTransform.dispose();
606     }
607 
608     /**
609      * Applies a shear transform.
610      *
611      * @param shearX  the x-factor.
612      * @param shearY  the y-factor.
613      */
shear(double shearX, double shearY)614     public void shear(double shearX, double shearY) {
615         transform(AffineTransform.getShearInstance(shearX, shearY));
616     }
617 
618     /**
619      * Draws the outline of the specified shape using the current stroke and
620      * paint settings.
621      *
622      * @param shape  the shape (<code>null</code> not permitted).
623      *
624      * @see #getPaint()
625      * @see #getStroke()
626      * @see #fill(Shape)
627      */
draw(Shape shape)628     public void draw(Shape shape) {
629         Path path = toSwtPath(shape);
630         this.gc.drawPath(path);
631         path.dispose();
632     }
633 
634     /**
635      * Draws a line from (x1, y1) to (x2, y2) using the current stroke
636      * and paint settings.
637      *
638      * @param x1  the x-coordinate for the starting point.
639      * @param y1  the y-coordinate for the starting point.
640      * @param x2  the x-coordinate for the ending point.
641      * @param y2  the y-coordinate for the ending point.
642      *
643      * @see #draw(Shape)
644      */
drawLine(int x1, int y1, int x2, int y2)645     public void drawLine(int x1, int y1, int x2, int y2) {
646         this.gc.drawLine(x1, y1, x2, y2);
647     }
648 
649     /**
650      * Draws the outline of the polygon specified by the given points, using
651      * the current paint and stroke settings.
652      *
653      * @param xPoints  the x-coordinates.
654      * @param yPoints  the y-coordinates.
655      * @param npoints  the number of points in the polygon.
656      *
657      * @see #draw(Shape)
658      */
drawPolygon(int [] xPoints, int [] yPoints, int npoints)659     public void drawPolygon(int [] xPoints, int [] yPoints, int npoints) {
660         drawPolyline(xPoints, yPoints, npoints);
661         if (npoints > 1) {
662             this.gc.drawLine(xPoints[npoints - 1], yPoints[npoints - 1],
663                     xPoints[0], yPoints[0]);
664         }
665     }
666 
667     /**
668      * Draws a sequence of connected lines specified by the given points, using
669      * the current paint and stroke settings.
670      *
671      * @param xPoints  the x-coordinates.
672      * @param yPoints  the y-coordinates.
673      * @param npoints  the number of points in the polygon.
674      *
675      * @see #draw(Shape)
676      */
drawPolyline(int [] xPoints, int [] yPoints, int npoints)677     public void drawPolyline(int [] xPoints, int [] yPoints, int npoints) {
678         if (npoints > 1) {
679             int x0 = xPoints[0];
680             int y0 = yPoints[0];
681             int x1 = 0, y1 = 0;
682             for (int i = 1; i < npoints; i++) {
683                 x1 = xPoints[i];
684                 y1 = yPoints[i];
685                 this.gc.drawLine(x0, y0, x1, y1);
686                 x0 = x1;
687                 y0 = y1;
688             }
689         }
690     }
691 
692     /**
693      * Draws an oval that fits within the specified rectangular region.
694      *
695      * @param x  the x-coordinate.
696      * @param y  the y-coordinate.
697      * @param width  the frame width.
698      * @param height  the frame height.
699      *
700      * @see #fillOval(int, int, int, int)
701      * @see #draw(Shape)
702      */
drawOval(int x, int y, int width, int height)703     public void drawOval(int x, int y, int width, int height) {
704         this.gc.drawOval(x, y, width - 1, height - 1);
705     }
706 
707     /**
708      * Draws an arc that is part of an ellipse that fits within the specified
709      * framing rectangle.
710      *
711      * @param x  the x-coordinate.
712      * @param y  the y-coordinate.
713      * @param width  the frame width.
714      * @param height  the frame height.
715      * @param arcStart  the arc starting point, in degrees.
716      * @param arcAngle  the extent of the arc.
717      *
718      * @see #fillArc(int, int, int, int, int, int)
719      */
drawArc(int x, int y, int width, int height, int arcStart, int arcAngle)720     public void drawArc(int x, int y, int width, int height, int arcStart,
721             int arcAngle) {
722         this.gc.drawArc(x, y, width - 1, height - 1, arcStart, arcAngle);
723     }
724 
725     /**
726      * Draws a rectangle with rounded corners that fits within the specified
727      * framing rectangle.
728      *
729      * @param x  the x-coordinate.
730      * @param y  the y-coordinate.
731      * @param width  the frame width.
732      * @param height  the frame height.
733      * @param arcWidth  the width of the arc defining the roundedness of the
734      *         rectangle's corners.
735      * @param arcHeight the height of the arc defining the roundedness of the
736      *         rectangle's corners.
737      *
738      * @see #fillRoundRect(int, int, int, int, int, int)
739      */
drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)740     public void drawRoundRect(int x, int y, int width, int height,
741             int arcWidth, int arcHeight) {
742         this.gc.drawRoundRectangle(x, y, width - 1, height - 1, arcWidth,
743                 arcHeight);
744     }
745 
746     /**
747      * Fills the specified shape using the current paint.
748      *
749      * @param shape  the shape (<code>null</code> not permitted).
750      *
751      * @see #getPaint()
752      * @see #draw(Shape)
753      */
fill(Shape shape)754     public void fill(Shape shape) {
755         Path path = toSwtPath(shape);
756         // Note that for consistency with the AWT implementation, it is
757         // necessary to switch temporarily the foreground and background
758         // colours
759         switchColors();
760         this.gc.fillPath(path);
761         switchColors();
762         path.dispose();
763     }
764 
765     /**
766      * Fill a rectangle area on the swt graphic composite.
767      * The <code>fillRectangle</code> method of the <code>GC</code>
768      * class uses the background color so we must switch colors.
769      * @see java.awt.Graphics#fillRect(int, int, int, int)
770      */
fillRect(int x, int y, int width, int height)771     public void fillRect(int x, int y, int width, int height) {
772         this.switchColors();
773         this.gc.fillRectangle(x, y, width, height);
774         this.switchColors();
775     }
776 
777     /**
778      * Fills the specified rectangle with the current background colour.
779      *
780      * @param x  the x-coordinate for the rectangle.
781      * @param y  the y-coordinate for the rectangle.
782      * @param width  the width.
783      * @param height  the height.
784      *
785      * @see #fillRect(int, int, int, int)
786      */
clearRect(int x, int y, int width, int height)787     public void clearRect(int x, int y, int width, int height) {
788         Color bgcolor = getBackground();
789         if (bgcolor == null) {
790             return;  // we can't do anything
791         }
792         Paint saved = getPaint();
793         setPaint(bgcolor);
794         fillRect(x, y, width, height);
795         setPaint(saved);
796     }
797 
798     /**
799      * Fills the specified polygon.
800      *
801      * @param xPoints  the x-coordinates.
802      * @param yPoints  the y-coordinates.
803      * @param npoints  the number of points.
804      */
fillPolygon(int[] xPoints, int[] yPoints, int npoints)805     public void fillPolygon(int[] xPoints, int[] yPoints, int npoints) {
806         int[] pointArray = new int[npoints * 2];
807         for (int i = 0; i < npoints; i++) {
808             pointArray[2 * i] = xPoints[i];
809             pointArray[2 * i + 1] = yPoints[i];
810         }
811         switchColors();
812         this.gc.fillPolygon(pointArray);
813         switchColors();
814     }
815 
816     /**
817      * Draws a rectangle with rounded corners that fits within the specified
818      * framing rectangle.
819      *
820      * @param x  the x-coordinate.
821      * @param y  the y-coordinate.
822      * @param width  the frame width.
823      * @param height  the frame height.
824      * @param arcWidth  the width of the arc defining the roundedness of the
825      *         rectangle's corners.
826      * @param arcHeight the height of the arc defining the roundedness of the
827      *         rectangle's corners.
828      *
829      * @see #drawRoundRect(int, int, int, int, int, int)
830      */
fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)831     public void fillRoundRect(int x, int y, int width, int height,
832             int arcWidth, int arcHeight) {
833         switchColors();
834         this.gc.fillRoundRectangle(x, y, width - 1, height - 1, arcWidth,
835                 arcHeight);
836         switchColors();
837     }
838 
839     /**
840      * Fills an oval that fits within the specified rectangular region.
841      *
842      * @param x  the x-coordinate.
843      * @param y  the y-coordinate.
844      * @param width  the frame width.
845      * @param height  the frame height.
846      *
847      * @see #drawOval(int, int, int, int)
848      * @see #fill(Shape)
849      */
fillOval(int x, int y, int width, int height)850     public void fillOval(int x, int y, int width, int height) {
851         switchColors();
852         this.gc.fillOval(x, y, width - 1, height - 1);
853         switchColors();
854     }
855 
856     /**
857      * Fills an arc that is part of an ellipse that fits within the specified
858      * framing rectangle.
859      *
860      * @param x  the x-coordinate.
861      * @param y  the y-coordinate.
862      * @param width  the frame width.
863      * @param height  the frame height.
864      * @param arcStart  the arc starting point, in degrees.
865      * @param arcAngle  the extent of the arc.
866      *
867      * @see #drawArc(int, int, int, int, int, int)
868      */
fillArc(int x, int y, int width, int height, int arcStart, int arcAngle)869     public void fillArc(int x, int y, int width, int height, int arcStart,
870             int arcAngle) {
871         switchColors();
872         this.gc.fillArc(x, y, width - 1, height - 1, arcStart, arcAngle);
873         switchColors();
874     }
875 
876     /**
877      * Returns the font in form of an awt font created
878      * with the parameters of the font of the swt graphic
879      * composite.
880      * @see java.awt.Graphics#getFont()
881      */
getFont()882     public Font getFont() {
883         // retrieve the swt font description in an os indept way
884         FontData[] fontData = this.gc.getFont().getFontData();
885         // create a new awt font with the appropiate data
886         return SWTUtils.toAwtFont(this.gc.getDevice(), fontData[0], true);
887     }
888 
889     /**
890      * Set the font swt graphic composite from the specified
891      * awt font. Be careful that the newly created swt font
892      * must be disposed separately.
893      * @see java.awt.Graphics#setFont(java.awt.Font)
894      */
setFont(Font font)895     public void setFont(Font font) {
896         org.eclipse.swt.graphics.Font swtFont = getSwtFontFromPool(font);
897         this.gc.setFont(swtFont);
898     }
899 
900     /**
901      * Returns the font metrics.
902      *
903      * @param font the font.
904      *
905      * @return The font metrics.
906      */
getFontMetrics(Font font)907     public FontMetrics getFontMetrics(Font font) {
908         return SWTUtils.DUMMY_PANEL.getFontMetrics(font);
909     }
910 
911     /**
912      * Returns the font render context.
913      *
914      * @return The font render context.
915      */
getFontRenderContext()916     public FontRenderContext getFontRenderContext() {
917         FontRenderContext fontRenderContext = new FontRenderContext(
918                 new AffineTransform(), true, true);
919         return fontRenderContext;
920     }
921 
922     /**
923      * Draws the specified glyph vector at the location <code>(x, y)</code>.
924      *
925      * @param g  the glyph vector (<code>null</code> not permitted).
926      * @param x  the x-coordinate.
927      * @param y  the y-coordinate.
928      */
drawGlyphVector(GlyphVector g, float x, float y)929     public void drawGlyphVector(GlyphVector g, float x, float y) {
930         fill(g.getOutline(x, y));
931     }
932 
933     /**
934      * Draws a string on the receiver. note that
935      * to be consistent with the awt method,
936      * the y has to be modified with the ascent of the font.
937      *
938      * @see java.awt.Graphics#drawString(java.lang.String, int, int)
939      */
drawString(String text, int x, int y)940     public void drawString(String text, int x, int y) {
941         drawString(text, (float) x, (float) y);
942     }
943 
944     /**
945      * Draws a string at the specified position.
946      *
947      * @param text  the string.
948      * @param x  the x-coordinate.
949      * @param y  the y-coordinate.
950      */
drawString(String text, float x, float y)951     public void drawString(String text, float x, float y) {
952         if (text == null) {
953             throw new NullPointerException("Null 'text' argument.");
954         }
955         float fm = this.gc.getFontMetrics().getAscent();
956         this.gc.drawString(text, (int) x, (int) (y - fm), true);
957     }
958 
959     /**
960      * Draws a string at the specified position.
961      *
962      * @param iterator  the string.
963      * @param x  the x-coordinate.
964      * @param y  the y-coordinate.
965      */
drawString(AttributedCharacterIterator iterator, int x, int y)966     public void drawString(AttributedCharacterIterator iterator, int x, int y) {
967         // for now we simply want to extract the chars from the iterator
968         // and call an unstyled text renderer
969         StringBuffer sb = new StringBuffer();
970         int numChars = iterator.getEndIndex() - iterator.getBeginIndex();
971         char c = iterator.first();
972         for (int i = 0; i < numChars; i++) {
973             sb.append(c);
974             c = iterator.next();
975         }
976         drawString(new String(sb),x,y);
977     }
978 
979     /**
980      * Draws a string at the specified position.
981      *
982      * @param iterator  the string.
983      * @param x  the x-coordinate.
984      * @param y  the y-coordinate.
985      */
drawString(AttributedCharacterIterator iterator, float x, float y)986     public void drawString(AttributedCharacterIterator iterator, float x,
987             float y) {
988         drawString(iterator, (int) x, (int) y);
989     }
990 
991     /**
992      * Returns <code>true</code> if the rectangle (in device space) intersects
993      * with the shape (the interior, if <code>onStroke</code> is false,
994      * otherwise the stroked outline of the shape).
995      *
996      * @param rect  a rectangle (in device space).
997      * @param s the shape.
998      * @param onStroke  test the stroked outline only?
999      *
1000      * @return A boolean.
1001      */
1002     @Override
hit(Rectangle rect, Shape s, boolean onStroke)1003     public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
1004         AffineTransform transform = getTransform();
1005         Shape ts;
1006         if (onStroke) {
1007             Stroke stroke = getStroke();
1008             ts = transform.createTransformedShape(stroke.createStrokedShape(s));
1009         } else {
1010             ts = transform.createTransformedShape(s);
1011         }
1012         if (!rect.getBounds2D().intersects(ts.getBounds2D())) {
1013             return false;
1014         }
1015         Area a1 = new Area(rect);
1016         Area a2 = new Area(ts);
1017         a1.intersect(a2);
1018         return !a1.isEmpty();
1019     }
1020 
1021     /**
1022      * Not implemented - see {@link Graphics#copyArea(int, int, int, int, int,
1023      * int)}.
1024      */
copyArea(int x, int y, int width, int height, int dx, int dy)1025     public void copyArea(int x, int y, int width, int height, int dx, int dy) {
1026         // TODO Auto-generated method stub
1027     }
1028 
1029     /**
1030      * Not implemented - see {@link Graphics2D#drawImage(Image,
1031      * AffineTransform, ImageObserver)}.
1032      *
1033      * @param image  the image.
1034      * @param xform  the transform.
1035      * @param obs  an image observer.
1036      *
1037      * @return A boolean.
1038      */
drawImage(Image image, AffineTransform xform, ImageObserver obs)1039     public boolean drawImage(Image image, AffineTransform xform,
1040             ImageObserver obs) {
1041         // TODO Auto-generated method stub
1042         return false;
1043     }
1044 
1045     /**
1046      * Draws an image.
1047      *
1048      * @param image  the image.
1049      * @param op  the image operation.
1050      * @param x  the x-coordinate.
1051      * @param y  the y-coordinate.
1052      */
drawImage(BufferedImage image, BufferedImageOp op, int x, int y)1053     public void drawImage(BufferedImage image, BufferedImageOp op, int x,
1054             int y) {
1055         org.eclipse.swt.graphics.Image im = new org.eclipse.swt.graphics.Image(
1056                 this.gc.getDevice(), SWTUtils.convertToSWT(image));
1057         this.gc.drawImage(im, x, y);
1058         im.dispose();
1059     }
1060 
1061     /**
1062      * Draws an SWT image with the top left corner of the image aligned to the
1063      * point (x, y).
1064      *
1065      * @param image  the image.
1066      * @param x  the x-coordinate.
1067      * @param y  the y-coordinate.
1068      */
drawImage(org.eclipse.swt.graphics.Image image, int x, int y)1069     public void drawImage(org.eclipse.swt.graphics.Image image, int x, int y) {
1070         this.gc.drawImage(image, x, y);
1071     }
1072 
1073     /**
1074      * Not implemented - see {@link Graphics2D#drawRenderedImage(RenderedImage,
1075      * AffineTransform)}.
1076      *
1077      * @param image  the image.
1078      * @param xform  the transform.
1079      */
drawRenderedImage(RenderedImage image, AffineTransform xform)1080     public void drawRenderedImage(RenderedImage image, AffineTransform xform) {
1081         // TODO Auto-generated method stub
1082     }
1083 
1084     /**
1085      * Not implemented - see {@link Graphics2D#drawRenderableImage(
1086      * RenderableImage, AffineTransform)}.
1087      *
1088      * @param image  the image.
1089      * @param xform  the transform.
1090      */
drawRenderableImage(RenderableImage image, AffineTransform xform)1091     public void drawRenderableImage(RenderableImage image,
1092             AffineTransform xform) {
1093         // TODO Auto-generated method stub
1094 
1095     }
1096 
1097     /**
1098      * Draws an image with the top left corner aligned to the point (x, y).
1099      *
1100      * @param image  the image.
1101      * @param x  the x-coordinate.
1102      * @param y  the y-coordinate.
1103      * @param observer  ignored here.
1104      *
1105      * @return <code>true</code> if the image has been drawn.
1106      */
drawImage(Image image, int x, int y, ImageObserver observer)1107     public boolean drawImage(Image image, int x, int y,
1108             ImageObserver observer) {
1109         ImageData data = SWTUtils.convertAWTImageToSWT(image);
1110         if (data == null) {
1111             return false;
1112         }
1113         org.eclipse.swt.graphics.Image im = new org.eclipse.swt.graphics.Image(
1114                 this.gc.getDevice(), data);
1115         this.gc.drawImage(im, x, y);
1116         im.dispose();
1117         return true;
1118     }
1119 
1120     /**
1121      * Draws an image with the top left corner aligned to the point (x, y),
1122      * and scaled to the specified width and height.
1123      *
1124      * @param image  the image.
1125      * @param x  the x-coordinate.
1126      * @param y  the y-coordinate.
1127      * @param width  the width for the rendered image.
1128      * @param height  the height for the rendered image.
1129      * @param observer  ignored here.
1130      *
1131      * @return <code>true</code> if the image has been drawn.
1132      */
drawImage(Image image, int x, int y, int width, int height, ImageObserver observer)1133     public boolean drawImage(Image image, int x, int y, int width, int height,
1134             ImageObserver observer) {
1135         ImageData data = SWTUtils.convertAWTImageToSWT(image);
1136         if (data == null) {
1137             return false;
1138         }
1139         org.eclipse.swt.graphics.Image im = new org.eclipse.swt.graphics.Image(
1140                 this.gc.getDevice(), data);
1141         org.eclipse.swt.graphics.Rectangle bounds = im.getBounds();
1142         this.gc.drawImage(im, 0, 0, bounds.width, bounds.height, x, y, width,
1143                 height);
1144         im.dispose();
1145         return true;
1146     }
1147 
1148     /**
1149      * Draws an image.
1150      *
1151      * @param image (<code>null</code> not permitted).
1152      * @param x  the x-coordinate.
1153      * @param y  the y-coordinate.
1154      * @param bgcolor  the background color.
1155      * @param observer  an image observer.
1156      *
1157      * @return A boolean.
1158      */
drawImage(Image image, int x, int y, Color bgcolor, ImageObserver observer)1159     public boolean drawImage(Image image, int x, int y, Color bgcolor,
1160             ImageObserver observer) {
1161         ParamChecks.nullNotPermitted(image, "image");
1162         int w = image.getWidth(null);
1163         int h = image.getHeight(null);
1164         if (w == -1 || h == -1) {
1165             return false;
1166         }
1167         Paint savedPaint = getPaint();
1168         fill(new Rectangle2D.Double(x, y, w, h));
1169         setPaint(savedPaint);
1170         return drawImage(image, x, y, observer);
1171     }
1172 
1173     /**
1174      * Draws an image.
1175      *
1176      * @param image  the image (<code>null</code> not permitted).
1177      * @param x  the x-coordinate.
1178      * @param y  the y-coordinate.
1179      * @param width  the width.
1180      * @param height  the height.
1181      * @param bgcolor  the background colour.
1182      * @param observer  an image observer.
1183      *
1184      * @return A boolean.
1185      */
drawImage(Image image, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)1186     public boolean drawImage(Image image, int x, int y, int width, int height,
1187             Color bgcolor, ImageObserver observer) {
1188         ParamChecks.nullNotPermitted(image, "image");
1189         int w = image.getWidth(null);
1190         int h = image.getHeight(null);
1191         if (w == -1 || h == -1) {
1192             return false;
1193         }
1194         Paint savedPaint = getPaint();
1195         fill(new Rectangle2D.Double(x, y, w, h));
1196         setPaint(savedPaint);
1197         return drawImage(image, x, y, width, height, observer);
1198     }
1199 
1200     /**
1201      * Not implemented - see {@link Graphics#drawImage(Image, int, int, int,
1202      *     int, int, int, int, int, ImageObserver)}.
1203      *
1204      * @param image  the image.
1205      * @param dx1
1206      * @param dy1
1207      * @param dx2
1208      * @param dy2
1209      * @param sx1
1210      * @param sy1
1211      * @param sx2
1212      * @param sy2
1213      * @param observer
1214      */
drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)1215     public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
1216             int sx1, int sy1, int sx2, int sy2, ImageObserver observer) {
1217         // TODO Auto-generated method stub
1218         return false;
1219     }
1220 
1221     /**
1222      * Not implemented - see {@link Graphics#drawImage(Image, int, int, int,
1223      *     int, int, int, int, int, Color, ImageObserver)}.
1224      *
1225      * @param image  the image.
1226      * @param dx1
1227      * @param dy1
1228      * @param dx2
1229      * @param dy2
1230      * @param sx1
1231      * @param sy1
1232      * @param sx2
1233      * @param sy2
1234      * @param bgcolor
1235      * @param observer
1236      */
drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer)1237     public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
1238             int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1239             ImageObserver observer) {
1240         // TODO Auto-generated method stub
1241         return false;
1242     }
1243 
1244     /**
1245      * Releases resources held by this instance (but note that the caller
1246      * must dispose of the 'GC' passed to the constructor).
1247      *
1248      * @see java.awt.Graphics#dispose()
1249      */
dispose()1250     public void dispose() {
1251         // we dispose resources we own but user must dispose gc
1252         disposeResourcePool();
1253     }
1254 
1255     /**
1256      * Add given swt resource to the resource pool. All resources added
1257      * to the resource pool will be disposed when {@link #dispose()} is called.
1258      *
1259      * @param resource the resource to add to the pool.
1260      * @return the swt <code>Resource</code> just added.
1261      */
addToResourcePool(Resource resource)1262     private Resource addToResourcePool(Resource resource) {
1263         this.resourcePool.add(resource);
1264         return resource;
1265     }
1266 
1267     /**
1268      * Dispose the resource pool.
1269      */
disposeResourcePool()1270     private void disposeResourcePool() {
1271         for (Iterator it = this.resourcePool.iterator(); it.hasNext();) {
1272             Resource resource = (Resource) it.next();
1273             resource.dispose();
1274         }
1275         this.fontsPool.clear();
1276         this.colorsPool.clear();
1277         this.transformsPool.clear();
1278         this.resourcePool.clear();
1279     }
1280 
1281     /**
1282      * Internal method to convert a AWT font object into
1283      * a SWT font resource. If a corresponding SWT font
1284      * instance is already in the pool, it will be used
1285      * instead of creating a new one. This is used in
1286      * {@link #setFont()} for instance.
1287      *
1288      * @param font The AWT font to convert.
1289      * @return The SWT font instance.
1290      */
getSwtFontFromPool(Font font)1291     private org.eclipse.swt.graphics.Font getSwtFontFromPool(Font font) {
1292         org.eclipse.swt.graphics.Font swtFont = (org.eclipse.swt.graphics.Font)
1293         this.fontsPool.get(font);
1294         if (swtFont == null) {
1295             swtFont = new org.eclipse.swt.graphics.Font(this.gc.getDevice(),
1296                     SWTUtils.toSwtFontData(this.gc.getDevice(), font, true));
1297             addToResourcePool(swtFont);
1298             this.fontsPool.put(font, swtFont);
1299         }
1300         return swtFont;
1301     }
1302 
1303     /**
1304      * Internal method to convert a AWT color object into
1305      * a SWT color resource. If a corresponding SWT color
1306      * instance is already in the pool, it will be used
1307      * instead of creating a new one. This is used in
1308      * {@link #setColor()} for instance.
1309      *
1310      * @param awtColor The AWT color to convert.
1311      * @return A SWT color instance.
1312      */
getSwtColorFromPool(Color awtColor)1313     private org.eclipse.swt.graphics.Color getSwtColorFromPool(Color awtColor) {
1314         org.eclipse.swt.graphics.Color swtColor =
1315                 (org.eclipse.swt.graphics.Color)
1316                 // we can't use the following valueOf() method, because it
1317                 // won't compile with JDK1.4
1318                 // this.colorsPool.get(Integer.valueOf(awtColor.getRGB()));
1319                 this.colorsPool.get(new Integer(awtColor.getRGB()));
1320         if (swtColor == null) {
1321             swtColor = SWTUtils.toSwtColor(this.gc.getDevice(), awtColor);
1322             addToResourcePool(swtColor);
1323             // see comment above
1324             //this.colorsPool.put(Integer.valueOf(awtColor.getRGB()), swtColor);
1325             this.colorsPool.put(new Integer(awtColor.getRGB()), swtColor);
1326         }
1327         return swtColor;
1328     }
1329 
1330     /**
1331      * Internal method to convert a AWT transform object into
1332      * a SWT transform resource. If a corresponding SWT transform
1333      * instance is already in the pool, it will be used
1334      * instead of creating a new one. This is used in
1335      * {@link #setTransform()} for instance.
1336      *
1337      * @param awtTransform The AWT transform to convert.
1338      * @return A SWT transform instance.
1339      */
getSwtTransformFromPool(AffineTransform awtTransform)1340     private Transform getSwtTransformFromPool(AffineTransform awtTransform) {
1341         Transform t = (Transform) this.transformsPool.get(awtTransform);
1342         if (t == null) {
1343             t = new Transform(this.gc.getDevice());
1344             double[] matrix = new double[6];
1345             awtTransform.getMatrix(matrix);
1346             t.setElements((float) matrix[0], (float) matrix[1],
1347                     (float) matrix[2], (float) matrix[3],
1348                     (float) matrix[4], (float) matrix[5]);
1349             addToResourcePool(t);
1350             this.transformsPool.put(awtTransform, t);
1351         }
1352         return t;
1353     }
1354 
1355     /**
1356      * Perform a switch between foreground and background
1357      * color of gc. This is needed for consistency with
1358      * the awt behaviour, and is required notably for the
1359      * filling methods.
1360      */
switchColors()1361     private void switchColors() {
1362         org.eclipse.swt.graphics.Color bg = this.gc.getBackground();
1363         org.eclipse.swt.graphics.Color fg = this.gc.getForeground();
1364         this.gc.setBackground(fg);
1365         this.gc.setForeground(bg);
1366     }
1367 
1368     /**
1369      * Converts an AWT <code>Shape</code> into a SWT <code>Path</code>.
1370      *
1371      * @param shape  the shape (<code>null</code> not permitted).
1372      *
1373      * @return The path.
1374      */
toSwtPath(Shape shape)1375     private Path toSwtPath(Shape shape) {
1376         int type;
1377         float[] coords = new float[6];
1378         Path path = new Path(this.gc.getDevice());
1379         PathIterator pit = shape.getPathIterator(null);
1380         while (!pit.isDone()) {
1381             type = pit.currentSegment(coords);
1382             switch (type) {
1383                 case (PathIterator.SEG_MOVETO):
1384                     path.moveTo(coords[0], coords[1]);
1385                     break;
1386                 case (PathIterator.SEG_LINETO):
1387                     path.lineTo(coords[0], coords[1]);
1388                     break;
1389                 case (PathIterator.SEG_QUADTO):
1390                     path.quadTo(coords[0], coords[1], coords[2], coords[3]);
1391                     break;
1392                 case (PathIterator.SEG_CUBICTO):
1393                     path.cubicTo(coords[0], coords[1], coords[2],
1394                             coords[3], coords[4], coords[5]);
1395                     break;
1396                 case (PathIterator.SEG_CLOSE):
1397                     path.close();
1398                     break;
1399                 default:
1400                     break;
1401             }
1402             pit.next();
1403         }
1404         return path;
1405     }
1406 
1407     /**
1408      * Converts an SWT transform into the equivalent AWT transform.
1409      *
1410      * @param swtTransform  the SWT transform.
1411      *
1412      * @return The AWT transform.
1413      */
toAwtTransform(Transform swtTransform)1414     private AffineTransform toAwtTransform(Transform swtTransform) {
1415         float[] elements = new float[6];
1416         swtTransform.getElements(elements);
1417         AffineTransform awtTransform = new AffineTransform(elements);
1418         return awtTransform;
1419     }
1420 
1421     /**
1422      * Returns the AWT line cap corresponding to the specified SWT line cap.
1423      *
1424      * @param swtLineCap  the SWT line cap.
1425      *
1426      * @return The AWT line cap.
1427      */
toAwtLineCap(int swtLineCap)1428     private int toAwtLineCap(int swtLineCap) {
1429         if (swtLineCap == SWT.CAP_FLAT) {
1430             return BasicStroke.CAP_BUTT;
1431         }
1432         else if (swtLineCap == SWT.CAP_ROUND) {
1433             return BasicStroke.CAP_ROUND;
1434         }
1435         else if (swtLineCap == SWT.CAP_SQUARE) {
1436             return BasicStroke.CAP_SQUARE;
1437         }
1438         else {
1439             throw new IllegalArgumentException("SWT LineCap " + swtLineCap
1440                 + " not recognised");
1441         }
1442     }
1443 
1444     /**
1445      * Returns the AWT line join corresponding to the specified SWT line join.
1446      *
1447      * @param swtLineJoin  the SWT line join.
1448      *
1449      * @return The AWT line join.
1450      */
toAwtLineJoin(int swtLineJoin)1451     private int toAwtLineJoin(int swtLineJoin) {
1452         if (swtLineJoin == SWT.JOIN_BEVEL) {
1453             return BasicStroke.JOIN_BEVEL;
1454         }
1455         else if (swtLineJoin == SWT.JOIN_MITER) {
1456             return BasicStroke.JOIN_MITER;
1457         }
1458         else if (swtLineJoin == SWT.JOIN_ROUND) {
1459             return BasicStroke.JOIN_ROUND;
1460         }
1461         else {
1462             throw new IllegalArgumentException("SWT LineJoin " + swtLineJoin
1463                 + " not recognised");
1464         }
1465     }
1466 
1467     /**
1468      * Returns the SWT line cap corresponding to the specified AWT line cap.
1469      *
1470      * @param awtLineCap  the AWT line cap.
1471      *
1472      * @return The SWT line cap.
1473      */
toSwtLineCap(int awtLineCap)1474     private int toSwtLineCap(int awtLineCap) {
1475         if (awtLineCap == BasicStroke.CAP_BUTT) {
1476             return SWT.CAP_FLAT;
1477         }
1478         else if (awtLineCap == BasicStroke.CAP_ROUND) {
1479             return SWT.CAP_ROUND;
1480         }
1481         else if (awtLineCap == BasicStroke.CAP_SQUARE) {
1482             return SWT.CAP_SQUARE;
1483         }
1484         else {
1485             throw new IllegalArgumentException("AWT LineCap " + awtLineCap
1486                 + " not recognised");
1487         }
1488     }
1489 
1490     /**
1491      * Returns the SWT line join corresponding to the specified AWT line join.
1492      *
1493      * @param awtLineJoin  the AWT line join.
1494      *
1495      * @return The SWT line join.
1496      */
toSwtLineJoin(int awtLineJoin)1497     private int toSwtLineJoin(int awtLineJoin) {
1498         if (awtLineJoin == BasicStroke.JOIN_BEVEL) {
1499             return SWT.JOIN_BEVEL;
1500         }
1501         else if (awtLineJoin == BasicStroke.JOIN_MITER) {
1502             return SWT.JOIN_MITER;
1503         }
1504         else if (awtLineJoin == BasicStroke.JOIN_ROUND) {
1505             return SWT.JOIN_ROUND;
1506         }
1507         else {
1508             throw new IllegalArgumentException("AWT LineJoin " + awtLineJoin
1509                 + " not recognised");
1510         }
1511     }
1512 }
1513