1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Alexey A. Petrenko 19 * @version $Revision$ 20 */ 21package org.apache.harmony.awt.gl; 22 23 24import java.awt.AlphaComposite; 25import java.awt.BasicStroke; 26import java.awt.Color; 27import java.awt.Composite; 28import java.awt.Font; 29import java.awt.FontMetrics; 30import java.awt.Graphics2D; 31import java.awt.Image; 32import java.awt.Paint; 33import java.awt.PaintContext; 34import java.awt.Point; 35import java.awt.Polygon; 36import java.awt.Rectangle; 37import java.awt.RenderingHints; 38import java.awt.Shape; 39import java.awt.Stroke; 40import java.awt.Toolkit; 41import java.awt.font.FontRenderContext; 42import java.awt.font.GlyphVector; 43import java.awt.image.AffineTransformOp; 44import java.awt.image.ImageObserver; 45import java.awt.image.BufferedImage; 46import java.awt.image.BufferedImageOp; 47import java.awt.image.Raster; 48import java.awt.image.RenderedImage; 49import java.awt.image.WritableRaster; 50import java.awt.image.renderable.RenderableImage; 51import java.awt.geom.AffineTransform; 52import java.awt.geom.Arc2D; 53import java.awt.geom.Ellipse2D; 54import java.awt.geom.Line2D; 55import java.awt.geom.PathIterator; 56import java.awt.geom.RoundRectangle2D; 57import java.text.AttributedCharacterIterator; 58import java.util.Map; 59 60import org.apache.harmony.awt.gl.Surface; 61import org.apache.harmony.awt.gl.image.OffscreenImage; 62import org.apache.harmony.awt.gl.render.Blitter; 63import org.apache.harmony.awt.gl.render.JavaArcRasterizer; 64import org.apache.harmony.awt.gl.render.JavaLineRasterizer; 65import org.apache.harmony.awt.gl.render.JavaShapeRasterizer; 66import org.apache.harmony.awt.gl.render.JavaTextRenderer; 67import org.apache.harmony.awt.gl.render.NullBlitter; 68 69/* 70 * List of abstract methods to implement in subclusses 71 * Graphics.copyArea(int x, int y, int width, int height, int dx, int dy) 72 * Graphics.create() 73 * Graphics2D.getDeviceConfiguration() 74 * CommonGraphics2D.fillMultiRectAreaColor(MultiRectArea mra); 75 * CommonGraphics2D.fillMultiRectAreaPaint(MultiRectArea mra); 76 */ 77 78/** 79 * CommonGraphics2D class is a super class for all system-dependent 80 * implementations. It implements major part of Graphics and Graphics2D 81 * abstract methods. 82 * <h2>CommonGraphics2D Class Internals</h2> 83 * <h3>Line and Shape Rasterizers</h3> 84 * <p> 85 * The CommonGraphics2D class splits all shapes into a set of rectangles 86 * to unify the drawing process for different operating systems and architectures. 87 * For this purpose Java 2D* uses the JavaShapeRasterizer and the JavaLineRasterizer 88 * classes from the org.apache.harmony.awt.gl.render package. The JavaShapeRasterizer 89 * class splits an object implementing a Shape interface into a set of rectangles and 90 * produces a MultiRectArea object. The JavaLineRasterizer class makes line drawing 91 * more accurate and processes lines with strokes, which are instances of the BasicStroke 92 * class. 93 * </p> 94 * <p> 95 * To port the shape drawing to another platform you just need to override 96 * rectangle-drawing methods. However, if your operating system has functions to draw 97 * particular shapes, you can optimize your subclass of the CommonGraphics2D class by 98 * using this functionality in overridden methods. 99 * </p> 100 101 * <h3>Blitters</h3> 102 * <p> 103 * Blitter classes draw images on the display or buffered images. All blitters inherit 104 * the org.apache.harmony.awt.gl.render.Blitter interface. 105 * </p> 106 * <p>Blitters are divided into: 107 * <ul> 108 * <li>Native blitters for simple types of images, which the underlying native library 109 * can draw.</li> 110 * <li>Java* blitters for those types of images, which the underlying native library 111 * cannot handle.</li> 112 * </ul></p> 113 * <p> 114 * DRL Java 2D* also uses blitters to fill the shapes and the user-defined subclasses 115 * of the java.awt.Paint class with paints, which the system does not support. 116 * </p> 117 * 118 *<h3>Text Renderers</h3> 119 *<p> 120 *Text renderers draw strings and glyph vectors. All text renderers are subclasses 121 *of the org.apache.harmony.awt.gl.TextRenderer class. 122 *</p> 123 * 124 */ 125public abstract class CommonGraphics2D extends Graphics2D { 126 protected Surface dstSurf = null; 127 protected Blitter blitter = NullBlitter.getInstance(); 128 protected RenderingHints hints = new RenderingHints(null); 129 130 // Clipping things 131 protected MultiRectArea clip = null; 132 133 protected Paint paint = Color.WHITE; 134 protected Color fgColor = Color.WHITE; 135 protected Color bgColor = Color.BLACK; 136 137 protected Composite composite = AlphaComposite.SrcOver; 138 139 protected Stroke stroke = new BasicStroke(); 140 141 //TODO: Think more about FontRenderContext 142 protected FontRenderContext frc = new FontRenderContext(null, false, false); 143 144 protected JavaShapeRasterizer jsr = new JavaShapeRasterizer(); 145 146 protected Font font = new Font("Dialog", Font.PLAIN, 12);; //$NON-NLS-1$ 147 148 protected TextRenderer jtr = JavaTextRenderer.inst; 149 150 // Current graphics transform 151 protected AffineTransform transform = new AffineTransform(); 152 protected double[] matrix = new double[6]; 153 154 // Original user->device translation as transform and point 155 //public AffineTransform origTransform = new AffineTransform(); 156 public Point origPoint = new Point(0, 0); 157 158 159 // Print debug output or not 160 protected static final boolean debugOutput = "1".equals(System.getProperty("g2d.debug")); //$NON-NLS-1$ //$NON-NLS-2$ 161 162 // Constructors 163 protected CommonGraphics2D() { 164 } 165 166 protected CommonGraphics2D(int tx, int ty) { 167 this(tx, ty, null); 168 } 169 170 protected CommonGraphics2D(int tx, int ty, MultiRectArea clip) { 171 setTransform(AffineTransform.getTranslateInstance(tx, ty)); 172 //origTransform = AffineTransform.getTranslateInstance(tx, ty); 173 origPoint = new Point(tx, ty); 174 setClip(clip); 175 } 176 177 // Public methods 178 @Override 179 public void addRenderingHints(Map<?,?> hints) { 180 this.hints.putAll(hints); 181 } 182 183 @Override 184 public void clearRect(int x, int y, int width, int height) { 185 Color c = getColor(); 186 Paint p = getPaint(); 187 setColor(getBackground()); 188 fillRect(x, y, width, height); 189 setColor(c); 190 setPaint(p); 191 if (debugOutput) { 192 System.err.println("CommonGraphics2D.clearRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 193 } 194 } 195 196 @Override 197 public void clipRect(int x, int y, int width, int height) { 198 clip(new Rectangle(x, y, width, height)); 199 } 200 201 202 @Override 203 public void clip(Shape s) { 204 if (s == null) { 205 clip = null; 206 return; 207 } 208 209 MultiRectArea mra = null; 210 if (s instanceof MultiRectArea) { 211 mra = new MultiRectArea((MultiRectArea)s); 212 mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY()); 213 } else { 214 int type = transform.getType(); 215 if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY | 216 AffineTransform.TYPE_TRANSLATION)) != 0){ 217 mra = new MultiRectArea((Rectangle)s); 218 if(type == AffineTransform.TYPE_TRANSLATION){ 219 mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY()); 220 } 221 } else { 222 s = transform.createTransformedShape(s); 223 mra = jsr.rasterize(s, 0.5); 224 } 225 } 226 227 if (clip == null) { 228 setTransformedClip(mra); 229 } else { 230 clip.intersect(mra); 231 setTransformedClip(clip); 232 } 233 } 234 235 @Override 236 public void dispose() { 237 // Do nothing for Java only classes 238 } 239 240 241 242 243 /*************************************************************************** 244 * 245 * Draw methods 246 * 247 ***************************************************************************/ 248 249 @Override 250 public void draw(Shape s) { 251 if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) { 252 //TODO: Think about drawing the shape in one fillMultiRectArea call 253 BasicStroke bstroke = (BasicStroke)stroke; 254 JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase()); 255 PathIterator pi = s.getPathIterator(transform, 0.5); 256 float []points = new float[6]; 257 int x1 = Integer.MIN_VALUE; 258 int y1 = Integer.MIN_VALUE; 259 int cx1 = Integer.MIN_VALUE; 260 int cy1 = Integer.MIN_VALUE; 261 while (!pi.isDone()) { 262 switch (pi.currentSegment(points)) { 263 case PathIterator.SEG_MOVETO: 264 x1 = (int)Math.floor(points[0]); 265 y1 = (int)Math.floor(points[1]); 266 cx1 = x1; 267 cy1 = y1; 268 break; 269 case PathIterator.SEG_LINETO: 270 int x2 = (int)Math.floor(points[0]); 271 int y2 = (int)Math.floor(points[1]); 272 fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false)); 273 x1 = x2; 274 y1 = y2; 275 break; 276 case PathIterator.SEG_CLOSE: 277 x2 = cx1; 278 y2 = cy1; 279 fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false)); 280 x1 = x2; 281 y1 = y2; 282 break; 283 } 284 pi.next(); 285 } 286 } else { 287 s = stroke.createStrokedShape(s); 288 s = transform.createTransformedShape(s); 289 fillMultiRectArea(jsr.rasterize(s, 0.5)); 290 } 291 } 292 293 @Override 294 public void drawArc(int x, int y, int width, int height, int sa, int ea) { 295 if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 && 296 ((BasicStroke)stroke).getDashArray() == null && 297 (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) { 298 Point p = new Point(x, y); 299 transform.transform(p, p); 300 MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, sa, ea, clip); 301 fillMultiRectArea(mra); 302 return; 303 } 304 draw(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.OPEN)); 305 } 306 307 308 @Override 309 public boolean drawImage(Image image, int x, int y, Color bgcolor, 310 ImageObserver imageObserver) { 311 312 if(image == null) { 313 return true; 314 } 315 316 boolean done = false; 317 boolean somebits = false; 318 Surface srcSurf = null; 319 if(image instanceof OffscreenImage){ 320 OffscreenImage oi = (OffscreenImage) image; 321 if((oi.getState() & ImageObserver.ERROR) != 0) { 322 return false; 323 } 324 done = oi.prepareImage(imageObserver); 325 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 326 srcSurf = oi.getImageSurface(); 327 }else{ 328 done = true; 329 srcSurf = Surface.getImageSurface(image); 330 } 331 332 if(done || somebits) { 333 int w = srcSurf.getWidth(); 334 int h = srcSurf.getHeight(); 335 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(), 336 composite, bgcolor, clip); 337 } 338 return done; 339 } 340 341 @Override 342 public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) { 343 return drawImage(image, x, y, null, imageObserver); 344 } 345 346 @Override 347 public boolean drawImage(Image image, int x, int y, int width, int height, 348 Color bgcolor, ImageObserver imageObserver) { 349 350 if(image == null) { 351 return true; 352 } 353 if(width == 0 || height == 0) { 354 return true; 355 } 356 357 boolean done = false; 358 boolean somebits = false; 359 Surface srcSurf = null; 360 361 if(image instanceof OffscreenImage){ 362 OffscreenImage oi = (OffscreenImage) image; 363 if((oi.getState() & ImageObserver.ERROR) != 0) { 364 return false; 365 } 366 done = oi.prepareImage(imageObserver); 367 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 368 srcSurf = oi.getImageSurface(); 369 }else{ 370 done = true; 371 srcSurf = Surface.getImageSurface(image); 372 } 373 374 if(done || somebits) { 375 int w = srcSurf.getWidth(); 376 int h = srcSurf.getHeight(); 377 if(w == width && h == height){ 378 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 379 (AffineTransform) transform.clone(), 380 composite, bgcolor, clip); 381 }else{ 382 AffineTransform xform = new AffineTransform(); 383 xform.setToScale((float)width / w, (float)height / h); 384 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 385 (AffineTransform) transform.clone(), 386 xform, composite, bgcolor, clip); 387 } 388 } 389 return done; 390 } 391 392 @Override 393 public boolean drawImage(Image image, int x, int y, int width, int height, 394 ImageObserver imageObserver) { 395 return drawImage(image, x, y, width, height, null, imageObserver); 396 } 397 398 @Override 399 public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, 400 int sx1, int sy1, int sx2, int sy2, Color bgcolor, 401 ImageObserver imageObserver) { 402 403 if(image == null) { 404 return true; 405 } 406 if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) { 407 return true; 408 } 409 410 boolean done = false; 411 boolean somebits = false; 412 Surface srcSurf = null; 413 if(image instanceof OffscreenImage){ 414 OffscreenImage oi = (OffscreenImage) image; 415 if((oi.getState() & ImageObserver.ERROR) != 0) { 416 return false; 417 } 418 done = oi.prepareImage(imageObserver); 419 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 420 srcSurf = oi.getImageSurface(); 421 }else{ 422 done = true; 423 srcSurf = Surface.getImageSurface(image); 424 } 425 426 if(done || somebits) { 427 428 int dstX = dx1; 429 int dstY = dy1; 430 int srcX = sx1; 431 int srcY = sy1; 432 433 int dstW = dx2 - dx1; 434 int dstH = dy2 - dy1; 435 int srcW = sx2 - sx1; 436 int srcH = sy2 - sy1; 437 438 if(srcW == dstW && srcH == dstH){ 439 blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, 440 (AffineTransform) transform.clone(), 441 composite, bgcolor, clip); 442 }else{ 443 AffineTransform xform = new AffineTransform(); 444 xform.setToScale((float)dstW / srcW, (float)dstH / srcH); 445 blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, 446 (AffineTransform) transform.clone(), 447 xform, composite, bgcolor, clip); 448 } 449 } 450 return done; 451 } 452 453 @Override 454 public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, 455 int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) { 456 457 return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, 458 imageObserver); 459 } 460 461 @Override 462 public void drawImage(BufferedImage bufImage, BufferedImageOp op, 463 int x, int y) { 464 465 if(bufImage == null) { 466 return; 467 } 468 469 if(op == null) { 470 drawImage(bufImage, x, y, null); 471 } else if(op instanceof AffineTransformOp){ 472 AffineTransformOp atop = (AffineTransformOp) op; 473 AffineTransform xform = atop.getTransform(); 474 Surface srcSurf = Surface.getImageSurface(bufImage); 475 int w = srcSurf.getWidth(); 476 int h = srcSurf.getHeight(); 477 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 478 (AffineTransform) transform.clone(), xform, 479 composite, null, clip); 480 } else { 481 bufImage = op.filter(bufImage, null); 482 Surface srcSurf = Surface.getImageSurface(bufImage); 483 int w = srcSurf.getWidth(); 484 int h = srcSurf.getHeight(); 485 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 486 (AffineTransform) transform.clone(), 487 composite, null, clip); 488 } 489 } 490 491 @Override 492 public boolean drawImage(Image image, AffineTransform trans, 493 ImageObserver imageObserver) { 494 495 if(image == null) { 496 return true; 497 } 498 if(trans == null || trans.isIdentity()) { 499 return drawImage(image, 0, 0, imageObserver); 500 } 501 502 boolean done = false; 503 boolean somebits = false; 504 Surface srcSurf = null; 505 if(image instanceof OffscreenImage){ 506 OffscreenImage oi = (OffscreenImage) image; 507 if((oi.getState() & ImageObserver.ERROR) != 0) { 508 return false; 509 } 510 done = oi.prepareImage(imageObserver); 511 somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; 512 srcSurf = oi.getImageSurface(); 513 }else{ 514 done = true; 515 srcSurf = Surface.getImageSurface(image); 516 } 517 518 if(done || somebits) { 519 int w = srcSurf.getWidth(); 520 int h = srcSurf.getHeight(); 521 AffineTransform xform = (AffineTransform) transform.clone(); 522 xform.concatenate(trans); 523 blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite, 524 null, clip); 525 } 526 return done; 527 } 528 529 @Override 530 public void drawLine(int x1, int y1, int x2, int y2) { 531 if (debugOutput) { 532 System.err.println("CommonGraphics2D.drawLine("+x1+", "+y1+", "+x2+", "+y2+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 533 } 534 535 if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) { 536 BasicStroke bstroke = (BasicStroke)stroke; 537 Point p1 = new Point(x1, y1); 538 Point p2 = new Point(x2, y2); 539 transform.transform(p1, p1); 540 transform.transform(p2, p2); 541 JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase()); 542 MultiRectArea mra = JavaLineRasterizer.rasterize(p1.x, p1.y, p2.x, p2.y, null, ld, false); 543 fillMultiRectArea(mra); 544 return; 545 } 546 draw(new Line2D.Float(x1, y1, x2, y2)); 547 } 548 549 @Override 550 public void drawOval(int x, int y, int width, int height) { 551 if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 && 552 ((BasicStroke)stroke).getDashArray() == null && 553 (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) { 554 Point p = new Point(x, y); 555 transform.transform(p, p); 556 MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, 0, 360, clip); 557 fillMultiRectArea(mra); 558 return; 559 } 560 draw(new Ellipse2D.Float(x, y, width, height)); 561 } 562 563 @Override 564 public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) { 565 draw(new Polygon(xpoints, ypoints, npoints)); 566 } 567 568 @Override 569 public void drawPolygon(Polygon polygon) { 570 draw(polygon); 571 } 572 573 @Override 574 public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) { 575 for (int i = 0; i < npoints-1; i++) { 576 drawLine(xpoints[i], ypoints[i], xpoints[i+1], ypoints[i+1]); 577 } 578 } 579 580 @Override 581 public void drawRenderableImage(RenderableImage img, AffineTransform xform) { 582 if (img == null) { 583 return; 584 } 585 586 double scaleX = xform.getScaleX(); 587 double scaleY = xform.getScaleY(); 588 if (scaleX == 1 && scaleY == 1) { 589 drawRenderedImage(img.createDefaultRendering(), xform); 590 } else { 591 int width = (int)Math.round(img.getWidth()*scaleX); 592 int height = (int)Math.round(img.getHeight()*scaleY); 593 xform = (AffineTransform)xform.clone(); 594 xform.scale(1, 1); 595 drawRenderedImage(img.createScaledRendering(width, height, null), xform); 596 } 597 } 598 599 @Override 600 public void drawRenderedImage(RenderedImage rimg, AffineTransform xform) { 601 if (rimg == null) { 602 return; 603 } 604 605 Image img = null; 606 607 if (rimg instanceof Image) { 608 img = (Image)rimg; 609 } else { 610 //TODO: Create new class to provide Image interface for RenderedImage or rewrite this method 611 img = new BufferedImage(rimg.getColorModel(), rimg.copyData(null), false, null); 612 } 613 614 drawImage(img, xform, null); 615 } 616 617 @Override 618 public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { 619 if (debugOutput) { 620 System.err.println("CommonGraphics2D.drawRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ 621 } 622 623 draw(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight)); 624 } 625 626 627 628 629 630 /*************************************************************************** 631 * 632 * String methods 633 * 634 ***************************************************************************/ 635 636 @Override 637 public void drawString(AttributedCharacterIterator iterator, float x, float y) { 638 GlyphVector gv = font.createGlyphVector(frc, iterator); 639 drawGlyphVector(gv, x, y); 640 } 641 642 @Override 643 public void drawString(AttributedCharacterIterator iterator, int x, int y) { 644 drawString(iterator, (float)x, (float)y); 645 } 646 647 @Override 648 public void drawString(String str, int x, int y) { 649 drawString(str, (float)x, (float)y); 650 } 651 652 @Override 653 public void drawString(String str, float x, float y) { 654 if (debugOutput) { 655 System.err.println("CommonGraphics2D.drawString("+str+", "+x+", "+y+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 656 } 657 658 AffineTransform at = (AffineTransform)this.getTransform().clone(); 659 AffineTransform fontTransform = font.getTransform(); 660 at.concatenate(fontTransform); 661 662 double[] matrix = new double[6]; 663 if (!at.isIdentity()){ 664 665 int atType = at.getType(); 666 at.getMatrix(matrix); 667 668 // TYPE_TRANSLATION 669 if (atType == AffineTransform.TYPE_TRANSLATION){ 670 jtr.drawString(this, str, 671 (float)(x+fontTransform.getTranslateX()), 672 (float)(y+fontTransform.getTranslateY())); 673 return; 674 } 675 // TODO: we use slow type of drawing strings when Font object 676 // in Graphics has transforms, we just fill outlines. New textrenderer 677 // is to be implemented. 678 Shape sh = font.createGlyphVector(this.getFontRenderContext(), str).getOutline(x, y); 679 this.fill(sh); 680 681 } else { 682 jtr.drawString(this, str, x, y); 683 } 684 685 } 686 687 @Override 688 public void drawGlyphVector(GlyphVector gv, float x, float y) { 689 690 AffineTransform at = gv.getFont().getTransform(); 691 692 double[] matrix = new double[6]; 693 if ((at != null) && (!at.isIdentity())){ 694 695 int atType = at.getType(); 696 at.getMatrix(matrix); 697 698 // TYPE_TRANSLATION 699 if ((atType == AffineTransform.TYPE_TRANSLATION) && 700 ((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){ 701 jtr.drawGlyphVector(this, gv, (int)(x+matrix[4]), (int)(y+matrix[5])); 702 return; 703 } 704 } else { 705 if (((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){ 706 jtr.drawGlyphVector(this, gv, x, y); 707 return; 708 } 709 } 710 711 // TODO: we use slow type of drawing strings when Font object 712 // in Graphics has transforms, we just fill outlines. New textrenderer 713 // is to be implemented. 714 715 Shape sh = gv.getOutline(x, y); 716 this.fill(sh); 717 718 } 719 720 721 722 723 /*************************************************************************** 724 * 725 * Fill methods 726 * 727 ***************************************************************************/ 728 729 @Override 730 public void fill(Shape s) { 731 s = transform.createTransformedShape(s); 732 MultiRectArea mra = jsr.rasterize(s, 0.5); 733 fillMultiRectArea(mra); 734 } 735 736 @Override 737 public void fillArc(int x, int y, int width, int height, int sa, int ea) { 738 fill(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.PIE)); 739 } 740 741 @Override 742 public void fillOval(int x, int y, int width, int height) { 743 fill(new Ellipse2D.Float(x, y, width, height)); 744 } 745 746 @Override 747 public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) { 748 fill(new Polygon(xpoints, ypoints, npoints)); 749 } 750 751 @Override 752 public void fillPolygon(Polygon polygon) { 753 fill(polygon); 754 } 755 756 @Override 757 public void fillRect(int x, int y, int width, int height) { 758 if (debugOutput) { 759 System.err.println("CommonGraphics2D.fillRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 760 } 761 762 fill(new Rectangle(x, y, width, height)); 763 } 764 765 @Override 766 public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { 767 if (debugOutput) { 768 System.err.println("CommonGraphics2D.fillRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ 769 } 770 771 fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight)); 772 } 773 774 775 776 777 /*************************************************************************** 778 * 779 * Get methods 780 * 781 ***************************************************************************/ 782 783 @Override 784 public Color getBackground() { 785 return bgColor; 786 } 787 788 @Override 789 public Shape getClip() { 790 if (clip == null) { 791 return null; 792 } 793 794 MultiRectArea res = new MultiRectArea(clip); 795 res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY())); 796 return res; 797 } 798 799 @Override 800 public Rectangle getClipBounds() { 801 if (clip == null) { 802 return null; 803 } 804 805 Rectangle res = (Rectangle) clip.getBounds().clone(); 806 res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY())); 807 return res; 808 } 809 810 @Override 811 public Color getColor() { 812 return fgColor; 813 } 814 815 @Override 816 public Composite getComposite() { 817 return composite; 818 } 819 820 @Override 821 public Font getFont() { 822 return font; 823 } 824 825 @SuppressWarnings("deprecation") 826 @Override 827 public FontMetrics getFontMetrics(Font font) { 828 return Toolkit.getDefaultToolkit().getFontMetrics(font); 829 } 830 831 @Override 832 public FontRenderContext getFontRenderContext() { 833 return frc; 834 } 835 836 @Override 837 public Paint getPaint() { 838 return paint; 839 } 840 841 @Override 842 public Object getRenderingHint(RenderingHints.Key key) { 843 return hints.get(key); 844 } 845 846 @Override 847 public RenderingHints getRenderingHints() { 848 return hints; 849 } 850 851 @Override 852 public Stroke getStroke() { 853 return stroke; 854 } 855 856 @Override 857 public AffineTransform getTransform() { 858 return (AffineTransform)transform.clone(); 859 } 860 861 @Override 862 public boolean hit(Rectangle rect, Shape s, boolean onStroke) { 863 //TODO: Implement method.... 864 return false; 865 } 866 867 868 869 870 /*************************************************************************** 871 * 872 * Transformation methods 873 * 874 ***************************************************************************/ 875 876 @Override 877 public void rotate(double theta) { 878 transform.rotate(theta); 879 transform.getMatrix(matrix); 880 } 881 882 @Override 883 public void rotate(double theta, double x, double y) { 884 transform.rotate(theta, x, y); 885 transform.getMatrix(matrix); 886 } 887 888 @Override 889 public void scale(double sx, double sy) { 890 transform.scale(sx, sy); 891 transform.getMatrix(matrix); 892 } 893 894 @Override 895 public void shear(double shx, double shy) { 896 transform.shear(shx, shy); 897 transform.getMatrix(matrix); 898 } 899 900 @Override 901 public void transform(AffineTransform at) { 902 transform.concatenate(at); 903 transform.getMatrix(matrix); 904 } 905 906 @Override 907 public void translate(double tx, double ty) { 908 if (debugOutput) { 909 System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 910 } 911 912 transform.translate(tx, ty); 913 transform.getMatrix(matrix); 914 } 915 916 @Override 917 public void translate(int tx, int ty) { 918 if (debugOutput) { 919 System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 920 } 921 922 transform.translate(tx, ty); 923 transform.getMatrix(matrix); 924 } 925 926 927 928 929 /*************************************************************************** 930 * 931 * Set methods 932 * 933 ***************************************************************************/ 934 935 @Override 936 public void setBackground(Color color) { 937 bgColor = color; 938 } 939 940 @Override 941 public void setClip(int x, int y, int width, int height) { 942 setClip(new Rectangle(x, y, width, height)); 943 } 944 945 @Override 946 public void setClip(Shape s) { 947 if (s == null) { 948 setTransformedClip(null); 949 if (debugOutput) { 950 System.err.println("CommonGraphics2D.setClip(null)"); //$NON-NLS-1$ 951 } 952 return; 953 } 954 955 if (debugOutput) { 956 System.err.println("CommonGraphics2D.setClip("+s.getBounds()+")"); //$NON-NLS-1$ //$NON-NLS-2$ 957 } 958 959 if (s instanceof MultiRectArea) { 960 MultiRectArea nclip = new MultiRectArea((MultiRectArea)s); 961 nclip.translate(Math.round((float)transform.getTranslateX()), Math.round((float)transform.getTranslateY())); 962 setTransformedClip(nclip); 963 } else { 964 int type = transform.getType(); 965 if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY | 966 AffineTransform.TYPE_TRANSLATION)) != 0){ 967 MultiRectArea nclip = new MultiRectArea((Rectangle)s); 968 if(type == AffineTransform.TYPE_TRANSLATION){ 969 nclip.translate((int)transform.getTranslateX(), (int)transform.getTranslateY()); 970 } 971 setTransformedClip(nclip); 972 } else { 973 s = transform.createTransformedShape(s); 974 setTransformedClip(jsr.rasterize(s, 0.5)); 975 } 976 } 977 } 978 979 @Override 980 public void setColor(Color color) { 981 if (color != null) { 982 fgColor = color; 983 paint = color; 984 } 985 } 986 987 @Override 988 public void setComposite(Composite composite) { 989 this.composite = composite; 990 } 991 992 @Override 993 public void setFont(Font font) { 994 this.font = font; 995 } 996 997 @Override 998 public void setPaint(Paint paint) { 999 if (paint == null) 1000 return; 1001 1002 this.paint = paint; 1003 if (paint instanceof Color) { 1004 fgColor = (Color)paint; 1005 } 1006 } 1007 1008 @Override 1009 public void setPaintMode() { 1010 composite = AlphaComposite.SrcOver; 1011 } 1012 1013 @Override 1014 public void setRenderingHint(RenderingHints.Key key, Object value) { 1015 hints.put(key, value); 1016 } 1017 1018 @Override 1019 public void setRenderingHints(Map<?,?> hints) { 1020 this.hints.clear(); 1021 this.hints.putAll(hints); 1022 } 1023 1024 @Override 1025 public void setStroke(Stroke stroke) { 1026 this.stroke = stroke; 1027 } 1028 1029 @Override 1030 public void setTransform(AffineTransform transform) { 1031 this.transform = transform; 1032 1033 transform.getMatrix(matrix); 1034 } 1035 1036 @Override 1037 public void setXORMode(Color color) { 1038 composite = new XORComposite(color); 1039 } 1040 1041 1042 // Protected methods 1043 protected void setTransformedClip(MultiRectArea clip) { 1044 this.clip = clip; 1045 } 1046 1047 /** 1048 * This method fills the given MultiRectArea with current paint. 1049 * It calls fillMultiRectAreaColor and fillMultiRectAreaPaint 1050 * methods depending on the type of current paint. 1051 * @param mra MultiRectArea to fill 1052 */ 1053 protected void fillMultiRectArea(MultiRectArea mra) { 1054 if (clip != null) { 1055 mra.intersect(clip); 1056 } 1057 1058 // Return if all stuff is clipped 1059 if (mra.rect[0] < 5) { 1060 return; 1061 } 1062 1063 if (debugOutput) { 1064 System.err.println("CommonGraphics2D.fillMultiRectArea("+mra+")"); //$NON-NLS-1$ //$NON-NLS-2$ 1065 } 1066 1067 if (paint instanceof Color){ 1068 fillMultiRectAreaColor(mra); 1069 }else{ 1070 fillMultiRectAreaPaint(mra); 1071 } 1072 } 1073 1074 /** 1075 * This method fills the given MultiRectArea with solid color. 1076 * @param mra MultiRectArea to fill 1077 */ 1078 protected void fillMultiRectAreaColor(MultiRectArea mra) { 1079 fillMultiRectAreaPaint(mra); 1080 } 1081 1082 /** 1083 * This method fills the given MultiRectArea with any paint. 1084 * @param mra MultiRectArea to fill 1085 */ 1086 protected void fillMultiRectAreaPaint(MultiRectArea mra) { 1087 Rectangle rec = mra.getBounds(); 1088 int x = rec.x; 1089 int y = rec.y; 1090 int w = rec.width; 1091 int h = rec.height; 1092 if(w <= 0 || h <= 0) { 1093 return; 1094 } 1095 PaintContext pc = paint.createContext(null, rec, rec, transform, hints); 1096 Raster r = pc.getRaster(x, y, w, h); 1097 WritableRaster wr; 1098 if(r instanceof WritableRaster){ 1099 wr = (WritableRaster) r; 1100 }else{ 1101 wr = r.createCompatibleWritableRaster(); 1102 wr.setRect(r); 1103 } 1104 Surface srcSurf = new ImageSurface(pc.getColorModel(), wr); 1105 blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, 1106 composite, null, mra); 1107 srcSurf.dispose(); 1108 } 1109 1110 /** 1111 * Copies graphics class fields. 1112 * Used in create method 1113 * 1114 * @param copy Graphics class to copy 1115 */ 1116 protected void copyInternalFields(CommonGraphics2D copy) { 1117 if (clip == null) { 1118 copy.setTransformedClip(null); 1119 } else { 1120 copy.setTransformedClip(new MultiRectArea(clip)); 1121 } 1122 copy.setBackground(bgColor); 1123 copy.setColor(fgColor); 1124 copy.setPaint(paint); 1125 copy.setComposite(composite); 1126 copy.setStroke(stroke); 1127 copy.setFont(font); 1128 copy.setTransform(new AffineTransform(transform)); 1129 //copy.origTransform = new AffineTransform(origTransform); 1130 copy.origPoint = new Point(origPoint); 1131 } 1132}