1 /*
   2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 #import "java_awt_print_PageFormat.h"
  28 #import "java_awt_print_Pageable.h"
  29 #import "sun_lwawt_macosx_CPrinterJob.h"
  30 #import "sun_lwawt_macosx_CPrinterPageDialog.h"
  31 
  32 #import <Cocoa/Cocoa.h>
  33 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  34 
  35 #import "PrinterView.h"
  36 #import "PrintModel.h"
  37 #import "ThreadUtilities.h"
  38 #import "GeomUtilities.h"
  39 
  40 static JNF_CLASS_CACHE(sjc_Paper, "java/awt/print/Paper");
  41 static JNF_CLASS_CACHE(sjc_PageFormat, "java/awt/print/PageFormat");
  42 static JNF_CLASS_CACHE(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
  43 static JNF_CLASS_CACHE(sjc_CPrinterDialog, "sun/lwawt/macosx/CPrinterDialog");
  44 static JNF_MEMBER_CACHE(sjm_getNSPrintInfo, sjc_CPrinterJob, "getNSPrintInfo", "()J");
  45 static JNF_MEMBER_CACHE(sjm_printerJob, sjc_CPrinterDialog, "fPrinterJob", "Lsun/lwawt/macosx/CPrinterJob;");
  46 
  47 static NSPrintInfo* createDefaultNSPrintInfo();
  48 
  49 static void makeBestFit(NSPrintInfo* src);
  50 
  51 static void nsPrintInfoToJavaPaper(JNIEnv* env, NSPrintInfo* src, jobject dst);
  52 static void javaPaperToNSPrintInfo(JNIEnv* env, jobject src, NSPrintInfo* dst);
  53 
  54 static void nsPrintInfoToJavaPageFormat(JNIEnv* env, NSPrintInfo* src, jobject dst);
  55 static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageFormat, NSPrintInfo* dst);
  56 
  57 static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable);
  58 static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst);
  59 
  60 
  61 static NSPrintInfo* createDefaultNSPrintInfo(JNIEnv* env, jstring printer)
  62 {
  63     NSPrintInfo* defaultPrintInfo = [[NSPrintInfo sharedPrintInfo] copy];
  64     if (printer != NULL)
  65     {
  66         NSPrinter* nsPrinter = [NSPrinter printerWithName:JNFJavaToNSString(env, printer)];
  67         if (nsPrinter != nil)
  68         {
  69             [defaultPrintInfo setPrinter:nsPrinter];
  70         }
  71     }
  72     [defaultPrintInfo setUpPrintOperationDefaultValues];
  73 
  74     // cmc 05/18/04 radr://3160443 : setUpPrintOperationDefaultValues sets the
  75     // page margins to 72, 72, 90, 90 - need to use [NSPrintInfo imageablePageBounds]
  76     // to get values from the printer.
  77     // NOTE: currently [NSPrintInfo imageablePageBounds] does not update itself when
  78     // the user selects a different printer - see radr://3657453. However, rather than
  79     // directly querying the PPD here, we'll let AppKit printing do the work. The AppKit
  80     // printing bug above is set to be fixed for Tiger.
  81     NSRect imageableRect = [defaultPrintInfo imageablePageBounds];
  82     [defaultPrintInfo setLeftMargin: imageableRect.origin.x];
  83     [defaultPrintInfo setBottomMargin: imageableRect.origin.y]; //top and bottom are flipped because [NSPrintInfo imageablePageBounds] returns a flipped NSRect (bottom-left to top-right).
  84     [defaultPrintInfo setRightMargin: [defaultPrintInfo paperSize].width-imageableRect.origin.x-imageableRect.size.width];
  85     [defaultPrintInfo setTopMargin: [defaultPrintInfo paperSize].height-imageableRect.origin.y-imageableRect.size.height];
  86 
  87     return defaultPrintInfo;
  88 }
  89 
  90 static void makeBestFit(NSPrintInfo* src)
  91 {
  92     // This will look at the NSPrintInfo's margins. If they are out of bounds to the
  93     // imageable area of the page, it will set them to the largest possible size.
  94 
  95     NSRect imageable = [src imageablePageBounds];
  96 
  97     NSSize paperSize = [src paperSize];
  98 
  99     CGFloat fullLeftM = imageable.origin.x;
 100     CGFloat fullRightM = paperSize.width - (imageable.origin.x + imageable.size.width);
 101 
 102     // These are flipped because [NSPrintInfo imageablePageBounds] returns a flipped
 103     //  NSRect (bottom-left to top-right).
 104     CGFloat fullTopM = paperSize.height - (imageable.origin.y + imageable.size.height);
 105     CGFloat fullBottomM = imageable.origin.y;
 106 
 107     if (fullLeftM > [src leftMargin])
 108     {
 109         [src setLeftMargin:fullLeftM];
 110     }
 111 
 112     if (fullRightM > [src rightMargin])
 113     {
 114         [src setRightMargin:fullRightM];
 115     }
 116 
 117     if (fullTopM > [src topMargin])
 118     {
 119         [src setTopMargin:fullTopM];
 120     }
 121 
 122     if (fullBottomM > [src bottomMargin])
 123     {
 124         [src setBottomMargin:fullBottomM];
 125     }
 126 }
 127 
 128 // In AppKit Printing, the rectangle is always oriented. In AppKit Printing, setting
 129 //  the rectangle will always set the orientation.
 130 // In java printing, the rectangle is oriented if accessed from PageFormat. It is
 131 //  not oriented when accessed from Paper.
 132 
 133 static void nsPrintInfoToJavaPaper(JNIEnv* env, NSPrintInfo* src, jobject dst)
 134 {
 135     static JNF_MEMBER_CACHE(jm_setSize, sjc_Paper, "setSize", "(DD)V");
 136     static JNF_MEMBER_CACHE(jm_setImageableArea, sjc_Paper, "setImageableArea", "(DDDD)V");
 137 
 138     jdouble jPaperW, jPaperH;
 139 
 140     // NSPrintInfo paperSize is oriented. java Paper is not oriented. Take
 141     //  the -[NSPrintInfo orientation] into account when setting the Paper
 142     //  rectangle.
 143 
 144     NSSize paperSize = [src paperSize];
 145     switch ([src orientation]) {
 146         case NSPortraitOrientation:
 147             jPaperW = paperSize.width;
 148             jPaperH = paperSize.height;
 149             break;
 150 
 151         case NSLandscapeOrientation:
 152             jPaperW = paperSize.height;
 153             jPaperH = paperSize.width;
 154             break;
 155 
 156         default:
 157             jPaperW = paperSize.width;
 158             jPaperH = paperSize.height;
 159             break;
 160     }
 161 
 162     JNFCallVoidMethod(env, dst, jm_setSize, jPaperW, jPaperH); // AWT_THREADING Safe (known object - always actual Paper)
 163 
 164     // Set the imageable area from the margins
 165     CGFloat leftM = [src leftMargin];
 166     CGFloat rightM = [src rightMargin];
 167     CGFloat topM = [src topMargin];
 168     CGFloat bottomM = [src bottomMargin];
 169 
 170     jdouble jImageX = leftM;
 171     jdouble jImageY = topM;
 172     jdouble jImageW = jPaperW - (leftM + rightM);
 173     jdouble jImageH = jPaperH - (topM + bottomM);
 174 
 175     JNFCallVoidMethod(env, dst, jm_setImageableArea, jImageX, jImageY, jImageW, jImageH); // AWT_THREADING Safe (known object - always actual Paper)
 176 }
 177 
 178 static void javaPaperToNSPrintInfo(JNIEnv* env, jobject src, NSPrintInfo* dst)
 179 {
 180     AWT_ASSERT_NOT_APPKIT_THREAD;
 181 
 182     static JNF_MEMBER_CACHE(jm_getWidth, sjc_Paper, "getWidth", "()D");
 183     static JNF_MEMBER_CACHE(jm_getHeight, sjc_Paper, "getHeight", "()D");
 184     static JNF_MEMBER_CACHE(jm_getImageableX, sjc_Paper, "getImageableX", "()D");
 185     static JNF_MEMBER_CACHE(jm_getImageableY, sjc_Paper, "getImageableY", "()D");
 186     static JNF_MEMBER_CACHE(jm_getImageableW, sjc_Paper, "getImageableWidth", "()D");
 187     static JNF_MEMBER_CACHE(jm_getImageableH, sjc_Paper, "getImageableHeight", "()D");
 188 
 189     // java Paper is always Portrait oriented. Set NSPrintInfo with this
 190     //  rectangle, and it's orientation may change. If necessary, be sure to call
 191     //  -[NSPrintInfo setOrientation] after this call, which will then
 192     //  adjust the -[NSPrintInfo paperSize] as well.
 193 
 194     jdouble jPhysicalWidth = JNFCallDoubleMethod(env, src, jm_getWidth); // AWT_THREADING Safe (!appKit)
 195     jdouble jPhysicalHeight = JNFCallDoubleMethod(env, src, jm_getHeight); // AWT_THREADING Safe (!appKit)
 196 
 197     [dst setPaperSize:NSMakeSize(jPhysicalWidth, jPhysicalHeight)];
 198 
 199     // Set the margins from the imageable area
 200     jdouble jImageX = JNFCallDoubleMethod(env, src, jm_getImageableX); // AWT_THREADING Safe (!appKit)
 201     jdouble jImageY = JNFCallDoubleMethod(env, src, jm_getImageableY); // AWT_THREADING Safe (!appKit)
 202     jdouble jImageW = JNFCallDoubleMethod(env, src, jm_getImageableW); // AWT_THREADING Safe (!appKit)
 203     jdouble jImageH = JNFCallDoubleMethod(env, src, jm_getImageableH); // AWT_THREADING Safe (!appKit)
 204 
 205     [dst setLeftMargin:(CGFloat)jImageX];
 206     [dst setTopMargin:(CGFloat)jImageY];
 207     [dst setRightMargin:(CGFloat)(jPhysicalWidth - jImageW - jImageX)];
 208     [dst setBottomMargin:(CGFloat)(jPhysicalHeight - jImageH - jImageY)];
 209 }
 210 
 211 static void nsPrintInfoToJavaPageFormat(JNIEnv* env, NSPrintInfo* src, jobject dst)
 212 {
 213     AWT_ASSERT_NOT_APPKIT_THREAD;
 214 
 215     static JNF_MEMBER_CACHE(jm_setOrientation, sjc_PageFormat, "setOrientation", "(I)V");
 216     static JNF_MEMBER_CACHE(jm_setPaper, sjc_PageFormat, "setPaper", "(Ljava/awt/print/Paper;)V");
 217     static JNF_CTOR_CACHE(jm_Paper_ctor, sjc_Paper, "()V");
 218 
 219     jint jOrientation;
 220     NSPrintingOrientation nsOrientation = [src orientation];
 221     switch (nsOrientation) {
 222         case NSPortraitOrientation:
 223             jOrientation = java_awt_print_PageFormat_PORTRAIT;
 224             break;
 225 
 226         case NSLandscapeOrientation:
 227             jOrientation = java_awt_print_PageFormat_LANDSCAPE; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
 228             break;
 229 
 230 /*
 231         // AppKit printing doesn't support REVERSE_LANDSCAPE. Radar 2960295.
 232         case NSReverseLandscapeOrientation:
 233             jOrientation = java_awt_print_PageFormat.REVERSE_LANDSCAPE; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
 234             break;
 235 */
 236 
 237         default:
 238             jOrientation = java_awt_print_PageFormat_PORTRAIT;
 239             break;
 240     }
 241 
 242     JNFCallVoidMethod(env, dst, jm_setOrientation, jOrientation); // AWT_THREADING Safe (!appKit)
 243 
 244     // Create a new Paper
 245     jobject paper = JNFNewObject(env, jm_Paper_ctor); // AWT_THREADING Safe (known object)
 246 
 247     nsPrintInfoToJavaPaper(env, src, paper);
 248 
 249     // Set the Paper in the PageFormat
 250     JNFCallVoidMethod(env, dst, jm_setPaper, paper); // AWT_THREADING Safe (!appKit)
 251 
 252     (*env)->DeleteLocalRef(env, paper);
 253 }
 254 
 255 static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobject srcPageFormat, NSPrintInfo* dstPrintInfo)
 256 {
 257     AWT_ASSERT_NOT_APPKIT_THREAD;
 258 
 259     static JNF_MEMBER_CACHE(jm_getOrientation, sjc_PageFormat, "getOrientation", "()I");
 260     static JNF_MEMBER_CACHE(jm_getPaper, sjc_PageFormat, "getPaper", "()Ljava/awt/print/Paper;");
 261     static JNF_MEMBER_CACHE(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;");
 262 
 263     // When setting page information (orientation, size) in NSPrintInfo, set the
 264     //  rectangle first. This is because setting the orientation will change the
 265     //  rectangle to match.
 266 
 267     // Set up the paper. This will force Portrait since java Paper is
 268     //  not oriented. Then setting the NSPrintInfo orientation below
 269     //  will flip NSPrintInfo's info as necessary.
 270     jobject paper = JNFCallObjectMethod(env, srcPageFormat, jm_getPaper); // AWT_THREADING Safe (!appKit)
 271     javaPaperToNSPrintInfo(env, paper, dstPrintInfo);
 272     (*env)->DeleteLocalRef(env, paper);
 273 
 274     switch (JNFCallIntMethod(env, srcPageFormat, jm_getOrientation)) { // AWT_THREADING Safe (!appKit)
 275         case java_awt_print_PageFormat_PORTRAIT:
 276             [dstPrintInfo setOrientation:NSPortraitOrientation];
 277             break;
 278 
 279         case java_awt_print_PageFormat_LANDSCAPE:
 280             [dstPrintInfo setOrientation:NSLandscapeOrientation]; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
 281             break;
 282 
 283         // AppKit printing doesn't support REVERSE_LANDSCAPE. Radar 2960295.
 284         case java_awt_print_PageFormat_REVERSE_LANDSCAPE:
 285             [dstPrintInfo setOrientation:NSLandscapeOrientation]; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
 286             break;
 287 
 288         default:
 289             [dstPrintInfo setOrientation:NSPortraitOrientation];
 290             break;
 291     }
 292 
 293     // <rdar://problem/4022422> NSPrinterInfo is not correctly set to the selected printer
 294     // from the Java side of CPrinterJob. Has always assumed the default printer was the one we wanted.
 295     if (srcPrintJob == NULL) return;
 296     jobject printerNameObj = JNFCallObjectMethod(env, srcPrintJob, jm_getPrinterName);
 297     if (printerNameObj == NULL) return;
 298     NSString *printerName = JNFJavaToNSString(env, printerNameObj);
 299     if (printerName == nil) return;
 300     NSPrinter *printer = [NSPrinter printerWithName:printerName];
 301     if (printer == nil) return;
 302     [dstPrintInfo setPrinter:printer];
 303 }
 304 
 305 static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable)
 306 {
 307     static JNF_MEMBER_CACHE(jm_setService, sjc_CPrinterJob, "setPrinterServiceFromNative", "(Ljava/lang/String;)V");
 308     static JNF_MEMBER_CACHE(jm_setCopies, sjc_CPrinterJob, "setCopies", "(I)V");
 309     static JNF_MEMBER_CACHE(jm_setCollated, sjc_CPrinterJob, "setCollated", "(Z)V");
 310     static JNF_MEMBER_CACHE(jm_setPageRange, sjc_CPrinterJob, "setPageRange", "(II)V");
 311 
 312     // get the selected printer's name, and set the appropriate PrintService on the Java side
 313     NSString *name = [[src printer] name];
 314     jstring printerName = JNFNSToJavaString(env, name);
 315     JNFCallVoidMethod(env, dstPrinterJob, jm_setService, printerName);
 316 
 317 
 318     NSMutableDictionary* printingDictionary = [src dictionary];
 319 
 320     NSNumber* nsCopies = [printingDictionary objectForKey:NSPrintCopies];
 321     if ([nsCopies respondsToSelector:@selector(integerValue)])
 322     {
 323         JNFCallVoidMethod(env, dstPrinterJob, jm_setCopies, [nsCopies integerValue]); // AWT_THREADING Safe (known object)
 324     }
 325 
 326     NSNumber* nsCollated = [printingDictionary objectForKey:NSPrintMustCollate];
 327     if ([nsCollated respondsToSelector:@selector(boolValue)])
 328     {
 329         JNFCallVoidMethod(env, dstPrinterJob, jm_setCollated, [nsCollated boolValue] ? JNI_TRUE : JNI_FALSE); // AWT_THREADING Safe (known object)
 330     }
 331 
 332     NSNumber* nsPrintAllPages = [printingDictionary objectForKey:NSPrintAllPages];
 333     if ([nsPrintAllPages respondsToSelector:@selector(boolValue)])
 334     {
 335         jint jFirstPage = 0, jLastPage = java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES;
 336         if (![nsPrintAllPages boolValue])
 337         {
 338             NSNumber* nsFirstPage = [printingDictionary objectForKey:NSPrintFirstPage];
 339             if ([nsFirstPage respondsToSelector:@selector(integerValue)])
 340             {
 341                 jFirstPage = [nsFirstPage integerValue] - 1;
 342             }
 343 
 344             NSNumber* nsLastPage = [printingDictionary objectForKey:NSPrintLastPage];
 345             if ([nsLastPage respondsToSelector:@selector(integerValue)])
 346             {
 347                 jLastPage = [nsLastPage integerValue] - 1;
 348             }
 349         }
 350 
 351         JNFCallVoidMethod(env, dstPrinterJob, jm_setPageRange, jFirstPage, jLastPage); // AWT_THREADING Safe (known object)
 352     }
 353 }
 354 
 355 static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst)
 356 {
 357     AWT_ASSERT_NOT_APPKIT_THREAD;
 358 
 359     static JNF_CLASS_CACHE(jc_Pageable, "java/awt/print/Pageable");
 360     static JNF_MEMBER_CACHE(jm_getCopies, sjc_CPrinterJob, "getCopiesInt", "()I");
 361     static JNF_MEMBER_CACHE(jm_isCollated, sjc_CPrinterJob, "isCollated", "()Z");
 362     static JNF_MEMBER_CACHE(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I");
 363 
 364     NSMutableDictionary* printingDictionary = [dst dictionary];
 365 
 366     jint copies = JNFCallIntMethod(env, srcPrinterJob, jm_getCopies); // AWT_THREADING Safe (known object)
 367     [printingDictionary setObject:[NSNumber numberWithInteger:copies] forKey:NSPrintCopies];
 368 
 369     jboolean collated = JNFCallBooleanMethod(env, srcPrinterJob, jm_isCollated); // AWT_THREADING Safe (known object)
 370     [printingDictionary setObject:[NSNumber numberWithBool:collated ? YES : NO] forKey:NSPrintMustCollate];
 371 
 372     jint jNumPages = JNFCallIntMethod(env, srcPageable, jm_getNumberOfPages); // AWT_THREADING Safe (!appKit)
 373     if (jNumPages != java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES)
 374     {
 375         [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages];
 376 
 377         [printingDictionary setObject:[NSNumber numberWithInteger:1] forKey:NSPrintFirstPage];
 378         [printingDictionary setObject:[NSNumber numberWithInteger:jNumPages] forKey:NSPrintLastPage];
 379     }
 380     else
 381     {
 382         [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages];
 383     }
 384 }
 385 
 386 /*
 387  * Class:     sun_lwawt_macosx_CPrinterJob
 388  * Method:    abortDoc
 389  * Signature: ()V
 390  */
 391 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_abortDoc
 392   (JNIEnv *env, jobject jthis)
 393 {
 394 JNF_COCOA_ENTER(env);
 395     // This is only called during the printLoop from the printLoop thread
 396     NSPrintOperation* printLoop = [NSPrintOperation currentOperation];
 397     NSPrintInfo* printInfo = [printLoop printInfo];
 398     [printInfo setJobDisposition:NSPrintCancelJob];
 399 JNF_COCOA_EXIT(env);
 400 }
 401 
 402 /*
 403  * Class:     sun_lwawt_macosx_CPrinterJob
 404  * Method:    getDefaultPage
 405  * Signature: (Ljava/awt/print/PageFormat;)V
 406  */
 407 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_getDefaultPage
 408   (JNIEnv *env, jobject jthis, jobject page)
 409 {
 410 JNF_COCOA_ENTER(env);
 411     NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
 412 
 413     nsPrintInfoToJavaPageFormat(env, printInfo, page);
 414 
 415     [printInfo release];
 416 JNF_COCOA_EXIT(env);
 417 }
 418 
 419 /*
 420  * Class:     sun_lwawt_macosx_CPrinterJob
 421  * Method:    validatePaper
 422  * Signature: (Ljava/awt/print/Paper;Ljava/awt/print/Paper;)V
 423  */
 424 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_validatePaper
 425   (JNIEnv *env, jobject jthis, jobject origpaper, jobject newpaper)
 426 {
 427 JNF_COCOA_ENTER(env);
 428 
 429     NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
 430     javaPaperToNSPrintInfo(env, origpaper, printInfo);
 431     makeBestFit(printInfo);
 432     nsPrintInfoToJavaPaper(env, printInfo, newpaper);
 433     [printInfo release];
 434 
 435 JNF_COCOA_EXIT(env);
 436 }
 437 
 438 /*
 439  * Class:     sun_lwawt_macosx_CPrinterJob
 440  * Method:    createNSPrintInfo
 441  * Signature: ()J
 442  */
 443 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPrinterJob_createNSPrintInfo
 444   (JNIEnv *env, jobject jthis)
 445 {
 446     jlong result = -1;
 447 JNF_COCOA_ENTER(env);
 448     // This is used to create the NSPrintInfo for this PrinterJob. Thread
 449     //  safety is assured by the java side of this call.
 450 
 451     NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
 452     if (printInfo) CFRetain(printInfo); // GC
 453     [printInfo release];
 454 
 455     result = ptr_to_jlong(printInfo);
 456 
 457 JNF_COCOA_EXIT(env);
 458     return result;
 459 }
 460 
 461 /*
 462  * Class:     sun_lwawt_macosx_CPrinterJob
 463  * Method:    dispose
 464  * Signature: (J)V
 465  */
 466 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_dispose
 467   (JNIEnv *env, jobject jthis, jlong nsPrintInfo)
 468 {
 469 JNF_COCOA_ENTER(env);
 470     if (nsPrintInfo != -1)
 471     {
 472         NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(nsPrintInfo);
 473         if (printInfo) CFRelease(printInfo); // GC
 474     }
 475 JNF_COCOA_EXIT(env);
 476 }
 477 
 478 
 479 /*
 480  * Class:     sun_lwawt_macosx_CPrinterJob
 481  * Method:    printLoop
 482  * Signature: ()V
 483  */
 484 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJob_printLoop
 485   (JNIEnv *env, jobject jthis, jboolean blocks, jint firstPage, jint lastPage)
 486 {
 487     AWT_ASSERT_NOT_APPKIT_THREAD;
 488 
 489     static JNF_MEMBER_CACHE(jm_getPageFormat, sjc_CPrinterJob, "getPageFormat", "(I)Ljava/awt/print/PageFormat;");
 490     static JNF_MEMBER_CACHE(jm_getPageFormatArea, sjc_CPrinterJob, "getPageFormatArea", "(Ljava/awt/print/PageFormat;)Ljava/awt/geom/Rectangle2D;");
 491     static JNF_MEMBER_CACHE(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;");
 492     static JNF_MEMBER_CACHE(jm_getPageable, sjc_CPrinterJob, "getPageable", "()Ljava/awt/print/Pageable;");
 493 
 494     jboolean retVal = JNI_FALSE;
 495 
 496 JNF_COCOA_ENTER(env);
 497     // Get the first page's PageFormat for setting things up (This introduces
 498     //  and is a facet of the same problem in Radar 2818593/2708932).
 499     jobject page = JNFCallObjectMethod(env, jthis, jm_getPageFormat, 0); // AWT_THREADING Safe (!appKit)
 500     if (page != NULL) {
 501         jobject pageFormatArea = JNFCallObjectMethod(env, jthis, jm_getPageFormatArea, page); // AWT_THREADING Safe (!appKit)
 502 
 503         PrinterView* printerView = [[PrinterView alloc] initWithFrame:JavaToNSRect(env, pageFormatArea) withEnv:env withPrinterJob:jthis];
 504         [printerView setFirstPage:firstPage lastPage:lastPage];
 505 
 506         NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(JNFCallLongMethod(env, jthis, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
 507 
 508         // <rdar://problem/4156975> passing jthis CPrinterJob as well, so we can extract the printer name from the current job
 509         javaPageFormatToNSPrintInfo(env, jthis, page, printInfo);
 510 
 511         // <rdar://problem/4093799> NSPrinterInfo is not correctly set to the selected printer
 512         // from the Java side of CPrinterJob. Had always assumed the default printer was the one we wanted.
 513         jobject printerNameObj = JNFCallObjectMethod(env, jthis, jm_getPrinterName);
 514         if (printerNameObj != NULL) {
 515             NSString *printerName = JNFJavaToNSString(env, printerNameObj);
 516             if (printerName != nil) {
 517                 NSPrinter *printer = [NSPrinter printerWithName:printerName];
 518                 if (printer != nil) [printInfo setPrinter:printer];
 519             }
 520         }
 521 
 522         // <rdar://problem/4367998> JTable.print attributes are ignored
 523         jobject pageable = JNFCallObjectMethod(env, jthis, jm_getPageable); // AWT_THREADING Safe (!appKit)
 524         javaPrinterJobToNSPrintInfo(env, jthis, pageable, printInfo);
 525 
 526         PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
 527 
 528         (void)[printModel runPrintLoopWithView:printerView waitUntilDone:blocks withEnv:env];
 529 
 530         // Only set this if we got far enough to call runPrintLoopWithView, or we will spin CPrinterJob.print() forever!
 531         retVal = JNI_TRUE;
 532 
 533         [printModel release];
 534         [printerView release];
 535 
 536         if (page != NULL)
 537         {
 538             (*env)->DeleteLocalRef(env, page);
 539         }
 540 
 541         if (pageFormatArea != NULL)
 542         {
 543             (*env)->DeleteLocalRef(env, pageFormatArea);
 544         }
 545     }
 546 JNF_COCOA_EXIT(env);
 547     return retVal;
 548 }
 549 
 550 /*
 551  * Class:     sun_lwawt_macosx_CPrinterPageDialog
 552  * Method:    showDialog
 553  * Signature: ()Z
 554  */
 555 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterPageDialog_showDialog
 556   (JNIEnv *env, jobject jthis)
 557 {
 558 
 559     static JNF_CLASS_CACHE(jc_CPrinterPageDialog, "sun/lwawt/macosx/CPrinterPageDialog");
 560     static JNF_MEMBER_CACHE(jm_page, jc_CPrinterPageDialog, "fPage", "Ljava/awt/print/PageFormat;");
 561 
 562     jboolean result = JNI_FALSE;
 563 JNF_COCOA_ENTER(env);
 564     jobject printerJob = JNFGetObjectField(env, jthis, sjm_printerJob);
 565     NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(JNFCallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
 566 
 567     jobject page = JNFGetObjectField(env, jthis, jm_page);
 568 
 569     // <rdar://problem/4156975> passing NULL, because only a CPrinterJob has a real printer associated with it
 570     javaPageFormatToNSPrintInfo(env, NULL, page, printInfo);
 571 
 572     PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
 573     result = [printModel runPageSetup];
 574     [printModel release];
 575 
 576     if (result)
 577     {
 578         nsPrintInfoToJavaPageFormat(env, printInfo, page);
 579     }
 580 
 581     if (printerJob != NULL)
 582     {
 583         (*env)->DeleteLocalRef(env, printerJob);
 584     }
 585 
 586     if (page != NULL)
 587     {
 588         (*env)->DeleteLocalRef(env, page);
 589     }
 590 
 591 JNF_COCOA_EXIT(env);
 592     return result;
 593 }
 594 
 595 /*
 596  * Class:     sun_lwawt_macosx_CPrinterJobDialog
 597  * Method:    showDialog
 598  * Signature: ()Z
 599  */
 600 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJobDialog_showDialog
 601   (JNIEnv *env, jobject jthis)
 602 {
 603     static JNF_CLASS_CACHE(jc_CPrinterJobDialog, "sun/lwawt/macosx/CPrinterJobDialog");
 604     static JNF_MEMBER_CACHE(jm_pageable, jc_CPrinterJobDialog, "fPageable", "Ljava/awt/print/Pageable;");
 605 
 606     jboolean result = JNI_FALSE;
 607 JNF_COCOA_ENTER(env);
 608     jobject printerJob = JNFGetObjectField(env, jthis, sjm_printerJob);
 609     NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(JNFCallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
 610 
 611     jobject pageable = JNFGetObjectField(env, jthis, jm_pageable);
 612 
 613     javaPrinterJobToNSPrintInfo(env, printerJob, pageable, printInfo);
 614 
 615     PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
 616     result = [printModel runJobSetup];
 617     [printModel release];
 618 
 619     if (result)
 620     {
 621         nsPrintInfoToJavaPrinterJob(env, printInfo, printerJob, pageable);
 622     }
 623 
 624     if (printerJob != NULL)
 625     {
 626         (*env)->DeleteLocalRef(env, printerJob);
 627     }
 628 
 629     if (pageable != NULL)
 630     {
 631         (*env)->DeleteLocalRef(env, pageable);
 632     }
 633 
 634 JNF_COCOA_EXIT(env);
 635     return result;
 636 }