jdk/src/macosx/native/sun/awt/CPrinterJob.m
changeset 12047 320a714614e9
child 15639 0ff6be5c9730
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/macosx/native/sun/awt/CPrinterJob.m	Tue Mar 06 20:34:38 2012 +0000
@@ -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;
+}