1/*
2 * Copyright (c) 2011, 2015, 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
34#import "PrinterView.h"
35#import "PrintModel.h"
36#import "ThreadUtilities.h"
37#import "GeomUtilities.h"
38#import "JNIUtilities.h"
39
40static jclass sjc_Paper = NULL;
41static jclass sjc_PageFormat = NULL;
42static jclass sjc_CPrinterJob = NULL;
43static jclass sjc_CPrinterDialog = NULL;
44static jmethodID sjm_getNSPrintInfo = NULL;
45static jmethodID sjm_printerJob = NULL;
46
47#define GET_PAPER_CLASS() GET_CLASS(sjc_Paper, "java/awt/print/Paper");
48#define GET_PAGEFORMAT_CLASS() GET_CLASS(sjc_PageFormat, "java/awt/print/PageFormat");
49#define GET_CPRINTERDIALOG_CLASS() GET_CLASS(sjc_CPrinterDialog, "sun/lwawt/macosx/CPrinterDialog");
50#define GET_CPRINTERDIALOG_CLASS_RETURN(ret) GET_CLASS_RETURN(sjc_CPrinterDialog, "sun/lwawt/macosx/CPrinterDialog", ret);
51#define GET_CPRINTERJOB_CLASS() GET_CLASS(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
52#define GET_CPRINTERJOB_CLASS_RETURN(ret) GET_CLASS_RETURN(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob", ret);
53
54#define GET_NSPRINTINFO_METHOD_RETURN(ret) \
55    GET_CPRINTERJOB_CLASS_RETURN(ret); \
56    GET_METHOD_RETURN(sjm_getNSPrintInfo, sjc_CPrinterJob, "getNSPrintInfo", "()J", ret);
57
58#define GET_CPRINTERDIALOG_FIELD_RETURN(ret) \
59   GET_CPRINTERDIALOG_CLASS_RETURN(ret); \
60   GET_FIELD_RETURN(sjm_printerJob, sjc_CPrinterDialog, "fPrinterJob", "Lsun/lwawt/macosx/CPrinterJob;", ret);
61
62static NSPrintInfo* createDefaultNSPrintInfo();
63
64static void makeBestFit(NSPrintInfo* src);
65
66static void nsPrintInfoToJavaPaper(JNIEnv* env, NSPrintInfo* src, jobject dst);
67static void javaPaperToNSPrintInfo(JNIEnv* env, jobject src, NSPrintInfo* dst);
68
69static void nsPrintInfoToJavaPageFormat(JNIEnv* env, NSPrintInfo* src, jobject dst);
70static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageFormat, NSPrintInfo* dst);
71
72static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable);
73static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst);
74
75
76#ifdef __MAC_10_9 // code for SDK 10.9 or newer
77#define NS_PORTRAIT NSPaperOrientationPortrait
78#define NS_LANDSCAPE NSPaperOrientationLandscape
79#else // code for SDK 10.8 or older
80#define NS_PORTRAIT NSPortraitOrientation
81#define NS_LANDSCAPE NSLandscapeOrientation
82#endif
83
84static NSPrintInfo* createDefaultNSPrintInfo(JNIEnv* env, jstring printer)
85{
86    NSPrintInfo* defaultPrintInfo = [[NSPrintInfo sharedPrintInfo] copy];
87    if (printer != NULL)
88    {
89        NSPrinter* nsPrinter = [NSPrinter printerWithName:JavaStringToNSString(env, printer)];
90        if (nsPrinter != nil)
91        {
92            [defaultPrintInfo setPrinter:nsPrinter];
93        }
94    }
95    [defaultPrintInfo setUpPrintOperationDefaultValues];
96
97    // cmc 05/18/04 radr://3160443 : setUpPrintOperationDefaultValues sets the
98    // page margins to 72, 72, 90, 90 - need to use [NSPrintInfo imageablePageBounds]
99    // to get values from the printer.
100    // NOTE: currently [NSPrintInfo imageablePageBounds] does not update itself when
101    // the user selects a different printer - see radr://3657453. However, rather than
102    // directly querying the PPD here, we'll let AppKit printing do the work. The AppKit
103    // printing bug above is set to be fixed for Tiger.
104    NSRect imageableRect = [defaultPrintInfo imageablePageBounds];
105    [defaultPrintInfo setLeftMargin: imageableRect.origin.x];
106    [defaultPrintInfo setBottomMargin: imageableRect.origin.y]; //top and bottom are flipped because [NSPrintInfo imageablePageBounds] returns a flipped NSRect (bottom-left to top-right).
107    [defaultPrintInfo setRightMargin: [defaultPrintInfo paperSize].width-imageableRect.origin.x-imageableRect.size.width];
108    [defaultPrintInfo setTopMargin: [defaultPrintInfo paperSize].height-imageableRect.origin.y-imageableRect.size.height];
109
110    return defaultPrintInfo;
111}
112
113static void makeBestFit(NSPrintInfo* src)
114{
115    // This will look at the NSPrintInfo's margins. If they are out of bounds to the
116    // imageable area of the page, it will set them to the largest possible size.
117
118    NSRect imageable = [src imageablePageBounds];
119
120    NSSize paperSize = [src paperSize];
121
122    CGFloat fullLeftM = imageable.origin.x;
123    CGFloat fullRightM = paperSize.width - (imageable.origin.x + imageable.size.width);
124
125    // These are flipped because [NSPrintInfo imageablePageBounds] returns a flipped
126    //  NSRect (bottom-left to top-right).
127    CGFloat fullTopM = paperSize.height - (imageable.origin.y + imageable.size.height);
128    CGFloat fullBottomM = imageable.origin.y;
129
130    if (fullLeftM > [src leftMargin])
131    {
132        [src setLeftMargin:fullLeftM];
133    }
134
135    if (fullRightM > [src rightMargin])
136    {
137        [src setRightMargin:fullRightM];
138    }
139
140    if (fullTopM > [src topMargin])
141    {
142        [src setTopMargin:fullTopM];
143    }
144
145    if (fullBottomM > [src bottomMargin])
146    {
147        [src setBottomMargin:fullBottomM];
148    }
149}
150
151// In AppKit Printing, the rectangle is always oriented. In AppKit Printing, setting
152//  the rectangle will always set the orientation.
153// In java printing, the rectangle is oriented if accessed from PageFormat. It is
154//  not oriented when accessed from Paper.
155
156static void nsPrintInfoToJavaPaper(JNIEnv* env, NSPrintInfo* src, jobject dst)
157{
158    GET_PAGEFORMAT_CLASS();
159    GET_PAPER_CLASS();
160    DECLARE_METHOD(jm_setSize, sjc_Paper, "setSize", "(DD)V");
161    DECLARE_METHOD(jm_setImageableArea, sjc_Paper, "setImageableArea", "(DDDD)V");
162
163    jdouble jPaperW, jPaperH;
164
165    // NSPrintInfo paperSize is oriented. java Paper is not oriented. Take
166    //  the -[NSPrintInfo orientation] into account when setting the Paper
167    //  rectangle.
168
169    NSSize paperSize = [src paperSize];
170    switch ([src orientation]) {
171        case NS_PORTRAIT:
172            jPaperW = paperSize.width;
173            jPaperH = paperSize.height;
174            break;
175
176        case NS_LANDSCAPE:
177            jPaperW = paperSize.height;
178            jPaperH = paperSize.width;
179            break;
180
181        default:
182            jPaperW = paperSize.width;
183            jPaperH = paperSize.height;
184            break;
185    }
186
187    (*env)->CallVoidMethod(env, dst, jm_setSize, jPaperW, jPaperH); // AWT_THREADING Safe (known object - always actual Paper)
188    CHECK_EXCEPTION();
189
190    // Set the imageable area from the margins
191    CGFloat leftM = [src leftMargin];
192    CGFloat rightM = [src rightMargin];
193    CGFloat topM = [src topMargin];
194    CGFloat bottomM = [src bottomMargin];
195
196    jdouble jImageX = leftM;
197    jdouble jImageY = topM;
198    jdouble jImageW = jPaperW - (leftM + rightM);
199    jdouble jImageH = jPaperH - (topM + bottomM);
200
201    (*env)->CallVoidMethod(env, dst, jm_setImageableArea, jImageX, jImageY, jImageW, jImageH); // AWT_THREADING Safe (known object - always actual Paper)
202    CHECK_EXCEPTION();
203}
204
205static void javaPaperToNSPrintInfo(JNIEnv* env, jobject src, NSPrintInfo* dst)
206{
207    AWT_ASSERT_NOT_APPKIT_THREAD;
208
209    GET_PAGEFORMAT_CLASS();
210    GET_PAPER_CLASS();
211    DECLARE_METHOD(jm_getWidth, sjc_Paper, "getWidth", "()D");
212    DECLARE_METHOD(jm_getHeight, sjc_Paper, "getHeight", "()D");
213    DECLARE_METHOD(jm_getImageableX, sjc_Paper, "getImageableX", "()D");
214    DECLARE_METHOD(jm_getImageableY, sjc_Paper, "getImageableY", "()D");
215    DECLARE_METHOD(jm_getImageableW, sjc_Paper, "getImageableWidth", "()D");
216    DECLARE_METHOD(jm_getImageableH, sjc_Paper, "getImageableHeight", "()D");
217
218    // java Paper is always Portrait oriented. Set NSPrintInfo with this
219    //  rectangle, and it's orientation may change. If necessary, be sure to call
220    //  -[NSPrintInfo setOrientation] after this call, which will then
221    //  adjust the -[NSPrintInfo paperSize] as well.
222
223    jdouble jPhysicalWidth = (*env)->CallDoubleMethod(env, src, jm_getWidth); // AWT_THREADING Safe (!appKit)
224    CHECK_EXCEPTION();
225    jdouble jPhysicalHeight = (*env)->CallDoubleMethod(env, src, jm_getHeight); // AWT_THREADING Safe (!appKit)
226    CHECK_EXCEPTION();
227
228    [dst setPaperSize:NSMakeSize(jPhysicalWidth, jPhysicalHeight)];
229
230    // Set the margins from the imageable area
231    jdouble jImageX = (*env)->CallDoubleMethod(env, src, jm_getImageableX); // AWT_THREADING Safe (!appKit)
232    CHECK_EXCEPTION();
233    jdouble jImageY = (*env)->CallDoubleMethod(env, src, jm_getImageableY); // AWT_THREADING Safe (!appKit)
234    CHECK_EXCEPTION();
235    jdouble jImageW = (*env)->CallDoubleMethod(env, src, jm_getImageableW); // AWT_THREADING Safe (!appKit)
236    CHECK_EXCEPTION();
237    jdouble jImageH = (*env)->CallDoubleMethod(env, src, jm_getImageableH); // AWT_THREADING Safe (!appKit)
238    CHECK_EXCEPTION();
239
240    [dst setLeftMargin:(CGFloat)jImageX];
241    [dst setTopMargin:(CGFloat)jImageY];
242    [dst setRightMargin:(CGFloat)(jPhysicalWidth - jImageW - jImageX)];
243    [dst setBottomMargin:(CGFloat)(jPhysicalHeight - jImageH - jImageY)];
244}
245
246static void nsPrintInfoToJavaPageFormat(JNIEnv* env, NSPrintInfo* src, jobject dst)
247{
248    AWT_ASSERT_NOT_APPKIT_THREAD;
249
250    GET_CPRINTERJOB_CLASS();
251    GET_PAGEFORMAT_CLASS();
252    GET_PAPER_CLASS();
253    DECLARE_METHOD(jm_setOrientation, sjc_PageFormat, "setOrientation", "(I)V");
254    DECLARE_METHOD(jm_setPaper, sjc_PageFormat, "setPaper", "(Ljava/awt/print/Paper;)V");
255    DECLARE_METHOD(jm_Paper_ctor, sjc_Paper, "<init>", "()V");
256
257    jint jOrientation;
258    switch ([src orientation]) {
259        case NS_PORTRAIT:
260            jOrientation = java_awt_print_PageFormat_PORTRAIT;
261            break;
262
263        case NS_LANDSCAPE:
264            jOrientation = java_awt_print_PageFormat_LANDSCAPE; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
265            break;
266
267/*
268        // AppKit printing doesn't support REVERSE_LANDSCAPE. Radar 2960295.
269        case NSReverseLandscapeOrientation:
270            jOrientation = java_awt_print_PageFormat.REVERSE_LANDSCAPE; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
271            break;
272*/
273
274        default:
275            jOrientation = java_awt_print_PageFormat_PORTRAIT;
276            break;
277    }
278
279    (*env)->CallVoidMethod(env, dst, jm_setOrientation, jOrientation); // AWT_THREADING Safe (!appKit)
280    CHECK_EXCEPTION();
281
282    // Create a new Paper
283    jobject paper = (*env)->NewObject(env, sjc_Paper, jm_Paper_ctor); // AWT_THREADING Safe (known object)
284    CHECK_EXCEPTION();
285    if (paper == NULL) {
286        return;
287    }
288
289    nsPrintInfoToJavaPaper(env, src, paper);
290
291    // Set the Paper in the PageFormat
292    (*env)->CallVoidMethod(env, dst, jm_setPaper, paper); // AWT_THREADING Safe (!appKit)
293    CHECK_EXCEPTION();
294
295    (*env)->DeleteLocalRef(env, paper);
296}
297
298static void javaPageFormatToNSPrintInfo(JNIEnv* env, jobject srcPrintJob, jobject srcPageFormat, NSPrintInfo* dstPrintInfo)
299{
300    AWT_ASSERT_NOT_APPKIT_THREAD;
301
302    GET_CPRINTERJOB_CLASS();
303    GET_PAGEFORMAT_CLASS();
304    GET_PAPER_CLASS();
305    DECLARE_METHOD(jm_getOrientation, sjc_PageFormat, "getOrientation", "()I");
306    DECLARE_METHOD(jm_getPaper, sjc_PageFormat, "getPaper", "()Ljava/awt/print/Paper;");
307    DECLARE_METHOD(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;");
308
309    // When setting page information (orientation, size) in NSPrintInfo, set the
310    //  rectangle first. This is because setting the orientation will change the
311    //  rectangle to match.
312
313    // Set up the paper. This will force Portrait since java Paper is
314    //  not oriented. Then setting the NSPrintInfo orientation below
315    //  will flip NSPrintInfo's info as necessary.
316    jobject paper = (*env)->CallObjectMethod(env, srcPageFormat, jm_getPaper); // AWT_THREADING Safe (!appKit)
317    CHECK_EXCEPTION();
318    javaPaperToNSPrintInfo(env, paper, dstPrintInfo);
319    (*env)->DeleteLocalRef(env, paper);
320
321    switch ((*env)->CallIntMethod(env, srcPageFormat, jm_getOrientation)) { // AWT_THREADING Safe (!appKit)
322        case java_awt_print_PageFormat_PORTRAIT:
323            [dstPrintInfo setOrientation:NS_PORTRAIT];
324            break;
325
326        case java_awt_print_PageFormat_LANDSCAPE:
327            [dstPrintInfo setOrientation:NS_LANDSCAPE]; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
328            break;
329
330        // AppKit printing doesn't support REVERSE_LANDSCAPE. Radar 2960295.
331        case java_awt_print_PageFormat_REVERSE_LANDSCAPE:
332            [dstPrintInfo setOrientation:NS_LANDSCAPE]; //+++gdb Are LANDSCAPE and REVERSE_LANDSCAPE still inverted?
333            break;
334
335        default:
336            [dstPrintInfo setOrientation:NS_PORTRAIT];
337            break;
338    }
339    CHECK_EXCEPTION();
340
341    // <rdar://problem/4022422> NSPrinterInfo is not correctly set to the selected printer
342    // from the Java side of CPrinterJob. Has always assumed the default printer was the one we wanted.
343    if (srcPrintJob == NULL) return;
344    jobject printerNameObj = (*env)->CallObjectMethod(env, srcPrintJob, jm_getPrinterName);
345    CHECK_EXCEPTION();
346    if (printerNameObj == NULL) return;
347    NSString *printerName = JavaStringToNSString(env, printerNameObj);
348    if (printerName == nil) return;
349    NSPrinter *printer = [NSPrinter printerWithName:printerName];
350    if (printer == nil) return;
351    [dstPrintInfo setPrinter:printer];
352}
353
354static void nsPrintInfoToJavaPrinterJob(JNIEnv* env, NSPrintInfo* src, jobject dstPrinterJob, jobject dstPageable)
355{
356    GET_CPRINTERJOB_CLASS();
357    DECLARE_METHOD(jm_setService, sjc_CPrinterJob, "setPrinterServiceFromNative", "(Ljava/lang/String;)V");
358    DECLARE_METHOD(jm_setCopiesAttribute, sjc_CPrinterJob, "setCopiesAttribute", "(I)V");
359    DECLARE_METHOD(jm_setCollated, sjc_CPrinterJob, "setCollated", "(Z)V");
360    DECLARE_METHOD(jm_setPageRangeAttribute, sjc_CPrinterJob, "setPageRangeAttribute", "(IIZ)V");
361    DECLARE_METHOD(jm_setPrintToFile, sjc_CPrinterJob, "setPrintToFile", "(Z)V");
362
363    if (src.jobDisposition == NSPrintSaveJob) {
364        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setPrintToFile, true);
365        CHECK_EXCEPTION();
366    } else {
367        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setPrintToFile, false);
368        CHECK_EXCEPTION();
369    }
370
371    // get the selected printer's name, and set the appropriate PrintService on the Java side
372    NSString *name = [[src printer] name];
373    jstring printerName = NSStringToJavaString(env, name);
374    (*env)->CallVoidMethod(env, dstPrinterJob, jm_setService, printerName);
375    CHECK_EXCEPTION();
376
377    NSMutableDictionary* printingDictionary = [src dictionary];
378
379    NSNumber* nsCopies = [printingDictionary objectForKey:NSPrintCopies];
380    if ([nsCopies respondsToSelector:@selector(integerValue)])
381    {
382        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setCopiesAttribute, [nsCopies integerValue]); // AWT_THREADING Safe (known object)
383        CHECK_EXCEPTION();
384    }
385
386    NSNumber* nsCollated = [printingDictionary objectForKey:NSPrintMustCollate];
387    if ([nsCollated respondsToSelector:@selector(boolValue)])
388    {
389        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setCollated, [nsCollated boolValue] ? JNI_TRUE : JNI_FALSE); // AWT_THREADING Safe (known object)
390        CHECK_EXCEPTION();
391    }
392
393    NSNumber* nsPrintAllPages = [printingDictionary objectForKey:NSPrintAllPages];
394    if ([nsPrintAllPages respondsToSelector:@selector(boolValue)])
395    {
396        jint jFirstPage = 0, jLastPage = java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES;
397        jboolean isRangeSet = false;
398        if (![nsPrintAllPages boolValue])
399        {
400            NSNumber* nsFirstPage = [printingDictionary objectForKey:NSPrintFirstPage];
401            if ([nsFirstPage respondsToSelector:@selector(integerValue)])
402            {
403                jFirstPage = [nsFirstPage integerValue] - 1;
404            }
405
406            NSNumber* nsLastPage = [printingDictionary objectForKey:NSPrintLastPage];
407            if ([nsLastPage respondsToSelector:@selector(integerValue)])
408            {
409                jLastPage = [nsLastPage integerValue] - 1;
410            }
411            isRangeSet = true;
412        }
413        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setPageRangeAttribute,
414                          jFirstPage, jLastPage, isRangeSet); // AWT_THREADING Safe (known object)
415        CHECK_EXCEPTION();
416
417    }
418}
419
420static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst)
421{
422    AWT_ASSERT_NOT_APPKIT_THREAD;
423
424    DECLARE_CLASS(jc_Pageable, "java/awt/print/Pageable");
425    DECLARE_METHOD(jm_getCopies, sjc_CPrinterJob, "getCopiesInt", "()I");
426    DECLARE_METHOD(jm_isCollated, sjc_CPrinterJob, "isCollated", "()Z");
427    DECLARE_METHOD(jm_getFromPage, sjc_CPrinterJob, "getFromPageAttrib", "()I");
428    DECLARE_METHOD(jm_getToPage, sjc_CPrinterJob, "getToPageAttrib", "()I");
429    DECLARE_METHOD(jm_getMinPage, sjc_CPrinterJob, "getMinPageAttrib", "()I");
430    DECLARE_METHOD(jm_getMaxPage, sjc_CPrinterJob, "getMaxPageAttrib", "()I");
431    DECLARE_METHOD(jm_getSelectAttrib, sjc_CPrinterJob, "getSelectAttrib", "()I");
432    DECLARE_METHOD(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I");
433    DECLARE_METHOD(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;");
434
435    NSMutableDictionary* printingDictionary = [dst dictionary];
436
437    jint copies = (*env)->CallIntMethod(env, srcPrinterJob, jm_getCopies); // AWT_THREADING Safe (known object)
438    CHECK_EXCEPTION();
439    [printingDictionary setObject:[NSNumber numberWithInteger:copies] forKey:NSPrintCopies];
440
441    jboolean collated = (*env)->CallBooleanMethod(env, srcPrinterJob, jm_isCollated); // AWT_THREADING Safe (known object)
442    CHECK_EXCEPTION();
443    [printingDictionary setObject:[NSNumber numberWithBool:collated ? YES : NO] forKey:NSPrintMustCollate];
444    jint selectID = (*env)->CallIntMethod(env, srcPrinterJob, jm_getSelectAttrib);
445    CHECK_EXCEPTION();
446    jint fromPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getFromPage);
447    CHECK_EXCEPTION();
448    jint toPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getToPage);
449    CHECK_EXCEPTION();
450    if (selectID ==0) {
451        [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages];
452    } else if (selectID == 2) {
453        // In Mac 10.7,  Print ALL is deselected if PrintSelection is YES whether
454        // NSPrintAllPages is YES or NO
455        [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages];
456        [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintSelectionOnly];
457    } else {
458        jint minPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getMinPage);
459        CHECK_EXCEPTION();
460        jint maxPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getMaxPage);
461        CHECK_EXCEPTION();
462
463        // for PD_SELECTION or PD_NOSELECTION, check from/to page
464        // to determine which radio button to select
465        if (fromPage > minPage || toPage < maxPage) {
466            [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages];
467        } else {
468            [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages];
469        }
470    }
471
472    // setting fromPage and toPage will not be shown in the dialog if printing All pages
473    [printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage];
474    [printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage];
475
476    jobject page = (*env)->CallObjectMethod(env, srcPrinterJob, jm_getPageFormat);
477    CHECK_EXCEPTION();
478    if (page != NULL) {
479        javaPageFormatToNSPrintInfo(env, NULL, page, dst);
480    }
481}
482
483/*
484 * Class:     sun_lwawt_macosx_CPrinterJob
485 * Method:    abortDoc
486 * Signature: ()V
487 */
488JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_abortDoc
489  (JNIEnv *env, jobject jthis)
490{
491JNI_COCOA_ENTER(env);
492    // This is only called during the printLoop from the printLoop thread
493    NSPrintOperation* printLoop = [NSPrintOperation currentOperation];
494    NSPrintInfo* printInfo = [printLoop printInfo];
495    [printInfo setJobDisposition:NSPrintCancelJob];
496JNI_COCOA_EXIT(env);
497}
498
499/*
500 * Class:     sun_lwawt_macosx_CPrinterJob
501 * Method:    getDefaultPage
502 * Signature: (Ljava/awt/print/PageFormat;)V
503 */
504JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_getDefaultPage
505  (JNIEnv *env, jobject jthis, jobject page)
506{
507JNI_COCOA_ENTER(env);
508    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
509
510    nsPrintInfoToJavaPageFormat(env, printInfo, page);
511
512    [printInfo release];
513JNI_COCOA_EXIT(env);
514}
515
516/*
517 * Class:     sun_lwawt_macosx_CPrinterJob
518 * Method:    validatePaper
519 * Signature: (Ljava/awt/print/Paper;Ljava/awt/print/Paper;)V
520 */
521JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_validatePaper
522  (JNIEnv *env, jobject jthis, jobject origpaper, jobject newpaper)
523{
524JNI_COCOA_ENTER(env);
525
526
527    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
528    javaPaperToNSPrintInfo(env, origpaper, printInfo);
529    makeBestFit(printInfo);
530    nsPrintInfoToJavaPaper(env, printInfo, newpaper);
531    [printInfo release];
532
533JNI_COCOA_EXIT(env);
534}
535
536/*
537 * Class:     sun_lwawt_macosx_CPrinterJob
538 * Method:    createNSPrintInfo
539 * Signature: ()J
540 */
541JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPrinterJob_createNSPrintInfo
542  (JNIEnv *env, jobject jthis)
543{
544    jlong result = -1;
545JNI_COCOA_ENTER(env);
546    // This is used to create the NSPrintInfo for this PrinterJob. Thread
547    //  safety is assured by the java side of this call.
548
549    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
550
551    result = ptr_to_jlong(printInfo);
552
553JNI_COCOA_EXIT(env);
554    return result;
555}
556
557/*
558 * Class:     sun_lwawt_macosx_CPrinterJob
559 * Method:    dispose
560 * Signature: (J)V
561 */
562JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_dispose
563  (JNIEnv *env, jobject jthis, jlong nsPrintInfo)
564{
565JNI_COCOA_ENTER(env);
566    if (nsPrintInfo != -1)
567    {
568        NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(nsPrintInfo);
569        [printInfo release];
570    }
571JNI_COCOA_EXIT(env);
572}
573
574
575/*
576 * Class:     sun_lwawt_macosx_CPrinterJob
577 * Method:    printLoop
578 * Signature: ()V
579 */
580JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJob_printLoop
581  (JNIEnv *env, jobject jthis, jboolean blocks, jint firstPage, jint lastPage)
582{
583    AWT_ASSERT_NOT_APPKIT_THREAD;
584
585    GET_CPRINTERJOB_CLASS_RETURN(NO);
586    DECLARE_METHOD_RETURN(jm_getPageFormat, sjc_CPrinterJob, "getPageFormat", "(I)Ljava/awt/print/PageFormat;", NO);
587    DECLARE_METHOD_RETURN(jm_getPageFormatArea, sjc_CPrinterJob, "getPageFormatArea", "(Ljava/awt/print/PageFormat;)Ljava/awt/geom/Rectangle2D;", NO);
588    DECLARE_METHOD_RETURN(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;", NO);
589    DECLARE_METHOD_RETURN(jm_getPageable, sjc_CPrinterJob, "getPageable", "()Ljava/awt/print/Pageable;", NO);
590
591    jboolean retVal = JNI_FALSE;
592
593JNI_COCOA_ENTER(env);
594    // Get the first page's PageFormat for setting things up (This introduces
595    //  and is a facet of the same problem in Radar 2818593/2708932).
596    jobject page = (*env)->CallObjectMethod(env, jthis, jm_getPageFormat, 0); // AWT_THREADING Safe (!appKit)
597    CHECK_EXCEPTION();
598    if (page != NULL) {
599        jobject pageFormatArea = (*env)->CallObjectMethod(env, jthis, jm_getPageFormatArea, page); // AWT_THREADING Safe (!appKit)
600        CHECK_EXCEPTION();
601
602        PrinterView* printerView = [[PrinterView alloc] initWithFrame:JavaToNSRect(env, pageFormatArea) withEnv:env withPrinterJob:jthis];
603        [printerView setFirstPage:firstPage lastPage:lastPage];
604
605        GET_NSPRINTINFO_METHOD_RETURN(NO)
606        NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, jthis, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
607        CHECK_EXCEPTION();
608
609        // <rdar://problem/4156975> passing jthis CPrinterJob as well, so we can extract the printer name from the current job
610        javaPageFormatToNSPrintInfo(env, jthis, page, printInfo);
611
612        // <rdar://problem/4093799> NSPrinterInfo is not correctly set to the selected printer
613        // from the Java side of CPrinterJob. Had always assumed the default printer was the one we wanted.
614        jobject printerNameObj = (*env)->CallObjectMethod(env, jthis, jm_getPrinterName);
615        CHECK_EXCEPTION();
616        if (printerNameObj != NULL) {
617            NSString *printerName = JavaStringToNSString(env, printerNameObj);
618            if (printerName != nil) {
619                NSPrinter *printer = [NSPrinter printerWithName:printerName];
620                if (printer != nil) [printInfo setPrinter:printer];
621            }
622        }
623
624        // <rdar://problem/4367998> JTable.print attributes are ignored
625        jobject pageable = (*env)->CallObjectMethod(env, jthis, jm_getPageable); // AWT_THREADING Safe (!appKit)
626        CHECK_EXCEPTION();
627        javaPrinterJobToNSPrintInfo(env, jthis, pageable, printInfo);
628
629        PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
630
631        (void)[printModel runPrintLoopWithView:printerView waitUntilDone:blocks withEnv:env];
632
633        // Only set this if we got far enough to call runPrintLoopWithView, or we will spin CPrinterJob.print() forever!
634        retVal = JNI_TRUE;
635
636        [printModel release];
637        [printerView release];
638
639        if (page != NULL)
640        {
641            (*env)->DeleteLocalRef(env, page);
642        }
643
644        if (pageFormatArea != NULL)
645        {
646            (*env)->DeleteLocalRef(env, pageFormatArea);
647        }
648    }
649JNI_COCOA_EXIT(env);
650    return retVal;
651}
652
653/*
654 * Class:     sun_lwawt_macosx_CPrinterPageDialog
655 * Method:    showDialog
656 * Signature: ()Z
657 */
658JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterPageDialog_showDialog
659  (JNIEnv *env, jobject jthis)
660{
661
662    DECLARE_CLASS_RETURN(jc_CPrinterPageDialog, "sun/lwawt/macosx/CPrinterPageDialog", NO);
663    DECLARE_FIELD_RETURN(jm_page, jc_CPrinterPageDialog, "fPage", "Ljava/awt/print/PageFormat;", NO);
664
665    jboolean result = JNI_FALSE;
666JNI_COCOA_ENTER(env);
667    GET_CPRINTERDIALOG_FIELD_RETURN(NO);
668    GET_NSPRINTINFO_METHOD_RETURN(NO)
669    jobject printerJob = (*env)->GetObjectField(env, jthis, sjm_printerJob);
670    if (printerJob == NULL) return NO;
671    NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
672    CHECK_EXCEPTION();
673    if (printInfo == NULL) return result;
674
675    jobject page = (*env)->GetObjectField(env, jthis, jm_page);
676    if (page == NULL) return NO;
677
678    // <rdar://problem/4156975> passing NULL, because only a CPrinterJob has a real printer associated with it
679    javaPageFormatToNSPrintInfo(env, NULL, page, printInfo);
680
681    PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
682    result = [printModel runPageSetup];
683    [printModel release];
684
685    if (result)
686    {
687        nsPrintInfoToJavaPageFormat(env, printInfo, page);
688    }
689
690    if (printerJob != NULL)
691    {
692        (*env)->DeleteLocalRef(env, printerJob);
693    }
694
695    if (page != NULL)
696    {
697        (*env)->DeleteLocalRef(env, page);
698    }
699
700JNI_COCOA_EXIT(env);
701    return result;
702}
703
704/*
705 * Class:     sun_lwawt_macosx_CPrinterJobDialog
706 * Method:    showDialog
707 * Signature: ()Z
708 */
709JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJobDialog_showDialog
710  (JNIEnv *env, jobject jthis)
711{
712    DECLARE_CLASS_RETURN(jc_CPrinterJobDialog, "sun/lwawt/macosx/CPrinterJobDialog", NO);
713    DECLARE_FIELD_RETURN(jm_pageable, jc_CPrinterJobDialog, "fPageable", "Ljava/awt/print/Pageable;", NO);
714
715    jboolean result = JNI_FALSE;
716JNI_COCOA_ENTER(env);
717    GET_CPRINTERDIALOG_FIELD_RETURN(NO);
718    jobject printerJob = (*env)->GetObjectField(env, jthis, sjm_printerJob);
719    if (printerJob == NULL) return NO;
720    GET_NSPRINTINFO_METHOD_RETURN(NO)
721    NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
722
723    jobject pageable = (*env)->GetObjectField(env, jthis, jm_pageable);
724    if (pageable == NULL) return NO;
725
726    javaPrinterJobToNSPrintInfo(env, printerJob, pageable, printInfo);
727
728    PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
729    result = [printModel runJobSetup];
730    [printModel release];
731
732    if (result)
733    {
734        nsPrintInfoToJavaPrinterJob(env, printInfo, printerJob, pageable);
735    }
736
737    if (printerJob != NULL)
738    {
739        (*env)->DeleteLocalRef(env, printerJob);
740    }
741
742    if (pageable != NULL)
743    {
744        (*env)->DeleteLocalRef(env, pageable);
745    }
746
747JNI_COCOA_EXIT(env);
748    return result;
749}
750