changeset 4772:ee9c8c9b5c2e

Printing support : http://java.net/jira/browse/MACOSX_PORT-34
author bino@apple.com
date Fri, 23 Sep 2011 13:42:06 -0700
parents 11f49dd9ab86
children 6c09aa87feaf
files make/sun/lwawt/FILES_c_macosx.gmk make/sun/lwawt/FILES_export_macosx.gmk src/macosx/classes/sun/awt/CGraphicsEnvironment.java src/macosx/classes/sun/java2d/CRenderer.java src/macosx/classes/sun/java2d/CompositeCRenderer.java src/macosx/classes/sun/java2d/DataBufferNIOInt.java src/macosx/classes/sun/java2d/IntegerNIORaster.java src/macosx/classes/sun/java2d/OSXOffScreenSurfaceData.java src/macosx/classes/sun/java2d/OSXSurfaceData.java src/macosx/classes/sun/lwawt/LWComponentPeer.java src/macosx/classes/sun/lwawt/LWToolkit.java src/macosx/classes/sun/lwawt/macosx/CPrinterDevice.java src/macosx/classes/sun/lwawt/macosx/CPrinterDialog.java src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java src/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java src/macosx/classes/sun/lwawt/macosx/CPrinterGraphicsConfig.java src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java src/macosx/classes/sun/lwawt/macosx/CPrinterJobDialog.java src/macosx/classes/sun/lwawt/macosx/CPrinterPageDialog.java src/macosx/classes/sun/lwawt/macosx/CPrinterSurfaceData.java src/macosx/classes/sun/lwawt/macosx/CTextPipe.java src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java src/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java src/macosx/native/sun/awt/AWTWindow.m src/macosx/native/sun/awt/AWT_debug.h src/macosx/native/sun/awt/CDropTarget.m src/macosx/native/sun/awt/CPrinterJob.m src/macosx/native/sun/awt/CTextPipe.m src/macosx/native/sun/awt/ImageSurfaceData.h src/macosx/native/sun/awt/ImageSurfaceData.m src/macosx/native/sun/awt/PrintModel.h src/macosx/native/sun/awt/PrintModel.m src/macosx/native/sun/awt/PrinterSurfaceData.h src/macosx/native/sun/awt/PrinterSurfaceData.m src/macosx/native/sun/awt/PrinterView.h src/macosx/native/sun/awt/PrinterView.m src/macosx/native/sun/awt/QuartzRenderer.m src/macosx/native/sun/awt/QuartzSurfaceData.h src/macosx/native/sun/awt/QuartzSurfaceData.m src/macosx/native/sun/font/CoreTextSupport.h src/macosx/native/sun/font/CoreTextSupport.m src/share/classes/java/awt/EventDispatchThread.java src/share/classes/sun/awt/image/BufImgSurfaceData.java src/share/classes/sun/java2d/SunGraphics2D.java src/share/classes/sun/print/PrintJob2D.java src/share/classes/sun/print/RasterPrinterJob.java src/solaris/native/java/lang/java_props_md.c
diffstat 47 files changed, 11086 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/lwawt/FILES_c_macosx.gmk	Fri Sep 23 21:13:13 2011 +0400
+++ b/make/sun/lwawt/FILES_c_macosx.gmk	Fri Sep 23 13:42:06 2011 -0700
@@ -71,7 +71,15 @@
         LWCToolkit.m \
         ThreadUtilities.m \
         GeomUtilities.m \
-        PropertiesUtilities.m
+        PropertiesUtilities.m \
+        CPrinterJob.m \
+        PrintModel.m \
+        PrinterSurfaceData.m \
+        PrinterView.m \
+        QuartzSurfaceData.m \
+        QuartzRenderer.m \
+        CTextPipe.m \
+        ImageSurfaceData.m
 
 FILES_c = \
         OGLBlitLoops.c \
--- a/make/sun/lwawt/FILES_export_macosx.gmk	Fri Sep 23 21:13:13 2011 +0400
+++ b/make/sun/lwawt/FILES_export_macosx.gmk	Fri Sep 23 13:42:06 2011 -0700
@@ -38,6 +38,12 @@
         sun/awt/image/ImageRepresentation.java \
         sun/awt/image/GifImageDecoder.java \
         sun/awt/image/NativeLibLoader.java \
+        sun/java2d/CRenderer.java \
+        sun/java2d/CompositeCRenderer.java \
+        sun/java2d/DataBufferNIOInt.java \
+        sun/java2d/IntegerNIORaster.java \
+        sun/java2d/OSXSurfaceData.java \
+        sun/java2d/OSXOffScreenSurfaceData.java \
         sun/java2d/loops/Blit.java \
         sun/java2d/loops/BlitBg.java \
         sun/java2d/loops/ScaledBlit.java \
@@ -101,6 +107,19 @@
         sun/lwawt/LWWindowPeer.java \
         sun/lwawt/PlatformWindow.java \
         sun/lwawt/SelectionClearListener.java \
+        sun/lwawt/macosx/CPrinterDevice.java \
+        sun/lwawt/macosx/CPrinterDialog.java \
+        sun/lwawt/macosx/CPrinterDialogPeer.java \
+        sun/lwawt/macosx/CPrinterGraphics.java \
+        sun/lwawt/macosx/CPrinterGraphicsConfig.java \
+        sun/lwawt/macosx/CPrinterJob.java \
+        sun/lwawt/macosx/CPrinterJobDialog.java \
+        sun/lwawt/macosx/CPrinterPageDialog.java \
+        sun/lwawt/macosx/CPrinterSurfaceData.java \
+        sun/lwawt/macosx/CTextPipe.java \
+        sun/java2d/CRenderer.java \
+        sun/lwawt/macosx/EventDispatchAccess.java \
+        sun/lwawt/macosx/NSPrintInfo.java \
         sun/lwawt/macosx/CAccessibility.java \
         sun/lwawt/macosx/CAccessible.java \
         sun/lwawt/macosx/CFRetainedResource.java \
@@ -166,7 +185,7 @@
         sun/java2d/opengl/OGLTextRenderer.java \
         sun/java2d/opengl/CGLGraphicsConfig.java \
         sun/java2d/opengl/CGLSurfaceData.java \
-        sun/awt/ExtendedKeyCodes.java
+        sun/awt/ExtendedKeyCodes.java 
 
 FILES_export2 = \
         java/awt/AlphaComposite.java \
@@ -244,4 +263,8 @@
         java/awt/event/NativeLibLoader.java \
         java/awt/peer/ComponentPeer.java \
         java/awt/dnd/DnDConstants.java \
-        sun/awt/CausedFocusEvent.java
+        sun/awt/CausedFocusEvent.java \
+        java/awt/print/PageFormat.java \
+        java/awt/print/Pageable.java \
+        java/awt/print/Printable.java \
+        java/awt/BasicStroke.java
--- a/src/macosx/classes/sun/awt/CGraphicsEnvironment.java	Fri Sep 23 21:13:13 2011 +0400
+++ b/src/macosx/classes/sun/awt/CGraphicsEnvironment.java	Fri Sep 23 13:42:06 2011 -0700
@@ -26,6 +26,7 @@
 package sun.awt;
 
 import java.awt.*;
+import java.awt.print.*;
 import java.util.*;
 
 import sun.java2d.*;
@@ -191,4 +192,5 @@
         }
         return allFontsWithLogical;
     }
+    
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/java2d/CRenderer.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.nio.*;
+
+import sun.awt.image.*;
+import sun.java2d.loops.*;
+import sun.java2d.pipe.*;
+import sun.lwawt.macosx.*;
+
+public class CRenderer implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, DrawImagePipe {
+    native static void init();
+    
+    // cache of the runtime options
+    static {
+        init(); // initialize coordinate tables for shapes
+    }
+    
+    native void doLine(SurfaceData sData, float x1, float y1, float x2, float y2);
+    
+    public void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) {
+        drawLine(sg2d, (float) x1, (float) y1, (float) x2, (float) y2);
+    }
+    
+    Line2D lineToShape;
+    
+    public void drawLine(SunGraphics2D sg2d, float x1, float y1, float x2, float y2) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doLine(this, sg2d, x1, y1, x2, y2);
+        } else {
+            if (lineToShape == null) {
+                synchronized (this) {
+                    if (lineToShape == null) {
+                        lineToShape = new Line2D.Float();
+                    }
+                }
+            }
+            synchronized (lineToShape) {
+                lineToShape.setLine(x1, y1, x2, y2);
+                drawfillShape(sg2d, sg2d.stroke.createStrokedShape(lineToShape), true, true);
+            }
+        }
+    }
+    
+    native void doRect(SurfaceData sData, float x, float y, float width, float height, boolean isfill);
+    
+    public void drawRect(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        drawRect(sg2d, (float) x, (float) y, (float) width, (float) height);
+    }
+    
+    Rectangle2D rectToShape;
+    
+    public void drawRect(SunGraphics2D sg2d, float x, float y, float width, float height) {
+        if ((width < 0) || (height < 0)) return;
+        
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doRect(this, sg2d, x, y, width, height, false);
+        } else {
+            if (rectToShape == null) {
+                synchronized (this) {
+                    if (rectToShape == null) {
+                        rectToShape = new Rectangle2D.Float();
+                    }
+                }
+            }
+            synchronized (rectToShape) {
+                rectToShape.setRect(x, y, width, height);
+                drawfillShape(sg2d, sg2d.stroke.createStrokedShape(rectToShape), true, true);
+            }
+        }
+    }
+    
+    public void fillRect(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        fillRect(sg2d, (float) x, (float) y, (float) width, (float) height);
+    }
+    
+    public void fillRect(SunGraphics2D sg2d, float x, float y, float width, float height) {
+        if ((width >= 0) && (height >= 0)) {
+            OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+            surfaceData.doRect(this, sg2d, x, y, width, height, true);
+        }
+    }
+    
+    native void doRoundRect(SurfaceData sData, float x, float y, float width, float height, float arcW, float arcH, boolean isfill);
+    
+    public void drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        drawRoundRect(sg2d, (float) x, (float) y, (float) width, (float) height, (float) arcWidth, (float) arcHeight);
+    }
+    
+    RoundRectangle2D roundrectToShape;
+    
+    public void drawRoundRect(SunGraphics2D sg2d, float x, float y, float width, float height, float arcWidth, float arcHeight) {
+        if ((width < 0) || (height < 0)) return;
+        
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doRoundRect(this, sg2d, x, y, width, height, arcWidth, arcHeight, false);
+        } else {
+            if (roundrectToShape == null) {
+                synchronized (this) {
+                    if (roundrectToShape == null) {
+                        roundrectToShape = new RoundRectangle2D.Float();
+                    }
+                }
+            }
+            synchronized (roundrectToShape) {
+                roundrectToShape.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+                drawfillShape(sg2d, sg2d.stroke.createStrokedShape(roundrectToShape), true, true);
+            }
+        }
+    }
+    
+    public void fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        fillRoundRect(sg2d, (float) x, (float) y, (float) width, (float) height, (float) arcWidth, (float) arcHeight);
+    }
+    
+    public void fillRoundRect(SunGraphics2D sg2d, float x, float y, float width, float height, float arcWidth, float arcHeight) {
+        if ((width < 0) || (height < 0)) return;
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        surfaceData.doRoundRect(this, sg2d, x, y, width, height, arcWidth, arcHeight, true);
+    }
+    
+    native void doOval(SurfaceData sData, float x, float y, float width, float height, boolean isfill);
+    
+    public void drawOval(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        drawOval(sg2d, (float) x, (float) y, (float) width, (float) height);
+    }
+    
+    Ellipse2D ovalToShape;
+    
+    public void drawOval(SunGraphics2D sg2d, float x, float y, float width, float height) {
+        if ((width < 0) || (height < 0)) return;
+        
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doOval(this, sg2d, x, y, width, height, false);
+        } else {
+            if (ovalToShape == null) {
+                synchronized (this) {
+                    if (ovalToShape == null) {
+                        ovalToShape = new Ellipse2D.Float();
+                    }
+                }
+            }
+            synchronized (ovalToShape) {
+                ovalToShape.setFrame(x, y, width, height);
+                drawfillShape(sg2d, sg2d.stroke.createStrokedShape(ovalToShape), true, true);
+            }
+        }
+    }
+    
+    public void fillOval(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        fillOval(sg2d, (float) x, (float) y, (float) width, (float) height);
+    }
+    
+    public void fillOval(SunGraphics2D sg2d, float x, float y, float width, float height) {
+        if ((width < 0) || (height < 0)) return;
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        surfaceData.doOval(this, sg2d, x, y, width, height, true);
+    }
+    
+    native void doArc(SurfaceData sData, float x, float y, float width, float height, float angleStart, float angleExtent, int type, boolean isfill);
+    
+    public void drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) {
+        drawArc(sg2d, x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
+    }
+    
+    Arc2D arcToShape;
+    
+    public void drawArc(SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type) {
+        if ((width < 0) || (height < 0)) return;
+        
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doArc(this, sg2d, x, y, width, height, startAngle, arcAngle, type, false);
+        } else {
+            if (arcToShape == null) {
+                synchronized (this) {
+                    if (arcToShape == null) {
+                        arcToShape = new Arc2D.Float();
+                    }
+                }
+            }
+            synchronized (arcToShape) {
+                arcToShape.setArc(x, y, width, height, startAngle, arcAngle, type);
+                drawfillShape(sg2d, sg2d.stroke.createStrokedShape(arcToShape), true, true);
+            }
+        }
+    }
+    
+    public void fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) {
+        fillArc(sg2d, x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
+    }
+    
+    public void fillArc(SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type) {
+        if ((width < 0) || (height < 0)) return;
+        
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        surfaceData.doArc(this, sg2d, x, y, width, height, startAngle, arcAngle, type, true);
+    }
+    
+    native void doPoly(SurfaceData sData, int[] xpoints, int[] ypoints, int npoints, boolean ispolygon, boolean isfill);
+    
+    public void drawPolyline(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doPolygon(this, sg2d, xpoints, ypoints, npoints, false, false);
+        } else {
+            GeneralPath polyToShape = new GeneralPath();
+            polyToShape.moveTo(xpoints[0], ypoints[0]);
+            for (int i = 1; i < npoints; i++) {
+                polyToShape.lineTo(xpoints[i], ypoints[i]);
+            }
+            drawfillShape(sg2d, sg2d.stroke.createStrokedShape(polyToShape), true, true);
+        }
+    }
+    
+    public void drawPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            surfaceData.doPolygon(this, sg2d, xpoints, ypoints, npoints, true, false);
+        } else {
+            GeneralPath polyToShape = new GeneralPath();
+            polyToShape.moveTo(xpoints[0], ypoints[0]);
+            for (int i = 1; i < npoints; i++) {
+                polyToShape.lineTo(xpoints[i], ypoints[i]);
+            }
+            polyToShape.lineTo(xpoints[0], ypoints[0]);
+            drawfillShape(sg2d, sg2d.stroke.createStrokedShape(polyToShape), true, true);
+        }
+    }
+    
+    public void fillPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        surfaceData.doPolygon(this, sg2d, xpoints, ypoints, npoints, true, true);
+    }
+    
+    native void doShape(SurfaceData sData, int length, FloatBuffer coordinates, IntBuffer types, int windingRule, boolean isfill, boolean shouldApplyOffset);
+    
+    void drawfillShape(SunGraphics2D sg2d, Shape s, boolean isfill, boolean shouldApplyOffset) {
+        if (s == null) { throw new NullPointerException(); }
+        
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        // TODO:
+        boolean sOptimizeShapes = true;
+        if (sOptimizeShapes && OSXSurfaceData.IsSimpleColor(sg2d.paint)) {
+            if (s instanceof Rectangle2D) {
+                Rectangle2D rectangle = (Rectangle2D) s;
+                
+                float x = (float) rectangle.getX();
+                float y = (float) rectangle.getY();
+                float w = (float) rectangle.getWidth();
+                float h = (float) rectangle.getHeight();
+                if (isfill) {
+                    fillRect(sg2d, x, y, w, h);
+                } else {
+                    drawRect(sg2d, x, y, w, h);
+                }
+            } else if (s instanceof Ellipse2D) {
+                Ellipse2D ellipse = (Ellipse2D) s;
+                
+                float x = (float) ellipse.getX();
+                float y = (float) ellipse.getY();
+                float w = (float) ellipse.getWidth();
+                float h = (float) ellipse.getHeight();
+                
+                if (isfill) {
+                    fillOval(sg2d, x, y, w, h);
+                } else {
+                    drawOval(sg2d, x, y, w, h);
+                }
+            } else if (s instanceof Arc2D) {
+                Arc2D arc = (Arc2D) s;
+                
+                float x = (float) arc.getX();
+                float y = (float) arc.getY();
+                float w = (float) arc.getWidth();
+                float h = (float) arc.getHeight();
+                float as = (float) arc.getAngleStart();
+                float ae = (float) arc.getAngleExtent();
+                
+                if (isfill) {
+                    fillArc(sg2d, x, y, w, h, as, ae, arc.getArcType());
+                } else {
+                    drawArc(sg2d, x, y, w, h, as, ae, arc.getArcType());
+                }
+            } else if (s instanceof RoundRectangle2D) {
+                RoundRectangle2D roundrect = (RoundRectangle2D) s;
+                
+                float x = (float) roundrect.getX();
+                float y = (float) roundrect.getY();
+                float w = (float) roundrect.getWidth();
+                float h = (float) roundrect.getHeight();
+                float aw = (float) roundrect.getArcWidth();
+                float ah = (float) roundrect.getArcHeight();
+                
+                if (isfill) {
+                    fillRoundRect(sg2d, x, y, w, h, aw, ah);
+                } else {
+                    drawRoundRect(sg2d, x, y, w, h, aw, ah);
+                }
+            } else if (s instanceof Line2D) {
+                Line2D line = (Line2D) s;
+                
+                float x1 = (float) line.getX1();
+                float y1 = (float) line.getY1();
+                float x2 = (float) line.getX2();
+                float y2 = (float) line.getY2();
+                
+                drawLine(sg2d, x1, y1, x2, y2);
+            } else if (s instanceof Point2D) {
+                Point2D point = (Point2D) s;
+                
+                float x = (float) point.getX();
+                float y = (float) point.getY();
+                
+                drawLine(sg2d, x, y, x, y);
+            } else {
+                GeneralPath gp;
+                
+                if (s instanceof GeneralPath) {
+                    gp = (GeneralPath) s;
+                } else {
+                    gp = new GeneralPath(s);
+                }
+                
+                PathIterator pi = gp.getPathIterator(null);
+                if (pi.isDone() == false) {
+                    surfaceData.drawfillShape(this, sg2d, gp, isfill, shouldApplyOffset);
+                }
+            }
+        } else {
+            GeneralPath gp;
+            
+            if (s instanceof GeneralPath) {
+                gp = (GeneralPath) s;
+            } else {
+                gp = new GeneralPath(s);
+            }
+            
+            PathIterator pi = gp.getPathIterator(null);
+            if (pi.isDone() == false) {
+                surfaceData.drawfillShape(this, sg2d, gp, isfill, shouldApplyOffset);
+            }
+        }
+    }
+    
+    public void draw(SunGraphics2D sg2d, Shape s) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        if ((sg2d.strokeState != SunGraphics2D.STROKE_CUSTOM) && (OSXSurfaceData.IsSimpleColor(sg2d.paint))) {
+            drawfillShape(sg2d, s, false, true);
+        } else {
+            drawfillShape(sg2d, sg2d.stroke.createStrokedShape(s), true, true);
+        }
+    }
+    
+    public void fill(SunGraphics2D sg2d, Shape s) {
+        drawfillShape(sg2d, s, true, false);
+    }
+    
+    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);
+    
+    // Copy img to scaled sg2d @ x,y with width height
+    public boolean scaleImage(SunGraphics2D sg2d, Image img, int x, int y, int width, int height, Color bgColor) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        
+        int sx = 0;
+        int sy = 0;
+        int iw = img.getWidth(null);
+        int ih = img.getHeight(null);
+        
+        return scaleImage(sg2d, img, x, y, x + width, y + height, sx, sy, sx + iw, sy + ih, bgColor);
+    }
+    
+    // Copy img, clipped to sx1, sy1 by sx2, sy2 to dx1, dy2 by dx2, dy2
+    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) {
+        
+        // System.err.println("scaleImage");
+        // System.err.println("    sx1="+sx1+", sy1="+sy1+", sx2="+sx2+", sy2="+sy2);
+        // System.err.println("    dx1="+dx1+", dy1="+dy1+", dx2="+dx2+", dy2="+dy2);
+        
+        int srcW, srcH, dstW, dstH;
+        int srcX, srcY, dstX, dstY;
+        boolean srcWidthFlip = false;
+        boolean srcHeightFlip = false;
+        boolean dstWidthFlip = false;
+        boolean dstHeightFlip = false;
+        
+        if (sx2 > sx1) {
+            srcW = sx2 - sx1;
+            srcX = sx1;
+        } else {
+            srcWidthFlip = true;
+            srcW = sx1 - sx2;
+            srcX = sx2;
+        }
+        if (sy2 > sy1) {
+            srcH = sy2 - sy1;
+            srcY = sy1;
+        } else {
+            srcHeightFlip = true;
+            srcH = sy1 - sy2;
+            srcY = sy2;
+        }
+        if (dx2 > dx1) {
+            dstW = dx2 - dx1;
+            dstX = dx1;
+        } else {
+            dstW = dx1 - dx2;
+            dstWidthFlip = true;
+            dstX = dx2;
+        }
+        if (dy2 > dy1) {
+            dstH = dy2 - dy1;
+            dstY = dy1;
+        } else {
+            dstH = dy1 - dy2;
+            dstHeightFlip = true;
+            dstY = dy2;
+        }
+        if (srcW <= 0 || srcH <= 0) { return true; }
+        
+        boolean flipv = (srcHeightFlip != dstHeightFlip);
+        boolean fliph = (srcWidthFlip != dstWidthFlip);
+        
+        return blitImage(sg2d, img, fliph, flipv, srcX, srcY, srcW, srcH, dstX, dstY, dstW, dstH, bgColor);
+    }
+    
+    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) {
+        CPrinterSurfaceData surfaceData = (CPrinterSurfaceData)sg2d.getSurfaceData();
+        OSXOffScreenSurfaceData imgSurfaceData = (OSXOffScreenSurfaceData) OSXOffScreenSurfaceData.createNewSurface((BufferedImage)img);
+        surfaceData.blitImage(this, sg2d, imgSurfaceData, fliph, flipv, sx, sy, sw, sh, dx, dy, dw, dh, bgColor);
+        return true;
+    }
+    
+    // Copy img to sg2d @ x, y
+    protected boolean copyImage(SunGraphics2D sg2d, Image img, int dx, int dy, Color bgColor) {
+        if (img == null) { return true; }
+        
+        int sx = 0;
+        int sy = 0;
+        int width = img.getWidth(null);
+        int height = img.getHeight(null);
+        
+        return blitImage(sg2d, img, false, false, sx, sy, width, height, dx, dy, width, height, bgColor);
+    }
+    
+    // Copy img, clipped to sx, sy with width, height to sg2d @ dx, dy
+    protected boolean copyImage(SunGraphics2D sg2d, Image img, int dx, int dy, int sx, int sy, int width, int height, Color bgColor) {
+        return blitImage(sg2d, img, false, false, sx, sy, width, height, dx, dy, width, height, bgColor);
+    }
+    
+    protected void transformImage(SunGraphics2D sg2d, Image img, int x, int y, BufferedImageOp op, AffineTransform xf, Color bgColor) {
+        if (img != null) {
+            int iw = img.getWidth(null);
+            int ih = img.getHeight(null);
+            
+            if ((op != null) && (img instanceof BufferedImage)) {
+                if (((BufferedImage) img).getType() == BufferedImage.TYPE_CUSTOM) {
+                    // BufferedImageOp can not handle custom images
+                    BufferedImage dest = null;
+                    dest = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_ARGB_PRE);
+                    Graphics g = dest.createGraphics();
+                    g.drawImage(img, 0, 0, null);
+                    g.dispose();
+                    img = op.filter(dest, null);
+                } else {
+                    // sun.awt.image.BufImgSurfaceData.createData((BufferedImage)img).finishLazyDrawing();
+                    img = op.filter((BufferedImage) img, null);
+                }
+                
+                iw = img.getWidth(null);
+                ih = img.getHeight(null);
+            }
+            
+            if (xf != null) {
+                AffineTransform reset = sg2d.getTransform();
+                sg2d.transform(xf);
+                scaleImage(sg2d, img, x, y, x + iw, y + ih, 0, 0, iw, ih, bgColor);
+                sg2d.setTransform(reset);
+            } else {
+                scaleImage(sg2d, img, x, y, x + iw, y + ih, 0, 0, iw, ih, bgColor);
+            }
+        } else {
+            throw new NullPointerException();
+        }
+    }
+    
+    // copied from DrawImage.java
+    protected boolean imageReady(sun.awt.image.ToolkitImage sunimg, ImageObserver observer) {
+        if (sunimg.hasError()) {
+            if (observer != null) {
+                observer.imageUpdate(sunimg, ImageObserver.ERROR | ImageObserver.ABORT, -1, -1, -1, -1);
+            }
+            return false;
+        }
+        return true;
+    }
+    
+    // copied from DrawImage.java
+    public boolean copyImage(SunGraphics2D sg2d, Image img, int x, int y, Color bgColor, ImageObserver observer) {
+        if (img == null) { throw new NullPointerException(); }
+        
+        if (!(img instanceof sun.awt.image.ToolkitImage)) { return copyImage(sg2d, img, x, y, bgColor); }
+        
+        sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
+        if (!imageReady(sunimg, observer)) { return false; }
+        ImageRepresentation ir = sunimg.getImageRep();
+        return ir.drawToBufImage(sg2d, sunimg, x, y, bgColor, observer);
+    }
+    
+    // copied from DrawImage.java
+    public boolean copyImage(SunGraphics2D sg2d, Image img, int dx, int dy, int sx, int sy, int width, int height, Color bgColor, ImageObserver observer) {
+        if (img == null) { throw new NullPointerException(); }
+        
+        if (!(img instanceof sun.awt.image.ToolkitImage)) { return copyImage(sg2d, img, dx, dy, sx, sy, width, height, bgColor); }
+        
+        sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
+        if (!imageReady(sunimg, observer)) { return false; }
+        ImageRepresentation ir = sunimg.getImageRep();
+        return ir.drawToBufImage(sg2d, sunimg, dx, dy, (dx + width), (dy + height), sx, sy, (sx + width), (sy + height), null, observer);
+    }
+    
+    // copied from DrawImage.java
+    public boolean scaleImage(SunGraphics2D sg2d, Image img, int x, int y, int width, int height, Color bgColor, ImageObserver observer) {
+        if (img == null) { throw new NullPointerException(); }
+        
+        if (!(img instanceof sun.awt.image.ToolkitImage)) { return scaleImage(sg2d, img, x, y, width, height, bgColor); }
+        
+        sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
+        if (!imageReady(sunimg, observer)) { return false; }
+        ImageRepresentation ir = sunimg.getImageRep();
+        return ir.drawToBufImage(sg2d, sunimg, x, y, width, height, bgColor, observer);
+    }
+    
+    // copied from DrawImage.java
+    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) {
+        if (img == null) { throw new NullPointerException(); }
+        
+        if (!(img instanceof sun.awt.image.ToolkitImage)) { return scaleImage(sg2d, img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgColor); }
+        
+        sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
+        if (!imageReady(sunimg, observer)) { return false; }
+        ImageRepresentation ir = sunimg.getImageRep();
+        return ir.drawToBufImage(sg2d, sunimg, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgColor, observer);
+    }
+    
+    // copied from DrawImage.java
+    public boolean transformImage(SunGraphics2D sg2d, Image img, AffineTransform atfm, ImageObserver observer) {
+        if (img == null) { throw new NullPointerException(); }
+        
+        if (!(img instanceof sun.awt.image.ToolkitImage)) {
+            transformImage(sg2d, img, 0, 0, null, atfm, null);
+            return true;
+        }
+        
+        sun.awt.image.ToolkitImage sunimg = (sun.awt.image.ToolkitImage) img;
+        if (!imageReady(sunimg, observer)) { return false; }
+        ImageRepresentation ir = sunimg.getImageRep();
+        return ir.drawToBufImage(sg2d, sunimg, atfm, observer);
+    }
+    
+    // copied from DrawImage.java
+    public void transformImage(SunGraphics2D sg2d, BufferedImage img, BufferedImageOp op, int x, int y) {
+        if (img != null) {
+            transformImage(sg2d, img, x, y, op, null, null);
+        } else {
+            throw new NullPointerException();
+        }
+    }
+    
+    public CRenderer traceWrap() {
+        return new Tracer();
+    }
+    
+    public static class Tracer extends CRenderer {
+        void doLine(SurfaceData sData, float x1, float y1, float x2, float y2) {
+            GraphicsPrimitive.tracePrimitive("QuartzLine");
+            super.doLine(sData, x1, y1, x2, y2);
+        }
+        
+        void doRect(SurfaceData sData, float x, float y, float width, float height, boolean isfill) {
+            GraphicsPrimitive.tracePrimitive("QuartzRect");
+            super.doRect(sData, x, y, width, height, isfill);
+        }
+        
+        void doRoundRect(SurfaceData sData, float x, float y, float width, float height, float arcW, float arcH, boolean isfill) {
+            GraphicsPrimitive.tracePrimitive("QuartzRoundRect");
+            super.doRoundRect(sData, x, y, width, height, arcW, arcH, isfill);
+        }
+        
+        void doOval(SurfaceData sData, float x, float y, float width, float height, boolean isfill) {
+            GraphicsPrimitive.tracePrimitive("QuartzOval");
+            super.doOval(sData, x, y, width, height, isfill);
+        }
+        
+        void doArc(SurfaceData sData, float x, float y, float width, float height, float angleStart, float angleExtent, int type, boolean isfill) {
+            GraphicsPrimitive.tracePrimitive("QuartzArc");
+            super.doArc(sData, x, y, width, height, angleStart, angleExtent, type, isfill);
+        }
+        
+        void doPoly(SurfaceData sData, int[] xpoints, int[] ypoints, int npoints, boolean ispolygon, boolean isfill) {
+            GraphicsPrimitive.tracePrimitive("QuartzDoPoly");
+            super.doPoly(sData, xpoints, ypoints, npoints, ispolygon, isfill);
+        }
+        
+        void doShape(SurfaceData sData, int length, FloatBuffer coordinates, IntBuffer types, int windingRule, boolean isfill, boolean shouldApplyOffset) {
+            GraphicsPrimitive.tracePrimitive("QuartzFillOrDrawShape");
+            super.doShape(sData, length, coordinates, types, windingRule, isfill, shouldApplyOffset);
+        }
+        
+        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) {
+            GraphicsPrimitive.tracePrimitive("QuartzDrawImage");
+            super.doImage(sData, img, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/java2d/CompositeCRenderer.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+
+import sun.awt.image.*;
+import sun.java2d.loops.*;
+import sun.java2d.pipe.*;
+
+public class CompositeCRenderer extends CRenderer implements PixelDrawPipe, PixelFillPipe, ShapeDrawPipe, DrawImagePipe, TextPipe {
+    final static int fPadding = 4;
+    final static int fPaddingHalf = fPadding / 2;
+    
+    private static AffineTransform sIdentityMatrix = new AffineTransform();
+    
+    AffineTransform ShapeTM = new AffineTransform();
+    Rectangle2D ShapeBounds = new Rectangle2D.Float();
+    
+    Line2D line = new Line2D.Float();
+    Rectangle2D rectangle = new Rectangle2D.Float();
+    RoundRectangle2D roundrectangle = new RoundRectangle2D.Float();
+    Ellipse2D ellipse = new Ellipse2D.Float();
+    Arc2D arc = new Arc2D.Float();
+    
+    public synchronized void drawLine(SunGraphics2D sg2d, int x1, int y1, int x2, int y2) {
+        // create shape corresponding to this primitive
+        line.setLine(x1, y1, x2, y2);
+        
+        draw(sg2d, line);
+    }
+    
+    public synchronized void drawRect(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        // create shape corresponding to this primitive
+        rectangle.setRect(x, y, width, height);
+        
+        draw(sg2d, rectangle);
+    }
+    
+    public synchronized void drawRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        // create shape corresponding to this primitive
+        roundrectangle.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+        
+        draw(sg2d, roundrectangle);
+    }
+    
+    public synchronized void drawOval(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        // create shape corresponding to this primitive
+        ellipse.setFrame(x, y, width, height);
+        
+        draw(sg2d, ellipse);
+    }
+    
+    public synchronized void drawArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) {
+        // create shape corresponding to this primitive
+        arc.setArc(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);
+        
+        draw(sg2d, arc);
+    }
+    
+    public synchronized void drawPolyline(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
+        doPolygon(sg2d, xpoints, ypoints, npoints, false, false);
+    }
+    
+    public synchronized void drawPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
+        doPolygon(sg2d, xpoints, ypoints, npoints, true, false);
+    }
+    
+    public synchronized void fillRect(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        // create shape corresponding to this primitive
+        rectangle.setRect(x, y, width, height);
+        
+        fill(sg2d, rectangle);
+    }
+    
+    public synchronized void fillRoundRect(SunGraphics2D sg2d, int x, int y, int width, int height, int arcWidth, int arcHeight) {
+        // create shape corresponding to this primitive
+        roundrectangle.setRoundRect(x, y, width, height, arcWidth, arcHeight);
+        
+        fill(sg2d, roundrectangle);
+    }
+    
+    public synchronized void fillOval(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        // create shape corresponding to this primitive
+        ellipse.setFrame(x, y, width, height);
+        
+        fill(sg2d, ellipse);
+    }
+    
+    public synchronized void fillArc(SunGraphics2D sg2d, int x, int y, int width, int height, int startAngle, int arcAngle) {
+        // create shape corresponding to this primitive
+        arc.setArc(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);
+        
+        fill(sg2d, arc);
+    }
+    
+    public synchronized void fillPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints) {
+        doPolygon(sg2d, xpoints, ypoints, npoints, true, true);
+    }
+    
+    public synchronized void doPolygon(SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints, boolean ispolygon, boolean isfill) {
+        GeneralPath gp = new GeneralPath(Path2D.WIND_NON_ZERO, npoints);
+        gp.moveTo(xpoints[0], ypoints[0]);
+        for (int i = 1; i < npoints; i++) {
+            gp.lineTo(xpoints[i], ypoints[i]);
+        }
+        if (ispolygon) {
+            // according to the specs (only applies to polygons, not polylines)
+            if ((xpoints[0] != xpoints[npoints - 1]) || (ypoints[0] != ypoints[npoints - 1])) {
+                gp.lineTo(xpoints[0], ypoints[0]);
+            }
+        }
+        
+        doShape(sg2d, (OSXSurfaceData) sg2d.getSurfaceData(), (Shape) gp, isfill);
+    }
+    
+    public synchronized void draw(SunGraphics2D sg2d, Shape shape) {
+        doShape(sg2d, (OSXSurfaceData) sg2d.getSurfaceData(), shape, false);
+    }
+    
+    public synchronized void fill(SunGraphics2D sg2d, Shape shape) {
+        doShape(sg2d, (OSXSurfaceData) sg2d.getSurfaceData(), shape, true);
+    }
+    
+    void doShape(SunGraphics2D sg2d, OSXSurfaceData surfaceData, Shape shape, boolean isfill) {
+        Rectangle2D shapeBounds = shape.getBounds2D();
+        
+        // We don't want to draw with negative width and height (CRender doesn't do it and Windows doesn't do it either)
+        // Drawing with negative w and h, can cause CG problems down the line <rdar://3960579> (vm)
+        if ((shapeBounds.getWidth() < 0) || (shapeBounds.getHeight() < 0)) { return; }
+        
+        // get final destination compositing bounds (after all transformations if needed)
+        Rectangle2D compositingBounds = padBounds(sg2d, shape);
+        
+        // constrain the bounds to be within surface bounds
+        clipBounds(sg2d, compositingBounds);
+        
+        // if the compositing region is empty we skip all remaining compositing work:
+        if (compositingBounds.isEmpty() == false) {
+            BufferedImage srcPixels;
+            // create a matching surface into which we'll render the primitive to be composited
+            // with the desired dimension
+            srcPixels = surfaceData.getCompositingSrcImage((int) (compositingBounds.getWidth()),
+                    (int) (compositingBounds.getHeight()));
+            
+            Graphics2D g = srcPixels.createGraphics();
+            
+            // sync up graphics state
+            ShapeTM.setToTranslation(-compositingBounds.getX(), -compositingBounds.getY());
+            ShapeTM.concatenate(sg2d.transform);
+            g.setTransform(ShapeTM);
+            g.setRenderingHints(sg2d.getRenderingHints());
+            g.setPaint(sg2d.getPaint());
+            g.setStroke(sg2d.getStroke());
+            
+            // render the primitive to be composited
+            if (isfill) {
+                g.fill(shape);
+            } else {
+                g.draw(shape);
+            }
+            
+            g.dispose();
+            
+            composite(sg2d, surfaceData, srcPixels, compositingBounds);
+        }
+    }
+    
+    public synchronized void drawString(SunGraphics2D sg2d, String str, double x, double y) {
+        drawGlyphVector(sg2d, sg2d.getFont().createGlyphVector(sg2d.getFontRenderContext(), str), x, y);
+    }
+    
+    public synchronized void drawChars(SunGraphics2D sg2d, char data[], int offset, int length, int x, int y) {
+        drawString(sg2d, new String(data, offset, length), x, y);
+    }
+    
+    public synchronized void drawGlyphVector(SunGraphics2D sg2d, GlyphVector glyphVector, double x, double y) {
+        drawGlyphVector(sg2d, glyphVector, (float) x, (float) y);
+    }
+    
+    public synchronized void drawGlyphVector(SunGraphics2D sg2d, GlyphVector glyphVector, float x, float y) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        
+        Shape shape = glyphVector.getOutline(x, y);
+        
+        // get final destination compositing bounds (after all transformations if needed)
+        Rectangle2D compositingBounds = padBounds(sg2d, shape);
+        
+        // constrain the bounds to be within surface bounds
+        clipBounds(sg2d, compositingBounds);
+        
+        // if the compositing region is empty we skip all remaining compositing work:
+        if (compositingBounds.isEmpty() == false) {
+            BufferedImage srcPixels;
+            {
+                // create matching image into which we'll render the primitive to be composited
+                srcPixels = surfaceData.getCompositingSrcImage((int) compositingBounds.getWidth(), (int) compositingBounds.getHeight());
+                
+                Graphics2D g = srcPixels.createGraphics();
+                
+                // sync up graphics state
+                ShapeTM.setToTranslation(-compositingBounds.getX(), -compositingBounds.getY());
+                ShapeTM.concatenate(sg2d.transform);
+                g.setTransform(ShapeTM);
+                g.setPaint(sg2d.getPaint());
+                g.setStroke(sg2d.getStroke());
+                g.setFont(sg2d.getFont());
+                g.setRenderingHints(sg2d.getRenderingHints());
+                
+                // render the primitive to be composited
+                g.drawGlyphVector(glyphVector, x, y);
+                g.dispose();
+            }
+            
+            composite(sg2d, surfaceData, srcPixels, compositingBounds);
+        }
+    }
+    
+    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) {
+        OSXSurfaceData surfaceData = (OSXSurfaceData) sg2d.getSurfaceData();
+        
+        // get final destination compositing bounds (after all transformations if needed)
+        dx = (flipv == false) ? dx : dx - dw;
+        dy = (fliph == false) ? dy : dy - dh;
+        ShapeBounds.setFrame(dx, dy, dw, dh);
+        Rectangle2D compositingBounds = ShapeBounds;
+        boolean complexTransform = (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE);
+        if (complexTransform == false) {
+            double newX = Math.floor(compositingBounds.getX() + sg2d.transX);
+            double newY = Math.floor(compositingBounds.getY() + sg2d.transY);
+            double newW = Math.ceil(compositingBounds.getWidth()) + (newX < compositingBounds.getX() ? 1 : 0);
+            double newH = Math.ceil(compositingBounds.getHeight()) + (newY < compositingBounds.getY() ? 1 : 0);
+            compositingBounds.setRect(newX, newY, newW, newH);
+        } else {
+            Shape transformedShape = sg2d.transform.createTransformedShape(compositingBounds);
+            compositingBounds = transformedShape.getBounds2D();
+            double newX = Math.floor(compositingBounds.getX());
+            double newY = Math.floor(compositingBounds.getY());
+            double newW = Math.ceil(compositingBounds.getWidth()) + (newX < compositingBounds.getX() ? 1 : 0);
+            double newH = Math.ceil(compositingBounds.getHeight()) + (newY < compositingBounds.getY() ? 1 : 0);
+            compositingBounds.setRect(newX, newY, newW, newH);
+        }
+        
+        // constrain the bounds to be within surface bounds
+        clipBounds(sg2d, compositingBounds);
+        
+        // if the compositing region is empty we skip all remaining compositing work:
+        if (compositingBounds.isEmpty() == false) {
+            BufferedImage srcPixels;
+            {
+                // create matching image into which we'll render the primitive to be composited
+                srcPixels = surfaceData.getCompositingSrcImage((int) compositingBounds.getWidth(), (int) compositingBounds.getHeight());
+                
+                Graphics2D g = srcPixels.createGraphics();
+                
+                // sync up graphics state
+                ShapeTM.setToTranslation(-compositingBounds.getX(), -compositingBounds.getY());
+                ShapeTM.concatenate(sg2d.transform);
+                g.setTransform(ShapeTM);
+                g.setRenderingHints(sg2d.getRenderingHints());
+                g.setComposite(AlphaComposite.Src);
+                
+                int sx2 = (flipv == false) ? sx + sw : sx - sw;
+                int sy2 = (fliph == false) ? sy + sh : sy - sh;
+                g.drawImage(img, dx, dy, dx + dw, dy + dh, sx, sy, sx2, sy2, null);
+                
+                g.dispose();
+            }
+            
+            composite(sg2d, surfaceData, srcPixels, compositingBounds);
+        }
+        
+        return true;
+    }
+    
+    Rectangle2D padBounds(SunGraphics2D sg2d, Shape shape) {
+        shape = sg2d.transformShape(shape);
+        
+        int paddingHalf = fPaddingHalf;
+        int padding = fPadding;
+        if (sg2d.stroke != null) {
+            if (sg2d.stroke instanceof BasicStroke) {
+                int width = (int) (((BasicStroke) sg2d.stroke).getLineWidth() + 0.5f);
+                int widthHalf = width / 2 + 1;
+                paddingHalf += widthHalf;
+                padding += 2 * widthHalf;
+            } else {
+                shape = sg2d.stroke.createStrokedShape(shape);
+            }
+        }
+        Rectangle2D bounds = shape.getBounds2D();
+        bounds.setRect(bounds.getX() - paddingHalf, bounds.getY() - paddingHalf, bounds.getWidth() + padding, bounds.getHeight() + padding);
+        
+        double newX = Math.floor(bounds.getX());
+        double newY = Math.floor(bounds.getY());
+        double newW = Math.ceil(bounds.getWidth()) + (newX < bounds.getX() ? 1 : 0);
+        double newH = Math.ceil(bounds.getHeight()) + (newY < bounds.getY() ? 1 : 0);
+        bounds.setRect(newX, newY, newW, newH);
+        
+        return bounds;
+    }
+    
+    void clipBounds(SunGraphics2D sg2d, Rectangle2D bounds) {
+        /*
+         * System.err.println("clipBounds"); System.err.println("    transform="+sg2d.transform);
+         * System.err.println("    getTransform()="+sg2d.getTransform());
+         * System.err.println("    complexTransform="+(sg2d.transformState > SunGraphics2D.TRANSFORM_TRANSLATESCALE));
+         * System.err.println("    transX="+sg2d.transX+" transY="+sg2d.transX);
+         * System.err.println("    sg2d.constrainClip="+sg2d.constrainClip); if (sg2d.constrainClip != null) {
+         * System.err
+         * .println("    constrainClip: x="+sg2d.constrainClip.getLoX()+" y="+sg2d.constrainClip.getLoY()+" w="
+         * +sg2d.constrainClip.getWidth()+" h="+sg2d.constrainClip.getHeight());}
+         * System.err.println("    constrainX="+sg2d.constrainX+" constrainY="+sg2d.constrainY);
+         * System.err.println("    usrClip="+sg2d.usrClip);
+         * System.err.println("    devClip: x="+sg2d.devClip.getLoX()+" y="
+         * +sg2d.devClip.getLoY()+" w="+sg2d.devClip.getWidth()+" h="+sg2d.devClip.getHeight());
+         */
+        Region intersection = sg2d.clipRegion.getIntersectionXYWH((int) bounds.getX(), (int) bounds.getY(), (int) bounds.getWidth(), (int) bounds.getHeight());
+        bounds.setRect(intersection.getLoX(), intersection.getLoY(), intersection.getWidth(), intersection.getHeight());
+    }
+    
+    BufferedImage getSurfacePixels(SunGraphics2D sg2d, OSXSurfaceData surfaceData, int x, int y, int w, int h) {
+        // create an image to copy the surface pixels into
+        BufferedImage dstInPixels = surfaceData.getCompositingDstInImage(w, h);
+        
+        // get the pixels from the dst surface
+        return surfaceData.copyArea(sg2d, x, y, w, h, dstInPixels);
+    }
+    
+    void composite(SunGraphics2D sg2d, OSXSurfaceData surfaceData, BufferedImage srcPixels, Rectangle2D compositingBounds) {
+        // Thread.dumpStack();
+        // System.err.println("composite");
+        // System.err.println("    compositingBounds="+compositingBounds);
+        int x = (int) compositingBounds.getX();
+        int y = (int) compositingBounds.getY();
+        int w = (int) compositingBounds.getWidth();
+        int h = (int) compositingBounds.getHeight();
+        
+        boolean succeded = false;
+        
+        Composite composite = sg2d.getComposite();
+        if (composite instanceof XORComposite) {
+            // 1st native XOR try
+            // we try to perform XOR using surface pixels directly
+            try {
+                succeded = surfaceData.xorSurfacePixels(sg2d, srcPixels, x, y, w, h, ((XORComposite) composite).getXorColor().getRGB());
+            } catch (Exception e) {
+                succeded = false;
+            }
+        }
+        
+        if (succeded == false) {
+            // create image with the original pixels of surface
+            BufferedImage dstInPixels = getSurfacePixels(sg2d, surfaceData, x, y, w, h);
+            BufferedImage dstOutPixels = null;
+            
+            if (composite instanceof XORComposite) {
+                // 2nd native XOR try
+                // we try to perform XOR on image's pixels (which were copied from surface first)
+                try {
+                    OSXSurfaceData osxsd = (OSXSurfaceData) (BufImgSurfaceData.createData(dstInPixels));
+                    succeded = osxsd.xorSurfacePixels(sg2d, srcPixels, 0, 0, w, h, ((XORComposite) composite).getXorColor().getRGB());
+                    dstOutPixels = dstInPixels;
+                } catch (Exception e) {
+                    succeded = false;
+                }
+            }
+            
+            // either 2nd native XOR failed OR we have a case of custom compositing
+            if (succeded == false) {
+                // create an image into which we'll composite result: we MUST use a different destination (compositing
+                // is NOT "in place" operation)
+                dstOutPixels = surfaceData.getCompositingDstOutImage(w, h);
+                
+                // prepare rasters for compositing
+                WritableRaster srcRaster = srcPixels.getRaster();
+                WritableRaster dstInRaster = dstInPixels.getRaster();
+                WritableRaster dstOutRaster = dstOutPixels.getRaster();
+                
+                CompositeContext compositeContext = composite.createContext(srcPixels.getColorModel(), dstOutPixels.getColorModel(), sg2d.getRenderingHints());
+                compositeContext.compose(srcRaster, dstInRaster, dstOutRaster);
+                compositeContext.dispose();
+                
+                // gznote: radar bug number
+                // "cut out" the shape we're interested in
+                // applyMask(BufImgSurfaceData.createData(dstOutPixels), BufImgSurfaceData.createData(srcPixels), w, h);
+            }
+            
+            // blit the results back to the dst surface
+            Composite savedComposite = sg2d.getComposite();
+            AffineTransform savedTM = sg2d.getTransform();
+            int savedCX = sg2d.constrainX;
+            int savedCY = sg2d.constrainY;
+            {
+                sg2d.setComposite(AlphaComposite.SrcOver);
+                // all the compositing is done in the coordinate space of the component. the x and the y are the
+                // position of that component in the surface
+                // so we need to set the sg2d.transform to identity and we must set the contrainX/Y to 0 for the
+                // setTransform() to not be constrained
+                sg2d.constrainX = 0;
+                sg2d.constrainY = 0;
+                sg2d.setTransform(sIdentityMatrix);
+                sg2d.drawImage(dstOutPixels, x, y, x + w, y + h, 0, 0, w, h, null);
+            }
+            sg2d.constrainX = savedCX;
+            sg2d.constrainY = savedCY;
+            sg2d.setTransform(savedTM);
+            sg2d.setComposite(savedComposite);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/java2d/DataBufferNIOInt.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d;
+
+import java.awt.image.DataBuffer;
+import java.nio.*;
+
+public final class DataBufferNIOInt extends DataBuffer {
+
+    /** The default data bank. */
+    IntBuffer data;
+
+    /** All data banks */
+    IntBuffer bankdata[];
+
+    /**
+     * Constructs an integer-based <CODE>DataBuffer</CODE> with a single bank 
+     * and the specified size.
+     *
+     * @param size The size of the <CODE>DataBuffer</CODE>.
+     */
+    public DataBufferNIOInt(int size) {
+        super(TYPE_INT,size);
+        //+++gdb how to get sizeof(int) in java? Using 4 for now.
+        data = getBufferOfSize(size * 4).asIntBuffer();
+        bankdata = new IntBuffer[1];
+        bankdata[0] = data;
+    }
+
+    /**
+     * Returns the default (first) IntBuffer in <CODE>DataBuffer</CODE>.
+     *    
+     * @return The first IntBuffer.
+     */
+    public IntBuffer getBuffer() {
+        return data;
+    }
+
+    /** 
+     * Returns the Buffer for the specified bank.    
+     *   
+     * @param bank The bank whose Buffer you want to get. 
+     * @return The Buffer for the specified bank.
+     */
+    public IntBuffer getBuffer(int bank) {
+        return bankdata[bank];
+    }
+
+    /**
+     * Returns the default (first) int data array in <CODE>DataBuffer</CODE>.
+     *    
+     * @return The first integer data array.
+     */
+    public int[] getData() {
+        return data.array();
+    }
+
+    /** 
+     * Returns the data array for the specified bank.    
+     *   
+     * @param bank The bank whose data array you want to get. 
+     * @return The data array for the specified bank.
+     */
+    public int[] getData(int bank) {
+        return bankdata[bank].array();
+    }
+
+    /** 
+     * Returns the data arrays for all banks. 
+     * @return All of the data arrays.
+     */
+    public int[][] getBankData() {
+        // Unsupported.
+        return null;
+    }
+
+    /**
+     * Returns the requested data array element from the first (default) bank.
+     * 
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int i) {
+        return data.get(i+offset);
+    }
+
+    /**
+     * Returns the requested data array element from the specified bank.
+     * 
+     * @param bank The bank from which you want to get a data array element.
+     * @param i The data array element you want to get.
+     * @return The requested data array element as an integer.
+     * @see #setElem(int, int)
+     * @see #setElem(int, int, int)
+     */
+    public int getElem(int bank, int i) {
+        return bankdata[bank].get(i+offsets[bank]);
+    }
+
+    /**
+     * Sets the requested data array element in the first (default) bank
+     * to the specified value.
+     *
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int i, int val) {
+        data.put(i+offset, val);
+    }
+
+    /**
+     * Sets the requested data array element in the specified bank
+     * to the integer value <CODE>i</CODE>.
+     * @param bank The bank in which you want to set the data array element.
+     * @param i The data array element you want to set.
+     * @param val The integer value to which you want to set the specified data array element.
+     * @see #getElem(int)
+     * @see #getElem(int, int)
+     */
+    public void setElem(int bank, int i, int val) {
+        bankdata[bank].put(i+offsets[bank], val);
+    }
+    
+    ByteBuffer getBufferOfSize(int size)
+    {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(size);
+        buffer.order(ByteOrder.nativeOrder());
+        return buffer;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/java2d/IntegerNIORaster.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.nio.IntBuffer;
+import sun.awt.image.SunWritableRaster;
+
+public class IntegerNIORaster extends SunWritableRaster {
+
+    protected IntBuffer data;
+    
+    public static WritableRaster createNIORaster(int w, int h, int bandMasks[], Point location) {
+        if ((w <= 0) || (h <= 0)) {
+            throw new IllegalArgumentException("Width (" + w + ") and height (" + h + 
+                                               ") cannot be <= 0");
+        }
+        // This is cribbed from java.awt.image.Raster.
+        DataBuffer db = new DataBufferNIOInt(w * h);
+        if (location == null) {
+            location = new Point(0, 0);
+        }
+        SinglePixelPackedSampleModel sppsm =  new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h, w, bandMasks);
+        return new IntegerNIORaster(sppsm, db, location);
+    }
+        
+    public IntegerNIORaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) {
+        // This is all cribbed from sun.awt.image.IntegerInterleavedRaster & sun.awt.image.IntegerComponentRaster
+        super(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), sampleModel.getHeight()), origin, null);
+        if (!(dataBuffer instanceof DataBufferNIOInt)) {
+           throw new RasterFormatException("IntegerNIORasters must have DataBufferNIOInt DataBuffers");
+        }
+        this.data = ((DataBufferNIOInt)dataBuffer).getBuffer();
+    }
+    
+    public WritableRaster createCompatibleWritableRaster() {
+        return new IntegerNIORaster(sampleModel, new DataBufferNIOInt(sampleModel.getWidth() * sampleModel.getHeight()), new Point(0,0));
+    }
+    
+    public WritableRaster createCompatibleWritableRaster(int w, int h) {
+        if (w <= 0 || h <=0) {
+            throw new RasterFormatException("negative " + ((w <= 0) ? "width" : "height"));
+        }
+
+        SampleModel sm = sampleModel.createCompatibleSampleModel(w,h);
+
+        return new IntegerNIORaster(sm, new DataBufferNIOInt(w * h), new Point(0,0));
+    }
+    
+    public WritableRaster createCompatibleWritableRaster(Rectangle rect) {
+        if (rect == null) {
+            throw new NullPointerException("Rect cannot be null");
+        }
+        return createCompatibleWritableRaster(rect.x, rect.y, rect.width, rect.height);
+    }
+    
+    public WritableRaster createCompatibleWritableRaster(int x, int y, int w, int h) {
+        WritableRaster ret = createCompatibleWritableRaster(w, h);
+        return ret.createWritableChild(0,0,w,h,x,y,null);
+    }
+    
+  
+    public IntBuffer getBuffer() {
+        return data;
+    }
+    
+    public String toString() {
+        return new String ("IntegerNIORaster: width = "+width
+                           +" height = " + height
+                           +" #Bands = " + numBands
+                           +" xOff = "+sampleModelTranslateX
+                           +" yOff = "+sampleModelTranslateY);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/java2d/OSXOffScreenSurfaceData.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d;
+
+import java.awt.*;
+import java.awt.color.*;
+import java.awt.image.*;
+import java.nio.*;
+
+import sun.awt.image.*;
+import sun.java2d.loops.*;
+
+public class OSXOffScreenSurfaceData extends OSXSurfaceData // implements RasterListener
+{
+    private static native void initIDs();
+    
+    static {
+        initIDs();
+    }
+    
+    // the image associated with this surface
+    BufferedImage bim;
+    // the image associated with this custom surface
+    BufferedImage bimBackup;
+    // <rdar://problem/4177639> nio based images use ARGB_PRE
+    static DirectColorModel dcmBackup = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, true, DataBuffer.TYPE_INT);
+    
+    Object lock;
+    
+    // cached rasters for easy access
+    WritableRaster bufImgRaster;
+    SunWritableRaster bufImgSunRaster;
+    
+    // these are extra image types we can handle
+    private static final int TYPE_3BYTE_RGB = BufferedImage.TYPE_BYTE_INDEXED + 1;
+    
+    // these are for callbacks when pixes have been touched
+    protected ByteBuffer fImageInfo;
+    IntBuffer fImageInfoInt;
+    private static final int kNeedToSyncFromJavaPixelsIndex = 0;
+    private static final int kNativePixelsChangedIndex = 1;
+    private static final int kImageStolenIndex = 2;
+    private static final int kSizeOfParameters = kImageStolenIndex + 1;
+    
+    public static native SurfaceData getSurfaceData(BufferedImage bufImg);
+    
+    protected static native void setSurfaceData(BufferedImage bufImg, SurfaceData sData);
+    
+    public static SurfaceData createData(BufferedImage bufImg) {
+        /*
+         * if ((bufImg.getWidth() == 32) && (bufImg.getHeight() == 32)) { Thread.dumpStack(); }
+         */
+        // This could be called from multiple threads. We need to synchronized on the image so that
+        // we can ensure that only one surface data is created per image. (<rdar://4564873>)
+        // Note: Eventually, we should switch to using the same mechanism (CachingSurfaceManager) that Sun uses
+        // <rdar://4563741>
+        synchronized (bufImg) {
+            SurfaceData sData = getSurfaceData(bufImg);
+            if (sData != null) { return sData; }
+            
+            OSXOffScreenSurfaceData osData = OSXOffScreenSurfaceData.createNewSurface(bufImg);
+            
+            OSXOffScreenSurfaceData.setSurfaceData(bufImg, osData);
+            osData.cacheRasters(bufImg);
+//            osData.setRasterListener();
+            
+            return osData;
+        }
+    }
+    
+    public static SurfaceData createData(Raster ras, ColorModel cm) {
+        throw new InternalError("SurfaceData not implemented for Raster/CM");
+    }
+    
+    static OSXOffScreenSurfaceData createNewSurface(BufferedImage bufImg) {
+        SurfaceData sData = null;
+        
+        ColorModel cm = bufImg.getColorModel();
+        int type = bufImg.getType();
+        // REMIND: Check the image type and pick an appropriate subclass
+        switch (type) {
+            case BufferedImage.TYPE_INT_BGR:
+                sData = createDataIC(bufImg, SurfaceType.IntBgr);
+                break;
+            case BufferedImage.TYPE_INT_RGB:
+                sData = createDataIC(bufImg, SurfaceType.IntRgb);
+                break;
+            case BufferedImage.TYPE_INT_ARGB:
+                sData = createDataIC(bufImg, SurfaceType.IntArgb);
+                break;
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+                sData = createDataIC(bufImg, SurfaceType.IntArgbPre);
+                break;
+            case BufferedImage.TYPE_3BYTE_BGR:
+                sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2);
+                break;
+            case BufferedImage.TYPE_4BYTE_ABGR:
+                sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3);
+                break;
+            case BufferedImage.TYPE_4BYTE_ABGR_PRE:
+                sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3);
+                break;
+            case BufferedImage.TYPE_USHORT_565_RGB:
+                sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null);
+                break;
+            case BufferedImage.TYPE_USHORT_555_RGB:
+                sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null);
+                break;
+            case BufferedImage.TYPE_BYTE_INDEXED: {
+                SurfaceType sType;
+                switch (cm.getTransparency()) {
+                    case OPAQUE:
+                        if (isOpaqueGray((IndexColorModel) cm)) {
+                            sType = SurfaceType.Index8Gray;
+                        } else {
+                            sType = SurfaceType.ByteIndexedOpaque;
+                        }
+                        break;
+                    case BITMASK:
+                        sType = SurfaceType.ByteIndexedBm;
+                        break;
+                    case TRANSLUCENT:
+                        sType = SurfaceType.ByteIndexed;
+                        break;
+                    default:
+                        throw new InternalError("Unrecognized transparency");
+                }
+                sData = createDataBC(bufImg, sType, 0);
+            }
+                break;
+            case BufferedImage.TYPE_BYTE_GRAY:
+                sData = createDataBC(bufImg, SurfaceType.ByteGray, 0);
+                break;
+            case BufferedImage.TYPE_USHORT_GRAY:
+                sData = createDataSC(bufImg, SurfaceType.UshortGray, null);
+                break;
+            case BufferedImage.TYPE_BYTE_BINARY:
+            case BufferedImage.TYPE_CUSTOM:
+            default: {
+                Raster raster = bufImg.getRaster();
+                
+                // we try to fit a custom image into one of the predefined BufferedImages (BufferedImage does that
+                // first, we further refine it here)
+                // we can do that because a pointer in C is a pointer (pixel pointer not dependent on DataBuffer type)
+                SampleModel sm = bufImg.getSampleModel();
+                SurfaceType sType = SurfaceType.Custom;
+                int transferType = cm.getTransferType();
+                int pixelSize = cm.getPixelSize();
+                int numOfComponents = cm.getNumColorComponents();
+                if ((numOfComponents == 3) && (cm instanceof ComponentColorModel) && (sm instanceof PixelInterleavedSampleModel)) {
+                    int sizes[] = cm.getComponentSize();
+                    boolean validsizes = (sizes[0] == 8) && (sizes[1] == 8) && (sizes[2] == 8);
+                    int[] offs = ((ComponentSampleModel) sm).getBandOffsets();
+                    int numBands = raster.getNumBands();
+                    boolean bigendian = (offs[0] == numBands - 3) && (offs[1] == numBands - 2) && (offs[2] == numBands - 1);
+                    boolean littleendian = (offs[0] == numBands - 1) && (offs[1] == numBands - 2) && (offs[2] == numBands - 3);
+                    
+                    if ((pixelSize == 32) && (transferType == DataBuffer.TYPE_INT)) {
+                        if (validsizes && bigendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_ARGB_PRE);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && bigendian && cm.hasAlpha() && sizes[3] == 8) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_ARGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian && cm.hasAlpha() && sizes[3] == 8) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_4BYTE_ABGR);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && bigendian) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 32) && (transferType == DataBuffer.TYPE_BYTE)) {
+                        if (validsizes && bigendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_ARGB_PRE);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                        if (validsizes && bigendian && cm.hasAlpha() && sizes[3] == 8) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_ARGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian && cm.hasAlpha() && sizes[3] == 8) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_4BYTE_ABGR);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_BGR);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && bigendian) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 24) && (transferType == DataBuffer.TYPE_INT)) {
+                        if (validsizes && bigendian) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian) {
+                            try {
+                                sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_BGR);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 24) && (transferType == DataBuffer.TYPE_BYTE)) {
+                        if (validsizes && bigendian) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 0, TYPE_3BYTE_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        } else if (validsizes && littleendian) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 0, BufferedImage.TYPE_3BYTE_BGR);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 16) && (transferType == DataBuffer.TYPE_USHORT)) {
+                        validsizes = (sizes[0] == 5) && (sizes[1] == 6) && (sizes[2] == 5);
+                        if (validsizes && bigendian) {
+                            try {
+                                sData = createDataSC(bufImg, sType, null, BufferedImage.TYPE_USHORT_565_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 16) && (transferType == DataBuffer.TYPE_BYTE)) {
+                        validsizes = (sizes[0] == 5) && (sizes[1] == 6) && (sizes[2] == 5);
+                        if (validsizes && bigendian) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 1, BufferedImage.TYPE_USHORT_565_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 15) && (transferType == DataBuffer.TYPE_USHORT)) {
+                        validsizes = (sizes[0] == 5) && (sizes[1] == 5) && (sizes[2] == 5);
+                        if (validsizes && bigendian) {
+                            try {
+                                sData = createDataSC(bufImg, sType, null, BufferedImage.TYPE_USHORT_555_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    } else if ((pixelSize == 15) && (transferType == DataBuffer.TYPE_BYTE)) {
+                        validsizes = (sizes[0] == 5) && (sizes[1] == 5) && (sizes[2] == 5);
+                        if (validsizes && bigendian) {
+                            try {
+                                sData = createDataBC(bufImg, sType, 1, BufferedImage.TYPE_USHORT_555_RGB);
+                            } catch (ClassCastException e) {
+                                sData = null;
+                            }
+                        }
+                    }
+                }
+            }
+                break;
+        }
+        
+        // we failed to match
+        if (sData == null) {
+            sData = new OSXOffScreenSurfaceData(bufImg, SurfaceType.Custom);
+            OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) sData;
+            
+            // 2004_03_26 cmc: We used to use createCompatibleImage here. Now that createCompatibleImage returns
+            // an INT_ARGB_PRE instead of an NIO-based image, we need to explicitly create an NIO-based image.
+            IntegerNIORaster backupRaster = (IntegerNIORaster) IntegerNIORaster.createNIORaster(bufImg.getWidth(), bufImg.getHeight(), dcmBackup.getMasks(), null);
+            offsd.bimBackup = new BufferedImage(dcmBackup, backupRaster, dcmBackup.isAlphaPremultiplied(), null);
+            
+            // the trick that makes it work - assign the raster from backup to the surface data of the original image
+            offsd.initCustomRaster(backupRaster.getBuffer(),
+                                    backupRaster.getWidth(),
+                                    backupRaster.getHeight(),
+                                    offsd.fGraphicsStates,
+                                    offsd.fGraphicsStatesObject,
+                                    offsd.fImageInfo);
+            
+            //offsd.checkIfLazyPixelConversionDisabled();
+            offsd.fImageInfoInt.put(kImageStolenIndex, 1);
+        }
+        
+        return (OSXOffScreenSurfaceData) sData;
+    }
+    
+    private static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType, int iType) {
+        OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
+        
+        IntegerComponentRaster icRaster = (IntegerComponentRaster) bImg.getRaster();
+        offsd.initRaster(icRaster.getDataStorage(),
+                            icRaster.getDataOffset(0) * 4,
+                            icRaster.getWidth(),
+                            icRaster.getHeight(),
+                            icRaster.getPixelStride() * 4,
+                            icRaster.getScanlineStride() * 4,
+                            null,
+                            iType,
+                            offsd.fGraphicsStates,
+                            offsd.fGraphicsStatesObject,
+                            offsd.fImageInfo);
+        
+       // offsd.checkIfLazyPixelConversionDisabled();
+        offsd.fImageInfoInt.put(kImageStolenIndex, 1);
+        return offsd;
+    }
+    
+    public static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType) {
+        return createDataIC(bImg, sType, bImg.getType());
+    }
+    
+    private static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm, int iType) {
+        OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
+        
+        ShortComponentRaster scRaster = (ShortComponentRaster) bImg.getRaster();
+        offsd.initRaster(scRaster.getDataStorage(),
+                            scRaster.getDataOffset(0) * 2,
+                            scRaster.getWidth(),
+                            scRaster.getHeight(),
+                            scRaster.getPixelStride() * 2,
+                            scRaster.getScanlineStride() * 2,
+                            icm,
+                            iType,
+                            offsd.fGraphicsStates,
+                            offsd.fGraphicsStatesObject,
+                            offsd.fImageInfo);
+        
+        //offsd.checkIfLazyPixelConversionDisabled();
+        offsd.fImageInfoInt.put(kImageStolenIndex, 1);
+        return offsd;
+    }
+    
+    public static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm) {
+        return createDataSC(bImg, sType, icm, bImg.getType());
+    }
+    
+    private static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank, int iType) {
+        OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
+        
+        ByteComponentRaster bcRaster = (ByteComponentRaster) bImg.getRaster();
+        ColorModel cm = bImg.getColorModel();
+        IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm : null);
+        offsd.initRaster(bcRaster.getDataStorage(),
+                            bcRaster.getDataOffset(primaryBank),
+                            bcRaster.getWidth(),
+                            bcRaster.getHeight(),
+                            bcRaster.getPixelStride(),
+                            bcRaster.getScanlineStride(),
+                            icm,
+                            iType,
+                            offsd.fGraphicsStates,
+                            offsd.fGraphicsStatesObject,
+                            offsd.fImageInfo);
+        
+        offsd.fImageInfoInt.put(kImageStolenIndex, 1);
+        
+        return offsd;
+    }
+    
+    public static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank) {
+        return createDataBC(bImg, sType, primaryBank, bImg.getType());
+    }
+    
+    private static SurfaceData createDataBP(BufferedImage bImg, SurfaceType sType, int iType) {
+        OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
+        
+        BytePackedRaster bpRaster = (BytePackedRaster) bImg.getRaster();
+        ColorModel cm = bImg.getColorModel();
+        IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm : null);
+        offsd.initRaster(bpRaster.getDataStorage(),
+                            bpRaster.getDataBitOffset(), // in bits, NOT bytes! (needs special attention in native
+                                                         // code!)
+                bpRaster.getWidth(),
+                            bpRaster.getHeight(),
+                            bpRaster.getPixelBitStride(),
+                            bpRaster.getScanlineStride() * 8,
+                            icm,
+                            iType,
+                            offsd.fGraphicsStates,
+                            offsd.fGraphicsStatesObject,
+                            offsd.fImageInfo);
+        
+        //offsd.checkIfLazyPixelConversionDisabled();
+        offsd.fImageInfoInt.put(kImageStolenIndex, 1);
+        return offsd;
+    }
+    
+    protected native void initRaster(Object theArray, int offset, int width, int height, int pixStr, int scanStr, IndexColorModel icm, int type, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo);
+    
+    protected native void initCustomRaster(IntBuffer buffer, int width, int height, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo);
+    
+    public Object getLockObject() {
+        return this.lock;
+    }
+    
+    // Makes the constructor package private instead of public.
+    OSXOffScreenSurfaceData(BufferedImage bufImg, SurfaceType sType) {
+        super(sType, bufImg.getColorModel());
+        setBounds(0, 0, bufImg.getWidth(), bufImg.getHeight());
+        
+        this.bim = bufImg;
+        
+        this.fImageInfo = ByteBuffer.allocateDirect(4 * kSizeOfParameters);
+        this.fImageInfo.order(ByteOrder.nativeOrder());
+        this.fImageInfoInt = this.fImageInfo.asIntBuffer();
+        
+        this.fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // need to sync from Java the very first time
+        this.fImageInfoInt.put(kNativePixelsChangedIndex, 0);
+        this.fImageInfoInt.put(kImageStolenIndex, 0);
+        
+        this.lock = new Object();
+    }
+    
+    /**
+     * Performs a copyArea within this surface.
+     */
+    public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) {
+        // <rdar://problem/4488745> For the Sun2D renderer we should rely on the implementation of the super class.
+        // BufImageSurfaceData.java doesn't have an implementation of copyArea() and relies on the super class.
+        
+        int offsetX = 0;
+        int offsetY = 0;
+        if (sg2d.transformState == SunGraphics2D.TRANSFORM_ANY_TRANSLATE ||
+                    sg2d.transformState == SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
+            offsetX = (int) sg2d.transform.getTranslateX();
+            offsetY = (int) sg2d.transform.getTranslateY();
+        } else if (sg2d.transformState != SunGraphics2D.TRANSFORM_ISIDENT) { return false; }
+        
+        // reset the clip (this is how it works on windows)
+        // we actually can handle a case with any clips but windows ignores the light clip
+        Shape clip = sg2d.getClip();
+        sg2d.setClip(getBounds());
+        
+        // clip copyArea
+        Rectangle clippedCopyAreaRect = clipCopyArea(sg2d, x, y, w, h, dx, dy);
+        if (clippedCopyAreaRect == null) {
+            // clipped out
+            return true;
+        }
+        
+        // the rectangle returned from clipCopyArea() is in the coordinate space of the surface (image)
+        // we need to substract the offsetX and offsetY to move it to the coordinate space of the graphics2d.
+        // sg2d.drawImage expects the destination rect to be in the coord space of the graphics2d. <rdar://3746194>
+        // (vm)
+        x = clippedCopyAreaRect.x - offsetX;
+        y = clippedCopyAreaRect.y - offsetY;
+        w = clippedCopyAreaRect.width;
+        h = clippedCopyAreaRect.height;
+        
+        // copy (dst coordinates are in the coord space of the graphics2d, and src coordinates are
+        // in the coordinate space of the image)
+        sg2d.drawImage(this.bim, x + dx, y + dy, x + dx + w, y + dy + h, x + offsetX, y + offsetY, x + w + offsetX, y + h + offsetY, null);
+        
+        // restore the clip
+        sg2d.setClip(clip);
+        
+        return true;
+    }
+    
+    /**
+     * Performs a copyarea from this surface to a buffered image. If null is passed in for the image a new image will be
+     * created.
+     * 
+     * Only used by compositor code (private API)
+     */
+    public BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage) {
+        // create the destination image if needed
+        if (dstImage == null) {
+            dstImage = getDeviceConfiguration().createCompatibleImage(w, h);
+        }
+        
+        // copy
+        Graphics g = dstImage.createGraphics();
+        g.drawImage(this.bim, 0, 0, w, h, x, y, x + w, y + h, null);
+        g.dispose();
+        
+        return dstImage;
+    }
+    
+    public boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR) {
+        
+        int type = this.bim.getType();
+        
+        if ((type == BufferedImage.TYPE_INT_ARGB_PRE) || (type == BufferedImage.TYPE_INT_ARGB) || (type == BufferedImage.TYPE_INT_RGB)) { return xorSurfacePixels(createData(srcPixels), colorXOR, x, y, w, h); }
+        
+        return false;
+    }
+    
+    native boolean xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h);
+    
+    public void clearRect(BufferedImage bim, int w, int h) {
+        OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) (OSXOffScreenSurfaceData.createData(bim));
+        // offsd.clear();
+        if (offsd.clearSurfacePixels(w, h) == false) {
+            Graphics2D g = bim.createGraphics();
+            g.setComposite(AlphaComposite.Clear);
+            g.fillRect(0, 0, w, h);
+            g.dispose();
+        }
+    }
+    
+    native boolean clearSurfacePixels(int w, int h);
+    
+    // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter.
+    // getCopyWithBgColor returns a new version of an image, drawn with a background
+    // color. Called by blitImage in OSXSurfaceData.java.
+    BufferedImage copyWithBgColor_cache = null;
+    
+    public SurfaceData getCopyWithBgColor(Color bgColor) {
+        int bimW = this.bim.getWidth();
+        int bimH = this.bim.getHeight();
+        
+        if ((this.copyWithBgColor_cache == null)
+                || (this.copyWithBgColor_cache.getWidth() < bimW) || (this.copyWithBgColor_cache.getHeight() < bimH)) {
+            GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
+            this.copyWithBgColor_cache = gc.createCompatibleImage(bimW, bimH);
+        }
+        
+        Graphics g2 = this.copyWithBgColor_cache.createGraphics();
+        g2.setColor(bgColor);
+        g2.fillRect(0, 0, bimW, bimH);
+        g2.drawImage(this.bim, 0, 0, bimW, bimH, null);
+        g2.dispose();
+        
+        return getSurfaceData(this.copyWithBgColor_cache);
+    }
+    
+    /**
+     * Invoked before the raster's contents are to be read (via one of the modifier methods in Raster such as
+     * getPixel())
+     */
+    public void rasterRead() {
+        if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
+            syncToJavaPixels();
+        }
+    }
+    
+    /**
+     * Invoked before the raster's contents are to be written to (via one of the modifier methods in Raster such as
+     * setPixel())
+     */
+    public void rasterWrite() {
+        if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
+            syncToJavaPixels();
+        }
+        
+        fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // the pixels will change
+    }
+    
+//    /**
+//     * Invoked when the raster's contents will be taken (via the Raster.getDataBuffer() method)
+//     */
+//    public void rasterStolen() {
+//        fImageInfoInt.put(kImageStolenIndex, 1); // this means we must convert between Java and native pixels every
+//                                                 // single primitive! (very expensive)
+//        if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
+//            syncToJavaPixels();
+//        }
+//        
+//        // we know the pixels have been stolen, no need to listen for changes any more
+////        if (this.bufImgSunRaster != null) {
+////            this.bufImgSunRaster.setRasterListener(null);
+////        }
+//    }
+    
+    private native void syncToJavaPixels();
+    
+    // we need to refer to rasters often, so cache them
+    void cacheRasters(BufferedImage bim) {
+        this.bufImgRaster = bim.getRaster();
+        if (this.bufImgRaster instanceof SunWritableRaster) {
+            this.bufImgSunRaster = (SunWritableRaster) this.bufImgRaster;
+        }
+    }
+    
+//    void setRasterListener() {
+//        if (this.bufImgSunRaster != null) {
+//            this.bufImgSunRaster.setRasterListener(this);
+//            
+//            Raster parentRaster = this.bufImgSunRaster.getParent();
+//            if (parentRaster != null) {
+//                if (parentRaster instanceof SunWritableRaster) {
+//                    // mark subimages stolen to turn off lazy pixel conversion (gznote: can we do better here?)
+//                    ((SunWritableRaster) parentRaster).notifyStolen();
+//                }
+//                rasterStolen();
+//            }
+//        } else {
+//            // it's a custom image (non-natively supported) and we can not set a raster listener
+//            // so mark the image as stolen - this will turn off LazyPixelConversion optimization (slow, but correct)
+//            rasterStolen();
+//        }
+//    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/java2d/OSXSurfaceData.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,1166 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.nio.*;
+
+import sun.awt.*;
+import sun.awt.image.*;
+import sun.java2d.loops.*;
+import sun.java2d.pipe.*;
+import sun.lwawt.macosx.*;
+
+/*
+ * This is the SurfaceData for a CGContextRef.
+ */
+public abstract class OSXSurfaceData extends BufImgSurfaceData {
+    final static float UPPER_BND = Float.MAX_VALUE / 2.0f;
+    final static float LOWER_BND = -UPPER_BND;
+    
+    protected static CRenderer sQuartzPipe = null;
+    protected static CTextPipe sCocoaTextPipe = null;
+    protected static CompositeCRenderer sQuartzCompositePipe = null;
+    
+    private GraphicsConfiguration fConfig;
+    private Rectangle fBounds; // bounds in user coordinates
+    
+    static {
+        sQuartzPipe = new CRenderer(); // Creates the singleton quartz pipe.
+    }
+    
+    // NOTE: Any subclasses must eventually call QuartzSurfaceData_InitOps in OSXSurfaceData.h
+    // This sets up the native side for the SurfaceData, and is required.
+    public OSXSurfaceData(SurfaceType sType, ColorModel cm) {
+        this(sType, cm, null, new Rectangle());
+    }
+    
+    public OSXSurfaceData(SurfaceType sType, ColorModel cm, GraphicsConfiguration config, Rectangle bounds) {
+        super(sType, cm);
+        
+        this.fConfig = config;
+        
+        this.fBounds = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.y + bounds.height);
+        
+        this.fGraphicsStates = getBufferOfSize(kSizeOfParameters);
+        this.fGraphicsStatesInt = this.fGraphicsStates.asIntBuffer();
+        this.fGraphicsStatesFloat = this.fGraphicsStates.asFloatBuffer();
+        this.fGraphicsStatesLong = this.fGraphicsStates.asLongBuffer();
+        this.fGraphicsStatesObject = new Object[6]; // clip coordinates + clip types + texture paint image + stroke dash
+                                                    // array + font + font paint
+        
+        // NOTE: All access to the DrawingQueue comes through this OSXSurfaceData instance. Therefore
+        // every instance method of OSXSurfaceData that accesses the fDrawingQueue is synchronized.
+        
+        // Thread.dumpStack();
+    }
+    
+    public void validatePipe(SunGraphics2D sg2d) {
+        
+        if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
+            if (sCocoaTextPipe == null) {
+                sCocoaTextPipe = new CTextPipe();
+            }
+            
+            sg2d.imagepipe = sQuartzPipe;
+            sg2d.drawpipe = sQuartzPipe;
+            sg2d.fillpipe = sQuartzPipe;
+            sg2d.shapepipe = sQuartzPipe;
+            sg2d.textpipe = sCocoaTextPipe;
+        } else {
+            setPipesToQuartzComposite(sg2d);
+        }
+    }
+    
+    protected void setPipesToQuartzComposite(SunGraphics2D sg2d) {
+        if (sQuartzCompositePipe == null) {
+            sQuartzCompositePipe = new CompositeCRenderer();
+        }
+        
+        if (sCocoaTextPipe == null) {
+            sCocoaTextPipe = new CTextPipe();
+        }
+        
+        sg2d.imagepipe = sQuartzCompositePipe;
+        sg2d.drawpipe = sQuartzCompositePipe;
+        sg2d.fillpipe = sQuartzCompositePipe;
+        sg2d.shapepipe = sQuartzCompositePipe;
+        sg2d.textpipe = sCocoaTextPipe;
+    }
+    
+    public Rectangle getBounds() {
+        // gznote: always return a copy, not the rect itself and translate into device space
+        return new Rectangle(fBounds.x, fBounds.y, fBounds.width, fBounds.height - fBounds.y);
+    }
+    
+    public GraphicsConfiguration getDeviceConfiguration() {
+        return fConfig;
+    }
+    
+    protected void setBounds(int x, int y, int w, int h) {
+        fBounds.reshape(x, y, w, y + h);
+    }
+    
+    // START compositing support API
+    public abstract BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage image);
+    
+    public abstract boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR);
+    
+    GraphicsConfiguration sDefaultGraphicsConfiguration = null;
+    
+    protected BufferedImage getCompositingImage(int w, int h) {
+        if (sDefaultGraphicsConfiguration == null) {
+            sDefaultGraphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
+        }
+        
+        BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
+        // clear the image.
+        clearRect(img, w, h); 
+        return img;
+    }
+    
+    protected BufferedImage getCompositingImageSame(BufferedImage img, int w, int h) {
+        if ((img == null) || (img.getWidth() != w) || (img.getHeight() != h)) {
+            img = getCompositingImage(w, h);
+        }
+        return img;
+    }
+    
+    BufferedImage sSrcComposite = null;
+    
+    public BufferedImage getCompositingSrcImage(int w, int h) {
+        // <rdar://problem/3720263>. Changed from getCompositingImageBiggerOrSame() to
+        // getCompositingImageSame(). (vm)
+        BufferedImage bim = getCompositingImageSame(sSrcComposite, w, h);
+        sSrcComposite = bim;
+        return bim;
+    }
+    
+    BufferedImage sDstInComposite = null;
+    
+    public BufferedImage getCompositingDstInImage(int w, int h) {
+        BufferedImage bim = getCompositingImageSame(sDstInComposite, w, h);
+        sDstInComposite = bim;
+        return bim;
+    }
+    
+    BufferedImage sDstOutComposite = null;
+    
+    public BufferedImage getCompositingDstOutImage(int w, int h) {
+        BufferedImage bim = getCompositingImageSame(sDstOutComposite, w, h);
+        sDstOutComposite = bim;
+        return bim;
+    }
+    
+    public void clearRect(BufferedImage bim, int w, int h) {
+        Graphics2D g = bim.createGraphics();
+        g.setComposite(AlphaComposite.Clear);
+        g.fillRect(0, 0, w, h);
+        g.dispose();
+    }
+    
+    // END compositing support API
+    
+    public void invalidate() {
+        // always valid
+    }
+    
+     // graphics primitives drawing implementation:
+    
+    // certain primitives don't care about all the states (ex. drawing an image needs not involve setting current paint)
+    static final int kPrimitive = 0;
+    static final int kImage = 1;
+    static final int kText = 2;
+    static final int kCopyArea = 3;
+    static final int kExternal = 4;
+    
+    static final int kLine = 5; // belongs to kPrimitive
+    static final int kRect = 6; // belongs to kPrimitive
+    static final int kRoundRect = 7; // belongs to kPrimitive
+    static final int kOval = 8; // belongs to kPrimitive
+    static final int kArc = 9; // belongs to kPrimitive
+    static final int kPolygon = 10; // belongs to kPrimitive
+    static final int kShape = 11; // belongs to kPrimitive
+    // static final int kImage = 12; // belongs to kImage
+    static final int kString = 13; // belongs to kText
+    static final int kGlyphs = 14; // belongs to kText
+    static final int kUnicodes = 15; // belongs to kText
+    // static final int kCopyArea = 16; // belongs to kCopyArea
+    // static final int kExternal = 17; // belongs to kExternal
+    
+    static final int kCommonParameterCount = 1 + 1 + 4 + 4; // type + change flags + color info (type(1) align(1) and
+                                                            // value(2)) + parameters ((x1, y1, x2, y2) OR (x, y, w, h))
+    static final int kLineParametersCount = kCommonParameterCount; // kCommonParameterCount
+    static final int kRectParametersCount = kCommonParameterCount + 1; // kCommonParameterCount + isfill
+    static final int kRoundRectParametersCount = kCommonParameterCount + 2 + 1; // kCommonParameterCount + arcW + arcH +
+                                                                                // isfill
+    static final int kOvalParametersCount = kCommonParameterCount + 1; // kCommonParameterCount + isfill
+    static final int kArcParametersCount = kCommonParameterCount + 2 + 1 + 1;// kCommonParameterCount + startAngle +
+                                                                             // arcAngle + isfill + type
+    static final int kPolygonParametersCount = 0; // not supported
+    static final int kShapeParametersCount = 0; // not supported
+    static final int kImageParametersCount = kCommonParameterCount + 2 + 2 + 4 + 4; // flip horz vert + w&h + src + dst
+    static final int kStringParametersCount = 0; // not supported
+    static final int kGlyphsParametersCount = 0; // not supported
+    static final int kUnicodesParametersCount = 0; // not supported
+    static final int kPixelParametersCount = 0; // not supported
+    static final int kExternalParametersCount = 0; // not supported
+    
+    // for intParameters
+    // states info
+    static final int kChangeFlagIndex = 0; // kBoundsChangedBit | .. | kFontChangedBit
+    // bounds info
+    static final int kBoundsXIndex = 1;
+    static final int kBoundsYIndex = 2;
+    static final int kBoundsWidthIndex = 3;
+    static final int kBoundsHeightIndex = 4;
+    // clip info
+    static final int kClipStateIndex = 5;
+    static final int kClipNumTypesIndex = 6;
+    static final int kClipNumCoordsIndex = 7;
+    static final int kClipWindingRuleIndex = 8;
+    static final int kClipXIndex = 9;
+    static final int kClipYIndex = 10;
+    static final int kClipWidthIndex = 11;
+    static final int kClipHeightIndex = 12;
+    // ctm info
+    static final int kCTMaIndex = 13;
+    static final int kCTMbIndex = 14;
+    static final int kCTMcIndex = 15;
+    static final int kCTMdIndex = 16;
+    static final int kCTMtxIndex = 17;
+    static final int kCTMtyIndex = 18;
+    // color info
+    static final int kColorStateIndex = 19; // kColorSimple or kColorGradient or kColorTexture
+    static final int kColorRGBValueIndex = 20; // if kColorSimple
+    static final int kColorIndexValueIndex = 21; // if kColorSystem
+    static final int kColorPointerIndex = 22; // 
+    static final int kColorPointerIndex2 = 23; //
+    static final int kColorRGBValue1Index = 24; // if kColorGradient
+    static final int kColorWidthIndex = 25; // if kColorTexture
+    static final int kColorRGBValue2Index = 26; // if kColorGradient
+    static final int kColorHeightIndex = 27; // if kColorTexture
+    static final int kColorIsCyclicIndex = 28; // if kColorGradient (kColorNonCyclic or kColorCyclic)
+    static final int kColorx1Index = 29;
+    static final int kColortxIndex = 30;
+    static final int kColory1Index = 31;
+    static final int kColortyIndex = 32;
+    static final int kColorx2Index = 33;
+    static final int kColorsxIndex = 34;
+    static final int kColory2Index = 35;
+    static final int kColorsyIndex = 36;
+    // composite info
+    static final int kCompositeRuleIndex = 37; // kCGCompositeClear or ... or kCGCompositeXor
+    static final int kCompositeValueIndex = 38;
+    // stroke info
+    static final int kStrokeJoinIndex = 39; // see BasicStroke.java
+    static final int kStrokeCapIndex = 40; // see BasicStroke.java
+    static final int kStrokeWidthIndex = 41;
+    static final int kStrokeDashPhaseIndex = 42;
+    static final int kStrokeLimitIndex = 43;
+    // hints info
+    static final int kHintsAntialiasIndex = 44;
+    static final int kHintsTextAntialiasIndex = 45;
+    static final int kHintsFractionalMetricsIndex = 46;
+    static final int kHintsRenderingIndex = 47;
+    static final int kHintsInterpolationIndex = 48;
+    // live resizing info
+    static final int kCanDrawDuringLiveResizeIndex = 49;
+    
+    static final int kSizeOfParameters = kCanDrawDuringLiveResizeIndex + 1;
+    
+    // for objectParameters
+    static final int kClipCoordinatesIndex = 0;
+    static final int kClipTypesIndex = 1;
+    static final int kTextureImageIndex = 2;
+    static final int kStrokeDashArrayIndex = 3;
+    static final int kFontIndex = 4;
+    static final int kFontPaintIndex = 5;
+    
+    // possible state changes
+    static final int kBoundsChangedBit = 1 << 0;
+    static final int kBoundsNotChangedBit = ~kBoundsChangedBit;
+    static final int kClipChangedBit = 1 << 1;
+    static final int kClipNotChangedBit = ~kClipChangedBit;
+    static final int kCTMChangedBit = 1 << 2;
+    static final int kCTMNotChangedBit = ~kCTMChangedBit;
+    static final int kColorChangedBit = 1 << 3;
+    static final int kColorNotChangedBit = ~kColorChangedBit;
+    static final int kCompositeChangedBit = 1 << 4;
+    static final int kCompositeNotChangedBit = ~kCompositeChangedBit;
+    static final int kStrokeChangedBit = 1 << 5;
+    static final int kStrokeNotChangedBit = ~kStrokeChangedBit;
+    static final int kHintsChangedBit = 1 << 6;
+    static final int kHintsNotChangedBit = ~kHintsChangedBit;
+    static final int kFontChangedBit = 1 << 7;
+    static final int kFontNotChangedBit = ~kFontChangedBit;
+    static final int kEverythingChangedFlag = 0xffffffff;
+    
+    // possible color states
+    static final int kColorSimple = 0;
+    static final int kColorSystem = 1;
+    static final int kColorGradient = 2;
+    static final int kColorTexture = 3;
+    
+    // possible gradient color states
+    static final int kColorNonCyclic = 0;
+    static final int kColorCyclic = 1;
+    
+    // possible clip states
+    static final int kClipRect = 0;
+    static final int kClipShape = 1;
+    
+    static int getRendererTypeForPrimitive(int primitiveType) {
+        switch (primitiveType) {
+            case kImage:
+                return kImage;
+            case kCopyArea:
+                return kCopyArea;
+            case kExternal:
+                return kExternal;
+            case kString:
+            case kGlyphs:
+            case kUnicodes:
+                return kText;
+            default:
+                return kPrimitive;
+        }
+    }
+    
+    int fChangeFlag;
+    protected ByteBuffer fGraphicsStates = null;
+    IntBuffer fGraphicsStatesInt = null;
+    FloatBuffer fGraphicsStatesFloat = null;
+    LongBuffer fGraphicsStatesLong = null;
+    protected Object[] fGraphicsStatesObject = null;
+    
+    Rectangle userBounds = new Rectangle();
+    float lastUserX = 0;
+    float lastUserY = 0;
+    float lastUserW = 0;
+    float lastUserH = 0;
+    
+    void setUserBounds(SunGraphics2D sg2d, int x, int y, int width, int height) {
+        if ((lastUserX != x) || (lastUserY != y) || (lastUserW != width) || (lastUserH != height)) {
+            lastUserX = x;
+            lastUserY = y;
+            lastUserW = width;
+            lastUserH = height;
+            
+            this.fGraphicsStatesInt.put(kBoundsXIndex, x);
+            this.fGraphicsStatesInt.put(kBoundsYIndex, y);
+            this.fGraphicsStatesInt.put(kBoundsWidthIndex, width);
+            this.fGraphicsStatesInt.put(kBoundsHeightIndex, height);
+            
+            userBounds.setBounds(x, y, width, height);
+            
+            this.fChangeFlag = (this.fChangeFlag | kBoundsChangedBit);
+        } else {
+            this.fChangeFlag = (this.fChangeFlag & kBoundsNotChangedBit);
+        }
+    }
+    
+    static ByteBuffer getBufferOfSize(int size) {
+        ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4);
+        buffer.order(ByteOrder.nativeOrder());
+        return buffer;
+    }
+    
+    FloatBuffer clipCoordinatesArray = null;
+    IntBuffer clipTypesArray = null;
+    Shape lastClipShape = null;
+    float lastClipX = 0;
+    float lastClipY = 0;
+    float lastClipW = 0;
+    float lastClipH = 0;
+    
+    void setupClip(SunGraphics2D sg2d) {
+        switch (sg2d.clipState) {
+            case SunGraphics2D.CLIP_DEVICE:
+            case SunGraphics2D.CLIP_RECTANGULAR: {
+                Region clip = sg2d.getCompClip();
+                float x = clip.getLoX();
+                float y = clip.getLoY();
+                float w = clip.getWidth();
+                float h = clip.getHeight();
+                if ((this.fGraphicsStatesInt.get(kClipStateIndex) != kClipRect) ||
+                        (x != lastClipX) ||
+                            (y != lastClipY) ||
+                                (w != lastClipW) ||
+                                    (h != lastClipH)) {
+                    this.fGraphicsStatesFloat.put(kClipXIndex, x);
+                    this.fGraphicsStatesFloat.put(kClipYIndex, y);
+                    this.fGraphicsStatesFloat.put(kClipWidthIndex, w);
+                    this.fGraphicsStatesFloat.put(kClipHeightIndex, h);
+                    
+                    lastClipX = x;
+                    lastClipY = y;
+                    lastClipW = w;
+                    lastClipH = h;
+                    
+                    this.fChangeFlag = (this.fChangeFlag | kClipChangedBit);
+                } else {
+                    this.fChangeFlag = (this.fChangeFlag & kClipNotChangedBit);
+                }
+                this.fGraphicsStatesInt.put(kClipStateIndex, kClipRect);
+                break;
+            }
+            case SunGraphics2D.CLIP_SHAPE: {
+                // if (lastClipShape != sg2d.usrClip) shapes are mutable!, and doing "equals" traverses all
+                // the coordinates, so we might as well do all of it anyhow
+                lastClipShape = sg2d.usrClip;
+                
+                GeneralPath gp = null;
+                
+                if (sg2d.usrClip instanceof GeneralPath) {
+                    gp = (GeneralPath) sg2d.usrClip;
+                } else {
+                    gp = new GeneralPath(sg2d.usrClip);
+                }
+                
+                int shapeLength = getPathLength(gp);
+                
+                if ((clipCoordinatesArray == null) || (clipCoordinatesArray.capacity() < (shapeLength * 6))) {
+                    clipCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a
+                                                                                             // max of 6 coordinates
+                }
+                if ((clipTypesArray == null) || (clipTypesArray.capacity() < shapeLength)) {
+                    clipTypesArray = getBufferOfSize(shapeLength).asIntBuffer();
+                }
+                
+                int windingRule = getPathCoordinates(gp, clipCoordinatesArray, clipTypesArray);
+                
+                this.fGraphicsStatesInt.put(kClipNumTypesIndex, clipTypesArray.position());
+                this.fGraphicsStatesInt.put(kClipNumCoordsIndex, clipCoordinatesArray.position());
+                this.fGraphicsStatesInt.put(kClipWindingRuleIndex, windingRule);
+                this.fGraphicsStatesObject[kClipTypesIndex] = clipTypesArray;
+                this.fGraphicsStatesObject[kClipCoordinatesIndex] = clipCoordinatesArray;
+                
+                this.fChangeFlag = (this.fChangeFlag | kClipChangedBit);
+                this.fGraphicsStatesInt.put(kClipStateIndex, kClipShape);
+                break;
+            }
+        }
+        
+    }
+    
+    final double[] lastCTM = new double[6];
+    float lastCTMa = 0;
+    float lastCTMb = 0;
+    float lastCTMc = 0;
+    float lastCTMd = 0;
+    float lastCTMtx = 0;
+    float lastCTMty = 0;
+    
+    void setupTransform(SunGraphics2D sg2d) {
+        sg2d.transform.getMatrix(lastCTM);
+        
+        float a = (float) lastCTM[0];
+        float b = (float) lastCTM[1];
+        float c = (float) lastCTM[2];
+        float d = (float) lastCTM[3];
+        float tx = (float) lastCTM[4];
+        float ty = (float) lastCTM[5];
+        if (tx != lastCTMtx ||
+                ty != lastCTMty ||
+                    a != lastCTMa ||
+                        b != lastCTMb ||
+                            c != lastCTMc ||
+                                d != lastCTMd) {
+            this.fGraphicsStatesFloat.put(kCTMaIndex, a);
+            this.fGraphicsStatesFloat.put(kCTMbIndex, b);
+            this.fGraphicsStatesFloat.put(kCTMcIndex, c);
+            this.fGraphicsStatesFloat.put(kCTMdIndex, d);
+            this.fGraphicsStatesFloat.put(kCTMtxIndex, tx);
+            this.fGraphicsStatesFloat.put(kCTMtyIndex, ty);
+            
+            lastCTMa = a;
+            lastCTMb = b;
+            lastCTMc = c;
+            lastCTMd = d;
+            lastCTMtx = tx;
+            lastCTMty = ty;
+            
+            this.fChangeFlag = (this.fChangeFlag | kCTMChangedBit);
+        } else {
+            this.fChangeFlag = (this.fChangeFlag & kCTMNotChangedBit);
+        }
+    }
+    
+    static AffineTransform sIdentityMatrix = new AffineTransform();
+    Paint lastPaint = null;
+    long lastPaintPtr = 0;
+    int lastPaintRGB = 0;
+    int lastPaintIndex = 0;
+    BufferedImage texturePaintImage = null;
+    
+    void setupPaint(SunGraphics2D sg2d, int x, int y, int w, int h) {
+        if (sg2d.paint instanceof SystemColor) {
+            SystemColor color = (SystemColor) sg2d.paint;
+            int index = color.hashCode(); // depends on Color.java hashCode implementation! (returns "value" of color)
+            if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorSystem) || (index != this.lastPaintIndex)) {
+                this.lastPaintIndex = index;
+                
+                this.fGraphicsStatesInt.put(kColorStateIndex, kColorSystem);
+                this.fGraphicsStatesInt.put(kColorIndexValueIndex, index);
+                
+                this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+            } else {
+                this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+            }
+        } else if (sg2d.paint instanceof Color) {
+            Color color = (Color) sg2d.paint;
+            int rgb = color.getRGB();
+            if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorSimple) || (rgb != this.lastPaintRGB)) {
+                this.lastPaintRGB = rgb;
+                
+                this.fGraphicsStatesInt.put(kColorStateIndex, kColorSimple);
+                this.fGraphicsStatesInt.put(kColorRGBValueIndex, rgb);
+                
+                this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+            } else {
+                this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+            }
+        } else if (sg2d.paint instanceof GradientPaint) {
+            if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorGradient) || (lastPaint != sg2d.paint)) {
+                GradientPaint color = (GradientPaint) sg2d.paint;
+                this.fGraphicsStatesInt.put(kColorStateIndex, kColorGradient);
+                this.fGraphicsStatesInt.put(kColorRGBValue1Index, color.getColor1().getRGB());
+                this.fGraphicsStatesInt.put(kColorRGBValue2Index, color.getColor2().getRGB());
+                this.fGraphicsStatesInt.put(kColorIsCyclicIndex, (color.isCyclic()) ? kColorCyclic : kColorNonCyclic);
+                Point2D p = color.getPoint1();
+                this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX());
+                this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY());
+                p = color.getPoint2();
+                this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX());
+                this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY());
+                
+                this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+            } else {
+                this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+            }
+        } else if (sg2d.paint instanceof TexturePaint) {
+            if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint)) {
+                TexturePaint color = (TexturePaint) sg2d.paint;
+                this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture);
+                texturePaintImage = color.getImage();
+                SurfaceData textureSurfaceData = BufImgSurfaceData.createData(texturePaintImage);
+                this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth());
+                this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight());
+                Rectangle2D anchor = color.getAnchorRect();
+                this.fGraphicsStatesFloat.put(kColortxIndex, (float) anchor.getX());
+                this.fGraphicsStatesFloat.put(kColortyIndex, (float) anchor.getY());
+                this.fGraphicsStatesFloat.put(kColorsxIndex, (float) (anchor.getWidth() / texturePaintImage.getWidth()));
+                this.fGraphicsStatesFloat.put(kColorsyIndex, (float) (anchor.getHeight() / texturePaintImage.getHeight()));
+                this.fGraphicsStatesObject[kTextureImageIndex] = textureSurfaceData;
+                
+                this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+            } else {
+                this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+            }
+        } else {
+            if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) {
+                PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints());
+                WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height));
+                ColorModel cm = context.getColorModel();
+                texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
+                
+                this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture);
+                this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth());
+                this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight());
+                this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX());
+                this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY());
+                this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f);
+                this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f);
+                this.fGraphicsStatesObject[kTextureImageIndex] = sun.awt.image.BufImgSurfaceData.createData(texturePaintImage);
+                
+                context.dispose();
+                
+                this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+            } else {
+                this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+            }
+        }
+        lastPaint = sg2d.paint;
+    }
+    
+    Composite lastComposite;
+    int lastCompositeAlphaRule = 0;
+    float lastCompositeAlphaValue = 0;
+    
+    void setupComposite(SunGraphics2D sg2d) {
+        Composite composite = sg2d.composite;
+        
+        if (lastComposite != composite) {
+            lastComposite = composite;
+            
+            // For composite state COMP_ISCOPY, COMP_XOR or COMP_CUSTOM set alpha compositor to COPY:
+            int alphaRule = AlphaComposite.SRC_OVER;
+            float alphaValue = 1.0f;
+            
+            // For composite state COMP_ISCOPY composite could be null. If it's not (or composite state == COMP_ALPHA)
+            // get alpha compositor's values:
+            if ((sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) && (composite != null)) {
+                AlphaComposite alphaComposite = (AlphaComposite) composite;
+                alphaRule = alphaComposite.getRule();
+                alphaValue = alphaComposite.getAlpha();
+            }
+            
+            // 2-17-03 VL: [Radar 3174922]
+            // For COMP_XOR and COMP_CUSTOM compositing modes we should be setting alphaRule = AlphaComposite.SRC
+            // which should map to kCGCompositeCopy.
+            
+            if ((lastCompositeAlphaRule != alphaRule) || (lastCompositeAlphaValue != alphaValue)) {
+                this.fGraphicsStatesInt.put(kCompositeRuleIndex, alphaRule);
+                this.fGraphicsStatesFloat.put(kCompositeValueIndex, alphaValue);
+                
+                lastCompositeAlphaRule = alphaRule;
+                lastCompositeAlphaValue = alphaValue;
+                
+                this.fChangeFlag = (this.fChangeFlag | kCompositeChangedBit);
+            } else {
+                this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit);
+            }
+        } else {
+            this.fChangeFlag = (this.fChangeFlag & kCompositeNotChangedBit);
+        }
+    }
+    
+    BasicStroke lastStroke = null;
+    static BasicStroke defaultBasicStroke = new BasicStroke();
+    
+    void setupStroke(SunGraphics2D sg2d) {
+        BasicStroke stroke = defaultBasicStroke;
+        
+        if (sg2d.stroke instanceof BasicStroke) {
+            stroke = (BasicStroke) sg2d.stroke;
+        }
+        
+        if (lastStroke != stroke) {
+            this.fGraphicsStatesObject[kStrokeDashArrayIndex] = stroke.getDashArray();
+            this.fGraphicsStatesFloat.put(kStrokeDashPhaseIndex, stroke.getDashPhase());
+            this.fGraphicsStatesInt.put(kStrokeCapIndex, stroke.getEndCap());
+            this.fGraphicsStatesInt.put(kStrokeJoinIndex, stroke.getLineJoin());
+            this.fGraphicsStatesFloat.put(kStrokeWidthIndex, stroke.getLineWidth());
+            this.fGraphicsStatesFloat.put(kStrokeLimitIndex, stroke.getMiterLimit());
+            
+            this.fChangeFlag = (this.fChangeFlag | kStrokeChangedBit);
+            
+            lastStroke = stroke;
+        } else {
+            this.fChangeFlag = (this.fChangeFlag & kStrokeNotChangedBit);
+        }
+    }
+    
+    Font lastFont;
+    
+    void setupFont(Font font, Paint paint) {
+        if (font == null) { return; }
+        
+        // We have to setup the kFontPaintIndex if we have changed the color so we added the last
+        // test to see if the color has changed - needed for complex strings
+        // see Radar 3368674
+        if ((font != lastFont) || ((this.fChangeFlag & kColorChangedBit) != 0)) {
+            this.fGraphicsStatesObject[kFontIndex] = font;
+            this.fGraphicsStatesObject[kFontPaintIndex] = paint;
+            
+            this.fChangeFlag = (this.fChangeFlag | kFontChangedBit);
+            
+            lastFont = font;
+        } else {
+            this.fChangeFlag = (this.fChangeFlag & kFontNotChangedBit);
+        }
+    }
+    
+    void setupRenderingHints(SunGraphics2D sg2d) {
+        boolean hintsChanged = false;
+        
+        // Significant for draw, fill, text, and image ops:
+        int antialiasHint = sg2d.antialiasHint;
+        if (this.fGraphicsStatesInt.get(kHintsAntialiasIndex) != antialiasHint) {
+            this.fGraphicsStatesInt.put(kHintsAntialiasIndex, antialiasHint);
+            hintsChanged = true;
+        }
+        
+        // Significant only for text ops:
+        int textAntialiasHint = sg2d.textAntialiasHint;
+        if (this.fGraphicsStatesInt.get(kHintsTextAntialiasIndex) != textAntialiasHint) {
+            this.fGraphicsStatesInt.put(kHintsTextAntialiasIndex, textAntialiasHint);
+            hintsChanged = true;
+        }
+        
+        // Significant only for text ops:
+        int fractionalMetricsHint = sg2d.fractionalMetricsHint;
+        if (this.fGraphicsStatesInt.get(kHintsFractionalMetricsIndex) != fractionalMetricsHint) {
+            this.fGraphicsStatesInt.put(kHintsFractionalMetricsIndex, fractionalMetricsHint);
+            hintsChanged = true;
+        }
+        
+        // Significant only for image ops:
+        int renderHint = sg2d.renderHint;
+        if (this.fGraphicsStatesInt.get(kHintsRenderingIndex) != renderHint) {
+            this.fGraphicsStatesInt.put(kHintsRenderingIndex, renderHint);
+            hintsChanged = true;
+        }
+        
+        // Significant only for image ops:
+        Object hintValue = sg2d.getRenderingHint(RenderingHints.KEY_INTERPOLATION);
+        int interpolationHint = (hintValue != null ? ((SunHints.Value) hintValue).getIndex() : -1);
+        if (this.fGraphicsStatesInt.get(kHintsInterpolationIndex) != interpolationHint) {
+            this.fGraphicsStatesInt.put(kHintsInterpolationIndex, interpolationHint);
+            hintsChanged = true;
+        }
+        
+        if (hintsChanged) {
+            this.fChangeFlag = (this.fChangeFlag | kHintsChangedBit);
+        } else {
+            this.fChangeFlag = (this.fChangeFlag & kHintsNotChangedBit);
+        }
+    }
+    
+    SunGraphics2D sg2dCurrent = null;
+    Thread threadCurrent = null;
+    
+    void setupGraphicsState(SunGraphics2D sg2d, int primitiveType) {
+        setupGraphicsState(sg2d, primitiveType, sg2d.font, 0, 0, fBounds.width, fBounds.height); // deviceBounds into userBounds
+    }
+    
+    void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, int x, int y, int w, int h) {
+        setupGraphicsState(sg2d, primitiveType, sg2d.font, x, y, w, h);
+    }
+    
+    // the method below is overriden by CPeerSurface to check the last peer used to draw
+    // if the peer changed we finish lazy drawing
+    void setupGraphicsState(SunGraphics2D sg2d, int primitiveType, Font font, int x, int y, int w, int h) {
+        this.fChangeFlag = 0;
+        
+        setUserBounds(sg2d, x, y, w, h);
+        
+        Thread thread = Thread.currentThread();
+        if ((this.sg2dCurrent != sg2d) || (this.threadCurrent != thread)) {
+            this.sg2dCurrent = sg2d;
+            this.threadCurrent = thread;
+            
+            setupClip(sg2d);
+            setupTransform(sg2d);
+            setupPaint(sg2d, x, y, w, h);
+            setupComposite(sg2d);
+            setupStroke(sg2d);
+            setupFont(font, sg2d.paint);
+            setupRenderingHints(sg2d);
+            
+            this.fChangeFlag = kEverythingChangedFlag;
+        } else {
+            int rendererType = getRendererTypeForPrimitive(primitiveType);
+            
+            setupClip(sg2d);
+            setupTransform(sg2d);
+            
+            if (rendererType != kCopyArea) {
+                setupComposite(sg2d);
+                setupRenderingHints(sg2d);
+                
+                if ((rendererType != kImage)) {
+                    setupPaint(sg2d, x, y, w, h);
+                    setupStroke(sg2d);
+                }
+                if (rendererType != kPrimitive) {
+                    setupFont(font, sg2d.paint);
+                }
+                
+            }
+        }
+        
+        this.fGraphicsStatesInt.put(kChangeFlagIndex, this.fChangeFlag);
+    }
+    
+    boolean isCustomPaint(SunGraphics2D sg2d) {
+        if ((sg2d.paint instanceof Color) || (sg2d.paint instanceof SystemColor) || (sg2d.paint instanceof GradientPaint) || (sg2d.paint instanceof TexturePaint)) { return false; }
+        
+        return true;
+    }
+    
+    final float[] segmentCoordinatesArray = new float[6];
+    
+    int getPathLength(GeneralPath gp) {
+        int length = 0;
+        
+        PathIterator pi = gp.getPathIterator(null);
+        while (pi.isDone() == false) {
+            pi.next();
+            length++;
+        }
+        
+        return length;
+    }
+    
+    int getPathCoordinates(GeneralPath gp, FloatBuffer coordinates, IntBuffer types) {
+        // System.err.println("getPathCoordinates");
+        boolean skip = false;
+        
+        coordinates.clear();
+        types.clear();
+        
+        int type;
+        
+        PathIterator pi = gp.getPathIterator(null);
+        while (pi.isDone() == false) {
+            skip = false;
+            type = pi.currentSegment(segmentCoordinatesArray);
+            
+            switch (type) {
+                case PathIterator.SEG_MOVETO:
+                    // System.err.println(" SEG_MOVETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")");
+                    if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND &&
+                            segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) {
+                        coordinates.put(segmentCoordinatesArray[0]);
+                        coordinates.put(segmentCoordinatesArray[1]);
+                    } else {
+                        skip = true;
+                    }
+                    break;
+                case PathIterator.SEG_LINETO:
+                    // System.err.println(" SEG_LINETO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+")");
+                    if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND &&
+                            segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND) {
+                        coordinates.put(segmentCoordinatesArray[0]);
+                        coordinates.put(segmentCoordinatesArray[1]);
+                    } else {
+                        skip = true;
+                    }
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+")");
+                    if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND &&
+                            segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND &&
+                            segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND &&
+                            segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND) {
+                        coordinates.put(segmentCoordinatesArray[0]);
+                        coordinates.put(segmentCoordinatesArray[1]);
+                        coordinates.put(segmentCoordinatesArray[2]);
+                        coordinates.put(segmentCoordinatesArray[3]);
+                    } else {
+                        skip = true;
+                    }
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    // System.err.println(" SEG_QUADTO ("+segmentCoordinatesArray[0]+", "+segmentCoordinatesArray[1]+"), ("+segmentCoordinatesArray[2]+", "+segmentCoordinatesArray[3]+"), ("+segmentCoordinatesArray[4]+", "+segmentCoordinatesArray[5]+")");
+                    if (segmentCoordinatesArray[0] < UPPER_BND && segmentCoordinatesArray[0] > LOWER_BND &&
+                            segmentCoordinatesArray[1] < UPPER_BND && segmentCoordinatesArray[1] > LOWER_BND &&
+                            segmentCoordinatesArray[2] < UPPER_BND && segmentCoordinatesArray[2] > LOWER_BND &&
+                            segmentCoordinatesArray[3] < UPPER_BND && segmentCoordinatesArray[3] > LOWER_BND &&
+                            segmentCoordinatesArray[4] < UPPER_BND && segmentCoordinatesArray[4] > LOWER_BND &&
+                            segmentCoordinatesArray[5] < UPPER_BND && segmentCoordinatesArray[5] > LOWER_BND) {
+                        coordinates.put(segmentCoordinatesArray[0]);
+                        coordinates.put(segmentCoordinatesArray[1]);
+                        coordinates.put(segmentCoordinatesArray[2]);
+                        coordinates.put(segmentCoordinatesArray[3]);
+                        coordinates.put(segmentCoordinatesArray[4]);
+                        coordinates.put(segmentCoordinatesArray[5]);
+                    } else {
+                        skip = true;
+                    }
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    // System.err.println(" SEG_CLOSE");
+                    break;
+            }
+            
+            if (!skip) {
+                types.put(type);
+            }
+            
+            pi.next();
+        }
+        
+        return pi.getWindingRule();
+    }
+    
+    public void doLine(CRenderer renderer, SunGraphics2D sg2d, float x1, float y1, float x2, float y2) {
+        // System.err.println("-- doLine x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2+" paint="+sg2d.paint);
+        setupGraphicsState(sg2d, kLine, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        renderer.doLine(this, x1, y1, x2, y2);
+    }
+    
+    public void doRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) {
+        // System.err.println("-- doRect x="+x+" y="+y+" w="+width+" h="+height+" isfill="+isfill+" paint="+sg2d.paint);
+        if ((isfill) && (isCustomPaint(sg2d))) {
+            setupGraphicsState(sg2d, kRect, (int) x, (int) y, (int) width, (int) height);
+        } else {
+            setupGraphicsState(sg2d, kRect, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        }
+        renderer.doRect(this, x, y, width, height, isfill);
+    }
+    
+    public void doRoundRect(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float arcW, float arcH, boolean isfill) {
+        // System.err.println("--- doRoundRect");
+        if ((isfill) && (isCustomPaint(sg2d))) {
+            setupGraphicsState(sg2d, kRoundRect, (int) x, (int) y, (int) width, (int) height);
+        } else {
+            setupGraphicsState(sg2d, kRoundRect, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        }
+        renderer.doRoundRect(this, x, y, width, height, arcW, arcH, isfill);
+    }
+    
+    public void doOval(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, boolean isfill) {
+        // System.err.println("--- doOval");
+        if ((isfill) && (isCustomPaint(sg2d))) {
+            setupGraphicsState(sg2d, kOval, (int) x, (int) y, (int) width, (int) height);
+        } else {
+            setupGraphicsState(sg2d, kOval, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        }
+        renderer.doOval(this, x, y, width, height, isfill);
+    }
+    
+    public void doArc(CRenderer renderer, SunGraphics2D sg2d, float x, float y, float width, float height, float startAngle, float arcAngle, int type, boolean isfill) {
+        // System.err.println("--- doArc");
+        if ((isfill) && (isCustomPaint(sg2d))) {
+            setupGraphicsState(sg2d, kArc, (int) x, (int) y, (int) width, (int) height);
+        } else {
+            setupGraphicsState(sg2d, kArc, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        }
+        
+        renderer.doArc(this, x, y, width, height, startAngle, arcAngle, type, isfill);
+    }
+    
+    public void doPolygon(CRenderer renderer, SunGraphics2D sg2d, int xpoints[], int ypoints[], int npoints, boolean ispolygon, boolean isfill) {
+        // System.err.println("--- doPolygon");
+        
+        if ((isfill) && (isCustomPaint(sg2d))) {
+            int minx = xpoints[0];
+            int miny = ypoints[0];
+            int maxx = minx;
+            int maxy = miny;
+            for (int i = 1; i < npoints; i++) {
+                int x = xpoints[i];
+                if (x < minx) {
+                    minx = x;
+                } else if (x > maxx) {
+                    maxx = x;
+                }
+                
+                int y = ypoints[i];
+                if (y < miny) {
+                    miny = y;
+                } else if (y > maxy) {
+                    maxy = y;
+                }
+            }
+            setupGraphicsState(sg2d, kPolygon, minx, miny, maxx - minx, maxy - miny);
+        } else {
+            setupGraphicsState(sg2d, kPolygon, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        }
+        renderer.doPoly(this, xpoints, ypoints, npoints, ispolygon, isfill);
+    }
+    
+    FloatBuffer shapeCoordinatesArray = null;
+    IntBuffer shapeTypesArray = null;
+    
+    public void drawfillShape(CRenderer renderer, SunGraphics2D sg2d, GeneralPath gp, boolean isfill, boolean shouldApplyOffset) {
+        // System.err.println("--- drawfillShape");
+        
+        if ((isfill) && (isCustomPaint(sg2d))) {
+            Rectangle bounds = gp.getBounds();
+            setupGraphicsState(sg2d, kShape, bounds.x, bounds.y, bounds.width, bounds.height);
+        } else {
+            setupGraphicsState(sg2d, kShape, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        }
+        
+        int shapeLength = getPathLength(gp);
+        
+        if ((shapeCoordinatesArray == null) || (shapeCoordinatesArray.capacity() < (shapeLength * 6))) {
+            shapeCoordinatesArray = getBufferOfSize(shapeLength * 6).asFloatBuffer(); // segment can have a max of 6
+                                                                                      // coordinates
+        }
+        if ((shapeTypesArray == null) || (shapeTypesArray.capacity() < shapeLength)) {
+            shapeTypesArray = getBufferOfSize(shapeLength).asIntBuffer();
+        }
+        
+        int windingRule = getPathCoordinates(gp, shapeCoordinatesArray, shapeTypesArray);
+        
+        renderer.doShape(this, shapeLength, shapeCoordinatesArray, shapeTypesArray, windingRule, isfill, shouldApplyOffset);
+    }
+    
+    public void blitImage(CRenderer renderer, SunGraphics2D sg2d, SurfaceData img, boolean fliph, boolean flipv, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh, Color bgColor) {
+        // System.err.println("--- blitImage sx="+sx+", sy="+sy+", sw="+sw+", sh="+sh+", img="+img);
+        OSXOffScreenSurfaceData osxsd = (OSXOffScreenSurfaceData) img;
+        synchronized (osxsd.getLockObject()) {
+            int w = osxsd.bim.getWidth();
+            int h = osxsd.bim.getHeight();
+            
+            // the image itself can have outstanding graphics primitives that might need to be flushed
+            setupGraphicsState(sg2d, kImage, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+            
+            // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter
+            if (bgColor != null) {
+                img = osxsd.getCopyWithBgColor(bgColor);
+            }
+            
+            renderer.doImage(this, img, fliph, flipv, w, h, sx, sy, sw, sh, dx, dy, dw, dh);
+        }
+    }
+    
+    public interface CGContextDrawable {
+        public void drawIntoCGContext(final long cgContext);
+    }
+    
+    public void drawString(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, String str, double x, double y) {
+        // System.err.println("--- drawString str=\""+str+"\"");
+        // see <rdar://problem/3825795>. We don't want to call anything if the string is empty!
+        if (str.length() == 0) { return; }
+        
+        setupGraphicsState(sg2d, kString, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        renderer.doDrawString(this, nativeStrikePtr, str, x, y);
+    }
+    
+    public void drawGlyphs(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, GlyphVector gv, float x, float y) {
+        // System.err.println("--- drawGlyphs");
+        setupGraphicsState(sg2d, kGlyphs, gv.getFont(), 0, 0, fBounds.width, fBounds.height);
+        renderer.doDrawGlyphs(this, nativeStrikePtr, gv, x, y);
+    }
+    
+    public void drawUnicodes(CTextPipe renderer, SunGraphics2D sg2d, long nativeStrikePtr, char unicodes[], int offset, int length, float x, float y) {
+        // System.err.println("--- drawUnicodes "+(new String(unicodes, offset, length)));
+        setupGraphicsState(sg2d, kUnicodes, sg2d.font, 0, 0, fBounds.width, fBounds.height);
+        if (length == 1) {
+            renderer.doOneUnicode(this, nativeStrikePtr, unicodes[offset], x, y);
+        } else {
+            renderer.doUnicodes(this, nativeStrikePtr, unicodes, offset, length, x, y);
+        }
+    }
+    
+    // used by copyArea:
+    
+    Rectangle srcCopyAreaRect = new Rectangle();
+    Rectangle dstCopyAreaRect = new Rectangle();
+    Rectangle finalCopyAreaRect = new Rectangle();
+    Rectangle copyAreaBounds = new Rectangle();
+    
+    void intersection(Rectangle r1, Rectangle r2, Rectangle r3) {
+        // this code is taken from Rectangle.java (modified to put results in r3)
+        int tx1 = r1.x;
+        int ty1 = r1.y;
+        long tx2 = tx1 + r1.width;
+        long ty2 = ty1 + r1.height;
+        
+        int rx1 = r2.x;
+        int ry1 = r2.y;
+        long rx2 = rx1 + r2.width;
+        long ry2 = ry1 + r2.height;
+        
+        if (tx1 < rx1) tx1 = rx1;
+        if (ty1 < ry1) ty1 = ry1;
+        if (tx2 > rx2) tx2 = rx2;
+        if (ty2 > ry2) ty2 = ry2;
+        
+        tx2 -= tx1;
+        ty2 -= ty1;
+        
+        // tx2,ty2 will never overflow (they will never be
+        // larger than the smallest of the two source w,h)
+        // they might underflow, though...
+        if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
+        if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
+        
+        r3.setBounds(tx1, ty1, (int) tx2, (int) ty2);
+    }
+    
+    /**
+     * Clips the copy area to the heavywieght bounds and returns the cliped rectangle. The tricky part here is the the
+     * passed arguments x, y are in the coordinate space of the sg2d/lightweight comp. In order to do the clipping we
+     * translate them to the coordinate space of the surface, and the returned clipped rectangle is in the coordinate
+     * space of the surface.
+     */
+    protected Rectangle clipCopyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) {
+        // we need to clip against the heavyweight bounds
+        copyAreaBounds.setBounds(sg2d.devClip.getLoX(), sg2d.devClip.getLoY(), sg2d.devClip.getWidth(), sg2d.devClip.getHeight());
+        
+        // put src rect into surface coordinate space
+        x += sg2d.transX;
+        y += sg2d.transY;
+        
+        // clip src rect
+        srcCopyAreaRect.setBounds(x, y, w, h);
+        intersection(srcCopyAreaRect, copyAreaBounds, srcCopyAreaRect);
+        if ((srcCopyAreaRect.width <= 0) || (srcCopyAreaRect.height <= 0)) {
+            // src rect outside bounds
+            return null;
+        }
+        
+        // clip dst rect
+        dstCopyAreaRect.setBounds(srcCopyAreaRect.x + dx, srcCopyAreaRect.y + dy, srcCopyAreaRect.width, srcCopyAreaRect.height);
+        intersection(dstCopyAreaRect, copyAreaBounds, dstCopyAreaRect);
+        if ((dstCopyAreaRect.width <= 0) || (dstCopyAreaRect.height <= 0)) {
+            // dst rect outside clip
+            return null;
+        }
+        
+        x = dstCopyAreaRect.x - dx;
+        y = dstCopyAreaRect.y - dy;
+        w = dstCopyAreaRect.width;
+        h = dstCopyAreaRect.height;
+        
+        finalCopyAreaRect.setBounds(x, y, w, h);
+        
+        return finalCopyAreaRect;
+    }
+    
+    // <rdar://3785539> We only need to mark dirty on screen surfaces. This method is
+    // marked as protected and it is intended for subclasses to override if they need to
+    // be notified when the surface is dirtied. See CPeerSurfaceData.markDirty() for implementation.
+    // We don't do anything for buffered images.
+    protected void markDirty(boolean markAsDirty) {
+        // do nothing by default
+    }
+    
+    // LazyDrawing optimization implementation:
+    
+    @Override
+    public boolean canRenderLCDText(SunGraphics2D sg2d) {
+        if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&
+                sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
+                sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR &&
+                // sg2d.surfaceData.getTransparency() == Transparency.OPAQUE &&
+                // This last test is a workaround until we fix loop selection
+                // in the pipe validation
+                sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) { return true; }
+        return false; /* for now - in the future we may want to search */
+    }
+    
+    public static boolean IsSimpleColor(Object c) {
+        return ((c instanceof Color) || (c instanceof SystemColor) || (c instanceof javax.swing.plaf.ColorUIResource));
+    }
+    
+    static {
+        if ((kColorPointerIndex % 2) != 0) {
+            System.err.println("kColorPointerIndex=" + kColorPointerIndex + " is NOT aligned for 64 bit");
+            System.exit(0);
+        }
+    }
+}
--- a/src/macosx/classes/sun/lwawt/LWComponentPeer.java	Fri Sep 23 21:13:13 2011 +0400
+++ b/src/macosx/classes/sun/lwawt/LWComponentPeer.java	Fri Sep 23 13:42:06 2011 -0700
@@ -47,12 +47,7 @@
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import sun.awt.AWTAccessor;
-import sun.awt.CausedFocusEvent;
-import sun.awt.PaintEventDispatcher;
-import sun.awt.RepaintArea;
-import sun.awt.SunToolkit;
-import sun.awt.AppContext;
+import sun.awt.*;
 
 import sun.awt.event.IgnorePaintEvent;
 
@@ -659,7 +654,15 @@
 
     @Override
     public void print(Graphics g) {
-        // TODO: not implemented
+        Component c = getTarget();
+        if (c instanceof Container) {
+            SunGraphicsCallback.PrintHeavyweightComponentsCallback.getInstance().
+                runComponents(((Container)getTarget()).getComponents(), g,
+                    SunGraphicsCallback.LIGHTWEIGHTS |
+                    SunGraphicsCallback.HEAVYWEIGHTS);
+        } else {
+            c.print(g);
+        }
     }
 
     @Override
--- a/src/macosx/classes/sun/lwawt/LWToolkit.java	Fri Sep 23 21:13:13 2011 +0400
+++ b/src/macosx/classes/sun/lwawt/LWToolkit.java	Fri Sep 23 13:42:06 2011 -0700
@@ -27,17 +27,17 @@
 
 import java.awt.*;
 import java.awt.List;
-import java.awt.datatransfer.Clipboard;
-import java.awt.dnd.DragGestureEvent;
-import java.awt.dnd.peer.DragSourceContextPeer;
-import java.awt.image.ColorModel;
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import java.awt.dnd.peer.*;
+import java.awt.image.*;
 import java.awt.peer.*;
 import java.security.*;
 import java.util.*;
 
-import sun.lwawt.macosx.CDragSourceContextPeer;
-
 import sun.awt.*;
+import sun.lwawt.macosx.*;
+import sun.print.*;
 
 public abstract class LWToolkit extends SunToolkit implements Runnable {
 
@@ -232,8 +232,20 @@
         return createDelegatedPeer(target, delegate);
     }
 
+    
+    CPrinterDialogPeer createCPrinterDialog(CPrinterDialog target) {
+        PlatformWindow delegate = createPlatformWindow(LWWindowPeer.PeerType.DIALOG);
+        CPrinterDialogPeer peer = new CPrinterDialogPeer(target, delegate);
+        targetCreatedPeer(target, peer);
+        return peer;
+    }
+    
     @Override
     public DialogPeer createDialog(Dialog target) {
+        if (target instanceof CPrinterDialog) {
+            return createCPrinterDialog((CPrinterDialog)target);
+        } 
+        
         PlatformWindow delegate = createPlatformWindow(LWWindowPeer.PeerType.DIALOG);
         return createDelegatedPeer(target, delegate);
     }
@@ -408,9 +420,22 @@
         return new LWMouseInfoPeer();
     }
 
-    @Override
-    public PrintJob getPrintJob(Frame frame, String jobtitle, Properties props) {
-        throw new RuntimeException("not implemented");
+    public PrintJob getPrintJob(Frame frame, String doctitle, Properties props) {
+        return getPrintJob(frame, doctitle, null, null);
+    }
+
+    public PrintJob getPrintJob(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) {
+        if (GraphicsEnvironment.isHeadless()) {
+            throw new IllegalArgumentException();
+        }
+        
+        PrintJob2D printJob = new PrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
+        
+        if (printJob.printDialog() == false) {
+            printJob = null;
+        }
+        
+        return printJob;
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterDevice.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+import java.awt.*;
+
+public class CPrinterDevice extends GraphicsDevice {
+    GraphicsConfiguration gc;
+    
+    public CPrinterDevice(CPrinterGraphicsConfig gc) {
+        this.gc = gc;
+    }
+
+    /**
+     * Returns the type of this <code>GraphicsDevice</code>.
+     * @return the type of this <code>GraphicsDevice</code>, which can
+     * either be TYPE_RASTER_SCREEN, TYPE_PRINTER or TYPE_IMAGE_BUFFER.
+     * @see #TYPE_RASTER_SCREEN
+     * @see #TYPE_PRINTER
+     * @see #TYPE_IMAGE_BUFFER
+     */
+    public int getType() {
+        return GraphicsDevice.TYPE_PRINTER;
+    }
+
+    /**
+     * Returns the identification string associated with this 
+     * <code>GraphicsDevice</code>.
+     * @return a <code>String</code> that is the identification
+     * of this <code>GraphicsDevice</code>.
+     */
+    public String getIDstring() {
+        return ("Printer");
+    }
+    
+    /**
+     * Returns all of the <code>GraphicsConfiguration</code>
+     * objects associated with this <code>GraphicsDevice</code>.
+     * @return an array of <code>GraphicsConfiguration</code>
+     * objects that are associated with this 
+     * <code>GraphicsDevice</code>.
+     */
+    public GraphicsConfiguration[] getConfigurations() {
+        return new GraphicsConfiguration[] { gc };
+    }
+
+    /**
+     * Returns the default <code>GraphicsConfiguration</code>
+     * associated with this <code>GraphicsDevice</code>.
+     * @return the default <code>GraphicsConfiguration</code>
+     * of this <code>GraphicsDevice</code>.
+     */
+    public GraphicsConfiguration getDefaultConfiguration() {
+        return gc;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterDialog.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+import java.awt.*;
+
+public abstract class CPrinterDialog extends Dialog {
+    private final CPrinterJob fPrinterJob; // used from native
+    
+    CPrinterDialog(Frame parent, CPrinterJob printerJob) {
+        super(parent, true);
+        fPrinterJob = printerJob;
+        setLayout(null);
+    }
+    
+    private boolean retval = false;
+    
+    public void setRetVal(boolean ret) {
+        retval = ret;
+    }
+    
+    public boolean getRetVal() {
+        return retval;
+    }
+    
+    protected abstract boolean showDialog();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+import java.awt.*;
+import java.awt.dnd.*;
+
+import sun.lwawt.*;
+
+public class CPrinterDialogPeer extends LWWindowPeer {
+    static {
+        // AWT has to be initialized for the native code to function correctly.
+        Toolkit.getDefaultToolkit();
+    }
+
+    Component fTarget;
+
+    public CPrinterDialogPeer(CPrinterDialog target, PlatformWindow delegate) {
+        super(target, delegate); 
+        //super(target);
+        fTarget = target;
+        super.initialize();
+    }
+
+    protected void disposeImpl() {
+        LWCToolkit.targetDisposedPeer(fTarget, this);
+    }
+
+    public void setVisible(boolean visible) {
+        if (visible) {
+            new Thread(new Runnable() {
+                public void run() {
+                    CPrinterDialog printerDialog = (CPrinterDialog)fTarget;
+                    printerDialog.setRetVal(printerDialog.showDialog());
+                    printerDialog.setVisible(false);
+                }
+            }).start();
+        }
+    }
+
+    // unused methods.
+    public void toFront() {}
+    public void toBack() {}
+    public void setResizable(boolean resizable) {}
+    public void setEnabled(boolean enable) {}
+    public void setBounds(int x, int y, int width, int height) {}
+    public boolean handleEvent(Event e) { return false; }
+    public void setForeground(Color c) {}
+    public void setBackground(Color c) {}
+    public void setFont(Font f) {}
+    public boolean requestFocus(boolean temporary, boolean focusedWindowChangeAllowed) {
+        return false;
+    }
+    void start() {}
+    void invalidate(int x, int y, int width, int height) {}
+    public void addDropTarget(DropTarget dt) {}
+    public void removeDropTarget(DropTarget dt) {}
+    
+    // 1.5 peer method
+    public boolean isRestackSupported() {
+        return false;
+    } 
+    
+    // 1.6 peer method
+    public void setAlwaysOnTop(boolean value) {
+        // no-op, since we just show the native print dialog
+    }
+    
+    // 1.6 peer method
+    public void updateMinimumSize() {}
+
+    // 1.6 peer method    
+    public void setModalBlocked(Dialog blocker, boolean blocked) {
+        // I don't think we care since this is a native dialog
+    }
+
+    // 1.6 peer method    
+    public void updateFocusableWindowState() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.print.*;
+import sun.print.*;
+
+public class CPrinterGraphics extends ProxyGraphics2D {
+    // NOTE: This is a ProxyGraphics2D, and not a PathGraphics. However
+    // the RasterPrinterJob, upon which CPrinterJob is based, refers to
+    // PathGraphics. However, this is not a code path that will be 
+    // encountered by CPrinterJob/CPrinterGraphics. This is because
+    // CPrinterGraphics wraps a SunGraphics2D that has a OSXSurfaceData
+    // based CPrinterSurfaceData. It can do "path graphics" because it
+    // is based upon CoreGraphics. See WPathGraphics and PSPathGraphics.
+
+    public CPrinterGraphics(Graphics2D graphics, PrinterJob printerJob) {
+        super(graphics, printerJob);
+    }
+
+    public boolean drawImage(Image img, int x, int y, 
+                 Color bgcolor,
+                 ImageObserver observer) {
+        // ProxyGraphics2D works around a problem that shouldn't be
+        // a problem with CPrinterSurfaceData (and the decision method,
+        // needToCopyBgColorImage, is private instead of protected!)
+        return getDelegate().drawImage(img, x, y, bgcolor, observer);
+    }
+
+    public boolean drawImage(Image img, int x, int y,
+                 int width, int height, 
+                 Color bgcolor,
+                 ImageObserver observer) {
+        // ProxyGraphics2D works around a problem that shouldn't be
+        // a problem with CPrinterSurfaceData (and the decision method,
+        // needToCopyBgColorImage, is private instead of protected!)
+        return getDelegate().drawImage(img, x, y, width, height, bgcolor, observer);
+    }
+
+    public boolean drawImage(Image img,
+                 int dx1, int dy1, int dx2, int dy2,
+                 int sx1, int sy1, int sx2, int sy2,
+                 Color bgcolor,
+                 ImageObserver observer) {
+        // ProxyGraphics2D works around a problem that shouldn't be
+        // a problem with CPrinterSurfaceData (and the decision method,
+        // needToCopyBgColorImage, is private instead of protected!)
+        return getDelegate().drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterGraphicsConfig.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.awt.print.*;
+
+public class CPrinterGraphicsConfig extends GraphicsConfiguration {
+    public static CPrinterGraphicsConfig getConfig(PageFormat pf) {
+        return new CPrinterGraphicsConfig(pf);
+    }
+    
+    GraphicsDevice gd;
+    PageFormat pf;
+    
+    public CPrinterGraphicsConfig(PageFormat pf) {
+        this.gd = new CPrinterDevice(this);
+        this.pf = pf;
+    }
+
+    public PageFormat getPageFormat() {
+        return pf;
+    }
+    
+    /**
+     * Returns the {@link GraphicsDevice} associated with this
+     * <code>GraphicsConfiguration</code>.
+     * @return a <code>GraphicsDevice</code> object that is 
+     * associated with this <code>GraphicsConfiguration</code>.
+     */
+    public GraphicsDevice getDevice() {
+        return gd;
+    }
+
+    /**
+     * Returns a {@link BufferedImage} with a data layout and color model
+     * compatible with this <code>GraphicsConfiguration</code>.  This
+     * method has nothing to do with memory-mapping
+     * a device.  The returned <code>BufferedImage</code> has
+     * a layout and color model that is closest to this native device
+     * configuration and can therefore be optimally blitted to this
+     * device.
+     * @param width the width of the returned <code>BufferedImage</code>
+     * @param height the height of the returned <code>BufferedImage</code>
+     * @return a <code>BufferedImage</code> whose data layout and color
+     * model is compatible with this <code>GraphicsConfiguration</code>.
+     */
+    public BufferedImage createCompatibleImage(int width, int height) {
+        return createCompatibleImage(width, height, Transparency.OPAQUE);
+    }
+
+    /**
+     * Returns a {@link VolatileImage} with a data layout and color model
+     * compatible with this <code>GraphicsConfiguration</code>.  
+     * The returned <code>VolatileImage</code> 
+     * may have data that is stored optimally for the underlying graphics 
+     * device and may therefore benefit from platform-specific rendering 
+     * acceleration.
+     * @param width the width of the returned <code>VolatileImage</code>
+     * @param height the height of the returned <code>VolatileImage</code>
+     * @return a <code>VolatileImage</code> whose data layout and color
+     * model is compatible with this <code>GraphicsConfiguration</code>.
+     * @see Component#createVolatileImage(int, int)
+     */
+    public VolatileImage createCompatibleVolatileImage(int width, int height) {
+        return createCompatibleVolatileImage(width, height, Transparency.OPAQUE);
+    }
+    
+    // empty implementation (this should not be called)
+    public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) {
+        return null;
+    }
+
+    /**
+     * Returns a <code>BufferedImage</code> that supports the specified
+     * transparency and has a data layout and color model
+     * compatible with this <code>GraphicsConfiguration</code>.  This
+     * method has nothing to do with memory-mapping
+     * a device. The returned <code>BufferedImage</code> has a layout and
+     * color model that can be optimally blitted to a device
+     * with this <code>GraphicsConfiguration</code>.
+     * @param width the width of the returned <code>BufferedImage</code>
+     * @param height the height of the returned <code>BufferedImage</code>
+     * @param transparency the specified transparency mode
+     * @return a <code>BufferedImage</code> whose data layout and color  
+     * model is compatible with this <code>GraphicsConfiguration</code>
+     * and also supports the specified transparency.
+     * @see Transparency#OPAQUE
+     * @see Transparency#BITMASK
+     * @see Transparency#TRANSLUCENT
+     */
+    public BufferedImage createCompatibleImage(int width, int height, int transparency) {
+        //+++gdb what to do?
+        return null;
+    }
+
+    /**
+     * Returns the {@link ColorModel} associated with this 
+     * <code>GraphicsConfiguration</code>.
+     * @return a <code>ColorModel</code> object that is associated with
+     * this <code>GraphicsConfiguration</code>.
+     */
+    public ColorModel getColorModel() {
+        return getColorModel(Transparency.OPAQUE);
+    }
+
+    /**
+     * Returns the <code>ColorModel</code> associated with this
+     * <code>GraphicsConfiguration</code> that supports the specified
+     * transparency.
+     * @param transparency the specified transparency mode
+     * @return a <code>ColorModel</code> object that is associated with
+     * this <code>GraphicsConfiguration</code> and supports the 
+     * specified transparency.
+     */
+    public ColorModel getColorModel(int transparency) {
+        return ColorModel.getRGBdefault();
+    }
+
+    /**
+     * Returns the default {@link AffineTransform} for this 
+     * <code>GraphicsConfiguration</code>. This
+     * <code>AffineTransform</code> is typically the Identity transform
+     * for most normal screens.  The default <code>AffineTransform</code>
+     * maps coordinates onto the device such that 72 user space
+     * coordinate units measure approximately 1 inch in device
+     * space.  The normalizing transform can be used to make
+     * this mapping more exact.  Coordinates in the coordinate space
+     * defined by the default <code>AffineTransform</code> for screen and
+     * printer devices have the origin in the upper left-hand corner of
+     * the target region of the device, with X coordinates
+     * increasing to the right and Y coordinates increasing downwards.
+     * For image buffers not associated with a device, such as those not
+     * created by <code>createCompatibleImage</code>,
+     * this <code>AffineTransform</code> is the Identity transform.
+     * @return the default <code>AffineTransform</code> for this
+     * <code>GraphicsConfiguration</code>.
+     */
+    public AffineTransform getDefaultTransform() {
+        return new AffineTransform();
+    }
+
+    /**
+     *
+     * Returns a <code>AffineTransform</code> that can be concatenated
+     * with the default <code>AffineTransform</code>
+     * of a <code>GraphicsConfiguration</code> so that 72 units in user
+     * space equals 1 inch in device space.  
+     * <p>
+     * For a particular {@link Graphics2D}, g, one
+     * can reset the transformation to create
+     * such a mapping by using the following pseudocode:
+     * <pre>
+     *      GraphicsConfiguration gc = g.getGraphicsConfiguration();
+     *
+     *      g.setTransform(gc.getDefaultTransform());
+     *      g.transform(gc.getNormalizingTransform());
+     * </pre>
+     * Note that sometimes this <code>AffineTransform</code> is identity,
+     * such as for printers or metafile output, and that this 
+     * <code>AffineTransform</code> is only as accurate as the information
+     * supplied by the underlying system.  For image buffers not
+     * associated with a device, such as those not created by
+     * <code>createCompatibleImage</code>, this
+     * <code>AffineTransform</code> is the Identity transform
+     * since there is no valid distance measurement.
+     * @return an <code>AffineTransform</code> to concatenate to the
+     * default <code>AffineTransform</code> so that 72 units in user
+     * space is mapped to 1 inch in device space.
+     */
+    public AffineTransform getNormalizingTransform() {
+        return new AffineTransform();
+    }
+
+    /**
+     * Returns the bounds of the <code>GraphicsConfiguration</code>
+     * in the device coordinates. In a multi-screen environment
+     * with a virtual device, the bounds can have negative X
+     * or Y origins.
+     * @return the bounds of the area covered by this
+     * <code>GraphicsConfiguration</code>.
+     * @since 1.3
+     */
+    public Rectangle getBounds() {
+        return new Rectangle(0, 0, (int)pf.getWidth(), (int)pf.getHeight());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,659 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.print.*;
+
+import javax.print.*;
+import javax.print.attribute.PrintRequestAttributeSet;
+
+import sun.java2d.*;
+import sun.print.*;
+
+public class CPrinterJob extends RasterPrinterJob {
+    // NOTE: This uses RasterPrinterJob as a base, but it doesn't use
+    // all of the RasterPrinterJob functions. RasterPrinterJob will
+    // break down printing to pieces that aren't necessary under MacOSX
+    // printing, such as controlling the # of copies and collating. These
+    // are handled by the native printing. RasterPrinterJob is kept for
+    // future compatibility and the state keeping that it handles.
+    
+    private static String sShouldNotReachHere = "Should not reach here.";
+    
+    private boolean noDefaultPrinter = false;
+
+    private static Font defaultFont;
+    
+    // This is the NSPrintInfo for this PrinterJob. Protect multi thread
+    //  access to it. It is used by the pageDialog, jobDialog, and printLoop.
+    //  This way the state of these items is shared across these calls.
+    //  PageFormat data is passed in and set on the fNSPrintInfo on a per call
+    //  basis.
+    private long fNSPrintInfo = -1;
+    private Object fNSPrintInfoLock = new Object();
+    
+    static {
+        // AWT has to be initialized for the native code to function correctly.
+        Toolkit.getDefaultToolkit();
+    }
+    
+    /**
+     * Presents a dialog to the user for changing the properties of
+     * the print job.
+     * This method will display a native dialog if a native print
+     * service is selected, and user choice of printers will be restricted
+     * to these native print services.
+     * To present the cross platform print dialog for all services,
+     * including native ones instead use
+     * <code>printDialog(PrintRequestAttributeSet)</code>.
+     * <p>
+     * PrinterJob implementations which can use PrintService's will update
+     * the PrintService for this PrinterJob to reflect the new service
+     * selected by the user.
+     * @return <code>true</code> if the user does not cancel the dialog;
+     * <code>false</code> otherwise.
+     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+     * returns true.
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     */
+    public boolean printDialog() throws HeadlessException {
+        if (GraphicsEnvironment.isHeadless()) {
+            throw new HeadlessException();
+        }
+        
+        if (noDefaultPrinter) {
+            return false;
+        }
+    
+        return jobSetup(getPageable(), checkAllowedToPrintToFile());
+    }
+    
+    /**
+     * Displays a dialog that allows modification of a
+     * <code>PageFormat</code> instance.
+     * The <code>page</code> argument is used to initialize controls
+     * in the page setup dialog.
+     * If the user cancels the dialog then this method returns the
+     * original <code>page</code> object unmodified.
+     * If the user okays the dialog then this method returns a new
+     * <code>PageFormat</code> object with the indicated changes.
+     * In either case, the original <code>page</code> object is
+     * not modified.
+     * @param page the default <code>PageFormat</code> presented to the
+     *            user for modification
+     * @return    the original <code>page</code> object if the dialog
+     *            is cancelled; a new <code>PageFormat</code> object
+     *          containing the format indicated by the user if the
+     *          dialog is acknowledged.
+     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
+     * returns true.
+     * @see java.awt.GraphicsEnvironment#isHeadless
+     * @since     1.2
+     */
+    public PageFormat pageDialog(PageFormat page) throws HeadlessException {
+        if (GraphicsEnvironment.isHeadless()) {
+            throw new HeadlessException();
+        }
+        
+        if (noDefaultPrinter) {
+            return page;
+        }
+        
+        PageFormat pageClone = (PageFormat) page.clone();
+        boolean doIt = pageSetup(pageClone, null);
+        return doIt ? pageClone : page;
+    }
+
+    /**
+     * Clones the <code>PageFormat</code> argument and alters the
+     * clone to describe a default page size and orientation.
+     * @param page the <code>PageFormat</code> to be cloned and altered
+     * @return clone of <code>page</code>, altered to describe a default
+     *                      <code>PageFormat</code>.
+     */
+    public PageFormat defaultPage(PageFormat page) {
+        PageFormat newPage = (PageFormat)page.clone();
+        getDefaultPage(newPage); 
+        return newPage;
+    }
+
+    protected void setAttributes(PrintRequestAttributeSet attributes) throws PrinterException {
+        super.setAttributes(attributes);
+        
+        if (attributes == null) {
+            return;
+        }
+        
+        // See if this has an NSPrintInfo in it.
+        NSPrintInfo nsPrintInfo = (NSPrintInfo)attributes.get(NSPrintInfo.class);
+        if (nsPrintInfo != null) {
+            fNSPrintInfo = nsPrintInfo.getValue();
+        }
+    }
+
+    volatile boolean onEventThread;
+    
+    private void completePrintLoop() {
+        Runnable r = new Runnable() { public void run() {
+            synchronized(this) {
+                performingPrinting = false;
+            }
+        }};
+        
+        if (onEventThread) {
+            try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); }
+        } else {
+            r.run();
+        }
+    }
+    
+    
+    public void print(PrintRequestAttributeSet attributes) throws PrinterException {
+        // NOTE: Some of this code is copied from RasterPrinterJob.
+        
+/*
+        // this code uses javax.print APIs
+        // this will make it print directly to the printer
+        // this will not work if the user clicks on the "Preview" button
+        PrintService psvc = getPrintService();
+        spoolToService(psvc, attributes);
+        return;
+*/
+        
+        setAttributes(attributes);
+        
+        /* Get the range of pages we are to print. If the
+         * last page to print is unknown, then we print to
+         * the end of the document. Note that firstPage
+         * and lastPage are 0 based page indices.
+         */
+        int numPages = mDocument.getNumberOfPages();
+        
+        int firstPage = getFirstPage();
+        int lastPage = getLastPage();
+        if(lastPage == Pageable.UNKNOWN_NUMBER_OF_PAGES) {
+            int totalPages = mDocument.getNumberOfPages();
+            if (totalPages != Pageable.UNKNOWN_NUMBER_OF_PAGES) {
+                lastPage = mDocument.getNumberOfPages() - 1;
+            }
+        }
+        
+        try {
+            synchronized (this) {
+                performingPrinting = true;
+                userCancelled = false;
+            }
+            
+            if (EventQueue.isDispatchThread()) {
+                // This is an AWT EventQueue, and this print rendering loop needs to block it.
+                
+                onEventThread = true;
+                
+                try {
+                    // Fire off the print rendering loop on the AppKit thread, and don't have
+                    //  it wait and block this thread.
+                    if (printLoop(false, firstPage, lastPage)) {
+                        // Fire off the EventConditional that will what until the condition is met, 
+                        //  but will still process AWTEvent's as they occur.
+                        new EventDispatchAccess() {
+                            public boolean evaluate() {
+                                return performingPrinting;
+                            }
+                        }.pumpEventsAndWait();
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            } else {
+                // Fire off the print rendering loop on the AppKit, and block this thread
+                //  until it is done.
+                // But don't actually block... we need to come back here!
+                onEventThread = false;
+                
+                try {
+                    printLoop(true, firstPage, lastPage);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        } finally {
+            synchronized (this) {
+                // NOTE: Native code shouldn't allow exceptions out while
+                // printing. They should cancel the print loop.
+                performingPrinting = false;
+                notify();
+            }
+        }
+        
+        // Normalize the collated, # copies, numPages, first/last pages. Need to
+        //  make note of pageRangesAttr.
+        
+        // Set up NSPrintInfo with the java settings (PageFormat & Paper).
+        
+        // Create an NSView for printing. Have knowsPageRange return YES, and give the correct
+        //  range, or MAX? if unknown. Have rectForPage do a peekGraphics check before returning 
+        //  the rectangle. Have drawRect do the real render of the page. Have printJobTitle do
+        //  the right thing.
+        
+        // Call NSPrintOperation, it will call NSView.drawRect: for each page.
+        
+        // NSView.drawRect: will create a CPrinterGraphics with the current CGContextRef, and then
+        //  pass this Graphics onto the Printable with the appropriate PageFormat and index.
+        
+        // Need to be able to cancel the NSPrintOperation (using code from RasterPrinterJob, be
+        //  sure to initialize userCancelled and performingPrinting member variables).
+        
+        // Extensions available from AppKit: Print to PDF or EPS file!
+    }
+    
+    /**
+     * Returns the resolution in dots per inch across the width
+     * of the page.
+     */
+    protected double getXRes() {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Returns the resolution in dots per inch down the height
+     * of the page.
+     */
+    protected double getYRes() {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }    
+
+    /**
+     * Must be obtained from the current printer.
+     * Value is in device pixels.
+     * Not adjusted for orientation of the paper.
+     */
+    protected double getPhysicalPrintableX(Paper p) {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Must be obtained from the current printer.
+     * Value is in device pixels.
+     * Not adjusted for orientation of the paper.
+     */
+    protected double getPhysicalPrintableY(Paper p) {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Must be obtained from the current printer.
+     * Value is in device pixels.
+     * Not adjusted for orientation of the paper.
+     */
+    protected double getPhysicalPrintableWidth(Paper p) {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Must be obtained from the current printer.
+     * Value is in device pixels.
+     * Not adjusted for orientation of the paper.
+     */
+    protected double getPhysicalPrintableHeight(Paper p) {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Must be obtained from the current printer.
+     * Value is in device pixels.
+     * Not adjusted for orientation of the paper.
+     */
+    protected double getPhysicalPageWidth(Paper p) {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Must be obtained from the current printer.
+     * Value is in device pixels.
+     * Not adjusted for orientation of the paper.
+     */
+    protected double getPhysicalPageHeight(Paper p) {
+        // NOTE: This is not used in the CPrinterJob code path.
+        return 0;
+    }
+
+    /**
+     * Begin a new page. This call's Window's
+     * StartPage routine.
+     */
+    protected void startPage(PageFormat format, Printable painter, int index) throws PrinterException {
+        // NOTE: This is not used in the CPrinterJob code path.
+        throw new PrinterException(sShouldNotReachHere);
+    }
+
+    /**
+     * End a page.
+     */
+    protected void endPage(PageFormat format, Printable painter, int index) throws PrinterException {
+        // NOTE: This is not used in the CPrinterJob code path.
+        throw new PrinterException(sShouldNotReachHere);
+    }
+
+    /**
+     * Prints the contents of the array of ints, 'data'
+     * to the current page. The band is placed at the
+     * location (x, y) in device coordinates on the
+     * page. The width and height of the band is
+     * specified by the caller.
+     */
+    protected void printBand(byte[] data, int x, int y, int width, int height) throws PrinterException {
+        // NOTE: This is not used in the CPrinterJob code path.
+        throw new PrinterException(sShouldNotReachHere);
+    }
+
+    /**
+     * Called by the print() method at the start of
+     * a print job.
+     */
+    protected void startDoc() throws PrinterException {
+        // NOTE: This is not used in the CPrinterJob code path.
+        throw new PrinterException(sShouldNotReachHere);
+    }
+
+    /**
+     * Called by the print() method at the end of
+     * a print job.
+     */
+    protected void endDoc() throws PrinterException {
+        // NOTE: This is not used in the CPrinterJob code path.
+        throw new PrinterException(sShouldNotReachHere);
+    }
+
+    /* Called by cancelDoc */
+    protected native void abortDoc();
+
+    /**
+     * Displays the page setup dialog placing the user's
+     * settings into 'page'.
+     */
+    public boolean pageSetup(PageFormat page, Printable painter) {
+        CPrinterDialog printerDialog = new CPrinterPageDialog(null, this, page, painter);
+        printerDialog.setVisible(true);
+        boolean result = printerDialog.getRetVal();
+        printerDialog.dispose();
+        return result;
+    }
+
+    /**
+     * Displays the print dialog and records the user's settings
+     * into this object. Return false if the user cancels the
+     * dialog.
+     * If the dialog is to use a set of attributes, useAttributes is true.
+     */
+    private boolean jobSetup(Pageable doc, boolean allowPrintToFile) {
+        CPrinterDialog printerDialog = new CPrinterJobDialog(null, this, doc, allowPrintToFile);
+        printerDialog.setVisible(true);
+        boolean result = printerDialog.getRetVal();
+        printerDialog.dispose();
+        return result;
+    }
+
+    /**
+     * Alters the orientation and Paper to match defaults obtained
+     * from a printer.
+     */
+    private native void getDefaultPage(PageFormat page);
+
+    /**
+     * validate the paper size against the current printer.
+     */
+    protected native void validatePaper(Paper origPaper, Paper newPaper );
+    
+    // The following methods are CPrinterJob specific.
+    
+    protected void finalize() {
+        if (fNSPrintInfo != -1) {
+            dispose(fNSPrintInfo);
+        }
+    }
+
+    private native long createNSPrintInfo();
+    private native void dispose(long printInfo);
+    
+    private long getNSPrintInfo() {
+        // This is called from the native side.
+        synchronized (fNSPrintInfoLock) {
+            if (fNSPrintInfo == -1) {
+                fNSPrintInfo = createNSPrintInfo();
+            }
+            return fNSPrintInfo;
+        }
+    }
+    
+    private native boolean printLoop(boolean waitUntilDone, int firstPage, int lastPage) throws PrinterException;
+    
+    private PageFormat getPageFormat(int pageIndex) {
+        // This is called from the native side.
+        PageFormat page;
+        try {
+            page = getPageable().getPageFormat(pageIndex);
+        } catch (Exception e) {
+            return null;
+        }
+        return page;
+    }
+    
+    private Printable getPrintable(int pageIndex) {
+        // This is called from the native side.
+        Printable painter;
+        try {
+            painter = getPageable().getPrintable(pageIndex);
+        } catch (Exception e) {
+            return null;
+        }
+        return painter;
+    }
+    
+    private String getPrinterName(){
+        // This is called from the native side.
+        PrintService service = getPrintService();
+        if (service == null) return null;
+        return service.getName();
+    }
+    
+    private void setPrinterServiceFromNative(String printerName) {
+        // This is called from the native side.
+        PrintService[] services = PrintServiceLookup.lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
+        
+        for (int i = 0; i < services.length; i++) {
+            PrintService service = services[i];
+            
+            if (printerName.equals(service.getName())) {
+                try {
+                    setPrintService(service);
+                } catch (PrinterException e) {
+                    // ignored
+                }
+                return;
+            }
+        }
+    }
+    
+    private Rectangle2D getPageFormatArea(PageFormat page) {
+        Rectangle2D.Double pageFormatArea =
+            new Rectangle2D.Double(page.getImageableX(),
+                    page.getImageableY(),
+                    page.getImageableWidth(),
+                    page.getImageableHeight());
+        return pageFormatArea;
+    }
+    
+    private boolean cancelCheck() {
+        // This is called from the native side.
+        
+        // This is used to avoid deadlock
+        // We would like to just call if isCancelled(), 
+        // but that will block the AppKit thread against whomever is holding the synchronized lock
+        boolean cancelled = (performingPrinting && userCancelled);
+        if (cancelled) {
+            try {
+                LWCToolkit.invokeLater(new Runnable() { public void run() {
+                    try {
+                    cancelDoc();
+                    } catch (PrinterAbortException pae) { 
+                        // no-op, let the native side handle it
+                    }
+                }}, null);
+            } catch (java.lang.reflect.InvocationTargetException ite) {}
+        }
+        return cancelled;
+    }
+    
+    private PeekGraphics createFirstPassGraphics(PrinterJob printerJob, PageFormat page) {
+        // This is called from the native side.
+        BufferedImage bimg = new BufferedImage((int)Math.round(page.getWidth()), (int)Math.round(page.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE);
+        PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob);
+        Rectangle2D pageFormatArea = getPageFormatArea(page);
+        initPrinterGraphics(peekGraphics, pageFormatArea);
+        return peekGraphics;
+    }
+    
+    private void printToPathGraphics(    final PeekGraphics graphics, // Always an actual PeekGraphics
+                                        final PrinterJob printerJob, // Always an actual CPrinterJob
+                                        final Printable painter, // Client class
+                                        final PageFormat page, // Client class
+                                        final int pageIndex,
+                                        final long context) throws PrinterException {
+        // This is called from the native side.
+        Runnable r = new Runnable() { public void run() {
+            try {
+                SurfaceData sd = CPrinterSurfaceData.createData(page, context); // Just stores page into an ivar
+                if (defaultFont == null) {
+                    defaultFont = new Font("Dialog", Font.PLAIN, 12);
+                }
+                Graphics2D delegate = new SunGraphics2D(sd, Color.black, Color.white, defaultFont);
+                
+                Graphics2D pathGraphics = new CPrinterGraphics(delegate, printerJob); // Just stores delegate into an ivar
+                Rectangle2D pageFormatArea = getPageFormatArea(page);
+                initPrinterGraphics(pathGraphics, pageFormatArea);
+                painter.print(pathGraphics, page, pageIndex);      
+                delegate.dispose();
+                delegate = null;
+        } catch (PrinterException pe) { throw new java.lang.reflect.UndeclaredThrowableException(pe); }
+        }};
+        
+        if (onEventThread) {
+            try { EventQueue.invokeAndWait(r); 
+            } catch (java.lang.reflect.InvocationTargetException ite) {
+                Throwable te = (Throwable)ite.getTargetException();
+                if (te instanceof PrinterException) throw (PrinterException)te;
+                else te.printStackTrace();
+            } catch (Exception e) { e.printStackTrace(); }
+        } else {
+            r.run();
+        }
+                                            
+    }
+    
+    // Returns either 1. an array of 3 object (PageFormat, Printable, PeekGraphics) or 2. null
+    private Object[] getPageformatPrintablePeekgraphics(final int pageIndex) {
+        final Object[] ret = new Object[3];
+        final PrinterJob printerJob = this;
+        
+        Runnable r = new Runnable() { public void run() { synchronized(ret) {
+            try {
+                Pageable pageable = getPageable();
+                PageFormat pageFormat = pageable.getPageFormat(pageIndex);
+                if (pageFormat != null) {
+                    Printable printable = pageable.getPrintable(pageIndex);
+                    if (printable != null) {
+                        BufferedImage bimg = new BufferedImage((int)Math.round(pageFormat.getWidth()), (int)Math.round(pageFormat.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE);
+                        PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob);
+                        Rectangle2D pageFormatArea = getPageFormatArea(pageFormat);
+                        initPrinterGraphics(peekGraphics, pageFormatArea);
+                        
+                        // Do the assignment here!
+                        ret[0] = pageFormat;
+                        ret[1] = printable;
+                        ret[2] = peekGraphics;
+                    }
+                }
+            } catch (Exception e) {} // Original code bailed on any exception
+        }}};
+        
+        if (onEventThread) {
+            try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); }
+        } else {
+            r.run();
+        }
+        
+        synchronized(ret) { 
+            if (ret[2] != null)
+                return ret; 
+            return null;
+        }
+    }
+    
+    private Rectangle2D printAndGetPageFormatArea(final Printable printable, final Graphics graphics, final PageFormat pageFormat, final int pageIndex) {
+        final Rectangle2D[] ret = new Rectangle2D[1];
+        
+        Runnable r = new Runnable() { public void run() { synchronized(ret) {
+            try {
+                int pageResult = printable.print(graphics, pageFormat, pageIndex);
+                if (pageResult != Printable.NO_SUCH_PAGE) {
+                    ret[0] = getPageFormatArea(pageFormat);
+                }
+            } catch (Exception e) {} // Original code bailed on any exception
+        }}};
+        
+        if (onEventThread) {
+            try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); }
+        } else {
+            r.run();
+        }
+        
+        synchronized(ret) { return ret[0]; }
+    }
+    
+    // upcall from native
+    private static void detachPrintLoop(final long target, final long arg) {
+        new Thread() { public void run() {
+            _safePrintLoop(target, arg);
+        }}.start();
+    }
+    private static native void _safePrintLoop(long target, long arg);
+
+    @Override
+    protected void startPage(PageFormat arg0, Printable arg1, int arg2, boolean arg3) throws PrinterException {
+        // TODO Auto-generated method stub
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterJobDialog.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+
+import java.awt.*;
+import java.awt.print.*;
+
+public class CPrinterJobDialog extends CPrinterDialog {
+    private Pageable fPageable;
+    private boolean fAllowPrintToFile;
+    
+    CPrinterJobDialog(Frame parent, CPrinterJob printerJob, Pageable doc, boolean allowPrintToFile) {
+        super(parent, printerJob);
+        fPageable = doc;
+        fAllowPrintToFile = allowPrintToFile;
+    }
+    
+    protected native boolean showDialog();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterPageDialog.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+
+import java.awt.*;
+import java.awt.print.*;
+
+public class CPrinterPageDialog extends CPrinterDialog {
+    private PageFormat fPage;
+    private Printable fPainter;
+    
+    CPrinterPageDialog(Frame parent, CPrinterJob printerJob, PageFormat page, Printable painter) {
+        super(parent, printerJob);
+        fPage = page;
+        fPainter = painter;
+    }
+    
+    protected native boolean showDialog();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CPrinterSurfaceData.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.print.PageFormat;
+import java.nio.ByteBuffer;
+
+import sun.java2d.*;
+import sun.java2d.loops.SurfaceType;
+
+public class CPrinterSurfaceData extends OSXSurfaceData{
+    public static final String DESC_INT_RGB_PQ = "Integer RGB Printer Quartz";
+//    public static final String DESC_INT_ARGB_PQ = "Integer ARGB Printer Quartz";
+    
+//    public static final SurfaceType IntArgbPQ = SurfaceType.IntArgb.deriveSubType(DESC_INT_ARGB_PQ);
+    public static final SurfaceType IntRgbPQ = SurfaceType.IntRgb.deriveSubType(DESC_INT_RGB_PQ);
+    
+    public static SurfaceData createData(PageFormat pf, long context) {
+        return new CPrinterSurfaceData(CPrinterGraphicsConfig.getConfig(pf), context);
+    }
+    
+    public CPrinterSurfaceData(GraphicsConfiguration gc, long context) {
+        super(IntRgbPQ, gc.getColorModel(), gc, gc.getBounds());
+        initOps(context, this.fGraphicsStates, this.fGraphicsStatesObject, gc.getBounds().width, gc.getBounds().height);
+    }
+    
+    public SurfaceData getReplacement() {
+        return this;
+    }
+    
+    private native void initOps(long context, ByteBuffer byteParameters, Object[] objectParameters, int width, int height);
+    
+    public void enableFlushing() {
+        _flush();
+    }
+    native void _flush();
+    
+    public Object getDestination() {
+        // this should never get called for the printer surface (see BufferStrategyPaintManager for one case of usage)
+        return null;
+    }
+    
+    public Raster getRaster(int x, int y, int w, int h) {
+        BufferedImage dstImage = new BufferedImage(x + w, y + h, BufferedImage.TYPE_INT_ARGB_PRE);
+        return dstImage.getRaster();
+    }
+    
+    public BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage) {
+        // create the destination image if needed
+        if (dstImage == null) {
+            dstImage = getDeviceConfiguration().createCompatibleImage(w, h);
+        }
+        
+        // copy
+        Graphics g = dstImage.createGraphics();
+        BufferedImage thisImage = getCompositingImage(w, h);
+        g.drawImage(thisImage, 0, 0, w, h, x, y, x+w, y+h, null);
+        g.dispose();
+        
+        return dstImage;
+    }
+    
+    public boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR) {
+        throw new InternalError("not implemented yet");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/CTextPipe.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+
+import java.awt.*;
+import java.awt.font.*;
+
+import sun.awt.*;
+import sun.font.*;
+import sun.java2d.*;
+import sun.java2d.loops.*;
+import sun.java2d.pipe.*;
+
+public class CTextPipe implements TextPipe {
+    public native void doDrawString(SurfaceData sData, long nativeStrikePtr, String s, double x, double y);
+    public native void doDrawGlyphs(SurfaceData sData, long nativeStrikePtr, GlyphVector gV, float x, float y);
+    public native void doUnicodes(SurfaceData sData, long nativeStrikePtr, char unicodes[], int offset, int length, float x, float y);
+    public native void doOneUnicode(SurfaceData sData, long nativeStrikePtr, char aUnicode, float x, float y);
+
+    long getNativeStrikePtr(final SunGraphics2D sg2d) {
+        final FontStrike fontStrike = sg2d.getFontInfo().fontStrike;
+        if (!(fontStrike instanceof CStrike)) return 0;
+        return ((CStrike)fontStrike).getNativeStrikePtr();
+    }
+    
+    void drawGlyphVectorAsShape(final SunGraphics2D sg2d, final GlyphVector gv, final float x, final float y) {
+        final int length = gv.getNumGlyphs();
+        for (int i = 0; i < length; i++) {
+            final Shape glyph = gv.getGlyphOutline(i, x, y);
+            sg2d.fill(glyph);
+        }
+    }
+
+    void drawTextAsShape(final SunGraphics2D sg2d, final String s, final double x, final double y) {
+        final Object oldAliasingHint = sg2d.getRenderingHint(SunHints.KEY_ANTIALIASING);
+        final FontRenderContext frc = sg2d.getFontRenderContext();
+        sg2d.setRenderingHint(SunHints.KEY_ANTIALIASING, (frc.isAntiAliased() ? SunHints.VALUE_ANTIALIAS_ON : SunHints.VALUE_ANTIALIAS_OFF));
+
+        final Font font = sg2d.getFont();
+        final GlyphVector gv = font.createGlyphVector(frc, s);
+        final int length = gv.getNumGlyphs();
+        for (int i = 0; i < length; i++) {
+            final Shape glyph = gv.getGlyphOutline(i, (float)x, (float)y);
+            sg2d.fill(glyph);
+        }
+
+        sg2d.setRenderingHint(SunHints.KEY_ANTIALIASING, oldAliasingHint);
+    }
+
+    public void drawString(final SunGraphics2D sg2d, final String s, final double x, final double y) {
+        final long nativeStrikePtr = getNativeStrikePtr(sg2d);
+        if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) {
+            final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData();
+            surfaceData.drawString(this, sg2d, nativeStrikePtr, s, x, y);
+        } else {
+            drawTextAsShape(sg2d, s, x, y);
+        }
+    }
+
+    public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) {
+        final Font prevFont = sg2d.getFont();
+        sg2d.setFont(gV.getFont());
+        
+        final long nativeStrikePtr = getNativeStrikePtr(sg2d);
+        if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) {
+            final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData();
+            surfaceData.drawGlyphs(this, sg2d, nativeStrikePtr, gV, x, y);
+        } else {
+            drawGlyphVectorAsShape(sg2d, gV, x, y);
+        }
+        sg2d.setFont(prevFont);
+    }
+
+    public void drawChars(final SunGraphics2D sg2d, final char data[], final int offset, final int length, final int x, final int y) {
+        final long nativeStrikePtr = getNativeStrikePtr(sg2d);
+        if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) {
+            final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData();
+            surfaceData.drawUnicodes(this, sg2d, nativeStrikePtr, data, offset, length, x, y);
+        } else {
+            drawTextAsShape(sg2d, new String(data, offset, length), x, y);
+        }
+    }
+
+    public CTextPipe traceWrap() {
+        return new Tracer();
+    }
+
+    public static class Tracer extends CTextPipe {
+        void doDrawString(final SurfaceData sData, final long nativeStrikePtr, final String s, final float x, final float y) {
+            GraphicsPrimitive.tracePrimitive("QuartzDrawString");
+            super.doDrawString(sData, nativeStrikePtr, s, x, y);
+        }
+
+        public void doDrawGlyphs(final SurfaceData sData, final long nativeStrikePtr, final GlyphVector gV, final float x, final float y) {
+            GraphicsPrimitive.tracePrimitive("QuartzDrawGlyphs");
+            super.doDrawGlyphs(sData, nativeStrikePtr, gV, x, y);
+        }
+
+        public void doUnicodes(final SurfaceData sData, final long nativeStrikePtr, final char unicodes[], final int offset, final int length, final float x, final float y) {
+            GraphicsPrimitive.tracePrimitive("QuartzDrawUnicodes");
+            super.doUnicodes(sData, nativeStrikePtr, unicodes, offset, length, x, y);
+        }
+
+        public void doOneUnicode(final SurfaceData sData, final long nativeStrikePtr, final char aUnicode, final float x, final float y) {
+            GraphicsPrimitive.tracePrimitive("QuartzDrawUnicode");
+            super.doOneUnicode(sData, nativeStrikePtr, aUnicode, x, y);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+// This exists strictly to work around the fact that java.awt.Conditional isn't a public class.
+// It uses java reflection to get the EventDispatchThread class and call a MacOSX only
+// method on it.
+//
+// NOTE: This uses reflection in its implementation, so it is not for performance critical code.
+// 
+// See java.awt.EventDispatchThread and apple.awt.CPrintJob for more.
+//
+public abstract class EventDispatchAccess {
+    public native void pumpEventsAndWait();
+    public abstract boolean evaluate();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/classes/sun/lwawt/macosx/NSPrintInfo.java	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.lwawt.macosx;
+
+
+import java.io.*;
+import javax.print.attribute.*;
+
+public final class NSPrintInfo implements PrintJobAttribute, PrintRequestAttribute, Serializable, Cloneable {
+
+    private long fNSPrintInfo;
+    
+    public NSPrintInfo(long nsPrintInfo) {
+        fNSPrintInfo = nsPrintInfo;
+    }
+    
+    public long getValue() {
+        return fNSPrintInfo;
+    }
+    
+    public boolean equals(Object object) {
+        return (object != null && object instanceof NSPrintInfo && fNSPrintInfo == ((NSPrintInfo)object).fNSPrintInfo);
+    }
+    
+    public int hashCode() {
+        return (int)fNSPrintInfo;
+    }
+    
+    public String toString() {
+        return "" + fNSPrintInfo;
+    }
+    
+    public final Class<? extends Attribute> getCategory() {
+        return NSPrintInfo.class;
+    }
+    
+    public final String getName() {
+        return "nsPrintInfo";
+    }
+}
--- a/src/macosx/native/sun/awt/AWTWindow.m	Fri Sep 23 21:13:13 2011 +0400
+++ b/src/macosx/native/sun/awt/AWTWindow.m	Fri Sep 23 13:42:06 2011 -0700
@@ -328,9 +328,9 @@
 }
 
 - (void) _deliverWindowFocusEvent:(BOOL)focused {
-AWT_ASSERT_APPKIT_THREAD;
+//AWT_ASSERT_APPKIT_THREAD;
     
-    JNIEnv *env = [ThreadUtilities getJNIEnv];
+    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
     static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(Z)V");
     JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused);
--- a/src/macosx/native/sun/awt/AWT_debug.h	Fri Sep 23 21:13:13 2011 +0400
+++ b/src/macosx/native/sun/awt/AWT_debug.h	Fri Sep 23 13:42:06 2011 -0700
@@ -32,7 +32,7 @@
 #define kInternalError "java/lang/InternalError"
 
 #define AWT_DEBUG_LOG(str) \
-    NSLog(@"Cocoa AWT: %@ (%s - %s:%d)", str, __FUNCTION__, __FILE__, __LINE__)
+    NSLog(@"Cocoa AWT: %@ %@", str, [NSThread callStackSymbols])
 
 #define AWT_DEBUG_BUG_REPORT_MESSAGE \
     NSLog(@"\tPlease file a bug report at http://java.net/jira/browse/MACOSX_PORT with this message and a reproducible test case.")
--- a/src/macosx/native/sun/awt/CDropTarget.m	Fri Sep 23 21:13:13 2011 +0400
+++ b/src/macosx/native/sun/awt/CDropTarget.m	Fri Sep 23 13:42:06 2011 -0700
@@ -77,7 +77,7 @@
 	
 	
     if (control != nil) {
-		JNIEnv *env = [ThreadUtilities getJNIEnv];
+        JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
         fComponent = JNFNewGlobalRef(env, jcomponent);
         fDropTarget = JNFNewGlobalRef(env, jdropTarget);
 		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/CPrinterJob.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+#import "java_awt_print_PageFormat.h"
+#import "java_awt_print_Pageable.h"
+#import "sun_lwawt_macosx_CPrinterJob.h"
+#import "sun_lwawt_macosx_CPrinterPageDialog.h"
+
+#import <Cocoa/Cocoa.h>
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "PrinterView.h"
+#import "PrintModel.h"
+#import "ThreadUtilities.h"
+#import "GeomUtilities.h"
+
+static JNF_CLASS_CACHE(sjc_Paper, "java/awt/print/Paper");
+static JNF_CLASS_CACHE(sjc_PageFormat, "java/awt/print/PageFormat");
+static JNF_CLASS_CACHE(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
+static JNF_CLASS_CACHE(sjc_CPrinterDialog, "sun/lwawt/macosx/CPrinterDialog");
+static JNF_MEMBER_CACHE(sjm_getNSPrintInfo, sjc_CPrinterJob, "getNSPrintInfo", "()J");
+static JNF_MEMBER_CACHE(sjm_printerJob, sjc_CPrinterDialog, "fPrinterJob", "Lsun/lwawt/macosx/CPrinterJob;");
+
+static NSPrintInfo* createDefaultNSPrintInfo();
+
+static void makeBestFit(NSPrintInfo* src);
+
+static void nsPrintInfoToJavaPaper(JNIEnv* env, NSPrintInfo* src, jobject dst);
+static void javaPaperToNSPrintInfo(JNIEnv* env, jobject src, NSPrintInfo* dst);
+
+static void nsPrintInfoToJavaPageFormat(JNIEnv* env, NSPrintInfo* src, jobject dst);
+static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageFormat, NSPrintInfo* dst);
+
+static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable);
+static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst);
+
+
+static NSPrintInfo* createDefaultNSPrintInfo(JNIEnv* env, jstring printer)
+{    
+    NSPrintInfo* defaultPrintInfo = [[NSPrintInfo sharedPrintInfo] copy];
+    if (printer != NULL)
+    {        
+        NSPrinter* nsPrinter = [NSPrinter printerWithName:JNFJavaToNSString(env, printer)];
+        if (nsPrinter != nil)
+        {
+            [defaultPrintInfo setPrinter:nsPrinter];
+        }
+    } 
+    [defaultPrintInfo setUpPrintOperationDefaultValues]; 
+    
+    // cmc 05/18/04 radr://3160443 : setUpPrintOperationDefaultValues sets the 
+    // page margins to 72, 72, 90, 90 - need to use [NSPrintInfo imageablePageBounds] 
+    // to get values from the printer.
+    // NOTE: currently [NSPrintInfo imageablePageBounds] does not update itself when 
+    // the user selects a different printer - see radr://3657453. However, rather than 
+    // directly querying the PPD here, we'll let AppKit printing do the work. The AppKit 
+    // printing bug above is set to be fixed for Tiger.
+    NSRect imageableRect = [defaultPrintInfo imageablePageBounds];
+    [defaultPrintInfo setLeftMargin: imageableRect.origin.x];
+    [defaultPrintInfo setBottomMargin: imageableRect.origin.y]; //top and bottom are flipped because [NSPrintInfo imageablePageBounds] returns a flipped NSRect (bottom-left to top-right).
+    [defaultPrintInfo setRightMargin: [defaultPrintInfo paperSize].width-imageableRect.origin.x-imageableRect.size.width];
+    [defaultPrintInfo setTopMargin: [defaultPrintInfo paperSize].height-imageableRect.origin.y-imageableRect.size.height];
+
+    return defaultPrintInfo;
+}
+
+static void makeBestFit(NSPrintInfo* src)
+{
+    // This will look at the NSPrintInfo's margins. If they are out of bounds to the 
+    // imageable area of the page, it will set them to the largest possible size.
+    
+    NSRect imageable = [src imageablePageBounds];
+    
+    NSSize paperSize = [src paperSize];
+
+    CGFloat fullLeftM = imageable.origin.x;
+    CGFloat fullRightM = paperSize.width - (imageable.origin.x + imageable.size.width);
+    
+    // These are flipped because [NSPrintInfo imageablePageBounds] returns a flipped
+    //  NSRect (bottom-left to top-right).
+    CGFloat fullTopM = paperSize.height - (imageable.origin.y + imageable.size.height);
+    CGFloat fullBottomM = imageable.origin.y;
+    
+    if (fullLeftM > [src leftMargin])
+    {
+        [src setLeftMargin:fullLeftM];
+    }
+    
+    if (fullRightM > [src rightMargin])
+    {
+        [src setRightMargin:fullRightM];
+    }
+    
+    if (fullTopM > [src topMargin])
+    {
+        [src setTopMargin:fullTopM];
+    }
+    
+    if (fullBottomM > [src bottomMargin])
+    {
+        [src setBottomMargin:fullBottomM];
+    }
+}
+
+// In AppKit Printing, the rectangle is always oriented. In AppKit Printing, setting
+//  the rectangle will always set the orientation.
+// In java printing, the rectangle is oriented if accessed from PageFormat. It is 
+//  not oriented when accessed from Paper.
+
+static void nsPrintInfoToJavaPaper(JNIEnv* env, NSPrintInfo* src, jobject dst)
+{
+    static JNF_MEMBER_CACHE(jm_setSize, sjc_Paper, "setSize", "(DD)V");
+    static JNF_MEMBER_CACHE(jm_setImageableArea, sjc_Paper, "setImageableArea", "(DDDD)V");
+    
+    jdouble jPaperW, jPaperH;
+    
+    // NSPrintInfo paperSize is oriented. java Paper is not oriented. Take
+    //  the -[NSPrintInfo orientation] into account when setting the Paper
+    //  rectangle.
+    
+    NSSize paperSize = [src paperSize];
+    switch ([src orientation]) {
+        case NSPortraitOrientation:
+            jPaperW = paperSize.width;
+            jPaperH = paperSize.height;
+            break;
+            
+        case NSLandscapeOrientation:
+            jPaperW = paperSize.height;
+            jPaperH = paperSize.width;
+            break;
+        
+        default:
+            jPaperW = paperSize.width;
+            jPaperH = paperSize.height;
+            break;
+    }
+
+    JNFCallVoidMethod(env, dst, jm_setSize, jPaperW, jPaperH); // AWT_THREADING Safe (known object - always actual Paper)
+    
+    // Set the imageable area from the margins
+    CGFloat leftM = [src leftMargin];
+    CGFloat rightM = [src rightMargin];
+    CGFloat topM = [src topMargin];
+    CGFloat bottomM = [src bottomMargin];
+            
+    jdouble jImageX = leftM;
+    jdouble jImageY = topM;
+    jdouble jImageW = jPaperW - (leftM + rightM);
+    jdouble jImageH = jPaperH - (topM + bottomM);
+    
+    JNFCallVoidMethod(env, dst, jm_setImageableArea, jImageX, jImageY, jImageW, jImageH); // AWT_THREADING Safe (known object - always actual Paper)
+}
+
+static void javaPaperToNSPrintInfo(JNIEnv* env, jobject src, NSPrintInfo* dst)
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_MEMBER_CACHE(jm_getWidth, sjc_Paper, "getWidth", "()D");
+    static JNF_MEMBER_CACHE(jm_getHeight, sjc_Paper, "getHeight", "()D");
+    static JNF_MEMBER_CACHE(jm_getImageableX, sjc_Paper, "getImageableX", "()D");
+    static JNF_MEMBER_CACHE(jm_getImageableY, sjc_Paper, "getImageableY", "()D");
+    static JNF_MEMBER_CACHE(jm_getImageableW, sjc_Paper, "getImageableWidth", "()D");
+    static JNF_MEMBER_CACHE(jm_getImageableH, sjc_Paper, "getImageableHeight", "()D");
+    
+    // java Paper is always Portrait oriented. Set NSPrintInfo with this 
+    //  rectangle, and it's orientation may change. If necessary, be sure to call
+    //  -[NSPrintInfo setOrientation] after this call, which will then
+    //  adjust the -[NSPrintInfo paperSize] as well.
+    
+    jdouble jPhysicalWidth = JNFCallDoubleMethod(env, src, jm_getWidth); // AWT_THREADING Safe (!appKit)
+    jdouble jPhysicalHeight = JNFCallDoubleMethod(env, src, jm_getHeight); // AWT_THREADING Safe (!appKit)
+    
+    [dst setPaperSize:NSMakeSize(jPhysicalWidth, jPhysicalHeight)];
+    
+    // Set the margins from the imageable area
+    jdouble jImageX = JNFCallDoubleMethod(env, src, jm_getImageableX); // AWT_THREADING Safe (!appKit)
+    jdouble jImageY = JNFCallDoubleMethod(env, src, jm_getImageableY); // AWT_THREADING Safe (!appKit)
+    jdouble jImageW = JNFCallDoubleMethod(env, src, jm_getImageableW); // AWT_THREADING Safe (!appKit)
+    jdouble jImageH = JNFCallDoubleMethod(env, src, jm_getImageableH); // AWT_THREADING Safe (!appKit)
+    
+    [dst setLeftMargin:(CGFloat)jImageX];
+    [dst setTopMargin:(CGFloat)jImageY];
+    [dst setRightMargin:(CGFloat)(jPhysicalWidth - jImageW - jImageX)];
+    [dst setBottomMargin:(CGFloat)(jPhysicalHeight - jImageH - jImageY)];
+}
+
+static void nsPrintInfoToJavaPageFormat(JNIEnv* env, NSPrintInfo* src, jobject dst)
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_MEMBER_CACHE(jm_setOrientation, sjc_PageFormat, "setOrientation", "(I)V");
+    static JNF_MEMBER_CACHE(jm_setPaper, sjc_PageFormat, "setPaper", "(Ljava/awt/print/Paper;)V");
+    static JNF_CTOR_CACHE(jm_Paper_ctor, sjc_Paper, "()V");
+
+    jint jOrientation;
+    NSPrintingOrientation nsOrientation = [src orientation];
+    switch (nsOrientation) {
+        case NSPortraitOrientation:
+            jOrientation = java_awt_print_PageFormat_PORTRAIT;
+            break;
+        
+        case NSLandscapeOrientation:
+            jOrientation = java_awt_print_PageFormat_LANDSCAPE; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
+            break;
+
+/*
+        // AppKit printing doesn't support REVERSE_LANDSCAPE. Radar 2960295.
+        case NSReverseLandscapeOrientation:
+            jOrientation = java_awt_print_PageFormat.REVERSE_LANDSCAPE; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
+            break;
+*/
+
+        default:
+            jOrientation = java_awt_print_PageFormat_PORTRAIT;
+            break;
+    }
+    
+    JNFCallVoidMethod(env, dst, jm_setOrientation, jOrientation); // AWT_THREADING Safe (!appKit)
+    
+    // Create a new Paper
+    jobject paper = JNFNewObject(env, jm_Paper_ctor); // AWT_THREADING Safe (known object)
+    
+    nsPrintInfoToJavaPaper(env, src, paper);
+    
+    // Set the Paper in the PageFormat
+    JNFCallVoidMethod(env, dst, jm_setPaper, paper); // AWT_THREADING Safe (!appKit)
+    
+    (*env)->DeleteLocalRef(env, paper);
+}
+
+static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobject srcPageFormat, NSPrintInfo* dstPrintInfo)
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_MEMBER_CACHE(jm_getOrientation, sjc_PageFormat, "getOrientation", "()I");
+    static JNF_MEMBER_CACHE(jm_getPaper, sjc_PageFormat, "getPaper", "()Ljava/awt/print/Paper;");
+    static JNF_MEMBER_CACHE(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;");
+    
+    // When setting page information (orientation, size) in NSPrintInfo, set the 
+    //  rectangle first. This is because setting the orientation will change the
+    //  rectangle to match.
+
+    // Set up the paper. This will force Portrait since java Paper is 
+    //  not oriented. Then setting the NSPrintInfo orientation below
+    //  will flip NSPrintInfo's info as necessary.
+    jobject paper = JNFCallObjectMethod(env, srcPageFormat, jm_getPaper); // AWT_THREADING Safe (!appKit)
+    javaPaperToNSPrintInfo(env, paper, dstPrintInfo);
+    (*env)->DeleteLocalRef(env, paper);
+        
+    switch (JNFCallIntMethod(env, srcPageFormat, jm_getOrientation)) { // AWT_THREADING Safe (!appKit)
+        case java_awt_print_PageFormat_PORTRAIT:
+            [dstPrintInfo setOrientation:NSPortraitOrientation];
+            break;
+            
+        case java_awt_print_PageFormat_LANDSCAPE:
+            [dstPrintInfo setOrientation:NSLandscapeOrientation]; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
+            break;
+            
+        // AppKit printing doesn't support REVERSE_LANDSCAPE. Radar 2960295.
+        case java_awt_print_PageFormat_REVERSE_LANDSCAPE:
+            [dstPrintInfo setOrientation:NSLandscapeOrientation]; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
+            break;
+            
+        default:
+            [dstPrintInfo setOrientation:NSPortraitOrientation];
+            break;
+    }
+    
+    // <rdar://problem/4022422> NSPrinterInfo is not correctly set to the selected printer
+    // from the Java side of CPrinterJob. Has always assumed the default printer was the one we wanted.
+    if (srcPrintJob == NULL) return;
+    jobject printerNameObj = JNFCallObjectMethod(env, srcPrintJob, jm_getPrinterName);
+    if (printerNameObj == NULL) return;
+    NSString *printerName = JNFJavaToNSString(env, printerNameObj);
+    if (printerName == nil) return;
+    NSPrinter *printer = [NSPrinter printerWithName:printerName];
+    if (printer == nil) return;
+    [dstPrintInfo setPrinter:printer];
+}
+
+static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable)
+{
+    static JNF_MEMBER_CACHE(jm_setService, sjc_CPrinterJob, "setPrinterServiceFromNative", "(Ljava/lang/String;)V");
+    static JNF_MEMBER_CACHE(jm_setCopies, sjc_CPrinterJob, "setCopies", "(I)V");
+    static JNF_MEMBER_CACHE(jm_setCollated, sjc_CPrinterJob, "setCollated", "(Z)V");
+    static JNF_MEMBER_CACHE(jm_setPageRange, sjc_CPrinterJob, "setPageRange", "(II)V");
+    
+    // get the selected printer's name, and set the appropriate PrintService on the Java side
+    NSString *name = [[src printer] name];
+    jstring printerName = JNFNSToJavaString(env, name);
+    JNFCallVoidMethod(env, dstPrinterJob, jm_setService, printerName);
+    
+    
+    NSMutableDictionary* printingDictionary = [src dictionary];
+
+    NSNumber* nsCopies = [printingDictionary objectForKey:NSPrintCopies];
+    if ([nsCopies respondsToSelector:@selector(integerValue)])
+    {
+        JNFCallVoidMethod(env, dstPrinterJob, jm_setCopies, [nsCopies integerValue]); // AWT_THREADING Safe (known object)
+    }
+    
+    NSNumber* nsCollated = [printingDictionary objectForKey:NSPrintMustCollate];
+    if ([nsCollated respondsToSelector:@selector(boolValue)])
+    {
+        JNFCallVoidMethod(env, dstPrinterJob, jm_setCollated, [nsCollated boolValue] ? JNI_TRUE : JNI_FALSE); // AWT_THREADING Safe (known object)
+    }
+    
+    NSNumber* nsPrintAllPages = [printingDictionary objectForKey:NSPrintAllPages];
+    if ([nsPrintAllPages respondsToSelector:@selector(boolValue)])
+    {
+        jint jFirstPage = 0, jLastPage = java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES;
+        if (![nsPrintAllPages boolValue])
+        {
+            NSNumber* nsFirstPage = [printingDictionary objectForKey:NSPrintFirstPage];
+            if ([nsFirstPage respondsToSelector:@selector(integerValue)])
+            {
+                jFirstPage = [nsFirstPage integerValue] - 1;
+            }
+            
+            NSNumber* nsLastPage = [printingDictionary objectForKey:NSPrintLastPage];
+            if ([nsLastPage respondsToSelector:@selector(integerValue)])
+            {
+                jLastPage = [nsLastPage integerValue] - 1;
+            }
+        }
+        
+        JNFCallVoidMethod(env, dstPrinterJob, jm_setPageRange, jFirstPage, jLastPage); // AWT_THREADING Safe (known object)
+    }
+}
+
+static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst)
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_CLASS_CACHE(jc_Pageable, "java/awt/print/Pageable");
+    static JNF_MEMBER_CACHE(jm_getCopies, sjc_CPrinterJob, "getCopiesInt", "()I");
+    static JNF_MEMBER_CACHE(jm_isCollated, sjc_CPrinterJob, "isCollated", "()Z");
+    static JNF_MEMBER_CACHE(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I");
+
+    NSMutableDictionary* printingDictionary = [dst dictionary];
+    
+    jint copies = JNFCallIntMethod(env, srcPrinterJob, jm_getCopies); // AWT_THREADING Safe (known object)
+    [printingDictionary setObject:[NSNumber numberWithInteger:copies] forKey:NSPrintCopies];
+    
+    jboolean collated = JNFCallBooleanMethod(env, srcPrinterJob, jm_isCollated); // AWT_THREADING Safe (known object)
+    [printingDictionary setObject:[NSNumber numberWithBool:collated ? YES : NO] forKey:NSPrintMustCollate];
+    
+    jint jNumPages = JNFCallIntMethod(env, srcPageable, jm_getNumberOfPages); // AWT_THREADING Safe (!appKit)
+    if (jNumPages != java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES)
+    {
+        [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages];
+        
+        [printingDictionary setObject:[NSNumber numberWithInteger:1] forKey:NSPrintFirstPage];
+        [printingDictionary setObject:[NSNumber numberWithInteger:jNumPages] forKey:NSPrintLastPage];
+    }
+    else
+    {
+        [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages];
+    }
+}
+
+/*
+ * Class:     sun_lwawt_macosx_EventDispatchAccess
+ * Method:    pumpEventsAndWait
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_EventDispatchAccess_pumpEventsAndWait
+(JNIEnv *env, jobject eda)
+{
+    static JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread");
+    static JNF_STATIC_MEMBER_CACHE(jm_currentThread, jc_Thread, "currentThread", "()Ljava/lang/Thread;");
+    static JNF_CLASS_CACHE(jc_EventDispatchThread, "java/awt/EventDispatchThread");
+    static JNF_MEMBER_CACHE(jm_macosxGetConditional, jc_EventDispatchThread, "_macosxGetConditional", "(Ljava/lang/Object;)Ljava/awt/Conditional;");
+    static JNF_MEMBER_CACHE(jm_pumpEvents, jc_EventDispatchThread, "pumpEvents", "(Ljava/awt/Conditional;)V");
+    
+JNF_COCOA_DURING(env);
+    
+    jobject thread = JNFCallStaticObjectMethod(env, jm_currentThread);
+    jobject conditional = JNFCallObjectMethod(env, thread, jm_macosxGetConditional, eda);
+    if (conditional != NULL) {
+        JNFCallVoidMethod(env, thread, jm_pumpEvents, conditional);
+    }
+    
+JNF_COCOA_HANDLE(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    abortDoc
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_abortDoc
+  (JNIEnv *env, jobject jthis)
+{
+JNF_COCOA_ENTER(env);
+    // This is only called during the printLoop from the printLoop thread
+    NSPrintOperation* printLoop = [NSPrintOperation currentOperation];
+    NSPrintInfo* printInfo = [printLoop printInfo];
+    [printInfo setJobDisposition:NSPrintCancelJob];
+JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    getDefaultPage
+ * Signature: (Ljava/awt/print/PageFormat;)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_getDefaultPage
+  (JNIEnv *env, jobject jthis, jobject page)
+{
+JNF_COCOA_ENTER(env);
+    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
+    
+    nsPrintInfoToJavaPageFormat(env, printInfo, page);
+    
+    [printInfo release];
+JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    validatePaper
+ * Signature: (Ljava/awt/print/Paper;Ljava/awt/print/Paper;)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_validatePaper
+  (JNIEnv *env, jobject jthis, jobject origpaper, jobject newpaper)
+{
+JNF_COCOA_ENTER(env);
+    
+    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
+    javaPaperToNSPrintInfo(env, origpaper, printInfo);
+    makeBestFit(printInfo);
+    nsPrintInfoToJavaPaper(env, printInfo, newpaper);
+    [printInfo release];
+    
+JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    createNSPrintInfo
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPrinterJob_createNSPrintInfo
+  (JNIEnv *env, jobject jthis)
+{
+    jlong result = -1;
+JNF_COCOA_ENTER(env);
+    // This is used to create the NSPrintInfo for this PrinterJob. Thread
+    //  safety is assured by the java side of this call.
+
+    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
+    if (printInfo) CFRetain(printInfo); // GC
+    [printInfo release];
+        
+    result = ptr_to_jlong(printInfo);
+    
+JNF_COCOA_EXIT(env);
+    return result;
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    dispose
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_dispose
+  (JNIEnv *env, jobject jthis, jlong nsPrintInfo)
+{
+JNF_COCOA_ENTER(env);
+    if (nsPrintInfo != -1)
+    {
+        NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(nsPrintInfo);
+        if (printInfo) CFRelease(printInfo); // GC
+    }
+JNF_COCOA_EXIT(env);
+}
+
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    printLoop
+ * Signature: ()V
+ */
+JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJob_printLoop
+  (JNIEnv *env, jobject jthis, jboolean blocks, jint firstPage, jint lastPage)
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+      
+    static JNF_MEMBER_CACHE(jm_getPageFormat, sjc_CPrinterJob, "getPageFormat", "(I)Ljava/awt/print/PageFormat;");
+    static JNF_MEMBER_CACHE(jm_getPageFormatArea, sjc_CPrinterJob, "getPageFormatArea", "(Ljava/awt/print/PageFormat;)Ljava/awt/geom/Rectangle2D;");
+    static JNF_MEMBER_CACHE(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;");
+    static JNF_MEMBER_CACHE(jm_getPageable, sjc_CPrinterJob, "getPageable", "()Ljava/awt/print/Pageable;");
+    
+    jboolean retVal = JNI_FALSE;
+    
+JNF_COCOA_ENTER(env);
+    // Get the first page's PageFormat for setting things up (This introduces
+    //  and is a facet of the same problem in Radar 2818593/2708932).
+    jobject page = JNFCallObjectMethod(env, jthis, jm_getPageFormat, 0); // AWT_THREADING Safe (!appKit)
+    if (page != NULL) {
+        jobject pageFormatArea = JNFCallObjectMethod(env, jthis, jm_getPageFormatArea, page); // AWT_THREADING Safe (!appKit)
+        
+        PrinterView* printerView = [[PrinterView alloc] initWithFrame:JavaToNSRect(env, pageFormatArea) withEnv:env withPrinterJob:jthis];
+        [printerView setFirstPage:firstPage lastPage:lastPage];
+        
+        NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(JNFCallLongMethod(env, jthis, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
+        
+        // <rdar://problem/4156975> passing jthis CPrinterJob as well, so we can extract the printer name from the current job
+        javaPageFormatToNSPrintInfo(env, jthis, page, printInfo);
+        
+        // <rdar://problem/4093799> NSPrinterInfo is not correctly set to the selected printer
+        // from the Java side of CPrinterJob. Had always assumed the default printer was the one we wanted.
+        jobject printerNameObj = JNFCallObjectMethod(env, jthis, jm_getPrinterName);
+        if (printerNameObj != NULL) {
+            NSString *printerName = JNFJavaToNSString(env, printerNameObj);
+            if (printerName != nil) {
+                NSPrinter *printer = [NSPrinter printerWithName:printerName];
+                if (printer != nil) [printInfo setPrinter:printer];
+            }
+        }
+        
+        // <rdar://problem/4367998> JTable.print attributes are ignored
+        jobject pageable = JNFCallObjectMethod(env, jthis, jm_getPageable); // AWT_THREADING Safe (!appKit)
+        javaPrinterJobToNSPrintInfo(env, jthis, pageable, printInfo);
+        
+        PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
+            
+        (void)[printModel runPrintLoopWithView:printerView waitUntilDone:blocks withEnv:env];
+   
+        // Only set this if we got far enough to call runPrintLoopWithView, or we will spin CPrinterJob.print() forever!
+        retVal = JNI_TRUE;
+        
+        [printModel release];
+        [printerView release];
+        
+        if (page != NULL)
+        {
+            (*env)->DeleteLocalRef(env, page);
+        }
+        
+        if (pageFormatArea != NULL)
+        {
+            (*env)->DeleteLocalRef(env, pageFormatArea);
+        }
+    }
+JNF_COCOA_EXIT(env);
+    return retVal;
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterPageDialog
+ * Method:    showDialog
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterPageDialog_showDialog
+  (JNIEnv *env, jobject jthis)
+{
+    
+    static JNF_CLASS_CACHE(jc_CPrinterPageDialog, "sun/lwawt/macosx/CPrinterPageDialog");
+    static JNF_MEMBER_CACHE(jm_page, jc_CPrinterPageDialog, "fPage", "Ljava/awt/print/PageFormat;");
+    
+    jboolean result = JNI_FALSE;
+JNF_COCOA_ENTER(env);
+    jobject printerJob = JNFGetObjectField(env, jthis, sjm_printerJob);
+    NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(JNFCallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
+
+    jobject page = JNFGetObjectField(env, jthis, jm_page);
+    
+    // <rdar://problem/4156975> passing NULL, because only a CPrinterJob has a real printer associated with it
+    javaPageFormatToNSPrintInfo(env, NULL, page, printInfo);
+    
+    PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
+    result = [printModel runPageSetup];
+    [printModel release];
+    
+    if (result)
+    {
+        nsPrintInfoToJavaPageFormat(env, printInfo, page);
+    }
+    
+    if (printerJob != NULL)
+    {
+        (*env)->DeleteLocalRef(env, printerJob);
+    }
+    
+    if (page != NULL)
+    {
+        (*env)->DeleteLocalRef(env, page);
+    }
+    
+JNF_COCOA_EXIT(env);
+    return result;
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJobDialog
+ * Method:    showDialog
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJobDialog_showDialog
+  (JNIEnv *env, jobject jthis)
+{
+    static JNF_CLASS_CACHE(jc_CPrinterJobDialog, "sun/lwawt/macosx/CPrinterJobDialog");
+    static JNF_MEMBER_CACHE(jm_pageable, jc_CPrinterJobDialog, "fPageable", "Ljava/awt/print/Pageable;");
+    
+    jboolean result = JNI_FALSE;
+JNF_COCOA_ENTER(env);
+    jobject printerJob = JNFGetObjectField(env, jthis, sjm_printerJob);
+    NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(JNFCallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
+    
+    jobject pageable = JNFGetObjectField(env, jthis, jm_pageable);
+
+    javaPrinterJobToNSPrintInfo(env, printerJob, pageable, printInfo);
+    
+    PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
+    result = [printModel runJobSetup];
+    [printModel release];
+    
+    if (result)
+    {
+        nsPrintInfoToJavaPrinterJob(env, printInfo, printerJob, pageable);
+    }
+    
+    if (printerJob != NULL)
+    {
+        (*env)->DeleteLocalRef(env, printerJob);
+    }
+    
+    if (pageable != NULL)
+    {
+        (*env)->DeleteLocalRef(env, pageable);
+    }
+    
+JNF_COCOA_EXIT(env);    
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/CTextPipe.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//  Native side of the Quartz text pipe, paints on Quartz Surface Datas.
+//  Interesting Docs : /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/FontHandling/FontHandling.html
+
+#import "sun_awt_SunHints.h"
+#import "sun_lwawt_macosx_CTextPipe.h"
+#import "sun_java2d_OSXSurfaceData.h"
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "CoreTextSupport.h"
+#import "QuartzSurfaceData.h"
+#include "AWTStrike.h"
+
+
+static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
+
+
+#pragma mark --- CoreText Support ---
+
+
+// Translates a Unicode into a CGGlyph/CTFontRef pair
+// Returns the substituted font, and places the appropriate glyph into "glyphRef"
+CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode
+(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
+    CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
+    if (fallback == NULL)
+    {
+        // use the original font if we somehow got duped into trying to fallback something we can't
+        fallback = (CTFontRef)font->fFont;
+        CFRetain(fallback);
+    }
+    
+    CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
+    return fallback;
+}
+
+// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
+// Returns the substituted font, and places the appropriate glyph into "glyph"
+CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForJavaGlyphCode
+(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
+{
+    // negative glyph codes are really unicodes, which were placed there by the mapper
+    // to indicate we should use CoreText to substitute the character
+    if (glyphCode >= 0)
+    {
+        *glyphRef = glyphCode;
+        CFRetain(font->fFont);
+        return (CTFontRef)font->fFont;
+    }
+    
+    UTF16Char character = -glyphCode;
+    return JavaCT_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+}
+
+// Breakup a 32 bit unicode value into the component surrogate pairs
+void JavaCT_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
+    int value = uniChar - 0x10000;
+    UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
+    UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
+    charRef[0] = high_surrogate;
+    charRef[1] = low_surrogate;
+}
+
+
+
+/*
+ * Callback for CoreText which uses the CoreTextProviderStruct to feed CT UniChars
+ * We only use it for one-off lines, and don't attempt to fragment our strings
+ */
+const UniChar *Java_CTProvider
+(CFIndex stringIndex, CFIndex *charCount, CFDictionaryRef *attributes, void *refCon)
+{
+    // if we have a zero length string we can just return NULL for the string
+    // or if the index anything other than 0 we are not using core text
+    // correctly since we only have one run.    
+    if (stringIndex != 0)
+    {
+        return NULL;
+    }
+    
+    CTS_ProviderStruct *ctps = (CTS_ProviderStruct *)refCon;
+    *charCount = ctps->length;
+    *attributes = ctps->attributes;
+    return ctps->unicodes;
+}
+
+
+/*
+ *    Gets a Dictionary filled with common details we want to use for CoreText when we are interacting
+ *    with it from Java.
+ */
+static NSDictionary* ctsDictionaryFor(const NSFont *font, BOOL useFractionalMetrics)
+{
+    NSNumber *gZeroNumber = [NSNumber numberWithInt:0];
+    NSNumber *gOneNumber = [NSNumber numberWithInt:1];
+    
+    return [NSDictionary dictionaryWithObjectsAndKeys:
+             font, NSFontAttributeName, 
+             gOneNumber,  (id)kCTForegroundColorFromContextAttributeName,
+             useFractionalMetrics ? gZeroNumber : gOneNumber, @"CTIntegerMetrics", // force integer hack in CoreText to help with Java's integer assumptions
+             gZeroNumber, NSLigatureAttributeName, 
+             gZeroNumber, NSKernAttributeName, 
+             nil];
+}
+
+// Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.
+// If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.
+void JavaCT_DrawGlyphVector
+(const QuartzSDOps *qsdo, const AWTStrike *strike, const BOOL useSubstituion, const int uniChars[], const CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)
+{
+    CGPoint pt = { 0, 0 };
+    
+    // get our baseline transform and font
+    CGContextRef cgRef = qsdo->cgRef;
+    CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);
+    //CGFontRef cgFont = CGContextGetFont(cgRef);
+    
+    CGContextSaveGState(cgRef);
+    CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
+    
+    NSUInteger i;
+    for (i = 0; i < length; i++)
+    {
+        CGGlyph glyph = glyphs[i];
+        int uniChar = uniChars[i];
+        // if we found a unichar instead of a glyph code, get the fallback font,
+        // find the glyph code for the fallback font, and set the font on the current context
+        if (uniChar != 0)
+        {
+            CTFontRef fallback;
+            if (uniChar > 0xFFFF) {
+                UTF16Char charRef[2];
+                JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
+                CGGlyph glyphTmp[2]; 
+                fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
+                glyph = glyphTmp[0];
+            } else {
+                const UTF16Char u = uniChar;
+                fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);
+            }
+            if (fallback) {
+                const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
+                CFRelease(fallback);
+                
+                if (cgFallback) {
+                    CGContextSetFont(cgRef, cgFallback);
+                    CFRelease(cgFallback);
+                }
+            }
+        }
+        
+        // if we have per-glyph transformations
+        int tin = (g_gvTXIndicesAsInts == NULL) ? -1 : (g_gvTXIndicesAsInts[i] - 1) * 6;
+        if (tin < 0)
+        {
+            CGContextShowGlyphsAtPoint(cgRef, pt.x, pt.y, &glyph, 1);
+        }
+        else
+        {
+            CGAffineTransform tx = CGAffineTransformMake(
+                                                         (CGFloat)g_gvTransformsAsDoubles[tin + 0], (CGFloat)g_gvTransformsAsDoubles[tin + 2],
+                                                         (CGFloat)g_gvTransformsAsDoubles[tin + 1], (CGFloat)g_gvTransformsAsDoubles[tin + 3],
+                                                         0, 0);
+            
+            CGPoint txOffset = { (CGFloat)g_gvTransformsAsDoubles[tin + 4], (CGFloat)g_gvTransformsAsDoubles[tin + 5] };
+            
+            txOffset = CGPointApplyAffineTransform(txOffset, invTx);
+            
+            // apply the transform, strike the glyph, can change the transform back
+            CGContextSetTextMatrix(cgRef, CGAffineTransformConcat(ctmText, tx));
+            CGContextShowGlyphsAtPoint(cgRef, txOffset.x + pt.x, txOffset.y + pt.y, &glyph, 1);
+            CGContextSetTextMatrix(cgRef, ctmText);
+            
+            // transform the measured advance for this strike
+            advances[i] = CGSizeApplyAffineTransform(advances[i], tx);
+            advances[i].width += txOffset.x;
+            advances[i].height += txOffset.y;
+        }
+        
+        // move our next x,y
+        pt.x += advances[i].width;
+        pt.y += advances[i].height;
+        
+        // reset the font on the context after striking a unicode with CoreText
+        if (uniChar != 0)
+        {
+           // CGContextSetFont(cgRef, cgFont);
+            CGContextSaveGState(cgRef);
+        }
+    }
+}
+
+// Using the Quartz Surface Data context, draw a hot-substituted character run
+void JavaCT_DrawTextUsingQSD(JNIEnv *env, const QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length)
+{
+    CGContextRef cgRef = qsdo->cgRef;
+    
+    AWTFont *awtFont = strike->fAWTFont;
+    CGFloat ptSize = strike->fSize;
+    CGAffineTransform tx = strike->fFontTx;
+    
+    NSFont *nsFont = [NSFont fontWithName:[awtFont->fFont fontName] size:ptSize];
+    
+    if (ptSize != 0) {
+        CGFloat invScale = 1 / ptSize;
+        tx = CGAffineTransformConcat(tx, CGAffineTransformMakeScale(invScale, invScale));
+        CGContextConcatCTM(cgRef, tx);
+    }
+    
+    CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity); // resets the damage from CoreText
+    
+    NSString *string = [NSString stringWithCharacters:chars length:length];
+    NSAttributedString *attribString = [[NSAttributedString alloc] initWithString:string];
+    
+    CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedStringAndOptions((CFAttributedStringRef) attribString, (CFDictionaryRef) ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle)));
+    
+    CFRange range = {0, length};
+    CTLineRef lineRef = CTTypesetterCreateLine(typeSetterRef, range);
+    
+    CTLineDraw(lineRef, cgRef);
+    
+    [attribString release];
+    CFRelease(lineRef);
+    CFRelease(typeSetterRef);
+}
+
+
+/*----------------------
+    DrawTextContext is the funnel for all of our CoreText drawing.
+    All three JNI apis call through this method.
+ ----------------------*/
+static void DrawTextContext
+(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length, const jdouble x, const jdouble y)
+{
+    if (length == 0)
+    {
+        return;
+    }
+    
+    qsdo->BeginSurface(env, qsdo, SD_Text);
+    if (qsdo->cgRef == NULL)
+    {
+        qsdo->FinishSurface(env, qsdo);
+        return;
+    }
+    
+    CGContextRef cgRef = qsdo->cgRef;
+    
+    
+    CGContextSaveGState(cgRef);
+    JRSFontSetRenderingStyleOnContext(cgRef, strike->fStyle);
+    
+    // we want to translate before we transform (scale or rotate) <rdar://4042541> (vm)
+    CGContextTranslateCTM(cgRef, x, y);
+    
+    AWTFont *awtfont = strike->fAWTFont; //(AWTFont *)(qsdo->fontInfo.awtfont);
+    NSCharacterSet *charSet = [awtfont->fFont coveredCharacterSet];
+    
+    JavaCT_DrawTextUsingQSD(env, qsdo, strike, chars, length);   // Draw with CoreText
+    
+    CGContextRestoreGState(cgRef);
+    
+    qsdo->FinishSurface(env, qsdo);
+}
+
+#pragma mark --- Glyph Vector Pipeline ---
+
+/*-----------------------------------
+    Glyph Vector Pipeline
+
+    doDrawGlyphs() has been separated into several pipelined functions to increase performance,
+    and improve accountability for JNI resources, malloc'd memory, and error handling.
+
+    Each stage of the pipeline is responsible for doing only one major thing, like allocating buffers,
+    aquiring transform arrays from JNI, filling buffers, or striking glyphs. All resources or memory
+    aquired at a given stage, must be released in that stage. Any error that occurs (like a failed malloc)
+    is to be handled in the stage it occurs in, and is to return immediatly after freeing it's resources.
+
+-----------------------------------*/
+
+static JNF_CLASS_CACHE(jc_StandardGlyphVector, "sun/font/StandardGlyphVector");
+
+// Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,
+// strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.
+static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
+(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
+{
+    // if we have no character substitution, and no per-glyph transformations - strike now!
+    static JNF_MEMBER_CACHE(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
+    jobject gti = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_gti);
+    if (gti == 0) 
+    {
+        if (useSubstituion)
+        {
+            // quasi-simple case, substitution, but no per-glyph transforms
+            JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
+        }
+        else
+        {
+            // fast path, straight to CG without per-glyph transforms
+            CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
+        }
+        return;
+    }
+    
+    static JNF_CLASS_CACHE(jc_StandardGlyphVector_GlyphTransformInfo, "sun/font/StandardGlyphVector$GlyphTransformInfo");
+    static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_transforms, jc_StandardGlyphVector_GlyphTransformInfo, "transforms", "[D");
+    jdoubleArray g_gtiTransformsArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_transforms); //(*env)->GetObjectField(env, gti, g_gtiTransforms);
+    jdouble *g_gvTransformsAsDoubles = (*env)->GetPrimitiveArrayCritical(env, g_gtiTransformsArray, NULL);
+    
+    static JNF_MEMBER_CACHE(jm_StandardGlyphVector_GlyphTransformInfo_indices, jc_StandardGlyphVector_GlyphTransformInfo, "indices", "[I");
+    jintArray g_gtiTXIndicesArray = JNFGetObjectField(env, gti, jm_StandardGlyphVector_GlyphTransformInfo_indices);
+    jint *g_gvTXIndicesAsInts = (*env)->GetPrimitiveArrayCritical(env, g_gtiTXIndicesArray, NULL);
+    
+    // slowest case, we have per-glyph transforms, and possibly glyph substitution as well
+    JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
+    
+    (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
+    (*env)->DeleteLocalRef(env, g_gtiTransformsArray);
+    
+    (*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
+    (*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
+}
+
+// Retrieves advances for translated unicodes
+// Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
+void JavaCT_GetAdvancesForUnichars
+(const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])
+{
+    // cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it
+    size_t i;
+    for (i = 0; i < length; i++)
+    {
+        UniChar uniChar = uniChars[i];
+        if (uniChar == 0) continue;
+        
+        CGGlyph glyph = 0;
+        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);
+        if (fallback) {
+            CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);
+            CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);
+            CFRelease(fallback);
+        }
+        
+        glyphs[i] = glyph;
+    }
+}
+
+// Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been
+// already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions
+// are translated into advances, since CG only understands advances.
+static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
+(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
+{
+    // fill the glyph buffer
+    jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);
+    
+    // if a glyph code from Java is negative, that means it is really a unicode value
+    // which we can use in CoreText to strike the character in another font
+    size_t i;
+    BOOL complex = NO;
+    for (i = 0; i < length; i++)
+    {
+        jint code = glyphsAsInts[i];
+        if (code < 0)
+        {
+            complex = YES;
+            uniChars[i] = -code;
+            glyphs[i] = 0;
+        }
+        else
+        {
+            uniChars[i] = 0;
+            glyphs[i] = code;
+        }
+    }
+    
+    (*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
+    
+    // fill the advance buffer
+    static JNF_MEMBER_CACHE(jm_StandardGlyphVector_positions, jc_StandardGlyphVector, "positions", "[F");
+    jfloatArray posArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_positions);
+    if (posArray != NULL)
+    {
+        // in this case, the positions have already been pre-calculated for us on the Java side
+        
+        jfloat *positions = (*env)->GetPrimitiveArrayCritical(env, posArray, NULL);
+        CGPoint prev;
+        prev.x = positions[0];
+        prev.y = positions[1];
+        
+        // <rdar://problem/4294061> take the first point, and move the context to that location
+        CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y);
+        
+        CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx);
+        
+        // for each position, figure out the advance (since CG won't take positions directly)
+        size_t i;
+        for (i = 0; i < length - 1; i++)
+        {
+            size_t i2 = (i+1) * 2;
+            CGPoint pt;
+            pt.x = positions[i2];
+            pt.y = positions[i2+1];
+            pt = CGPointApplyAffineTransform(pt, invTx);
+            advances[i].width = pt.x - prev.x;
+            advances[i].height = -(pt.y - prev.y); // negative to translate to device space
+            prev.x = pt.x;
+            prev.y = pt.y;
+        }
+        
+        (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, JNI_ABORT);
+        (*env)->DeleteLocalRef(env, posArray);
+    }
+    else
+    {
+        // in this case, we have to go and calculate the positions ourselves
+        // there were no pre-calculated positions from the glyph buffer on the Java side
+        AWTFont *awtFont = strike->fAWTFont;
+        CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);
+        
+        if (complex)
+        {
+            JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);
+        }
+    }
+    
+    // continue on to the next stage of the pipe
+    doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);
+}
+
+// Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,
+// we malloc a buffer to hold the glyphs and their advances, otherwise we use stack allocated buffers.
+static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
+(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector)
+{
+    static JNF_MEMBER_CACHE(jm_StandardGlyphVector_glyphs, jc_StandardGlyphVector, "glyphs", "[I");
+    jintArray glyphsArray = JNFGetObjectField(env, gVector, jm_StandardGlyphVector_glyphs);
+    jsize length = (*env)->GetArrayLength(env, glyphsArray);
+    
+    if (length == 0)
+    {
+        // nothing to draw
+        (*env)->DeleteLocalRef(env, glyphsArray);
+        return;
+    }
+    
+    if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE)
+    {
+        // if we are small enough, fit everything onto the stack
+        CGGlyph glyphs[length];
+        int uniChars[length];
+        CGSize advances[length];
+        doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
+    }
+    else
+    {
+        // otherwise, we should malloc and free buffers for this large run
+        CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
+        int *uniChars = (int *)malloc(sizeof(int) * length);
+        CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
+        
+        if (glyphs == NULL || advances == NULL)
+        {
+            (*env)->DeleteLocalRef(env, glyphsArray);
+            [NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
+            return;
+        }
+        
+        doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
+        
+        free(glyphs);
+        free(uniChars);
+        free(advances);
+    }
+    
+    (*env)->DeleteLocalRef(env, glyphsArray);
+}
+
+// Setup and save the state of the CGContext, and apply any java.awt.Font transforms to the context.
+static inline void doDrawGlyphsPipe_applyFontTransforms
+(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, const jfloat x, const jfloat y)
+{    
+    CGContextRef cgRef = qsdo->cgRef;
+    CGContextSetFontSize(cgRef, 1.0);
+    CGContextSetFont(cgRef, strike->fAWTFont->fNativeCGFont);
+    CGContextSetTextMatrix(cgRef, CGAffineTransformIdentity);
+    
+    CGAffineTransform tx = strike->fFontTx;
+    tx.tx += x;
+    tx.ty += y;
+    CGContextConcatCTM(cgRef, tx);
+    
+    doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc(env, qsdo, strike, gVector);
+}
+
+
+#pragma mark --- CTextPipe JNI ---
+
+
+/*
+ * Class:     sun_lwawt_macosx_CTextPipe
+ * Method:    doDrawString
+ * Signature: (Lsun/java2d/SurfaceData;JLjava/lang/String;DD)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawString
+(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jstring str, jdouble x, jdouble y)
+{
+    QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
+    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
+    
+JNF_COCOA_ENTER(env);
+    
+    jsize len = (*env)->GetStringLength(env, str);
+    
+    if (len < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation <rdar://problem/4285041>
+    {
+        jchar unichars[len];
+        (*env)->GetStringRegion(env, str, 0, len, unichars);
+        JNF_CHECK_AND_RETHROW_EXCEPTION(env);
+        
+        // Draw the text context
+        DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
+    }
+    else
+    {
+        // Get string to draw and the length
+        const jchar *unichars = JNFGetStringUTF16UniChars(env, str);
+
+        // Draw the text context
+        DrawTextContext(env, qsdo, awtStrike, unichars, len, x, y);
+        
+        JNFReleaseStringUTF16UniChars(env, str, unichars);
+    }
+    
+JNF_COCOA_RENDERER_EXIT(env);
+}
+
+
+/*
+ * Class:     sun_lwawt_macosx_CTextPipe
+ * Method:    doUnicodes
+ * Signature: (Lsun/java2d/SurfaceData;J[CIIFF)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doUnicodes
+(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jcharArray unicodes, jint offset, jint length, jfloat x, jfloat y)
+{
+    QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
+    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
+    
+JNF_COCOA_ENTER(env);
+    
+    // Setup the text context    
+    if (length < MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE) // optimized for stack allocation
+    {
+        jchar copyUnichars[length];
+        (*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
+        JNF_CHECK_AND_RETHROW_EXCEPTION(env);
+        DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
+    }
+    else
+    {
+        jchar *copyUnichars = malloc(length * sizeof(jchar));
+        if (!copyUnichars) {
+            [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory to create the glyphs for string drawing"];
+        }
+        
+        @try {
+            (*env)->GetCharArrayRegion(env, unicodes, offset, length, copyUnichars);
+            JNF_CHECK_AND_RETHROW_EXCEPTION(env);
+            DrawTextContext(env, qsdo, awtStrike, copyUnichars, length, x, y);
+        } @finally {
+            free(copyUnichars);
+        }
+    }
+
+JNF_COCOA_RENDERER_EXIT(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CTextPipe
+ * Method:    doOneUnicode
+ * Signature: (Lsun/java2d/SurfaceData;JCFF)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doOneUnicode
+(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jchar aUnicode, jfloat x, jfloat y)
+{
+    QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
+    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
+    
+JNF_COCOA_ENTER(env);
+        
+    DrawTextContext(env, qsdo, awtStrike, &aUnicode, 1, x, y);    
+    
+JNF_COCOA_RENDERER_EXIT(env);
+}
+
+/*
+ * Class: sun_lwawt_macosx_CTextPipe
+ * Method: doDrawGlyphs
+ * Signature: (Lsun/java2d/SurfaceData;JLjava/awt/font/GlyphVector;FF)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTextPipe_doDrawGlyphs
+(JNIEnv *env, jobject jthis, jobject jsurfacedata, jlong awtStrikePtr, jobject gVector, jfloat x, jfloat y)
+{
+    QuartzSDOps *qsdo = (QuartzSDOps *)SurfaceData_GetOps(env, jsurfacedata);
+    AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
+    
+JNF_COCOA_ENTER(env);
+    
+    qsdo->BeginSurface(env, qsdo, SD_Text);
+    if (qsdo->cgRef == NULL)
+    {
+        qsdo->FinishSurface(env, qsdo);
+        return;
+    }
+    
+    CGContextSaveGState(qsdo->cgRef);
+    JRSFontSetRenderingStyleOnContext(qsdo->cgRef, JRSFontGetRenderingStyleForHints(sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON, sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_ON));
+
+    doDrawGlyphsPipe_applyFontTransforms(env, qsdo, awtStrike, gVector, x, y);
+
+    CGContextRestoreGState(qsdo->cgRef);
+    
+    qsdo->FinishSurface(env, qsdo);
+    
+JNF_COCOA_RENDERER_EXIT(env);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/ImageSurfaceData.h	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "QuartzSurfaceData.h"
+#import <pthread.h>
+
+typedef UInt8 Pixel8bit;
+typedef UInt16 Pixel16bit;
+typedef UInt32 Pixel32bit;
+
+typedef struct _ImageSDOps ImageSDOps;
+
+ImageSDOps*    LockImage(JNIEnv* env, jobject imageSurfaceData);
+void        UnlockImage(JNIEnv* env, ImageSDOps* isdo);
+ImageSDOps*    LockImagePixels(JNIEnv* env, jobject imageSurfaceData);
+void        UnlockImagePixels(JNIEnv* env, ImageSDOps* isdo);
+
+// if there is no image created for isdo.imgRef, it creates and image using the isdo.dataProvider
+// If there is an image present, this is a no-op
+void makeSureImageIsCreated(ImageSDOps* isdo);
+
+struct _ContextInfo
+{
+    BOOL                useWindowContextReference;
+    BOOL                canUseJavaPixelsAsContext;
+    size_t                bitsPerComponent;
+    size_t                bytesPerPixel;
+    size_t                bytesPerRow;
+    CGImageAlphaInfo    alphaInfo;
+    CGColorSpaceRef        colorSpace;
+}
+typedef ContextInfo;
+
+struct _ImageInfo
+{
+    size_t                bitsPerComponent;
+    size_t                bitsPerPixel;
+    size_t                bytesPerPixel;
+    size_t                bytesPerRow;
+    CGImageAlphaInfo    alphaInfo;
+    CGColorSpaceRef        colorSpace;
+}
+typedef ImageInfo;
+
+struct _ImageSDOps
+{
+    QuartzSDOps                qsdo; // must be the first entry!
+    
+    ContextInfo                contextInfo;
+    ImageInfo                imageInfo;
+    BOOL                    isSubImage;
+    
+    jint*                    javaImageInfo;
+    
+    // parameters specifying this BufferedImage given to us from Java
+    jobject                    array;
+    jint                    offset;
+    jint                    width;
+    jint                    height;
+    jint                    javaPixelBytes;
+    jint                    javaPixelsBytesPerRow;
+    jobject                    icm;
+    jint                    type;
+    
+    Pixel8bit*                pixels;
+    Pixel8bit*                pixelsLocked;
+    
+    // needed by TYPE_BYTE_INDEXED
+    UInt16*                    indexedColorTable;
+    UInt32*                    lutData;
+    UInt32                    lutDataSize;
+    
+    // Used as a cached image ref created from the isdo.dataprovider. This is only a chached image, and it might become invalid
+    // if somebody draws on the bitmap context, or the pixels are changed in java. In that case, we need to NULL out
+    // this image and recreate it from the data provider.
+    CGImageRef                imgRef;
+    
+    // Cached instance of CGDataProvider. dataProvider is alloced the first time a bitmap context is created, providing the
+    // native pixels as a source of the data. The dataProviders life cycle is the same as ISDO. The reference gets
+    // released when we are done with the ISDO.
+    CGDataProviderRef        dataProvider;
+    
+    // Pointer in memory that is used for create the CGBitmapContext and the CGDataProvider (used for imgRef). This is a native
+    // copy of the pixels for the Image. There is a spearate copy of the pixels that lives in Java heap. There are two main
+    // reasons why we keep those pixels spearate: 1) CG doesn't support all the Java pixel formats 2) The Garbage collector can
+    // move the java pixels at any time. There are possible workarounds for both problems. Number 2) seems to be a more serious issue, since
+    // we can solve 1) by only supporting certain image types.
+    void *                    nativePixels;
+    NSGraphicsContext*        nsRef;
+    
+    pthread_mutex_t            lock;
+    jint                    nrOfPixelsOwners;    
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/ImageSurfaceData.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,2002 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "ImageSurfaceData.h"
+
+#import "java_awt_Transparency.h"
+#import "java_awt_image_BufferedImage.h"
+#import "sun_awt_image_BufImgSurfaceData.h"
+#import "sun_java2d_OSXOffScreenSurfaceData.h"
+
+#import "jni_util.h"
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "BufImgSurfaceData.h"
+#import "ThreadUtilities.h"
+
+
+
+//#define DEBUG 1
+#if defined DEBUG
+    #define IMAGE_SURFACE_INLINE
+    #define PRINT(msg) {fprintf(stderr, "%s\n", msg);fflush(stderr);}
+#else
+    #define IMAGE_SURFACE_INLINE static inline
+    #define PRINT(msg) {}
+#endif
+
+// same value as defined in Sun's own code
+#define XOR_ALPHA_CUTOFF 128
+
+// for vImage framework headers
+#include <Accelerate/Accelerate.h>
+
+
+// private Quartz routines needed here
+CG_EXTERN void CGContextSetCTM(CGContextRef ref, CGAffineTransform tx);
+
+static ContextInfo sDefaultContextInfo[sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB+1] =
+{
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_CUSTOM            // special case
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_RGB
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB_PRE
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_BGR
+    {YES,    NO,        8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_BGR        // use the default ARGB_PRE context synce we have to sync by hand anyway
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_4BYTE_ABGR
+    {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_4BYTE_ABGR_PRE
+#ifdef __LITTLE_ENDIAN__
+    {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_565_RGB
+    {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_555_RGB
+#else
+    {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_565_RGB
+    {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_555_RGB
+#endif
+    {YES,    YES,    8,        1,        0,        kCGImageAlphaNone,                                            NULL},    // TYPE_BYTE_GRAY
+    {YES,    NO,        8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_USHORT_GRAY        // use the default ARGB_PRE context synce we have to sync by hand anyway
+    {NO,    NO,        8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_BYTE_BINARY        mapped to TYPE_CUSTOM
+    {YES,    NO,        8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_BYTE_INDEXED    // use the default ARGB_PRE context synce we have to sync by hand anyway
+    {YES,    NO,        8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_RGB
+};
+
+static ImageInfo sDefaultImageInfo[sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB+1] =
+{
+    {8,        32,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_CUSTOM
+    {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_RGB
+    {8,        32,        4,        0,        kCGImageAlphaFirst | kCGBitmapByteOrder32Host,                NULL},    // TYPE_INT_ARGB
+    {8,        32,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB_PRE
+    {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_BGR
+    {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_BGR
+    {8,        32,        4,        0,        kCGImageAlphaFirst | kCGBitmapByteOrder32Host,                NULL},    // TYPE_4BYTE_ABGR
+    {8,        32,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_4BYTE_ABGR_PRE
+#ifdef __LITTLE_ENDIAN__
+    {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_565_RGB
+    {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_555_RGB
+#else
+    {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_565_RGB
+    {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_555_RGB
+#endif
+    {8,        8,        1,        0,        kCGImageAlphaNone,                                            NULL},    // TYPE_BYTE_GRAY
+    {16,    16,        2,        0,        kCGImageAlphaNone | kCGBitmapByteOrder16Host,                NULL},    // TYPE_USHORT_GRAY
+    {0,        0,        0,        0,        -1,                                                            NULL},    // TYPE_BYTE_BINARY        mapped to TYPE_CUSTOM
+    {8,        32,        4,        0,        kCGImageAlphaFirst | kCGBitmapByteOrder32Host,                NULL},    // TYPE_BYTE_INDEXED  // Fully OPAQUE INDEXED images will use kCGImageAlphaNoneSkipFirst for performance reasosn. see <rdar://4224874>
+    {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_RGB
+};
+
+static jfieldID        rgbID;
+static jfieldID        mapSizeID;
+static jfieldID        CMpDataID;
+static jfieldID        allGrayID;
+
+
+static JNF_CLASS_CACHE(jc_OSXOffScreenSurfaceData, "sun/java2d/OSXOffScreenSurfaceData");
+static JNF_MEMBER_CACHE(jm_syncFromCustom, jc_OSXOffScreenSurfaceData, "syncFromCustom", "()V");
+static JNF_MEMBER_CACHE(jm_syncToCustom, jc_OSXOffScreenSurfaceData, "syncToCustom", "()V");
+static JNF_CLASS_CACHE(jc_BufferedImage, "java/awt/image/BufferedImage");
+static JNF_MEMBER_CACHE(jm_SurfaceData, jc_BufferedImage, "sData", "Lsun/java2d/SurfaceData;");
+static JNF_CLASS_CACHE(jc_IndexColorModel, "java/awt/image/IndexColorModel");
+static JNF_MEMBER_CACHE(jm_rgb, jc_IndexColorModel, "rgb", "[I");
+static JNF_MEMBER_CACHE(jm_transparency, jc_IndexColorModel, "transparency", "I");
+static JNF_MEMBER_CACHE(jm_transparent_index, jc_IndexColorModel, "transparent_index", "I");
+
+CGColorSpaceRef gColorspaceRGB = NULL;
+CGColorSpaceRef gColorspaceGray = NULL;
+
+IMAGE_SURFACE_INLINE void PrintImageInfo(ImageSDOps* isdo)
+{
+    fprintf(stderr, "\n");
+    fprintf(stderr, "PrintImageInfo:\n");
+    fprintf(stderr, "\t \n");
+    //fprintf(stderr, "\t magicID=%d\n", (jint)isdo->magicID);
+    //fprintf(stderr, "\n");
+    fprintf(stderr, "\t isdo=%p\n", isdo);
+    fprintf(stderr, "\t \n");
+    fprintf(stderr, "\t contextInfo:\n");
+    fprintf(stderr, "\t        useWindowContextReference=%d\n", isdo->contextInfo.useWindowContextReference);
+    fprintf(stderr, "\t        canUseJavaPixelsAsContext=%d\n", isdo->contextInfo.canUseJavaPixelsAsContext);
+    fprintf(stderr, "\t        bitsPerComponent=%ld\n", (long)isdo->contextInfo.bitsPerComponent);
+    fprintf(stderr, "\t        bytesPerPixel=%ld\n", (long)isdo->contextInfo.bytesPerPixel);
+    fprintf(stderr, "\t        bytesPerRow=%ld\n", (long)isdo->contextInfo.bytesPerRow);
+    fprintf(stderr, "\t        alphaInfo=%ld\n", (long)isdo->contextInfo.alphaInfo);
+    fprintf(stderr, "\t \n");
+    fprintf(stderr, "\t imageInfo:\n");
+    fprintf(stderr, "\t        bitsPerComponent=%ld\n", (long)isdo->imageInfo.bitsPerComponent);
+    fprintf(stderr, "\t        bitsPerPixel=%ld\n", (long)isdo->imageInfo.bitsPerPixel);
+    fprintf(stderr, "\t        bytesPerPixel=%ld\n", (long)isdo->imageInfo.bytesPerPixel);
+    fprintf(stderr, "\t        bytesPerRow=%ld\n", (long)isdo->imageInfo.bytesPerRow);
+    fprintf(stderr, "\t        alphaInfo=%ld\n", (long)isdo->imageInfo.alphaInfo);
+    fprintf(stderr, "\t \n");
+    fprintf(stderr, "\t isSubImage=%d\n", isdo->isSubImage);
+    fprintf(stderr, "\t \n");
+    fprintf(stderr, "\t java info:\n");
+    fprintf(stderr, "\t        array=%p\n", isdo->array);
+    fprintf(stderr, "\t        offset=%d\n", (int)isdo->offset);
+    fprintf(stderr, "\t        width=%d\n", (int)isdo->width);
+    fprintf(stderr, "\t        height=%d\n", (int)isdo->height);
+    fprintf(stderr, "\t        javaPixelBytes=%d\n", (int)isdo->javaPixelBytes);
+    fprintf(stderr, "\t        javaPixelsBytesPerRow=%d\n", (int)isdo->javaPixelsBytesPerRow);
+    fprintf(stderr, "\t        icm=%p\n", isdo->icm);
+    fprintf(stderr, "\t        type=%d\n", (int)isdo->type);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\t cgRef=%p\n", isdo->qsdo.cgRef);
+    fprintf(stderr, "\t nsRef=%p\n", isdo->nsRef);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\t pixelsLocked=%p\n", isdo->pixelsLocked);
+    fprintf(stderr, "\t pixels=%p\n", isdo->pixels);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\t indexedColorTable=%p\n", isdo->indexedColorTable);
+    fprintf(stderr, "\t lutData=%p\n", isdo->lutData);
+    fprintf(stderr, "\t lutDataSize=%u\n", (unsigned)isdo->lutDataSize);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "\t nrOfPixelsOwners=%u\n", (unsigned)isdo->nrOfPixelsOwners);
+    fprintf(stderr, "\n");
+}
+
+// if there is no image created for isdo.imgRef, it creates and image using the isdo.dataProvider
+// If there is an image present, this is a no-op
+void makeSureImageIsCreated(ImageSDOps* isdo)
+{
+    if (isdo->imgRef == NULL)  // create the image
+    {
+        isdo->imgRef = CGImageCreate(isdo->width, 
+                                      isdo->height, 
+                                      isdo->contextInfo.bitsPerComponent, 
+                                      isdo->contextInfo.bytesPerPixel * 8, 
+                                      isdo->contextInfo.bytesPerRow,
+                                      isdo->contextInfo.colorSpace, 
+                                      isdo->contextInfo.alphaInfo, 
+                                      isdo->dataProvider, 
+                                      NULL, 
+                                      NO, 
+                                      kCGRenderingIntentDefault);
+    }
+}
+
+IMAGE_SURFACE_INLINE void customPixelsFromJava(JNIEnv *env, ImageSDOps *isdo)
+{
+PRINT("    customPixelsFromJava")
+    
+    SurfaceDataOps *sdo = (SurfaceDataOps*)isdo;
+    JNFCallVoidMethod([ThreadUtilities getJNIEnv], sdo->sdObject, jm_syncFromCustom); // AWT_THREADING Safe (known object)
+}
+
+
+IMAGE_SURFACE_INLINE void copyBits(jint w, jint h, jint javaPixelsBytesPerRow, Pixel8bit *pixelsSrc, jint dstPixelsBytesPerRow, Pixel8bit *pixelsDst)
+{
+PRINT("    copyBits")
+    
+    if (javaPixelsBytesPerRow == dstPixelsBytesPerRow)
+    {
+        memcpy(pixelsDst, pixelsSrc, h*javaPixelsBytesPerRow);
+    }
+    else
+    {
+        register jint y;
+        for (y=0; y<h; y++)
+        {
+            memcpy(pixelsDst, pixelsSrc, dstPixelsBytesPerRow);
+            
+            pixelsSrc += javaPixelsBytesPerRow;
+            pixelsDst += dstPixelsBytesPerRow;
+        }
+    }
+}
+
+IMAGE_SURFACE_INLINE void copySwapRandB_32bit_TYPE_4BYTE(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
+{
+PRINT("    copySwapRandB_32bit_TYPE_4BYTE")
+    
+    register Pixel8bit *p8Bit = NULL;
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register Pixel32bit pixel, red, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc++;
+            
+#ifdef __LITTLE_ENDIAN__
+            pixel = CFSwapInt32BigToHost(pixel);   // the jint is in big endian format, we need to swap the bits
+#endif
+            
+            red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
+            blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
+            
+            pixel    = (pixel & 0xff00ff00); // erase original red&blue
+            
+            pixel    = pixel | red | blue; // construct new pixel
+
+            *pixelsDst++ = pixel;
+        }
+        pixelsSrc += skip;
+        
+        p8Bit = (Pixel8bit *) pixelsDst;
+        p8Bit += extraBytesPerRow;
+        pixelsDst = (Pixel32bit *) p8Bit;    
+    }
+}
+
+
+IMAGE_SURFACE_INLINE void copySwapRandB_32bit_TYPE_INT(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
+{
+PRINT("    copySwapRandB_32bit_TYPE_INT")
+    
+    register Pixel8bit *p8Bit = NULL;
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register Pixel32bit pixel, red, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc++;
+            
+            red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
+            blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
+            
+            pixel    = (pixel & 0xff00ff00); // erase original red&blue
+            
+            pixel    = pixel | red | blue; // construct new pixel
+            
+            *pixelsDst++ = pixel;
+        }
+        pixelsSrc += skip;
+        
+        p8Bit = (Pixel8bit *) pixelsDst;
+        p8Bit += extraBytesPerRow;
+        pixelsDst = (Pixel32bit *) p8Bit;    
+    }
+}
+
+
+IMAGE_SURFACE_INLINE void copyBGR_24bitToXRGB_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
+{
+PRINT("    copyBGR_24bitToXRGB_32bit")
+    
+    register Pixel8bit *p8Bit = NULL;
+    register jint skip = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsSrc units
+    register Pixel32bit red, green, blue, pixel;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel        = *pixelsSrc++;
+            blue        = pixel << 0;
+            
+            pixel        = *pixelsSrc++;
+            green        = pixel << 8;
+            
+            pixel        = *pixelsSrc++;
+            red            = pixel << 16;
+            
+            *pixelsDst    = red | green | blue;
+            
+            *pixelsDst = 0xff000000 | *pixelsDst;
+            
+            pixelsDst++;
+        }
+        pixelsSrc += skip;
+        
+        p8Bit = (Pixel8bit *) pixelsDst;
+        p8Bit += extraBytesPerRow;
+        pixelsDst = (Pixel32bit *) p8Bit;
+    }
+}
+
+IMAGE_SURFACE_INLINE void copyRGB_24bitToXRGB_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
+{
+PRINT("    copyRGB_24bitToXRGB_32bit")
+    
+    register Pixel8bit *p8Bit = NULL;
+    register jint skip = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsSrc units
+    register Pixel32bit red, green, blue, pixel;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel        = *pixelsSrc++;
+            red            = pixel << 16;
+            
+            pixel        = *pixelsSrc++;
+            green        = pixel << 8;
+            
+            pixel        = *pixelsSrc++;
+            blue        = pixel << 0;
+            
+            *pixelsDst    = red | green | blue;
+            
+            *pixelsDst = 0xff000000 | *pixelsDst;
+            
+            pixelsDst++;
+        }
+        pixelsSrc += skip;
+        
+        p8Bit = (Pixel8bit *) pixelsDst;
+        p8Bit += extraBytesPerRow;
+        pixelsDst = (Pixel32bit *) p8Bit;
+    }
+}
+
+IMAGE_SURFACE_INLINE void copyIndexed_8bitToARGB_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsSrc,
+                                                        Pixel32bit* lutdata, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
+{
+PRINT("    copyIndexed_8bitToARGB_32bit")
+    
+    //gznote: how is the performance if the extraBytesPerRow != 0 ?
+    const vImage_Buffer src = {pixelsSrc, h, w, javaPixelsBytesPerRow};
+    const vImage_Buffer dest = {pixelsDst, h, w, w*sizeof(Pixel32bit)+extraBytesPerRow};
+    vImage_Error err = vImageLookupTable_Planar8toPlanarF(&src, &dest, (Pixel_F*)lutdata, kvImageDoNotTile);
+    if (err != kvImageNoError)
+    {
+        fprintf(stderr, "Error in copyIndexed_8bitToARGB_32bit: vImageLookupTable_Planar8toPlanarF returns %ld\n", (long)err);
+        register Pixel8bit *p8Bit = NULL;
+        register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+        register jint x, y;
+        for (y=0; y<h; y++)
+        {    
+            for (x=0; x<w; x++)
+            {
+                *pixelsDst++ = lutdata[*pixelsSrc++];        // case 1
+                //*pixelsDst++ = *(lutdata + *pixelsSrc++);    // case 2: at best ~1% better than case 1
+            }
+            pixelsSrc += skip;
+
+            p8Bit = (Pixel8bit *) pixelsDst;
+            p8Bit += extraBytesPerRow;
+            pixelsDst = (Pixel32bit *) p8Bit;    
+        }
+    }
+}
+
+IMAGE_SURFACE_INLINE void copy565_16bitTo555_16bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel16bit *pixelsSrc, Pixel16bit *pixelsDst, size_t extraBytesPerRow)
+{
+PRINT("    copy565_16bitTo555_16bit")
+    
+    register Pixel8bit *p8Bit = NULL;
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register jint green;
+    register Pixel16bit pixel;
+    register jint x, y;
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {
+            pixel = *pixelsSrc++;
+            
+            green = ((pixel >> 5) & 63);  // rrrrrggggggbbbbb => shift 5 right = 00000rrrrrgggggg => and 63 = 0000000000gggggg
+            green = ((jint) (((CGFloat) green / 63.0f) * 31.0f)) & 31; // first normalize to value between 0 and 1 and then un-normalize to 5 bit (31 = 0000000000011111)
+            
+            *pixelsDst++ = ((pixel&0xf800)>>1) | (green << 5) | (pixel&0x01f);
+        }
+        pixelsSrc += skip;
+        
+        p8Bit = (Pixel8bit *) pixelsDst;
+        p8Bit += extraBytesPerRow;
+        pixelsDst = (Pixel16bit *) p8Bit;    
+    }
+}
+
+
+IMAGE_SURFACE_INLINE void customPixelsToJava(JNIEnv *env, ImageSDOps *isdo)
+{
+PRINT("    customPixelsToJava")
+    
+    SurfaceDataOps *sdo = (SurfaceDataOps*)isdo;
+    JNFCallVoidMethod([ThreadUtilities getJNIEnv], sdo->sdObject, jm_syncToCustom); // AWT_THREADING Safe (known object)
+}
+
+IMAGE_SURFACE_INLINE void removeAlphaPre_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
+{
+PRINT("    removeAlphaPre_32bit")
+    
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register Pixel32bit pixel, alpha, red, green, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc;
+            
+            alpha        = (pixel >> 24) & 0xff;
+            
+            if (alpha != 0)
+            {
+                // get color components
+                red            = (pixel >> 16) & 0xff;
+                green        = (pixel >> 8) & 0xff;
+                blue        = (pixel >> 0) & 0xff;
+                
+                // remove alpha pre
+                red            = ((red * 0xff) + 0x7f) / alpha;
+                green        = ((green * 0xff) + 0x7f) / alpha;
+                blue        = ((blue * 0xff) + 0x7f) / alpha;
+                
+                // clamp
+                red            = (red <= 0xff) ? red : 0xff;
+                green        = (green <= 0xff) ? green : 0xff;
+                blue        = (blue <= 0xff) ? blue : 0xff;
+                
+                *pixelsSrc++ = (alpha<<24) | (red<<16) | (green<<8) | blue; // construct new pixel
+            }
+            else
+            {
+                *pixelsSrc++ = 0;
+            }
+        }
+        
+        pixelsSrc += skip;
+    }
+}
+
+IMAGE_SURFACE_INLINE void swapRandBAndRemoveAlphaPre_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
+{
+PRINT("    swapRandBAndRemoveAlphaPre_32bit")
+    
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register Pixel32bit pixel, alpha, red, green, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc;
+            
+            alpha        = (pixel & 0xff000000) >> 24;
+            
+            if (alpha != 0)
+            {
+                // get color components
+                red            = (pixel & 0x00ff0000) >> 16;
+                green        = (pixel & 0x0000ff00) >> 8;
+                blue        = (pixel & 0x000000ff) >> 0;
+                
+                // remove alpha pre
+                red            = ((red * 0xff) + 0x7f) / alpha;
+                green        = ((green * 0xff) + 0x7f) / alpha;
+                blue        = ((blue * 0xff) + 0x7f) / alpha;
+                
+                // clamp
+                red            = (red <= 0xff) ? red : 0xff;
+                green        = (green <= 0xff) ? green : 0xff;
+                blue        = (blue <= 0xff) ? blue : 0xff;
+                
+                pixel = (alpha<<24) | (blue<<16) | (green<<8) | red; // construct new pixel
+
+#ifdef __LITTLE_ENDIAN__
+                pixel = CFSwapInt32HostToBig(pixel);  // the jint is little endian, we need to swap the bits before we send it back to Java
+#endif
+                            
+                *pixelsSrc++ = pixel;
+            }
+            else
+            {
+                *pixelsSrc++ = 0;
+            }
+        }
+        
+        pixelsSrc += skip;
+    }
+}
+
+IMAGE_SURFACE_INLINE void swapRandB_32bit_TYPE_INT(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
+{
+PRINT("    swapRandB_32bit_TYPE_INT")
+    
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register Pixel32bit pixel, red, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc;
+            
+            red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
+            blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
+            
+            pixel    = (pixel & 0xff00ff00); // erase original red&blue
+            
+            pixel    = pixel | red | blue; // construct new pixel
+            
+            *pixelsSrc++ = pixel;
+        }
+        
+        pixelsSrc += skip;
+    }
+}
+
+IMAGE_SURFACE_INLINE void swapRandB_32bit_TYPE_4BYTE(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
+{
+PRINT("    swapRandB_32bit_TYPE_4BYTE")
+    
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register Pixel32bit pixel, red, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc;
+            
+            red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
+            blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
+            
+            pixel    = (pixel & 0xff00ff00); // erase original red&blue
+            
+            pixel    = pixel | red | blue; // construct new pixel
+            
+#ifdef __LITTLE_ENDIAN__
+            pixel = CFSwapInt32HostToBig(pixel); // the jint is little endian, we need to swap the bits before we send it back to Java
+#endif
+            
+            *pixelsSrc++ = pixel;
+        }
+        
+        pixelsSrc += skip;
+    }
+}
+
+IMAGE_SURFACE_INLINE void map555_16bitTo565_16bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel16bit *pixelsSrc)
+{
+PRINT("    map555_16bitTo565_16bit")
+    register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register jint green;
+    register Pixel16bit pixel;
+    register jint x, y;
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {
+            pixel = *pixelsSrc;
+            
+            green = ((pixel >> 5)  & 31);   // rrrrrgggggbbbbb => shift 5 right = 000000rrrrrggggg => and 31 = 00000000000ggggg
+            green = ((jint) (((CGFloat) green / 31.0f) * 63.0f)) & 63; // first normalize between 0 and 1 and then un-normalize to 6 bit (63 = 0000000000111111)
+            
+            *pixelsSrc++ = ((pixel&0x7c00)<<1) | (green << 5) | (pixel&0x01f);
+        }
+        
+        pixelsSrc += skip;
+    }
+}
+
+IMAGE_SURFACE_INLINE void copyARGB_PRE_32bitToBGR_24bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsDst)
+{
+PRINT("    copyARGB_PRE_32bitToBGR_24bit")
+    
+    static const jint mask = 0x000000ff;
+    register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
+    register jint skipDst = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsDst units
+    register Pixel32bit pixel, alpha, red, green, blue;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc;
+            
+            alpha        = (pixel >> 24) & mask;
+            
+            if (alpha != 0)
+            {
+                // extract color components
+                red            = (pixel >> 16) & mask;
+                green        = (pixel >> 8) & mask;
+                blue        = (pixel >> 0) & mask;
+                
+                // remove alpha pre
+                red            = ((red * 0xff) + 0x7f) / alpha;
+                green        = ((green * 0xff) + 0x7f) / alpha;
+                blue        = ((blue * 0xff) + 0x7f) / alpha;
+                
+                // clamp
+                *pixelsDst++ = (blue <= 0xff) ? blue : 0xff;
+                *pixelsDst++ = (green <= 0xff) ? green : 0xff;
+                *pixelsDst++ = (red <= 0xff) ? red : 0xff;
+            }
+            else
+            {
+                *pixelsDst++ = 0; // blue
+                *pixelsDst++ = 0; // green
+                *pixelsDst++ = 0; // red
+            }
+            
+            pixelsSrc++;
+        }
+        
+        pixelsSrc += skipSrc;
+        pixelsDst += skipDst;
+    }
+}
+
+
+IMAGE_SURFACE_INLINE void copyARGB_PRE_32bitToRGB_24bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsDst)
+{
+    PRINT("    copyARGB_PRE_32bitToRGB_24bit")
+    
+    static const jint mask = 0x000000ff;
+    register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
+    register jint skipDst = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsDst units
+    register Pixel32bit pixel, alpha, red, green, blue;
+    register jint x, y;
+
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel = *pixelsSrc;        
+                
+            alpha        = (pixel >> 24) & mask;
+            
+            if (alpha != 0)
+            {
+                // extract color components            
+                red            = (pixel >> 16) & mask;
+                green        = (pixel >> 8) & mask;
+                blue        = (pixel >> 0) & mask;
+                
+                // remove alpha pre
+                red            = ((red * 0xff) + 0x7f) / alpha;
+                green        = ((green * 0xff) + 0x7f) / alpha;
+                blue        = ((blue * 0xff) + 0x7f) / alpha;
+                
+                // clamp
+                *pixelsDst++ = (red <= 0xff) ? red : 0xff;
+                *pixelsDst++ = (green <= 0xff) ? green : 0xff;
+                *pixelsDst++ = (blue <= 0xff) ? blue : 0xff;
+            }
+            else
+            {
+                *pixelsDst++ = 0; // blue
+                *pixelsDst++ = 0; // green
+                *pixelsDst++ = 0; // red
+            }
+            
+            pixelsSrc++;
+        }
+        
+        pixelsSrc += skipSrc;
+        pixelsDst += skipDst;
+    }
+}
+
+
+// gray = 0.3red + 0.59green + 0.11blue - NTSC standard (according to Luke Wallis)
+IMAGE_SURFACE_INLINE void copyARGB_PRE_32bitToGray_16bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel16bit *pixelsDst)
+{
+PRINT("    copyARGB_PRE_32bitToGray_16bit")
+    
+    static const jint mask = 0x000000ff;
+    register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
+    register jint skipDst = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsDst units
+    register Pixel32bit alpha;
+    register Pixel32bit pixel, red, green, blue;
+    register CGFloat pixelFloat;
+    register jint x, y;
+    
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            pixel        = *pixelsSrc;
+            
+            // gznote: do we remove alpha pre here?
+            alpha        = ((pixel >> 24) & mask); //extract
+            
+            if (alpha != 0)
+            {
+                red            = ((pixel >> 16) & mask); // extract
+                green        = ((pixel >> 8) & mask); // extract
+                blue        = ((pixel >> 0) & mask); // extract
+                            
+                alpha        *= 0xff; // upsample to 16bit
+                red            *= 0xff; // upsample to 16bit
+                green        *= 0xff; // upsample to 16bit
+                blue        *= 0xff; // upsample to 16bit
+                
+                red            = ((red * 0xffff) + 0x7fff) / alpha; // remove alpha pre
+                red            = (red <= 0xffff) ? red : 0xffff;
+                green        = ((green * 0xffff) + 0x7fff) / alpha; // remove alpha pre
+                green        = (green <= 0xffff) ? green : 0xffff;
+                blue        = ((blue * 0xffff) + 0x7fff) / alpha; // remove alpha pre
+                blue        = (blue <= 0xffff) ? blue : 0xffff;
+                
+                pixelFloat    = red*0.3f + green*0.59f + blue*0.11f; // rgb->gray NTSC conversion
+            }
+            else
+            {
+                pixelFloat = 0;
+            }
+            
+            *pixelsDst    = (jint)pixelFloat;
+            pixelsDst++;
+            
+            pixelsSrc++;
+        }
+        
+        pixelsSrc += skipSrc;
+        pixelsDst += skipDst;
+    }
+}
+
+// 1. first "dither" the true color down by creating a 16 bit value of the real color that will serve as an index into the cache of indexes
+// 2. if the cache has a valid entry use it otherwise go through 3 and 4
+// 3. go through the color table and calculate Euclidian distance between the true color and the indexed colors
+// 4. map the shortest distance into the one and true index color and stick it into the dst (and cache)
+IMAGE_SURFACE_INLINE UInt16* copyARGB_PRE_bitToIndexed_8bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsDst, Pixel32bit* lutdata, UInt32 lutDataSize, UInt16 *indexedColorTable)
+{
+PRINT("    copyARGB_PRE_bitToIndexed_8bit")
+    static const UInt32 mask            = 0x000000ff;
+    
+    static const UInt32 indexSize        = 65536;        // 2^16 - 16 bits of precision
+    static const UInt32 indexMask        = 0x000000f0;    // 00000000000000000000000011110000
+    static const UInt16 invalidIndex    = 0xffff;        // 1111111111111111
+    
+    register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
+    register jint skipDst = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
+    register jint indexOfBest, indexOfBestCached = -1;
+    register CGFloat distanceOfBest, distance;
+    register UInt32 p1, p1Cached = 0, p1a, p1r, p1g, p1b, p2;
+    register SInt32 da, dr, dg, db;
+    register jint x, y, i;    
+    BOOL cachedValueReady = NO;
+    
+    if (indexedColorTable == NULL)
+    {
+        indexedColorTable = (UInt16*)malloc(indexSize*sizeof(UInt16));    // 15 bit precision, each entry capable of holding a 2 byte value
+                                                                        // (lower byte for the actual index, higher byte to mark it valid/invalid)
+    
+        if (indexedColorTable != NULL)
+        {
+            memset((void*)indexedColorTable, invalidIndex, indexSize*sizeof(UInt16));
+        }
+        else
+        {
+            fprintf(stderr, "ERROR: malloc returns NULL for isdo->indexedColorTable in copyARGB_PRE_bitToIndexed_8bit");
+            return NULL;
+        }
+    }
+    
+    register UInt16 cacheIndex;
+
+    for (y=0; y<h; y++)
+    {        
+        for (x=0; x<w; x++)
+        {        
+            p1 = *pixelsSrc;
+            
+            if ((p1Cached != p1) || (cachedValueReady == NO))
+            {
+                p1a = ((p1 >> 24) & mask);
+                
+                if (p1a != 0)
+                {
+                    // extract color components
+                    p1r = ((p1 >> 16) & mask);
+                    p1g = ((p1 >> 8) & mask);
+                    p1b = ((p1 >> 0) & mask);
+                    
+                    // remove alpha pre
+                    p1r = ((p1r * 0xff) + 0x7f) / p1a;
+                    p1g = ((p1g * 0xff) + 0x7f) / p1a;
+                    p1b = ((p1b * 0xff) + 0x7f) / p1a;
+                    
+                    // clamp
+                    p1r = (p1r <= 0xff) ? p1r : 0xff;
+                    p1g = (p1g <= 0xff) ? p1g : 0xff;
+                    p1b = (p1b <= 0xff) ? p1b : 0xff;
+                }
+                else
+                {
+                    p1r = 0;
+                    p1g = 0;
+                    p1b = 0;
+                }
+                
+                cacheIndex = (UInt16)(((p1a & indexMask) << 8) | ((p1r & indexMask) << 4) | ((p1g & indexMask) << 0) | ((p1b & indexMask) >> 4));
+                if (indexedColorTable[cacheIndex] == invalidIndex)
+                {
+                    indexOfBest = 0;
+                    distanceOfBest = DBL_MAX;
+                    
+                    for (i=0; i<lutDataSize; i++)
+                    {
+                        p2 = lutdata[i];
+                        
+                        da = p1a - ((p2 >> 24) & mask);
+                        dr = p1r - ((p2 >> 16) & mask);
+                        dg = p1g - ((p2 >> 8) & mask);
+                        db = p1b - ((p2 >> 0) & mask);
+                        
+                        distance = sqrt((da*da)+(dr*dr)+(dg*dg)+(db*db));
+                        if (distance < distanceOfBest)
+                        {
+                            distanceOfBest = distance;
+                            indexOfBest = i;
+                        }
+                    }
+                    
+                    indexedColorTable[cacheIndex] = indexOfBest;
+                }
+                else
+                {
+                    indexOfBest = indexedColorTable[cacheIndex];
+                }
+                
+                cachedValueReady = YES;
+                p1Cached = p1;
+                indexOfBestCached = indexOfBest;
+            }
+            else
+            {
+                indexOfBest = indexOfBestCached;
+            }
+            
+            *pixelsDst = indexOfBest;
+            
+            pixelsDst++;
+            pixelsSrc++;
+        }
+        pixelsSrc += skipSrc;
+        pixelsDst += skipDst;
+    }
+    
+    return indexedColorTable;
+}
+
+// callback from CG telling us it's done with the data. <rdar://problem/4762033>
+static void releaseDataFromProvider(void *info, const void *data, size_t size)
+{
+    if (data != NULL)
+    {
+        free(data);
+    }
+}
+
+IMAGE_SURFACE_INLINE void createContext(JNIEnv *env, ImageSDOps *isdo)
+{
+PRINT("createContext")    
+    
+    QuartzSDOps *qsdo = (QuartzSDOps*)isdo;    
+    if (qsdo->cgRef == NULL)  // lazy creation
+    {
+        size_t bitsPerComponent = isdo->contextInfo.bitsPerComponent;
+        CGColorSpaceRef colorSpace = isdo->contextInfo.colorSpace;
+        CGImageAlphaInfo alphaInfo = isdo->contextInfo.alphaInfo;
+        
+        size_t bytesPerRow = isdo->contextInfo.bytesPerRow;
+        size_t size = bytesPerRow * isdo->height; 
+        isdo->nativePixels = malloc(size);
+
+        if (isdo->nativePixels == NULL)
+        {
+            fprintf(stderr, "malloc failed for size %d bytes in ImageSurfaceData.createContext()\n", (int) size);
+        }
+
+//fprintf(stderr, "isdo=%p isdo->type=%d, bitsPerComponent=%d, bytesPerRow=%d, colorSpace=%p, alphaInfo=%d, width=%d, height=%d, size=%d\n", isdo, type, (jint)bitsPerComponent, (jint)bytesPerRow, colorSpace, (jint)alphaInfo, (jint) isdo->width, (jint) isdo->height, (jint) size);
+        
+        qsdo->cgRef = CGBitmapContextCreate(isdo->nativePixels, isdo->width, isdo->height, bitsPerComponent, bytesPerRow, colorSpace, alphaInfo);        
+        isdo->dataProvider = CGDataProviderCreateWithData(NULL, isdo->nativePixels, size, releaseDataFromProvider);
+    }
+
+//fprintf(stderr, "cgRef=%p\n", qsdo->cgRef);
+    if (qsdo->cgRef == NULL)
+    {
+        fprintf(stderr, "ERROR: (qsdo->cgRef == NULL) in createContext!\n");
+    }
+    
+    // intitalize the context to match the Java coordinate system
+    
+    // BG, since the context is created above, we can just concat
+    //CGContextSetCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, -1, 0, isdo->height));
+    CGContextConcatCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, -1, 0, isdo->height));
+    
+    CGContextSaveGState(qsdo->cgRef); // this will make sure we don't go pass device context settings
+    CGContextSaveGState(qsdo->cgRef); // this will put user settings on top, used by LazyStateManagement code
+    qsdo->newContext = YES;    
+}
+
+IMAGE_SURFACE_INLINE void holdJavaPixels(JNIEnv* env, ImageSDOps* isdo)
+{
+PRINT("holdJavaPixels")
+    
+    if (isdo->type != java_awt_image_BufferedImage_TYPE_CUSTOM)
+    {
+        Pixel8bit* pixels = NULL;
+        if (isdo->nrOfPixelsOwners == 0)
+        {
+            pixels = (Pixel8bit*)((*env)->GetPrimitiveArrayCritical(env, isdo->array, NULL));
+            if (pixels != NULL)
+            {
+                isdo->pixelsLocked = pixels;
+                
+                isdo->pixels = isdo->pixelsLocked + isdo->offset;
+            }
+            else
+            {
+                fprintf(stderr, "ERROR: GetPrimitiveArrayCritical returns NULL for pixels in holdJavaPixels!\n");
+            }
+        }
+        isdo->nrOfPixelsOwners++;
+    }
+    else if (isdo->pixels == NULL)
+    {
+        isdo->pixels = (Pixel8bit*)((*env)->GetDirectBufferAddress(env, isdo->array));
+    }
+}
+
+IMAGE_SURFACE_INLINE void unholdJavaPixels(JNIEnv* env, ImageSDOps* isdo)
+{
+PRINT("unholdJavaPixels")
+    
+    if (isdo->type != java_awt_image_BufferedImage_TYPE_CUSTOM)
+    {
+        isdo->nrOfPixelsOwners--;
+        if (isdo->nrOfPixelsOwners == 0)
+        {
+            isdo->pixels = NULL;
+            
+            (*env)->ReleasePrimitiveArrayCritical(env, isdo->array, isdo->pixelsLocked, 0); // Do not use JNI_COMMIT, as that will not free the buffer copy when +ProtectJavaHeap is on.
+            isdo->pixelsLocked = NULL;            
+        }
+    }
+}
+
+static void imageDataProvider_UnholdJavaPixels(void *info, const void *data, size_t size)
+{
+PRINT("imageDataProvider_UnholdJavaPixels")
+    
+    ImageSDOps* isdo = (ImageSDOps*)info;
+    unholdJavaPixels([ThreadUtilities getJNIEnv], isdo);
+}
+static void imageDataProvider_FreeTempPixels(void *info, const void *data, size_t size)
+{
+PRINT("imageDataProvider_FreeTempPixels")
+    
+    free((void *)data);
+}
+IMAGE_SURFACE_INLINE void syncFromJavaPixels(JNIEnv* env, ImageSDOps* isdo)
+{
+PRINT("syncFromJavaPixels")
+    
+    // check to see if we have any work to do
+    if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
+    {
+        // if we do, lock down Java pixels, this halts GarbageCollector!
+        holdJavaPixels(env, isdo);
+        if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
+        {
+            isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 0;
+            
+            void *dataProviderData = NULL;
+            void *dataProviderInfo = NULL;
+            void *dataProviderCallback = NULL;
+            size_t dataProviderDataSize = 0;
+            size_t width = isdo->width;
+            size_t height = isdo->height;
+            size_t bitsPerComponent = isdo->imageInfo.bitsPerComponent;
+            size_t bitsPerPixel = isdo->imageInfo.bitsPerPixel;
+            size_t bytesPerRow = 0;
+            size_t extraBytesPerRow = 0; // these are the extra bytesPerRow used for alignement
+            
+            switch (isdo->type)
+            {
+                //case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: // mapped to TYPE_CUSTOM
+                case java_awt_image_BufferedImage_TYPE_CUSTOM:
+                    holdJavaPixels(env, isdo);    // we lock again since we are reusing pixels, but we must ensure CGImageRef immutability
+                                                // we can lock these pixels down because they are nio based, so we don't halt the GarbageCollector
+                    bytesPerRow = isdo->javaPixelsBytesPerRow;
+                    dataProviderDataSize = bytesPerRow*isdo->height;
+                    dataProviderData = isdo->pixels;
+                    dataProviderInfo = isdo;
+                    dataProviderCallback = imageDataProvider_UnholdJavaPixels;
+                    break;
+                default:
+                    bytesPerRow = isdo->imageInfo.bytesPerRow;
+                    dataProviderDataSize = bytesPerRow*height;
+                    dataProviderData = malloc(dataProviderDataSize);
+                    dataProviderInfo = isdo;
+                    dataProviderCallback = imageDataProvider_FreeTempPixels;
+            }
+            
+            switch (isdo->type)
+            {
+                //case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: // mapped to TYPE_CUSTOM
+                case java_awt_image_BufferedImage_TYPE_CUSTOM:
+                    customPixelsFromJava(env, isdo);
+                    break;
+                case java_awt_image_BufferedImage_TYPE_INT_RGB:
+                case java_awt_image_BufferedImage_TYPE_INT_ARGB:
+                case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
+                case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB:
+                case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
+                case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
+                    copyBits(width, height, isdo->javaPixelsBytesPerRow, (Pixel8bit*)isdo->pixels, bytesPerRow, dataProviderData);
+                    break;
+                case java_awt_image_BufferedImage_TYPE_INT_BGR:
+                    copySwapRandB_32bit_TYPE_INT(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels, dataProviderData, extraBytesPerRow);
+                    break;
+                case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
+                case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
+                    copySwapRandB_32bit_TYPE_4BYTE(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels, dataProviderData, extraBytesPerRow);
+                    break;
+                case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
+                    copyBGR_24bitToXRGB_32bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, dataProviderData, extraBytesPerRow);
+                    break;
+                case sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB:
+                    copyRGB_24bitToXRGB_32bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, dataProviderData, extraBytesPerRow);
+                    break;                    
+                case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
+                    copy565_16bitTo555_16bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel16bit*)isdo->pixels, dataProviderData, extraBytesPerRow);
+                    break;
+                case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
+                    copyIndexed_8bitToARGB_32bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, isdo->lutData, dataProviderData, extraBytesPerRow);
+                    break;
+                default:
+                    break;
+            }
+            
+            CGDataProviderRef provider = CGDataProviderCreateWithData(dataProviderInfo, dataProviderData, dataProviderDataSize, dataProviderCallback);
+            CGImageRef javaImg = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow,
+                                                isdo->imageInfo.colorSpace, isdo->imageInfo.alphaInfo, provider, NULL, NO, kCGRenderingIntentDefault);
+//fprintf(stderr, "javaImg=%p\n", javaImg);
+            CGDataProviderRelease(provider);
+            
+            if (javaImg != NULL)
+            {
+                QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
+                
+                if (isdo->imgRef != NULL)
+                {
+                    CGImageRelease(isdo->imgRef);
+                    isdo->imgRef = NULL;
+                }
+        
+                if (qsdo->cgRef == NULL)
+                {
+                    createContext(env, isdo);
+                }
+                
+                if (qsdo->cgRef != NULL)
+                {
+                    CGContextSaveGState(qsdo->cgRef);
+                    CGContextSetCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, 1, 0, 0));
+                    CGContextSetBlendMode(qsdo->cgRef, kCGBlendModeCopy);
+                    CGContextSetAlpha(qsdo->cgRef, 1.0f);
+                    CGContextDrawImage(qsdo->cgRef, CGRectMake(0, 0, width, height), javaImg);
+                    CGContextFlush(qsdo->cgRef);
+                    CGContextRestoreGState(qsdo->cgRef);
+                    CGImageRelease(javaImg);
+                }
+                else
+                {
+                    fprintf(stderr, "ERROR: (cgRef == NULL) in syncFromJavaPixels!\n");
+                }
+            }
+            else
+            {
+//fprintf(stderr, "isdo->type=%d, isdo->width=%d, isdo->height=%d, isdo->imageInfo.bitsPerComponent=%d, isdo->imageInfo.bytesPerPixel=%d, isdo->imageInfo.bitsPerPixel=%d, isdo->imageInfo.bytesPerRow=%d, isdo->imageInfo.colorSpace=%p, isdo->imageInfo.alphaInfo=%d\n",
+//(jint)isdo->type, (jint)isdo->width, (jint)isdo->height, (jint)isdo->imageInfo.bitsPerComponent, (jint)isdo->imageInfo.bytesPerPixel, (jint)isdo->imageInfo.bitsPerPixel, (jint)isdo->imageInfo.bytesPerRow, isdo->imageInfo.colorSpace, (jint)isdo->imageInfo.alphaInfo);
+                fprintf(stderr, "ERROR: (javaImg == NULL) in syncFromJavaPixels!\n");
+            }
+        }
+        
+        unholdJavaPixels(env, isdo);
+    }
+}
+
+IMAGE_SURFACE_INLINE void processPixels(ImageSDOps* isdo, jint x, jint y, jint width, jint height, void (*processPixelsCallback) (ImageSDOps *, jint, Pixel32bit *, jint, jint, jint, jint))
+{    
+    processPixelsCallback(isdo, (jint) isdo->contextInfo.bytesPerRow, (Pixel32bit *) isdo->nativePixels, x, y, width, height);    
+}
+
+IMAGE_SURFACE_INLINE void syncToJavaPixels_processPixelsCallback(ImageSDOps* isdo, jint nativePixelsBytesPerRow, Pixel32bit *dataSrc, jint x, jint y, jint width, jint height)
+{
+    switch (isdo->type)
+    {
+        case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
+            copyARGB_PRE_32bitToBGR_24bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels);
+            break;
+        case sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB:
+            copyARGB_PRE_32bitToRGB_24bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels);
+            break;
+        case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
+            copyARGB_PRE_32bitToGray_16bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel16bit*)isdo->pixels);
+            break;
+        case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
+            isdo->indexedColorTable = copyARGB_PRE_bitToIndexed_8bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, isdo->lutData, isdo->lutDataSize, isdo->indexedColorTable);
+            break;
+        default:
+            break;
+    }
+}
+
+
+IMAGE_SURFACE_INLINE void syncToJavaPixels(JNIEnv* env, ImageSDOps* isdo)
+{
+PRINT("syncToJavaPixels")
+    
+    holdJavaPixels(env, isdo);
+
+    QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
+    if (qsdo->cgRef == NULL)
+    {
+        createContext(env, isdo);
+    }
+            
+    isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNativePixelsChangedIndex] = 0;
+    
+    if (isdo->contextInfo.canUseJavaPixelsAsContext == YES)
+    {
+    
+        jint srcBytesPerRow = isdo->contextInfo.bytesPerRow;
+        jint dstBytesPerRow = isdo->javaPixelsBytesPerRow;
+        jint h = isdo->height;
+        Pixel8bit *pixelsSrc = isdo->nativePixels;
+        Pixel8bit *pixelsDst = isdo->pixels;
+        
+        if (srcBytesPerRow == dstBytesPerRow)
+        {
+            memcpy(pixelsDst, pixelsSrc, h * dstBytesPerRow);
+        }
+        else
+        {
+            jint widthInBytes = isdo->width * isdo->contextInfo.bytesPerPixel;
+            jint y;
+            for (y=0; y < h; y++)
+            {
+                memcpy(pixelsDst, pixelsSrc, widthInBytes);
+                
+                pixelsSrc += srcBytesPerRow;
+                pixelsDst += dstBytesPerRow;
+            }
+        }
+        
+        switch (isdo->type)
+        {
+            //case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: // mapped to TYPE_CUSTOM
+            case java_awt_image_BufferedImage_TYPE_CUSTOM:
+                customPixelsToJava(env, isdo);
+                break;
+            case java_awt_image_BufferedImage_TYPE_INT_ARGB:
+                removeAlphaPre_32bit(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
+                break;
+            case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
+                swapRandBAndRemoveAlphaPre_32bit(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
+                break;
+            case java_awt_image_BufferedImage_TYPE_INT_BGR:
+                swapRandB_32bit_TYPE_INT(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
+                break;
+            case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
+                swapRandB_32bit_TYPE_4BYTE(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
+                break;
+            case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
+                map555_16bitTo565_16bit(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel16bit*)isdo->pixels);
+                break;
+            default:
+                break;
+        }
+    }
+    else
+    {
+        processPixels(isdo, 0, 0, isdo->width, isdo->height, &syncToJavaPixels_processPixelsCallback);
+    }
+    
+    unholdJavaPixels(env, isdo);
+}
+
+
+IMAGE_SURFACE_INLINE jboolean xorSurfacePixels(JNIEnv *env, jobject dstIsd, jobject srcIsd, jint colorXOR, jint x, jint y, jint w, jint h)
+{
+PRINT("xorSurfacePixels")
+    
+    jboolean handled = JNI_FALSE;
+    
+JNF_COCOA_ENTER(env);
+    ImageSDOps* srcIsdo = LockImagePixels(env, srcIsd);    
+    ImageSDOps* dstIsdo = LockImagePixels(env, dstIsd);
+    
+    if ((x < 0) || (y < 0) || (x+w > dstIsdo->width) || (y+h > dstIsdo->height) || (w > srcIsdo->width) || (h > srcIsdo->height))
+    {
+#ifdef PRINT_WARNINGS
+fprintf(stderr, "xorSurfacePixels INVALID parameters: x=%d, y=%d, w=%d, h=%d\n", x, y, w, h);
+fprintf(stderr, "   dstIsdo->width=%d, dstIsdo->height=%d, biqsdoPixels->width=%d, biqsdoPixels->height=%d\n",
+                        dstIsdo->width, dstIsdo->height, srcIsdo->width, srcIsdo->height);
+#endif
+        UnlockImagePixels(env, srcIsdo);
+        UnlockImagePixels(env, dstIsdo);
+        
+        return JNI_FALSE;
+    }
+    
+    jint offset = (dstIsdo->width*y)+x;
+    register Pixel32bit* dstPixels = (Pixel32bit*)dstIsdo->pixels;
+    register jint skip = dstIsdo->width - w;
+    register Pixel32bit* srcPixels = (Pixel32bit*)srcIsdo->pixels;
+    register jint skipPixels = srcIsdo->width - w;
+    register jint i, j;
+    
+    dstPixels += offset;
+    
+    switch (dstIsdo->type)
+    {
+        case java_awt_image_BufferedImage_TYPE_INT_RGB:
+        case java_awt_image_BufferedImage_TYPE_INT_ARGB:
+        case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
+        {            
+            dstIsdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
+
+            if (dstIsdo->type == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE)
+            {
+                Pixel8bit alpha = (colorXOR>>24)&0xff;
+                Pixel8bit red = (colorXOR>>16)&0xff;
+                red = (jint)(((CGFloat)red/255.0f * (CGFloat)alpha/255.0f)*255.0f);
+                Pixel8bit green = (colorXOR>>8)&0xff;
+                green = (jint)(((CGFloat)green/255.0f * (CGFloat)alpha/255.0f)*255.0f);
+                Pixel8bit blue = (colorXOR>>0)&0xff;
+                blue = (jint)(((CGFloat)blue/255.0f * (CGFloat)alpha/255.0f)*255.0f);
+                colorXOR = (alpha<<24) | (red<<16) | (green<<8) | blue; // the color is now alpha premultiplied
+            }
+            
+            for (i=0; i<h; i++)
+            {
+                for (j=0; j<w; j++)
+                {
+                    Pixel32bit srcPixel = *srcPixels;
+                    Pixel8bit pixelAlpha = (srcPixel>>24);
+                    if (pixelAlpha > XOR_ALPHA_CUTOFF)
+                    {
+                        *dstPixels = (*dstPixels ^ (srcPixel ^ colorXOR));
+                    }                    
+                    dstPixels++; srcPixels++;
+                }
+                
+                dstPixels += skip;
+                srcPixels += skipPixels;
+            }
+            
+            handled = JNI_TRUE;
+            break;
+        }
+        default:
+        {
+            handled = JNI_FALSE;
+#if defined(PRINT_WARNINGS)
+            fprintf(stderr, "WARNING: unknown type (%d) in compositeXOR\n", dstIsdo->type);
+            PrintImageInfo(dstIsdo);
+#endif
+        }
+    }
+    
+    UnlockImagePixels(env, srcIsdo);
+    UnlockImagePixels(env, dstIsdo);
+        
+JNF_COCOA_EXIT(env);
+    return handled;
+}
+
+IMAGE_SURFACE_INLINE jboolean clearSurfacePixels(JNIEnv *env, jobject bisd, jint w, jint h)
+{
+PRINT("clearSurfacePixels")    
+    jboolean handled = JNI_FALSE;
+    
+JNF_COCOA_ENTER(env);
+
+    ImageSDOps *isdo = LockImagePixels(env, bisd);
+
+    if (isdo->type == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE)
+    {
+        isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
+        
+        w = (w < isdo->width) ? w : isdo->width;
+        h = (h < isdo->height) ? h : isdo->height;
+                
+        register Pixel32bit* data = (Pixel32bit*)isdo->pixels;
+        register jint i;        
+        if ((w < isdo->width) || (h < isdo->height)) //cmcnote: necessary to special-case for small height? wouldn't 4*w*h do it?
+        {
+            register jint skip = isdo->width;
+            register jint row = 4*w;
+            for (i=0; i<h; i++)
+            {
+                bzero(data, row);
+                data += skip;
+            }
+        }
+        else
+        {
+            bzero(data, 4*w*h);
+        }
+        
+        handled = JNI_TRUE;
+    }
+    UnlockImagePixels(env, isdo);
+    
+JNF_COCOA_EXIT(env);
+    
+    return handled;
+}
+
+static void ImageSD_startCGContext(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType)
+{
+PRINT("ImageSD_startCGContext")
+    
+    ImageSDOps *isdo = (ImageSDOps*)qsdo;
+    
+    pthread_mutex_lock(&isdo->lock);
+    
+    if (isdo->imgRef != NULL)
+    {
+        CGImageRelease(isdo->imgRef);
+        isdo->imgRef = NULL;
+    }
+
+    if (qsdo->cgRef == NULL)
+    {
+        createContext(env, isdo);
+    }
+    else
+    {
+        qsdo->newContext = NO;
+    }
+    
+    if (qsdo->cgRef != NULL)
+    {
+        if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1)
+        {
+            isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;            
+        }
+        
+        // sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex can be set right above or somewhere else
+        if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
+        {
+            syncFromJavaPixels(env, isdo);
+        }
+        
+        isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNativePixelsChangedIndex] = 1;
+        
+        SetUpCGContext(env, qsdo, renderType);
+    }
+}
+static void ImageSD_finishCGContext(JNIEnv *env, QuartzSDOps *qsdo)
+{
+PRINT("ImageSD_finishCGContext")
+    
+    ImageSDOps *isdo = (ImageSDOps*)qsdo;
+    
+    if (qsdo->cgRef != NULL)
+    {
+        CompleteCGContext(env, qsdo);
+        
+        if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1)
+        {
+            syncToJavaPixels(env, isdo);
+            isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
+        }
+    }
+
+    pthread_mutex_unlock(&isdo->lock);
+}
+
+static void ImageSD_dispose(JNIEnv *env, SurfaceDataOps *ops)
+{
+PRINT("ImageSD_dispose")
+    
+    // copied from BufImg_Dispose in BufImgSurfaceData.c
+    {
+        /* ops is assumed non-null as it is checked in SurfaceData_DisposeOps */
+        BufImgSDOps *bisdo = (BufImgSDOps *)ops;
+        (*env)->DeleteWeakGlobalRef(env, bisdo->array);
+        if (bisdo->lutarray != NULL) {
+        (*env)->DeleteWeakGlobalRef(env, bisdo->lutarray);
+        }
+        if (bisdo->icm != NULL) {
+        (*env)->DeleteWeakGlobalRef(env, bisdo->icm);
+        }
+    }
+    
+    QuartzSDOps *qsdo = (QuartzSDOps *)ops;
+        
+    if (qsdo->graphicsStateInfo.batchedLines != NULL)
+    {
+        free(qsdo->graphicsStateInfo.batchedLines);
+        qsdo->graphicsStateInfo.batchedLines = NULL;
+    }
+    
+    JNFDeleteGlobalRef(env, qsdo->javaGraphicsStatesObjects);
+    
+    if (qsdo->cgRef != NULL)
+    {
+        CGContextRelease(qsdo->cgRef);
+        qsdo->cgRef = NULL;
+    }
+
+    ImageSDOps *isdo = (ImageSDOps *)ops;
+
+    if (isdo->dataProvider != NULL)
+    {
+        CGDataProviderRelease(isdo->dataProvider);
+        isdo->dataProvider = NULL;
+    }
+    if (isdo->imgRef != NULL)
+    {
+        CGImageRelease(isdo->imgRef);
+        isdo->imgRef = NULL;
+    }
+    if (isdo->indexedColorTable != NULL)
+    {
+        free(isdo->indexedColorTable);
+        isdo->indexedColorTable = NULL;
+    }
+    if (isdo->lutData != NULL)
+    {
+        free(isdo->lutData);
+        isdo->indexedColorTable = NULL;
+    }
+    if (isdo->array != NULL)
+    {
+        JNFDeleteGlobalRef(env, isdo->array);
+        isdo->array = NULL;
+    }
+    if (isdo->icm != NULL)
+    {
+        JNFDeleteGlobalRef(env, isdo->icm);
+        isdo->icm = NULL;
+    }
+    
+    if (isdo->nsRef) {
+        CFRelease(isdo->nsRef); // GC
+        isdo->nsRef = nil;
+    }
+    
+    pthread_mutex_destroy(&isdo->lock);
+}
+
+// used by XOR (Java pixels must be up to date)
+ImageSDOps* LockImagePixels(JNIEnv* env, jobject imageSurfaceData)
+{
+PRINT("LockImagePixels")
+    
+    ImageSDOps* isdo = (ImageSDOps*)SurfaceData_GetOps(env, imageSurfaceData);
+    
+    pthread_mutex_lock(&isdo->lock);
+    
+    holdJavaPixels(env, isdo);
+    
+    // if we need to access this image's pixels we need to convert native pixels (if any) back to Java
+    if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNativePixelsChangedIndex] == 1)
+    {
+        syncToJavaPixels(env, isdo);
+        isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
+    }
+    
+    return isdo;
+}
+void UnlockImagePixels(JNIEnv* env, ImageSDOps* isdo)
+{
+PRINT("UnlockImagePixels")
+    // don't do that since the native pixels haven't changed (Java pixels == native pixels)
+    //syncToJavaPixels(env, isdo);
+    
+    unholdJavaPixels(env, isdo);
+    
+    pthread_mutex_unlock(&isdo->lock);
+}
+
+// used by drawImage (native pixels must be up to date)
+ImageSDOps* LockImage(JNIEnv* env, jobject imageSurfaceData)
+{
+PRINT("LockImage")
+    
+    ImageSDOps* isdo = (ImageSDOps*)SurfaceData_GetOps(env, imageSurfaceData);
+    
+    pthread_mutex_lock(&isdo->lock);
+    
+    // if we need to access this image's pixels we need to convert native pixels (if any) back to Java
+    // for those images whose context type doesn't match layer type or is a custom image
+    if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1)
+    {
+        isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
+    }
+    
+    // sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex can be set right above or somewhere else
+    if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
+    {
+        syncFromJavaPixels(env, isdo);
+    }
+        
+    return isdo;
+}
+void UnlockImage(JNIEnv* env, ImageSDOps* isdo)
+{
+PRINT("UnlockImage")
+    
+    // don't do that since the native pixels haven't changed (Java pixels == native pixels)
+    //syncToJavaPixels(env, isdo);
+    
+    pthread_mutex_unlock(&isdo->lock);
+}
+
+JNIEXPORT jobject JNICALL Java_sun_awt_image_BufImgSurfaceData_getSurfaceData
+    (JNIEnv *env, jclass bisd, jobject bufImg)
+{
+    static jfieldID sDataID = 0;
+    if (sDataID == 0)
+    {
+        static char *bimgName = "java/awt/image/BufferedImage";
+        jclass bimg = (*env)->FindClass(env, bimgName);
+        sDataID = (*env)->GetFieldID(env, bimg, "sData", "Lsun/java2d/SurfaceData;");
+    }
+    
+    return (*env)->GetObjectField(env, bufImg, sDataID);
+}
+
+JNIEXPORT void JNICALL Java_sun_awt_image_BufImgSurfaceData_setSurfaceData
+    (JNIEnv *env, jclass bisd, jobject bufImg, jobject sData)
+{
+    static jfieldID sDataID = 0;
+    if (sDataID == 0)
+    {
+        static char *bimgName = "java/awt/image/BufferedImage";
+        jclass bimg = (*env)->FindClass(env, bimgName);
+        sDataID = (*env)->GetFieldID(env, bimg, "sData", "Lsun/java2d/SurfaceData;");
+    }
+    
+    (*env)->SetObjectField(env, bufImg, sDataID, sData);
+}
+
+JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_initIDs(JNIEnv *env, jclass bisd)
+{
+//PRINT("initIDs")
+    // copied from Java_sun_awt_image_BufImgSurfaceData_initIDs in BufImgSurfaceData.c
+    {        
+        static char *icmName = "java/awt/image/IndexColorModel";
+        jclass icm;
+
+        if (sizeof(BufImgRIPrivate) > SD_RASINFO_PRIVATE_SIZE) {
+        JNU_ThrowInternalError(env, "Private RasInfo structure too large!");
+        return;
+        }
+
+        icm = (*env)->FindClass(env, icmName);
+        if (icm == NULL) {
+            return;
+        }
+
+        rgbID = (*env)->GetFieldID(env, icm, "rgb", "[I");
+        allGrayID = (*env)->GetFieldID(env, icm, "allgrayopaque", "Z");
+        mapSizeID = (*env)->GetFieldID(env, icm, "map_size", "I");
+        CMpDataID = (*env)->GetFieldID(env, icm, "pData", "J");
+        if (allGrayID == 0 || rgbID == 0 || mapSizeID == 0 || CMpDataID == 0) {
+        JNU_ThrowInternalError(env, "Could not get field IDs");
+        }
+    }
+    
+    gColorspaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+    gColorspaceGray = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
+//fprintf(stderr, "gColorspaceRGB=%p, gColorspaceGray=%p\n", gColorspaceRGB, gColorspaceGray);
+}
+
+JNIEXPORT jobject JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_getSurfaceData
+    (JNIEnv *env, jclass bisd, jobject bufImg)
+{
+PRINT("getSurfaceData")
+    
+    return JNFGetObjectField(env, bufImg, jm_SurfaceData);
+}
+
+JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_setSurfaceData
+    (JNIEnv *env, jclass bisd, jobject bufImg, jobject sData)
+{
+PRINT("setSurfaceData")
+    
+    JNFSetObjectField(env, bufImg, jm_SurfaceData, sData);
+}
+
+static jint ImageSD_Lock(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo, jint lockflags)
+{
+    ImageSDOps *isdo = (ImageSDOps*)ops;
+    pthread_mutex_lock(&isdo->lock);
+    
+    // copied from BufImg_Lock in BufImgSurfaceData.c
+    {
+        BufImgSDOps *bisdo = (BufImgSDOps *)ops;
+        BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
+
+        if ((lockflags & (SD_LOCK_LUT)) != 0 && !bisdo->lutarray) {
+            /* REMIND: Should this be an InvalidPipe exception? */
+            JNU_ThrowNullPointerException(env, "Attempt to lock missing colormap");
+            return SD_FAILURE;
+        }
+// TODO:BG
+        /*
+        if ((lockflags & SD_LOCK_INVCOLOR) != 0 ||
+            (lockflags & SD_LOCK_INVGRAY) != 0) 
+        {
+            bipriv->cData = BufImg_SetupICM(env, bisdo);
+            if (bipriv->cData == NULL) {
+                JNU_ThrowNullPointerException(env, "Could not initialize "
+                                              "inverse tables");
+                return SD_FAILURE;
+            }
+        } else {
+            bipriv->cData = NULL;
+        }
+        */
+        bipriv->cData = NULL;
+
+        bipriv->lockFlags = lockflags;
+        bipriv->base = NULL;
+        bipriv->lutbase = NULL;
+
+        SurfaceData_IntersectBounds(&pRasInfo->bounds, &bisdo->rasbounds);
+
+        /* TODO:BG
+        if ((bipriv->lockFlags & SD_LOCK_WRITE) &&
+            bisdo->sdOps.dirty != TRUE) {
+            SurfaceData_MarkDirty(env, &bisdo->sdOps);
+        } */
+        return SD_SUCCESS;
+    }
+}
+static void ImageSD_Unlock(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo)
+{
+    ImageSDOps *isdo = (ImageSDOps*)ops;
+
+    // For every ImageSD_Unlock, we need to be be conservative and mark the pixels
+    // as modified by the Sun2D renderer.
+    isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
+
+    pthread_mutex_unlock(&isdo->lock);
+}
+static void ImageSD_GetRasInfo(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo)
+{    
+    // copied from BufImg_GetRasInfo in BufImgSurfaceData.c
+    {
+        BufImgSDOps *bisdo = (BufImgSDOps *)ops;
+        BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
+
+        if ((bipriv->lockFlags & (SD_LOCK_RD_WR)) != 0) {
+            bipriv->base =
+                (*env)->GetPrimitiveArrayCritical(env, bisdo->array, NULL);
+        }
+        if ((bipriv->lockFlags & (SD_LOCK_LUT)) != 0) {
+            bipriv->lutbase =
+                (*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL);
+        }
+
+        if (bipriv->base == NULL) {
+            pRasInfo->rasBase = NULL;
+            pRasInfo->pixelStride = 0;
+            pRasInfo->scanStride = 0;
+        } else {
+            pRasInfo->rasBase = (void *)
+                (((uintptr_t) bipriv->base) + bisdo->offset);
+            pRasInfo->pixelStride = bisdo->pixStr;
+            pRasInfo->scanStride = bisdo->scanStr;
+        }
+        if (bipriv->lutbase == NULL) {
+            pRasInfo->lutBase = NULL;
+            pRasInfo->lutSize = 0;
+        } else {
+            pRasInfo->lutBase = bipriv->lutbase;
+            pRasInfo->lutSize = bisdo->lutsize;
+        }
+        if (bipriv->cData == NULL) {
+            pRasInfo->invColorTable = NULL;
+            pRasInfo->redErrTable = NULL;
+            pRasInfo->grnErrTable = NULL;
+            pRasInfo->bluErrTable = NULL;
+        } else {
+            pRasInfo->invColorTable = bipriv->cData->img_clr_tbl;
+            pRasInfo->redErrTable = bipriv->cData->img_oda_red;
+            pRasInfo->grnErrTable = bipriv->cData->img_oda_green;
+            pRasInfo->bluErrTable = bipriv->cData->img_oda_blue;
+            pRasInfo->invGrayTable = bipriv->cData->pGrayInverseLutData;
+        }
+    }
+}
+static void ImageSD_Release(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo)
+{
+    // copied from BufImg_Release in BufImgSurfaceData.c
+    {
+        BufImgSDOps *bisdo = (BufImgSDOps *)ops;
+        BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
+
+        if (bipriv->base != NULL) {
+            jint mode = (((bipriv->lockFlags & (SD_LOCK_WRITE)) != 0)
+                         ? 0 : JNI_ABORT);
+            (*env)->ReleasePrimitiveArrayCritical(env, bisdo->array,
+                                                  bipriv->base, mode);
+        }
+        if (bipriv->lutbase != NULL) {
+            (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray,
+                                                  bipriv->lutbase, JNI_ABORT);
+        }
+    }    
+}
+
+JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_initRaster(JNIEnv *env, jobject bisd, jobject array, jint offset, jint width, jint height,
+                                                                                jint pixelStride, jint scanStride, jobject icm, jint type,
+                                                                                    jobject jGraphicsState, jobjectArray jGraphicsStateObject, jobject jImageInfo)
+{
+PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_initRaster")
+    
+    ImageSDOps* isdo = (ImageSDOps*)SurfaceData_InitOps(env, bisd, sizeof(ImageSDOps));
+    
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&isdo->lock, &attr);
+    pthread_mutex_lock(&isdo->lock);
+    pthread_mutexattr_destroy(&attr);
+    
+    // copied (and modified) from Java_sun_awt_image_BufImgSurfaceData_initRaster in BufImgSurfaceData.c
+    {
+        BufImgSDOps *bisdo = 
+        //(BufImgSDOps*)SurfaceData_InitOps(env, bisd, sizeof(BufImgSDOps));
+        (BufImgSDOps*)isdo;
+        //bisdo->sdOps.Lock = BufImg_Lock;
+        //bisdo->sdOps.GetRasInfo = BufImg_GetRasInfo;
+        //bisdo->sdOps.Release = BufImg_Release;
+        //bisdo->sdOps.Unlock = NULL;
+        //bisdo->sdOps.Dispose = BufImg_Dispose;
+     
+        bisdo->array = (*env)->NewWeakGlobalRef(env, array);
+        bisdo->offset = offset;
+        //bisdo->scanStr = scanStr;
+        bisdo->scanStr = scanStride;
+        //bisdo->pixStr = pixStr;
+        bisdo->pixStr = pixelStride;
+        if (!icm) {
+        bisdo->lutarray = NULL;
+        bisdo->lutsize = 0;
+        bisdo->icm = NULL;
+        } else {
+        jobject lutarray = (*env)->GetObjectField(env, icm, rgbID);
+        bisdo->lutarray = (*env)->NewWeakGlobalRef(env, lutarray);
+        bisdo->lutsize = (*env)->GetIntField(env, icm, mapSizeID);
+        bisdo->icm = (*env)->NewWeakGlobalRef(env, icm);
+        }
+        bisdo->rasbounds.x1 = 0;
+        bisdo->rasbounds.y1 = 0;
+        bisdo->rasbounds.x2 = width;
+        bisdo->rasbounds.y2 = height;
+    }
+    
+    isdo->nrOfPixelsOwners = 0;
+    
+    isdo->contextInfo                    = sDefaultContextInfo[type];
+    isdo->imageInfo                        = sDefaultImageInfo[type];
+    
+    isdo->contextInfo.bytesPerRow        = width*isdo->contextInfo.bytesPerPixel;
+    isdo->imageInfo.bytesPerRow            = width*isdo->imageInfo.bytesPerPixel;
+    
+    switch (type)
+    {
+        case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
+            isdo->contextInfo.colorSpace = isdo->imageInfo.colorSpace = gColorspaceGray;
+            break;
+        case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
+            isdo->contextInfo.colorSpace = gColorspaceRGB;
+            isdo->imageInfo.colorSpace = gColorspaceGray;
+            break;
+        default:
+            isdo->contextInfo.colorSpace = isdo->imageInfo.colorSpace = gColorspaceRGB;
+            break;
+    }
+    isdo->isSubImage                    = (offset%scanStride != 0) || (scanStride != (pixelStride*width));
+    
+    // parameters specifying this image given to us from Java
+    isdo->javaImageInfo                    = (jint*)((*env)->GetDirectBufferAddress(env, jImageInfo));
+    isdo->array                            = (array != NULL) ? JNFNewGlobalRef(env, array) : NULL;
+    isdo->offset                        = offset;
+    isdo->width                            = width;
+    isdo->height                        = height;
+    isdo->javaPixelBytes                = pixelStride;
+    isdo->javaPixelsBytesPerRow            = scanStride;
+    isdo->icm                            = (icm != NULL) ? JNFNewGlobalRef(env, icm) : NULL;
+    isdo->type                            = type;
+        
+    if ((isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1) ||
+        (isdo->type == java_awt_image_BufferedImage_TYPE_CUSTOM))
+    {
+        // don't waste (precious, precious) VRAM on stolen or custom images that will be slow no matter what
+        isdo->contextInfo.useWindowContextReference = NO;
+    }
+    
+    // needed by TYPE_BYTE_INDEXED
+    isdo->indexedColorTable                = NULL;
+    isdo->lutData                        = NULL;
+    isdo->lutDataSize                    = 0;
+    if ((type == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED) && ((*env)->IsSameObject(env, icm, NULL) == NO))
+    {
+        jarray lutarray = JNFGetObjectField(env, icm, jm_rgb);
+        isdo->lutDataSize = (*env)->GetArrayLength(env, lutarray);
+        if (isdo->lutDataSize > 0)
+        {
+            jint transparency = JNFGetIntField(env, icm, jm_transparency);
+            jint transparent_index = -1;
+            if (transparency == java_awt_Transparency_BITMASK)
+            {
+                transparent_index = JNFGetIntField(env, icm, jm_transparent_index);
+            }
+            
+            Pixel32bit* lutdata = (Pixel32bit*)((*env)->GetPrimitiveArrayCritical(env, lutarray, NULL));
+            if (lutdata != NULL)
+            {
+                isdo->lutData = NULL;
+                
+                isdo->lutData = malloc(isdo->lutDataSize * sizeof(Pixel32bit));
+                if (isdo->lutData != NULL)
+                {
+                    if (transparency == java_awt_Transparency_BITMASK)
+                    {
+                        Pixel32bit* src = lutdata;
+                        Pixel32bit* dst = isdo->lutData;
+                        jint i;
+                        for (i=0; i<isdo->lutDataSize; i++)
+                        {
+                            if (i != transparent_index)
+                            {
+                                *dst = *src; 
+                                // rdar://problem/3390518 - don't force all indexed colors
+                                // to be fully opaque. They could be set up for us.
+                                // we used to call:  *dst = 0xff000000 | *src;
+                                // but that was forcing colors to be opaque when developers
+                                // could have set the alpha.
+                            }
+                            else
+                            {
+                                *dst = 0x00000000; // mark as translucent color
+                            }
+                            dst++; src++;
+                        }
+                    }
+                    else //if ((transparency == java_awt_Transparency_OPAQUE) || (transparency == java_awt_Transparency_TRANSLUCENT))
+                    {
+                        jint mask = 0x00000000;
+                        // <rdar://4224874> If the color model is OPAQUE than we need to create an opaque image for performance purposes.
+                        // the default alphaInfo for INDEXED images is kCGImageAlphaFirst. Therefore we need to special case this.
+                        if ((transparency == java_awt_Transparency_OPAQUE))
+                        {
+                            isdo->imageInfo.alphaInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
+                            mask = 0xff000000; // this is just a safeguard to make sure we fill the alpha
+                        }
+                        
+                        Pixel32bit* src = lutdata;
+                        Pixel32bit* dst = isdo->lutData;
+                        jint i;
+                        for (i=0; i<isdo->lutDataSize; i++)
+                        {
+                            *dst = *src | mask;
+                            dst++; src++;
+                        }
+                    }
+                    
+                    (*env)->ReleasePrimitiveArrayCritical(env, lutarray, lutdata, 0);
+                }
+                else
+                {
+                    fprintf(stderr, "ERROR: malloc returns NULL for isdo->lutData in initRaster!\n");
+                }
+            }
+            else
+            {
+                fprintf(stderr, "ERROR: GetPrimitiveArrayCritical returns NULL for lutdata in initRaster!\n");
+            }
+        }
+        (*env)->DeleteLocalRef(env, lutarray);
+    }
+                
+    QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
+    qsdo->BeginSurface                    = ImageSD_startCGContext;
+    qsdo->FinishSurface                    = ImageSD_finishCGContext;
+    
+    qsdo->javaGraphicsStates            = (jint*)((*env)->GetDirectBufferAddress(env, jGraphicsState));
+    qsdo->javaGraphicsStatesObjects        = JNFNewGlobalRef(env, jGraphicsStateObject);
+
+    qsdo->graphicsStateInfo.batchedLines = NULL;
+    qsdo->graphicsStateInfo.batchedLinesCount = 0;
+    
+    SurfaceDataOps *sdo = (SurfaceDataOps*)qsdo;
+    sdo->Lock        = ImageSD_Lock;
+    sdo->Unlock        = ImageSD_Unlock;
+    sdo->GetRasInfo    = ImageSD_GetRasInfo;
+    sdo->Release    = ImageSD_Release;
+    sdo->Setup        = NULL;
+    sdo->Dispose    = ImageSD_dispose;
+        
+    pthread_mutex_unlock(&isdo->lock);
+    
+//PrintImageInfo(isdo);
+}
+
+JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_initCustomRaster(JNIEnv* env, jobject bisd, jobject array, jint width, jint height,
+                                                                                    jobject jGraphicsState, jobject jGraphicsStateObject, jobject jImageInfo)
+{
+PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_initCustomRaster")
+    jint offset = 0;
+    jint pixelStride = 4;
+    jint scanStride = pixelStride*width;
+    jobject icm = NULL;
+    jint type = java_awt_image_BufferedImage_TYPE_CUSTOM;
+    
+    Java_sun_java2d_OSXOffScreenSurfaceData_initRaster(env, bisd, array, offset, width, height, pixelStride, scanStride, icm, type, jGraphicsState, jGraphicsStateObject, jImageInfo);
+}
+
+JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_syncToJavaPixels(JNIEnv *env, jobject bisd)
+{
+PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_syncToJavaPixels")
+    
+    syncToJavaPixels(env, (ImageSDOps*)SurfaceData_GetOps(env, bisd));
+}
+
+JNIEXPORT jboolean JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_xorSurfacePixels
+  (JNIEnv *env, jobject dstIsd, jobject srcIsd, jint colorXOR, jint x, jint y, jint w, jint h)
+{
+PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_xorSurfacePixels")
+    return xorSurfacePixels(env, dstIsd, srcIsd, colorXOR, x, y, w, h);
+}
+
+JNIEXPORT jboolean JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_clearSurfacePixels
+  (JNIEnv *env, jobject bisd, jint w, jint h)
+{
+PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_clearSurfacePixels")        
+    return clearSurfacePixels(env, bisd, w, h);
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/PrintModel.h	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+#import <Foundation/Foundation.h>
+#import <jni.h>
+
+@class NSPrintInfo;
+@class NSView;
+
+@interface PrintModel : NSObject {
+    NSPrintInfo* fPrintInfo;
+}
+
+- (id)initWithPrintInfo:(NSPrintInfo*)printInfo;
+- (BOOL)runPageSetup;
+- (BOOL)runJobSetup;
+- (BOOL)runPrintLoopWithView:(NSView*)printerView waitUntilDone:(BOOL)wait withEnv:(JNIEnv *)env;
+- (BOOL)safePrintLoop:(id)arg withEnv:(JNIEnv *)env;
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/PrintModel.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+#import "PrintModel.h"
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "PrinterView.h"
+#import "ThreadUtilities.h"
+
+@implementation PrintModel
+
+- (id)initWithPrintInfo:(NSPrintInfo*)printInfo {
+    self = [super init];
+    if (self) {
+        fPrintInfo = [printInfo retain];
+    }
+    
+    return self;
+}
+
+- (void)dealloc {
+    [fPrintInfo release];
+    fPrintInfo = nil;
+    
+    [super dealloc];
+}
+//- (void)finalize { [super finalize]; }
+
+- (BOOL)runPageSetup {
+    __block BOOL fResult = NO;
+        
+    [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
+        NSPageLayout* pageLayout = [NSPageLayout pageLayout];
+        fResult = ([pageLayout runModalWithPrintInfo:fPrintInfo] == NSOKButton);
+    }];
+    
+    return fResult;
+}
+
+- (BOOL)runJobSetup {
+    __block BOOL fResult = NO;
+    
+    [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
+        NSPrintPanel* printPanel = [NSPrintPanel printPanel];
+        fResult = ([printPanel runModalWithPrintInfo:fPrintInfo] == NSOKButton);
+    }];
+    
+    return fResult;
+}
+
+- (BOOL)runPrintLoopWithView:(NSView*)printerView waitUntilDone:(BOOL)wait withEnv:(JNIEnv *)env
+{
+AWT_ASSERT_NOT_APPKIT_THREAD;
+
+    BOOL fResult = NO;
+
+    // <rdar://problem/4310184> Because people like to put up modal dialogs during print operations, 
+    // we have to run the print operation on a non-AppKit thread or else we get a deadlock and errors
+    // the AppKit team believes it's OK for us to call runOperation from non-AppKit threads, 
+    // as long as we don't show any panels, and we don't touch the NSPrintInfo or the NSView from other threads.
+    if (wait) {
+        fResult = [self safePrintLoop:printerView withEnv:env];
+    } else {
+        // Retain these so they don't go away while we're in Java
+        CFRetain(self); // GC
+        if (printerView) CFRetain(printerView); // GC
+        
+        static JNF_CLASS_CACHE(jc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
+        static JNF_STATIC_MEMBER_CACHE(jm_detachPrintLoop, jc_CPrinterJob, "detachPrintLoop", "(JJ)V");
+        JNFCallStaticVoidMethod(env, jm_detachPrintLoop, ptr_to_jlong(self), ptr_to_jlong(printerView)); // AWT_THREADING Safe (known object)
+    }
+    
+    return fResult;
+}
+
+- (BOOL) safePrintLoop:(id)arg withEnv:(JNIEnv *)env
+{
+AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    PrinterView* printerView = (PrinterView*)arg;
+    BOOL fResult;
+    @try {
+        NSPrintOperation* printLoop = [NSPrintOperation printOperationWithView:printerView printInfo:fPrintInfo];
+        [printLoop setShowPanels:NO];    //+++gdb Problem: This will avoid progress bars...
+        //[printLoop setCanSpawnSeparateThread:YES]; //+++gdb Need to check this...
+        
+        fResult = [printLoop runOperation];
+    } @finally {
+        // Tell CPrinterJob that things are done.
+        [printerView complete:env];
+    }
+    return fResult;
+}
+
+@end
+
+/*
+ * Class:     sun_lwawt_macosx_CPrinterJob
+ * Method:    _safePrintLoop
+ * Signature: (JJ)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob__1safePrintLoop
+(JNIEnv *env, jclass clz, jlong target, jlong view)
+{
+JNF_COCOA_ENTER(env);
+      
+    PrintModel *model = (PrintModel *)jlong_to_ptr(target);
+    PrinterView *arg = (PrinterView *)jlong_to_ptr(view);
+    
+    [model safePrintLoop:arg withEnv:env];
+    
+    // These are to match the retains in runPrintLoopWithView:
+    if (model) CFRelease(model); // GC
+    if (arg) CFRelease(arg); // GC
+   
+JNF_COCOA_EXIT(env);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/PrinterSurfaceData.h	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "QuartzSurfaceData.h"
+
+struct _PrintSDOps
+{
+    QuartzSDOps                qsdo; // must be the first entry!
+    
+    NSGraphicsContext        *nsRef;
+    
+    jint                    width;
+    jint                    height;
+};
+typedef struct _PrintSDOps PrintSDOps;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/PrinterSurfaceData.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+#import "PrinterSurfaceData.h"
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+
+//#define DEBUG 1
+#if defined DEBUG
+    #define PRINT(msg) {fprintf(stderr, "%s\n", msg);}
+#else
+    #define PRINT(msg) {}
+#endif
+
+static LockFunc PrintSD_Lock;
+static UnlockFunc PrintSD_Unlock;
+static GetRasInfoFunc PrintSD_GetRasInfo;
+static ReleaseFunc PrintSD_ReleaseRasInfo;
+static void flush(JNIEnv *env, QuartzSDOps *qsdo);
+
+static void PrintSD_startCGContext(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType)
+{
+PRINT(" PrintSD_startCGContext")
+    
+    if (qsdo->cgRef != NULL)
+    {
+        flush(env, qsdo);
+        
+        SetUpCGContext(env, qsdo, renderType);
+    }
+}
+
+static void PrintSD_finishCGContext(JNIEnv *env, QuartzSDOps *qsdo)
+{
+PRINT("    PrintSD_finishCGContext")
+    
+    if (qsdo->cgRef != NULL)    
+    {
+        CompleteCGContext(env, qsdo); 
+    }
+}
+
+static void PrintSD_dispose(JNIEnv *env, SurfaceDataOps *sdo)
+{
+PRINT(" PrintSD_dispose")
+    QuartzSDOps *qsdo = (QuartzSDOps *)sdo;
+    
+    (*env)->DeleteGlobalRef(env, qsdo->javaGraphicsStatesObjects);
+    
+    if (qsdo->graphicsStateInfo.batchedLines != NULL)
+    {
+        free(qsdo->graphicsStateInfo.batchedLines);
+        qsdo->graphicsStateInfo.batchedLines = NULL;
+    }
+    
+    qsdo->BeginSurface            = NULL;
+    qsdo->FinishSurface            = NULL;
+}
+
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterSurfaceData_initOps(JNIEnv *env, jobject jthis, jlong nsRef, jobject jGraphicsState, jobjectArray jGraphicsStateObject, jint width, jint height)
+{
+JNF_COCOA_ENTER(env);
+    
+PRINT("Java_sun_lwawt_macosx_CPrinterSurfaceData_initOps")
+    
+    PrintSDOps *psdo = (PrintSDOps*)SurfaceData_InitOps(env, jthis, sizeof(PrintSDOps));
+    psdo->nsRef            = (NSGraphicsContext*)jlong_to_ptr(nsRef);
+    psdo->width            = width;
+    psdo->height        = height;
+    
+    QuartzSDOps *qsdo = (QuartzSDOps*)psdo;
+    qsdo->BeginSurface            = PrintSD_startCGContext;
+    qsdo->FinishSurface            = PrintSD_finishCGContext;
+    qsdo->cgRef                    = [psdo->nsRef graphicsPort];
+    
+    qsdo->javaGraphicsStates            = (jint*)((*env)->GetDirectBufferAddress(env, jGraphicsState));
+    qsdo->javaGraphicsStatesObjects        = (*env)->NewGlobalRef(env, jGraphicsStateObject);
+    
+    qsdo->graphicsStateInfo.batchedLines        = NULL;
+    qsdo->graphicsStateInfo.batchedLinesCount    = 0;
+    
+    SurfaceDataOps *sdo = (SurfaceDataOps*)qsdo;
+    sdo->Lock        = PrintSD_Lock;
+    sdo->Unlock        = PrintSD_Unlock;
+    sdo->GetRasInfo    = PrintSD_GetRasInfo;
+    sdo->Release    = PrintSD_ReleaseRasInfo;
+    sdo->Setup        = NULL;
+    sdo->Dispose    = PrintSD_dispose;
+    
+JNF_COCOA_EXIT(env);
+}
+
+static jint PrintSD_Lock(JNIEnv *env, SurfaceDataOps *sdo, SurfaceDataRasInfo *pRasInfo, jint lockflags)
+{
+PRINT(" PrintSD_Lock")
+    jint status = SD_FAILURE;
+    
+    //QuartzSDOps *qsdo = (QuartzSDOps*)sdo;
+    //PrintSD_startCGContext(env, qsdo, SD_Image);
+    
+    status = SD_SUCCESS;
+    
+    return status;
+}
+static void PrintSD_Unlock(JNIEnv *env, SurfaceDataOps *sdo, SurfaceDataRasInfo *pRasInfo)
+{
+PRINT(" PrintSD_Unlock")    
+        
+    //QuartzSDOps *qsdo = (QuartzSDOps*)sdo;
+    //PrintSD_finishCGContext(env, qsdo);
+}
+static void PrintSD_GetRasInfo(JNIEnv *env, SurfaceDataOps *sdo, SurfaceDataRasInfo *pRasInfo)
+{
+PRINT(" PrintSD_GetRasInfo")    
+    PrintSDOps *psdo = (PrintSDOps*)sdo;
+    
+    pRasInfo->pixelStride = 4; // ARGB
+    pRasInfo->scanStride = psdo->width * pRasInfo->pixelStride;
+
+    pRasInfo->rasBase = NULL; //psdo->dataForSun2D;
+}
+static void PrintSD_ReleaseRasInfo(JNIEnv *env, SurfaceDataOps *sdo, SurfaceDataRasInfo *pRasInfo)
+{
+PRINT(" PrintSD_ReleaseRasInfo")
+        
+    pRasInfo->pixelStride = 0;
+    pRasInfo->scanStride = 0;
+    pRasInfo->rasBase = NULL;
+}
+
+static void dataProvider_FreeSun2DPixels(void *info, const void *data, size_t size)
+{
+PRINT("dataProvider_FreeSun2DPixels")
+   // CGBitmapFreeData(info);
+    free(info);
+}
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterSurfaceData__1flush
+  (JNIEnv *env, jobject jsurfacedata)
+{
+    flush(env, (QuartzSDOps*)SurfaceData_GetOps(env, jsurfacedata));
+}
+static void flush(JNIEnv *env, QuartzSDOps *qsdo)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/PrinterView.h	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <jni.h>
+
+@interface PrinterView : NSView {
+    jobject fPrinterJob; // CPrinterJob
+    jobject fCurPageFormat;
+    jobject fCurPainter;
+    jobject fCurPeekGraphics;
+    
+    jint fFirstPage, fLastPage;
+}
+
+- (id)initWithFrame:(NSRect)aRect withEnv:(JNIEnv*)env withPrinterJob:(jobject)printerJob;
+
+- (void)setFirstPage:(jint)firstPage lastPage:(jint)lastPage;
+
+- (void)releaseReferences:(JNIEnv*)env;
+
+- (void)drawRect:(NSRect)aRect;
+
+- (NSString*)printJobTitle;
+- (BOOL)knowsPageRange:(NSRangePointer)aRange;
+- (NSRect)rectForPage:(NSInteger)pageNumber;
+
+- (BOOL)cancelCheck:(JNIEnv*)env;
+
+- (void)complete:(JNIEnv*)env;
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/PrinterView.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "PrinterView.h"
+
+#import "java_awt_print_Pageable.h"
+#import "java_awt_print_Printable.h"
+
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "ThreadUtilities.h"
+#import "GeomUtilities.h"
+
+
+static JNF_CLASS_CACHE(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
+
+@implementation PrinterView
+
+- (id)initWithFrame:(NSRect)aRect withEnv:(JNIEnv*)env withPrinterJob:(jobject)printerJob
+{
+    self = [super initWithFrame:aRect];
+    if (self)
+    {
+        fPrinterJob = JNFNewGlobalRef(env, printerJob);
+        fCurPageFormat = NULL;
+        fCurPainter = NULL;
+        fCurPeekGraphics = NULL;
+    }
+    return self;
+}
+
+- (void)releaseReferences:(JNIEnv*)env
+{
+    if (fCurPageFormat != NULL)
+    {
+        JNFDeleteGlobalRef(env, fCurPageFormat);
+        fCurPageFormat = NULL;
+    }
+    if (fCurPainter != NULL)
+    {
+        JNFDeleteGlobalRef(env, fCurPainter);
+        fCurPainter = NULL;
+    }
+    if (fCurPeekGraphics != NULL)
+    {
+        JNFDeleteGlobalRef(env, fCurPeekGraphics);
+        fCurPeekGraphics = NULL;
+    }
+}
+
+- (void)setFirstPage:(jint)firstPage lastPage:(jint)lastPage {
+    fFirstPage = firstPage;
+    fLastPage = lastPage;
+}
+
+- (void)drawRect:(NSRect)aRect
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_MEMBER_CACHE(jm_printToPathGraphics, sjc_CPrinterJob, "printToPathGraphics", "(Lsun/print/PeekGraphics;Ljava/awt/print/PrinterJob;Ljava/awt/print/Printable;Ljava/awt/print/PageFormat;IJ)V");
+
+    // Create and draw into a new CPrinterGraphics with the current Context.
+    assert(fCurPageFormat != NULL);
+    assert(fCurPainter != NULL);
+    assert(fCurPeekGraphics != NULL);
+
+    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
+
+    if ([self cancelCheck:env])
+    {
+        [self releaseReferences:env];
+        return;
+    }
+
+    NSPrintOperation* printLoop = [NSPrintOperation currentOperation];
+    jint jPageIndex = [printLoop currentPage] - 1;
+    
+    jlong context = ptr_to_jlong([printLoop context]);
+    CGContextRef cgRef = (CGContextRef)[[printLoop context] graphicsPort];
+    CGContextSaveGState(cgRef); //04/28/2004: state needs to be saved here due to addition of lazy state management
+    
+    JNFCallVoidMethod(env, fPrinterJob, jm_printToPathGraphics, fCurPeekGraphics, fPrinterJob, fCurPainter, fCurPageFormat, jPageIndex, context); // AWT_THREADING Safe (AWTRunLoop)
+    
+    CGContextRestoreGState(cgRef);
+    
+    [self releaseReferences:env];
+}
+
+- (NSString*)printJobTitle
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_MEMBER_CACHE(jm_getJobName, sjc_CPrinterJob, "getJobName", "()Ljava/lang/String;");
+    
+    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
+    
+    jobject o = JNFCallObjectMethod(env, fPrinterJob, jm_getJobName); // AWT_THREADING Safe (known object)
+    id result = JNFJavaToNSString(env, o);
+    (*env)->DeleteLocalRef(env, o);
+    return result;
+}
+
+- (BOOL)knowsPageRange:(NSRangePointer)aRange
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+
+    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
+    if ([self cancelCheck:env])
+    {
+        return NO;
+    }
+
+    aRange->location = fFirstPage + 1;
+
+    if (fLastPage == java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES)
+    {
+        aRange->length = NSIntegerMax;
+    }
+    else
+    {
+        aRange->length = (fLastPage + 1) - fFirstPage;
+    }
+
+    return YES;
+}
+
+- (NSRect)rectForPage:(NSInteger)pageNumber
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+
+    static JNF_MEMBER_CACHE(jm_getPageformatPrintablePeekgraphics, sjc_CPrinterJob, "getPageformatPrintablePeekgraphics", "(I)[Ljava/lang/Object;");
+    static JNF_MEMBER_CACHE(jm_printAndGetPageFormatArea, sjc_CPrinterJob, "printAndGetPageFormatArea", "(Ljava/awt/print/Printable;Ljava/awt/Graphics;Ljava/awt/print/PageFormat;I)Ljava/awt/geom/Rectangle2D;");
+
+    // Assertions removed, and corresponding JNFDeleteGlobalRefs added, for radr://3962543 
+    // Actual fix that will keep these assertions from being true is radr://3205462 ,
+    // which will hopefully be fixed by the blocking AppKit bug radr://3056694
+    //assert(fCurPageFormat == NULL);     
+    //assert(fCurPainter == NULL);
+    //assert(fCurPeekGraphics == NULL);
+
+    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
+    if(fCurPageFormat != NULL) {
+        JNFDeleteGlobalRef(env, fCurPageFormat);
+    }
+    if(fCurPainter != NULL) {
+        JNFDeleteGlobalRef(env, fCurPainter);
+    }
+    if(fCurPeekGraphics != NULL) {
+        JNFDeleteGlobalRef(env, fCurPeekGraphics);
+    }
+
+    //+++gdb Check the pageNumber for validity (PageAttrs)
+
+    jint jPageNumber = pageNumber - 1;
+    
+    NSRect result;
+    
+    if ([self cancelCheck:env])
+    {
+        return NSZeroRect;
+    }
+    
+    jobjectArray objectArray = JNFCallObjectMethod(env, fPrinterJob, jm_getPageformatPrintablePeekgraphics, jPageNumber); // AWT_THREADING Safe (AWTRunLoopMode)
+    if (objectArray != NULL) {
+        // Get references to the return objects -> PageFormat, Printable, PeekGraphics
+        // Cheat - we know we either got NULL or a 3 element array
+        jobject pageFormat = (*env)->GetObjectArrayElement(env, objectArray, 0);
+        fCurPageFormat = JNFNewGlobalRef(env, pageFormat);
+        (*env)->DeleteLocalRef(env, pageFormat);
+        
+        jobject painter = (*env)->GetObjectArrayElement(env, objectArray, 1);
+        fCurPainter = JNFNewGlobalRef(env, painter);
+        (*env)->DeleteLocalRef(env, painter);
+        
+        jobject peekGraphics = (*env)->GetObjectArrayElement(env, objectArray, 2);
+        fCurPeekGraphics = JNFNewGlobalRef(env, peekGraphics);
+        (*env)->DeleteLocalRef(env, peekGraphics);
+        
+        // Actually print and get the PageFormatArea
+        jobject pageFormatArea = JNFCallObjectMethod(env, fPrinterJob, jm_printAndGetPageFormatArea, fCurPainter, fCurPeekGraphics, fCurPageFormat, jPageNumber); // AWT_THREADING Safe (AWTRunLoopMode)
+        if (pageFormatArea != NULL) {
+            result = JavaToNSRect(env, pageFormatArea);
+            (*env)->DeleteLocalRef(env, pageFormatArea);
+        } else {
+            [self releaseReferences:env];
+            result = NSZeroRect;
+        }
+        
+        (*env)->DeleteLocalRef(env, objectArray);
+    } else {
+        [self releaseReferences:env];
+        result = NSZeroRect;
+    }
+    
+    return result;
+}
+
+- (BOOL)cancelCheck:(JNIEnv*)env
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+
+    static JNF_MEMBER_CACHE(jm_cancelCheck, sjc_CPrinterJob, "cancelCheck", "()Z");
+    
+    return JNFCallBooleanMethod(env, fPrinterJob, jm_cancelCheck); // AWT_THREADING Safe (known object)
+}
+
+// This is called by -[PrintModel safePrintLoop]
+- (void)complete:(JNIEnv*)env
+{
+    AWT_ASSERT_NOT_APPKIT_THREAD;
+    
+    static JNF_MEMBER_CACHE(jf_completePrintLoop, sjc_CPrinterJob, "completePrintLoop", "()V");
+    JNFCallVoidMethod(env, fPrinterJob, jf_completePrintLoop);
+
+    // Clean up after ourselves
+    // Can't put these into -dealloc since that happens (potentially) after the JNIEnv is stale
+    [self releaseReferences:env];
+    if (fPrinterJob != NULL)
+    {
+        JNFDeleteGlobalRef(env, fPrinterJob);
+        fPrinterJob = NULL;
+    }
+}
+
+- (BOOL)isFlipped
+{
+    return TRUE;
+}
+
+@end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/macosx/native/sun/awt/QuartzRenderer.m	Fri Sep 23 13:42:06 2011 -0700
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#import "java_awt_image_BufferedImage.h"
+#import "java_awt_geom_PathIterator.h"
+#import "sun_java2d_OSXSurfaceData.h"
+
+#import <stdio.h>
+#import <JavaNativeFoundation/JavaNativeFoundation.h>
+
+#import "ImageSurfaceData.h"
+
+
+//#define DEBUG 1
+#if defined DEBUG
+    #define QUARTZ_RENDERER_INLINE
+    #define PRINT(msg) {fprintf(stderr, "%s\n", msg);fflush(stderr);}
+#else
+    #define QUARTZ_RENDERER_INLINE static inline
+    #define PRINT(msg) {}
+#endif
+
+// Copied the following from Math.java
+#define PI 3.14159265358979323846f
+
+#define BATCHED_POINTS_SIZE 1024
+
+// same value as defined in Sun's own code
+#define XOR_ALPHA_CUTOFF 128
+
+// private Quartz routines needed here
+CG_EXTERN void CGContextSetCTM(CGContextRef ref, CGAffineTransform tx);
+
+
+static CGFloat gRoundRectCtrlpts[10][12] =
+{
+    {0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    {0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.0f, 0.0f},
+    {1.0f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    {1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, -0.5f},
+    {1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    {1.0f, 0.0f, 0.0f, 0.0f,  1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -0.5f, 0.0f, 0.0f},
+    {0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f},
+    {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+};
+
+CG_EXTERN CGRect CGRectApplyAffineTransform(CGRect rect, CGAffineTransform t);
+
+
+CGRect sanitizedRect(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2) {
+    CGFloat temp;
+    if (x1 > x2) {
+        temp = x2;
+        x2 = x1;
+        x1 = temp;
+    }
+    if (y1 > y2) {
+        temp = y2;
+        y2 = y1;
+        y1 = temp;
+    }
+    return CGRectMake(x1, y1, x2-x1, y2-y1);
+}
+
+QUARTZ_RENDERER_INLINE SDRenderType doLineUsingCG(CGContextRef cgRef, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, BOOL simple, CGFloat offsetX, CGFloat offsetY)
+{
+//fprintf(stderr, "doLine start=(%f, %f), end=(%f, %f), linewidth:%f, offsetX:%f, offsetY:%f\n", x1, y1, x2, y2, CGContextGetLineWidth(cgRef), offsetX, offsetY);
+    SDRenderType renderType = SD_Nothing;
+            
+    if (simple == YES)
+    {
+        struct CGPoint oneLinePoints[2];
+        
+        oneLinePoints[0] = CGPointMake(x1+offsetX, y1+offsetY);
+        oneLinePoints[1] = CGPointMake(x2+offsetX, y2+offsetY);
+        
+        CGContextStrokeLineSegments(cgRef, oneLinePoints, 2);
+        renderType = SD_Nothing;
+    }
+    else
+    {
+        CGContextMoveToPoint(cgRef, x1+offsetX, y1+offsetY);
+        CGContextAddLineToPoint(cgRef, x2+offsetX, y2+offsetY);
+        renderType = SD_Stroke;
+    }
+    
+    return renderType;
+}
+QUARTZ_RENDERER_INLINE SDRenderType doLine(QuartzSDOps *qsdo, CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2)
+{    
+PRINT(" doLine")
+    if (YES)
+    {
+        return doLineUsingCG(qsdo->cgRef, x1, y1, x2, y2,
+                                qsdo->graphicsStateInfo.simpleStroke, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY);
+    }
+    // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.)
+}
+
+
+QUARTZ_RENDERER_INLINE SDRenderType doRectUsingCG(CGContextRef cgRef, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill, BOOL simple, CGFloat offsetX, CGFloat offsetY)
+{    
+//fprintf(stderr, "doRect point=(%f, %f), size=(%f, %f), offsets=(%f, %f) fill=%d simple=%d\n", x, y, w, h, offsetX, offsetY, fill, simple);
+//CGRect clip = CGContextGetClipBoundingBox(cgRef);
+//fprintf(stderr, "    clip: ((%f, %f), (%f, %f))\n", clip.origin.x, clip.origin.y, clip.size.width, clip.size.height);
+//CGAffineTransform ctm = CGContextGetCTM(cgRef);
+//fprintf(stderr, "    ctm: (%f, %f, %f, %f, %f, %f)\n", ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty);
+    SDRenderType renderType = SD_Nothing;
+        
+    if (fill == YES)
+    {
+        if (simple == YES)
+        {
+            CGContextFillRect(cgRef, CGRectMake(x, y, w, h));
+            renderType = SD_Nothing;
+        }
+        else
+        {
+            CGContextAddRect(cgRef, CGRectMake(x, y, w, h));
+            renderType = SD_Fill;
+        }
+    }
+    else
+    {
+        if (simple == YES)
+        {
+            CGContextStrokeRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h));
+            renderType = SD_Nothing;
+        }
+        else
+        {
+            CGContextAddRect(cgRef, CGRectMake(x+offsetX, y+offsetY, w, h));
+            renderType = SD_Stroke;
+        }
+    }
+    
+    return renderType;
+}
+QUARTZ_RENDERER_INLINE SDRenderType doRect(QuartzSDOps *qsdo, CGFloat x, CGFloat y, CGFloat w, CGFloat h, BOOL fill)
+{    
+PRINT(" doRect")
+    if (YES)
+    {
+        return doRectUsingCG(qsdo->cgRef, x, y, w, h, fill,
+                                qsdo->graphicsStateInfo.simpleStroke, qsdo->graphicsStateInfo.offsetX, qsdo->graphicsStateInfo.offsetY);
+    }
+    // here we can add other implementations (ex. using QuickDraw, OpenGL, etc.)
+}
+
+// from RoundRectIterator.java
+QUARTZ_RENDERER_INLINE SDRenderType doRoundRectUsingCG(CGContextRef cgRef, CGFloat x, CGFloat y, CGFloat w, CGFloat h, CGFloat arcWidth, CGFloat arcHeight, BOOL fill, CGFloat offsetX, CGFloat offsetY)
+{
+    SDRenderType renderType = SD_Nothing;
+    
+    if (fill == YES)
+    {
+        renderType = SD_Fill;
+    }
+    else
+    {
+        renderType = SD_Stroke;
+    }
+    
+    // radr://3593731 RoundRects with corner width/height of 0 don't draw
+    arcWidth = (arcWidth > 0.0f) ? arcWidth : 0.0f;
+    arcHeight = (arcHeight > 0.0f) ? arcHeight : 0.0f;
+    
+    CGFloat aw = (w < arcWidth) ? w : arcWidth;
+    CGFloat ah = (h < arcHeight) ? h : arcHeight;
+    
+    CGFloat *ctrls, p1, q1, p2, q2, p3, q3;
+    ctrls = gRoundRectCtrlpts[0];
+    p1 = (x + ctrls[0] * w + ctrls[1] * aw);
+    q1 = (y + ctrls[2] * h + ctrls[3] * ah);
+    CGContextMoveToPoint(cgRef, p1+offsetX, q1+offsetY);
+    
+    ctrls = gRoundRectCtrlpts[1];
+    p1 = (x + ctrls[0] * w + ctrls[1] * aw);
+    q1 = (y + ctrls[2] * h + ctrls[3] * ah);
+    CGContextAddLineToPoint(cgRef, p1+offsetX, q1+offsetY);
+    
+    ctrls = gRoundRectCtrlp