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