1 /*
   2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.java2d;
  27 
  28 import java.awt.*;
  29 import java.awt.geom.*;
  30 import java.awt.image.*;
  31 import java.nio.*;
  32 
  33 import sun.awt.image.*;
  34 import sun.java2d.loops.*;
  35 import sun.java2d.pipe.*;
  36 import sun.lwawt.macosx.*;
  37 
  38 public class CRenderer implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, DrawImagePipe {
  39     native static void init();
  40 
  41     // cache of the runtime options
  42     static {
  43         init(); // initialize coordinate tables for shapes
  44     }
  45 
  46     native void doLine(SurfaceData sData, float x1, float y1, float x2, float y2);
  47 
  48     public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) {
  49         drawLine(sg2d, (float) x1, (float) y1, (float) x2, (float) y2);
  50     }
  51 
  52     Line2D lineToShape;
  53 
  54     public void drawLine(SunGraphics2D sg2d, float x1, float y1, float x2, float y2) {
  55         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
  56         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
  57             surfaceData.doLine(this, sg2d, x1, y1, x2, y2);
  58         } else {
  59             if (lineToShape == null) {
  60                 synchronized (this) {
  61                     if (lineToShape == null) {
  62                         lineToShape = new Line2D.Float();
  63                     }
  64                 }
  65             }
  66             synchronized (lineToShape) {
  67                 lineToShape.setLine(x1, y1, x2, y2);
  68                 drawfillShape(sg2d, sg2d.stroke.createStrokedShape(lineToShape), true, true);
  69             }
  70         }
  71     }
  72 
  73     native void doRect(SurfaceData sData, float x, float y, float width, float height, boolean isfill);
  74 
  75     public void drawRect(SunGraphics2D sg2d, int x, int y, int width, int height) {
  76         drawRect(sg2d, (float) x, (float) y, (float) width, (float) height);
  77     }
  78 
  79     Rectangle2D rectToShape;
  80 
  81     public void drawRect(SunGraphics2D sg2d, float x, float y, float width, float height) {
  82         if ((width < 0) || (height < 0)) return;
  83 
  84         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
  85         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
  86             surfaceData.doRect(this, sg2d, x, y, width, height, false);
  87         } else {
  88             if (rectToShape == null) {
  89                 synchronized (this) {
  90                     if (rectToShape == null) {
  91                         rectToShape = new Rectangle2D.Float();
  92                     }
  93                 }
  94             }
  95             synchronized (rectToShape) {
  96                 rectToShape.setRect(x, y, width, height);
  97                 drawfillShape(sg2d, sg2d.stroke.createStrokedShape(rectToShape), true, true);
  98             }
  99         }
 100     }
 101 
 102     public void fillRect(SunGraphics2D sg2d, int x, int y, int width, int height) {
 103         fillRect(sg2d, (float) x, (float) y, (float) width, (float) height);
 104     }
 105 
 106     public void fillRect(SunGraphics2D sg2d, float x, float y, float width, float height) {
 107         if ((width >= 0) && (height >= 0)) {
 108             OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 109             surfaceData.doRect(this, sg2d, x, y, width, height, true);
 110         }
 111     }
 112 
 113     native void doRoundRect(SurfaceData sData, float x, float y, float width, float height, float arcW, float arcH, boolean isfill);
 114 
 115     public void drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) {
 116         drawRoundRect(sg2d, (float) x, (float) y, (float) width, (float) height, (float) arcWidth, (float) arcHeight);
 117     }
 118 
 119     RoundRectangle2D roundrectToShape;
 120 
 121     public void drawRoundRect(SunGraphics2D sg2d, float x, float y, float width, float height, float arcWidth, float arcHeight) {
 122         if ((width < 0) || (height < 0)) return;
 123 
 124         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 125         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
 126             surfaceData.doRoundRect(this, sg2d, x, y, width, height, arcWidth, arcHeight, false);
 127         } else {
 128             if (roundrectToShape == null) {
 129                 synchronized (this) {
 130                     if (roundrectToShape == null) {
 131                         roundrectToShape = new RoundRectangle2D.Float();
 132                     }
 133                 }
 134             }
 135             synchronized (roundrectToShape) {
 136                 roundrectToShape.setRoundRect(x, y, width, height, arcWidth, arcHeight);
 137                 drawfillShape(sg2d, sg2d.stroke.createStrokedShape(roundrectToShape), true, true);
 138             }
 139         }
 140     }
 141 
 142     public void fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) {
 143         fillRoundRect(sg2d, (float) x, (float) y, (float) width, (float) height, (float) arcWidth, (float) arcHeight);
 144     }
 145 
 146     public void fillRoundRect(SunGraphics2D sg2d, float x, float y, float width, float height, float arcWidth, float arcHeight) {
 147         if ((width < 0) || (height < 0)) return;
 148         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 149         surfaceData.doRoundRect(this, sg2d, x, y, width, height, arcWidth, arcHeight, true);
 150     }
 151 
 152     native void doOval(SurfaceData sData, float x, float y, float width, float height, boolean isfill);
 153 
 154     public void drawOval(SunGraphics2D sg2d, int x, int y, int width, int height) {
 155         drawOval(sg2d, (float) x, (float) y, (float) width, (float) height);
 156     }
 157 
 158     Ellipse2D ovalToShape;
 159 
 160     public void drawOval(SunGraphics2D sg2d, float x, float y, float width, float height) {
 161         if ((width < 0) || (height < 0)) return;
 162 
 163         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 164         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
 165             surfaceData.doOval(this, sg2d, x, y, width, height, false);
 166         } else {
 167             if (ovalToShape == null) {
 168                 synchronized (this) {
 169                     if (ovalToShape == null) {
 170                         ovalToShape = new Ellipse2D.Float();
 171                     }
 172                 }
 173             }
 174             synchronized (ovalToShape) {
 175                 ovalToShape.setFrame(x, y, width, height);
 176                 drawfillShape(sg2d, sg2d.stroke.createStrokedShape(ovalToShape), true, true);
 177             }
 178         }
 179     }
 180 
 181     public void fillOval(SunGraphics2D sg2d, int x, int y, int width, int height) {
 182         fillOval(sg2d, (float) x, (float) y, (float) width, (float) height);
 183     }
 184 
 185     public void fillOval(SunGraphics2D sg2d, float x, float y, float width, float height) {
 186         if ((width < 0) || (height < 0)) return;
 187         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 188         surfaceData.doOval(this, sg2d, x, y, width, height, true);
 189     }
 190 
 191     native void doArc(SurfaceData sData, float x, float y, float width, float height, float angleStart, float angleExtent, int type, boolean isfill);
 192 
 193     public void drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) {
 194         drawArc(sg2d, x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
 195     }
 196 
 197     Arc2D arcToShape;
 198 
 199     public void drawArc(SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type) {
 200         if ((width < 0) || (height < 0)) return;
 201 
 202         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 203         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
 204             surfaceData.doArc(this, sg2d, x, y, width, height, startAngle, arcAngle, type, false);
 205         } else {
 206             if (arcToShape == null) {
 207                 synchronized (this) {
 208                     if (arcToShape == null) {
 209                         arcToShape = new Arc2D.Float();
 210                     }
 211                 }
 212             }
 213             synchronized (arcToShape) {
 214                 arcToShape.setArc(x, y, width, height, startAngle, arcAngle, type);
 215                 drawfillShape(sg2d, sg2d.stroke.createStrokedShape(arcToShape), true, true);
 216             }
 217         }
 218     }
 219 
 220     public void fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) {
 221         fillArc(sg2d, x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
 222     }
 223 
 224     public void fillArc(SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type) {
 225         if ((width < 0) || (height < 0)) return;
 226 
 227         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 228         surfaceData.doArc(this, sg2d, x, y, width, height, startAngle, arcAngle, type, true);
 229     }
 230 
 231     native void doPoly(SurfaceData sData, int[] xpoints, int[] ypoints, int npoints, boolean ispolygon, boolean isfill);
 232 
 233     public void drawPolyline(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
 234         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 235         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
 236             surfaceData.doPolygon(this, sg2d, xpoints, ypoints, npoints, false, false);
 237         } else {
 238             GeneralPath polyToShape = new GeneralPath();
 239             polyToShape.moveTo(xpoints[0], ypoints[0]);
 240             for (int i = 1; i < npoints; i++) {
 241                 polyToShape.lineTo(xpoints[i], ypoints[i]);
 242             }
 243             drawfillShape(sg2d, sg2d.stroke.createStrokedShape(polyToShape), true, true);
 244         }
 245     }
 246 
 247     public void drawPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
 248         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 249         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
 250             surfaceData.doPolygon(this, sg2d, xpoints, ypoints, npoints, true, false);
 251         } else {
 252             GeneralPath polyToShape = new GeneralPath();
 253             polyToShape.moveTo(xpoints[0], ypoints[0]);
 254             for (int i = 1; i < npoints; i++) {
 255                 polyToShape.lineTo(xpoints[i], ypoints[i]);
 256             }
 257             polyToShape.lineTo(xpoints[0], ypoints[0]);
 258             drawfillShape(sg2d, sg2d.stroke.createStrokedShape(polyToShape), true, true);
 259         }
 260     }
 261 
 262     public void fillPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
 263         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 264         surfaceData.doPolygon(this, sg2d, xpoints, ypoints, npoints, true, true);
 265     }
 266 
 267     native void doShape(SurfaceData sData, int length, FloatBuffer coordinates, IntBuffer types, int windingRule, boolean isfill, boolean shouldApplyOffset);
 268 
 269     void drawfillShape(SunGraphics2D sg2d, Shape s, boolean isfill, boolean shouldApplyOffset) {
 270         if (s == null) { throw new NullPointerException(); }
 271 
 272         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 273         // TODO:
 274         boolean sOptimizeShapes = true;
 275         if (sOptimizeShapes && OSXSurfaceData.IsSimpleColor(sg2d.paint)) {
 276             if (s instanceof Rectangle2D) {
 277                 Rectangle2D rectangle = (Rectangle2D) s;
 278 
 279                 float x = (float) rectangle.getX();
 280                 float y = (float) rectangle.getY();
 281                 float w = (float) rectangle.getWidth();
 282                 float h = (float) rectangle.getHeight();
 283                 if (isfill) {
 284                     fillRect(sg2d, x, y, w, h);
 285                 } else {
 286                     drawRect(sg2d, x, y, w, h);
 287                 }
 288             } else if (s instanceof Ellipse2D) {
 289                 Ellipse2D ellipse = (Ellipse2D) s;
 290 
 291                 float x = (float) ellipse.getX();
 292                 float y = (float) ellipse.getY();
 293                 float w = (float) ellipse.getWidth();
 294                 float h = (float) ellipse.getHeight();
 295 
 296                 if (isfill) {
 297                     fillOval(sg2d, x, y, w, h);
 298                 } else {
 299                     drawOval(sg2d, x, y, w, h);
 300                 }
 301             } else if (s instanceof Arc2D) {
 302                 Arc2D arc = (Arc2D) s;
 303 
 304                 float x = (float) arc.getX();
 305                 float y = (float) arc.getY();
 306                 float w = (float) arc.getWidth();
 307                 float h = (float) arc.getHeight();
 308                 float as = (float) arc.getAngleStart();
 309                 float ae = (float) arc.getAngleExtent();
 310 
 311                 if (isfill) {
 312                     fillArc(sg2d, x, y, w, h, as, ae, arc.getArcType());
 313                 } else {
 314                     drawArc(sg2d, x, y, w, h, as, ae, arc.getArcType());
 315                 }
 316             } else if (s instanceof RoundRectangle2D) {
 317                 RoundRectangle2D roundrect = (RoundRectangle2D) s;
 318 
 319                 float x = (float) roundrect.getX();
 320                 float y = (float) roundrect.getY();
 321                 float w = (float) roundrect.getWidth();
 322                 float h = (float) roundrect.getHeight();
 323                 float aw = (float) roundrect.getArcWidth();
 324                 float ah = (float) roundrect.getArcHeight();
 325 
 326                 if (isfill) {
 327                     fillRoundRect(sg2d, x, y, w, h, aw, ah);
 328                 } else {
 329                     drawRoundRect(sg2d, x, y, w, h, aw, ah);
 330                 }
 331             } else if (s instanceof Line2D) {
 332                 Line2D line = (Line2D) s;
 333 
 334                 float x1 = (float) line.getX1();
 335                 float y1 = (float) line.getY1();
 336                 float x2 = (float) line.getX2();
 337                 float y2 = (float) line.getY2();
 338 
 339                 drawLine(sg2d, x1, y1, x2, y2);
 340             } else if (s instanceof Point2D) {
 341                 Point2D point = (Point2D) s;
 342 
 343                 float x = (float) point.getX();
 344                 float y = (float) point.getY();
 345 
 346                 drawLine(sg2d, x, y, x, y);
 347             } else {
 348                 GeneralPath gp;
 349 
 350                 if (s instanceof GeneralPath) {
 351                     gp = (GeneralPath) s;
 352                 } else {
 353                     gp = new GeneralPath(s);
 354                 }
 355 
 356                 PathIterator pi = gp.getPathIterator(null);
 357                 if (pi.isDone() == false) {
 358                     surfaceData.drawfillShape(this, sg2d, gp, isfill, shouldApplyOffset);
 359                 }
 360             }
 361         } else {
 362             GeneralPath gp;
 363 
 364             if (s instanceof GeneralPath) {
 365                 gp = (GeneralPath) s;
 366             } else {
 367                 gp = new GeneralPath(s);
 368             }
 369 
 370             PathIterator pi = gp.getPathIterator(null);
 371             if (pi.isDone() == false) {
 372                 surfaceData.drawfillShape(this, sg2d, gp, isfill, shouldApplyOffset);
 373             }
 374         }
 375     }
 376 
 377     public void draw(SunGraphics2D sg2d, Shape s) {
 378         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 379         if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
 380             drawfillShape(sg2d, s, false, true);
 381         } else {
 382             drawfillShape(sg2d, sg2d.stroke.createStrokedShape(s), true, true);
 383         }
 384     }
 385 
 386     public void fill(SunGraphics2D sg2d, Shape s) {
 387         drawfillShape(sg2d, s, true, false);
 388     }
 389 
 390     native void doImage(SurfaceData sData, SurfaceData img, boolean fliph, boolean flipv, int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh);
 391 
 392     // Copy img to scaled sg2d @ x,y with width height
 393     public boolean scaleImage(SunGraphics2D sg2d, Image img, int x, int y, int width, int height, Color bgColor) {
 394         OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
 395 
 396         int sx = 0;
 397         int sy = 0;
 398         int iw = img.getWidth(null);
 399         int ih = img.getHeight(null);
 400 
 401         return scaleImage(sg2d, img, x, y, x + width, y + height, sx, sy, sx + iw, sy + ih, bgColor);
 402     }
 403 
 404     // Copy img, clipped to sx1, sy1 by sx2, sy2 to dx1, dy2 by dx2, dy2
 405     public boolean scaleImage(SunGraphics2D sg2d, Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgColor) {
 406 
 407         // System.err.println("scaleImage");
 408         // System.err.println("    sx1="+sx1+", sy1="+sy1+", sx2="+sx2+", sy2="+sy2);
 409         // System.err.println("    dx1="+dx1+", dy1="+dy1+", dx2="+dx2+", dy2="+dy2);
 410 
 411         int srcW, srcH, dstW, dstH;
 412         int srcX, srcY, dstX, dstY;
 413         boolean srcWidthFlip = false;
 414         boolean srcHeightFlip = false;
 415         boolean dstWidthFlip = false;
 416         boolean dstHeightFlip = false;
 417 
 418         if (sx2 > sx1) {
 419             srcW = sx2 - sx1;
 420             srcX = sx1;
 421         } else {
 422             srcWidthFlip = true;
 423             srcW = sx1 - sx2;
 424             srcX = sx2;
 425         }
 426         if (sy2 > sy1) {
 427             srcH = sy2 - sy1;
 428             srcY = sy1;
 429         } else {
 430             srcHeightFlip = true;
 431             srcH = sy1 - sy2;
 432             srcY = sy2;
 433         }
 434         if (dx2 > dx1) {
 435             dstW = dx2 - dx1;
 436             dstX = dx1;
 437         } else {
 438             dstW = dx1 - dx2;
 439             dstWidthFlip = true;
 440             dstX = dx2;
 441         }
 442         if (dy2 > dy1) {
 443             dstH = dy2 - dy1;
 444             dstY = dy1;
 445         } else {
 446             dstH = dy1 - dy2;
 447             dstHeightFlip = true;
 448             dstY = dy2;
 449         }
 450         if (srcW <= 0 || srcH <= 0) { return true; }
 451 
 452         boolean flipv = (srcHeightFlip != dstHeightFlip);
 453         boolean fliph = (srcWidthFlip != dstWidthFlip);
 454 
 455         return blitImage(sg2d, img, fliph, flipv, srcX, srcY, srcW, srcH, dstX, dstY, dstW, dstH, bgColor);
 456     }
 457 
 458     protected boolean blitImage(SunGraphics2D sg2d, Image img, boolean fliph, boolean flipv, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, Color bgColor) {
 459         CPrinterSurfaceData surfaceData = (CPrinterSurfaceData)sg2d.getSurfaceData();
 460         OSXOffScreenSurfaceData imgSurfaceData = (OSXOffScreenSurfaceData) OSXOffScreenSurfaceData.createNewSurface((BufferedImage)img);
 461         surfaceData.blitImage(this, sg2d, imgSurfaceData, fliph, flipv, sx, sy, sw, sh, dx, dy, dw, dh, bgColor);
 462         return true;
 463     }
 464 
 465     // Copy img to sg2d @ x, y
 466     protected boolean copyImage(SunGraphics2D sg2d, Image img, int dx, int dy, Color bgColor) {
 467         if (img == null) { return true; }
 468 
 469         int sx = 0;
 470         int sy = 0;
 471         int width = img.getWidth(null);
 472         int height = img.getHeight(null);
 473 
 474         return blitImage(sg2d, img, false, false, sx, sy, width, height, dx, dy, width, height, bgColor);
 475     }
 476 
 477     // Copy img, clipped to sx, sy with width, height to sg2d @ dx, dy
 478     protected boolean copyImage(SunGraphics2D sg2d, Image img, int dx, int dy, int sx, int sy, int width, int height, Color bgColor) {
 479         return blitImage(sg2d, img, false, false, sx, sy, width, height, dx, dy, width, height, bgColor);
 480     }
 481 
 482     protected void transformImage(SunGraphics2D sg2d, Image img, int x, int y, BufferedImageOp op, AffineTransform xf, Color bgColor) {
 483         if (img != null) {
 484             int iw = img.getWidth(null);
 485             int ih = img.getHeight(null);
 486 
 487             if ((op != null) && (img instanceof BufferedImage)) {
 488                 if (((BufferedImage) img).getType() == BufferedImage.TYPE_CUSTOM) {
 489                     // BufferedImageOp can not handle custom images
 490                     BufferedImage dest = null;
 491                     dest = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_ARGB_PRE);
 492                     Graphics g = dest.createGraphics();
 493                     g.drawImage(img, 0, 0, null);
 494                     g.dispose();
 495                     img = op.filter(dest, null);
 496                 } else {
 497                     // sun.awt.image.BufImgSurfaceData.createData((BufferedImage)img).finishLazyDrawing();
 498                     img = op.filter((BufferedImage) img, null);
 499                 }
 500 
 501                 iw = img.getWidth(null);
 502                 ih = img.getHeight(null);
 503             }
 504 
 505             if (xf != null) {
 506                 AffineTransform reset = sg2d.getTransform();
 507                 sg2d.transform(xf);
 508                 scaleImage(sg2d, img, x, y, x + iw, y + ih, 0, 0, iw, ih, bgColor);
 509                 sg2d.setTransform(reset);
 510             } else {
 511                 scaleImage(sg2d, img, x, y, x + iw, y + ih, 0, 0, iw, ih, bgColor);
 512             }
 513         } else {
 514             throw new NullPointerException();
 515         }
 516     }
 517 
 518     // copied from DrawImage.java
 519     protected boolean imageReady(sun.awt.image.ToolkitImage sunimg, ImageObserver observer) {
 520         if (sunimg.hasError()) {
 521             if (observer != null) {
 522                 observer.imageUpdate(sunimg, ImageObserver.ERROR | ImageObserver.ABORT, -1, -1, -1, -1);
 523             }
 524             return false;
 525         }
 526         return true;
 527     }
 528 
 529     // copied from DrawImage.java
 530     public boolean copyImage(SunGraphics2D sg2d, Image img, int x, int y, Color bgColor, ImageObserver observer) {
 531         if (img == null) { throw new NullPointerException(); }
 532 
 533         if (!(img instanceof sun.awt.image.ToolkitImage)) { return copyImage(sg2d, img, x, y, bgColor); }
 534 
 535         sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
 536         if (!imageReady(sunimg, observer)) { return false; }
 537         ImageRepresentation ir = sunimg.getImageRep();
 538         return ir.drawToBufImage(sg2d, sunimg, x, y, bgColor, observer);
 539     }
 540 
 541     // copied from DrawImage.java
 542     public boolean copyImage(SunGraphics2D sg2d, Image img, int dx, int dy, int sx, int sy, int width, int height, Color bgColor, ImageObserver observer) {
 543         if (img == null) { throw new NullPointerException(); }
 544 
 545         if (!(img instanceof sun.awt.image.ToolkitImage)) { return copyImage(sg2d, img, dx, dy, sx, sy, width, height, bgColor); }
 546 
 547         sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
 548         if (!imageReady(sunimg, observer)) { return false; }
 549         ImageRepresentation ir = sunimg.getImageRep();
 550         return ir.drawToBufImage(sg2d, sunimg, dx, dy, (dx + width), (dy + height), sx, sy, (sx + width), (sy + height), null, observer);
 551     }
 552 
 553     // copied from DrawImage.java
 554     public boolean scaleImage(SunGraphics2D sg2d, Image img, int x, int y, int width, int height, Color bgColor, ImageObserver observer) {
 555         if (img == null) { throw new NullPointerException(); }
 556 
 557         if (!(img instanceof sun.awt.image.ToolkitImage)) { return scaleImage(sg2d, img, x, y, width, height, bgColor); }
 558 
 559         sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
 560         if (!imageReady(sunimg, observer)) { return false; }
 561         ImageRepresentation ir = sunimg.getImageRep();
 562         return ir.drawToBufImage(sg2d, sunimg, x, y, width, height, bgColor, observer);
 563     }
 564 
 565     // copied from DrawImage.java
 566     public boolean scaleImage(SunGraphics2D sg2d, Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgColor, ImageObserver observer) {
 567         if (img == null) { throw new NullPointerException(); }
 568 
 569         if (!(img instanceof sun.awt.image.ToolkitImage)) { return scaleImage(sg2d, img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgColor); }
 570 
 571         sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
 572         if (!imageReady(sunimg, observer)) { return false; }
 573         ImageRepresentation ir = sunimg.getImageRep();
 574         return ir.drawToBufImage(sg2d, sunimg, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgColor, observer);
 575     }
 576 
 577     // copied from DrawImage.java
 578     public boolean transformImage(SunGraphics2D sg2d, Image img, AffineTransform atfm, ImageObserver observer) {
 579         if (img == null) { throw new NullPointerException(); }
 580 
 581         if (!(img instanceof sun.awt.image.ToolkitImage)) {
 582             transformImage(sg2d, img, 0, 0, null, atfm, null);
 583             return true;
 584         }
 585 
 586         sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
 587         if (!imageReady(sunimg, observer)) { return false; }
 588         ImageRepresentation ir = sunimg.getImageRep();
 589         return ir.drawToBufImage(sg2d, sunimg, atfm, observer);
 590     }
 591 
 592     // copied from DrawImage.java
 593     public void transformImage(SunGraphics2D sg2d, BufferedImage img, BufferedImageOp op, int x, int y) {
 594         if (img != null) {
 595             transformImage(sg2d, img, x, y, op, null, null);
 596         } else {
 597             throw new NullPointerException();
 598         }
 599     }
 600 
 601     public CRenderer traceWrap() {
 602         return new Tracer();
 603     }
 604 
 605     public static class Tracer extends CRenderer {
 606         void doLine(SurfaceData sData, float x1, float y1, float x2, float y2) {
 607             GraphicsPrimitive.tracePrimitive("QuartzLine");
 608             super.doLine(sData, x1, y1, x2, y2);
 609         }
 610 
 611         void doRect(SurfaceData sData, float x, float y, float width, float height, boolean isfill) {
 612             GraphicsPrimitive.tracePrimitive("QuartzRect");
 613             super.doRect(sData, x, y, width, height, isfill);
 614         }
 615 
 616         void doRoundRect(SurfaceData sData, float x, float y, float width, float height, float arcW, float arcH, boolean isfill) {
 617             GraphicsPrimitive.tracePrimitive("QuartzRoundRect");
 618             super.doRoundRect(sData, x, y, width, height, arcW, arcH, isfill);
 619         }
 620 
 621         void doOval(SurfaceData sData, float x, float y, float width, float height, boolean isfill) {
 622             GraphicsPrimitive.tracePrimitive("QuartzOval");
 623             super.doOval(sData, x, y, width, height, isfill);
 624         }
 625 
 626         void doArc(SurfaceData sData, float x, float y, float width, float height, float angleStart, float angleExtent, int type, boolean isfill) {
 627             GraphicsPrimitive.tracePrimitive("QuartzArc");
 628             super.doArc(sData, x, y, width, height, angleStart, angleExtent, type, isfill);
 629         }
 630 
 631         void doPoly(SurfaceData sData, int[] xpoints, int[] ypoints, int npoints, boolean ispolygon, boolean isfill) {
 632             GraphicsPrimitive.tracePrimitive("QuartzDoPoly");
 633             super.doPoly(sData, xpoints, ypoints, npoints, ispolygon, isfill);
 634         }
 635 
 636         void doShape(SurfaceData sData, int length, FloatBuffer coordinates, IntBuffer types, int windingRule, boolean isfill, boolean shouldApplyOffset) {
 637             GraphicsPrimitive.tracePrimitive("QuartzFillOrDrawShape");
 638             super.doShape(sData, length, coordinates, types, windingRule, isfill, shouldApplyOffset);
 639         }
 640 
 641         void doImage(SurfaceData sData, SurfaceData img, boolean fliph, boolean flipv, int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh) {
 642             GraphicsPrimitive.tracePrimitive("QuartzDrawImage");
 643             super.doImage(sData, img, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh);
 644         }
 645     }
 646 }