1/*
2 * Copyright (c) 2011, 2020, 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    } else {
366        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setPrintToFile, false);
367    }
368
369    // get the selected printer's name, and set the appropriate PrintService on the Java side
370    NSString *name = [[src printer] name];
371    jstring printerName = NSStringToJavaString(env, name);
372    (*env)->CallVoidMethod(env, dstPrinterJob, jm_setService, printerName);
373    CHECK_EXCEPTION();
374
375    NSMutableDictionary* printingDictionary = [src dictionary];
376
377    NSNumber* nsCopies = [printingDictionary objectForKey:NSPrintCopies];
378    if ([nsCopies respondsToSelector:@selector(integerValue)])
379    {
380        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setCopiesAttribute, [nsCopies integerValue]); // AWT_THREADING Safe (known object)
381        CHECK_EXCEPTION();
382    }
383
384    NSNumber* nsCollated = [printingDictionary objectForKey:NSPrintMustCollate];
385    if ([nsCollated respondsToSelector:@selector(boolValue)])
386    {
387        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setCollated, [nsCollated boolValue] ? JNI_TRUE : JNI_FALSE); // AWT_THREADING Safe (known object)
388        CHECK_EXCEPTION();
389    }
390
391    NSNumber* nsPrintAllPages = [printingDictionary objectForKey:NSPrintAllPages];
392    if ([nsPrintAllPages respondsToSelector:@selector(boolValue)])
393    {
394        jint jFirstPage = 0, jLastPage = java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES;
395        jboolean isRangeSet = false;
396        if (![nsPrintAllPages boolValue])
397        {
398            NSNumber* nsFirstPage = [printingDictionary objectForKey:NSPrintFirstPage];
399            if ([nsFirstPage respondsToSelector:@selector(integerValue)])
400            {
401                jFirstPage = [nsFirstPage integerValue] - 1;
402            }
403
404            NSNumber* nsLastPage = [printingDictionary objectForKey:NSPrintLastPage];
405            if ([nsLastPage respondsToSelector:@selector(integerValue)])
406            {
407                jLastPage = [nsLastPage integerValue] - 1;
408            }
409            isRangeSet = true;
410        }
411        (*env)->CallVoidMethod(env, dstPrinterJob, jm_setPageRangeAttribute,
412                          jFirstPage, jLastPage, isRangeSet); // AWT_THREADING Safe (known object)
413        CHECK_EXCEPTION();
414
415    }
416}
417
418static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobject srcPageable, NSPrintInfo* dst)
419{
420    AWT_ASSERT_NOT_APPKIT_THREAD;
421
422    DECLARE_CLASS(jc_Pageable, "java/awt/print/Pageable");
423    DECLARE_METHOD(jm_getCopies, sjc_CPrinterJob, "getCopiesInt", "()I");
424    DECLARE_METHOD(jm_isCollated, sjc_CPrinterJob, "isCollated", "()Z");
425    DECLARE_METHOD(jm_getFromPage, sjc_CPrinterJob, "getFromPageAttrib", "()I");
426    DECLARE_METHOD(jm_getToPage, sjc_CPrinterJob, "getToPageAttrib", "()I");
427    DECLARE_METHOD(jm_getMinPage, sjc_CPrinterJob, "getMinPageAttrib", "()I");
428    DECLARE_METHOD(jm_getMaxPage, sjc_CPrinterJob, "getMaxPageAttrib", "()I");
429    DECLARE_METHOD(jm_getSelectAttrib, sjc_CPrinterJob, "getSelectAttrib", "()I");
430    DECLARE_METHOD(jm_getNumberOfPages, jc_Pageable, "getNumberOfPages", "()I");
431    DECLARE_METHOD(jm_getPageFormat, sjc_CPrinterJob, "getPageFormatFromAttributes", "()Ljava/awt/print/PageFormat;");
432
433    NSMutableDictionary* printingDictionary = [dst dictionary];
434
435    jint copies = (*env)->CallIntMethod(env, srcPrinterJob, jm_getCopies); // AWT_THREADING Safe (known object)
436    CHECK_EXCEPTION();
437    [printingDictionary setObject:[NSNumber numberWithInteger:copies] forKey:NSPrintCopies];
438
439    jboolean collated = (*env)->CallBooleanMethod(env, srcPrinterJob, jm_isCollated); // AWT_THREADING Safe (known object)
440    CHECK_EXCEPTION();
441    [printingDictionary setObject:[NSNumber numberWithBool:collated ? YES : NO] forKey:NSPrintMustCollate];
442    jint selectID = (*env)->CallIntMethod(env, srcPrinterJob, jm_getSelectAttrib);
443    CHECK_EXCEPTION();
444    jint fromPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getFromPage);
445    CHECK_EXCEPTION();
446    jint toPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getToPage);
447    CHECK_EXCEPTION();
448    if (selectID ==0) {
449        [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages];
450    } else if (selectID == 2) {
451        // In Mac 10.7,  Print ALL is deselected if PrintSelection is YES whether
452        // NSPrintAllPages is YES or NO
453        [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages];
454        [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintSelectionOnly];
455    } else {
456        jint minPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getMinPage);
457        CHECK_EXCEPTION();
458        jint maxPage = (*env)->CallIntMethod(env, srcPrinterJob, jm_getMaxPage);
459        CHECK_EXCEPTION();
460
461        // for PD_SELECTION or PD_NOSELECTION, check from/to page
462        // to determine which radio button to select
463        if (fromPage > minPage || toPage < maxPage) {
464            [printingDictionary setObject:[NSNumber numberWithBool:NO] forKey:NSPrintAllPages];
465        } else {
466            [printingDictionary setObject:[NSNumber numberWithBool:YES] forKey:NSPrintAllPages];
467        }
468    }
469
470    // setting fromPage and toPage will not be shown in the dialog if printing All pages
471    [printingDictionary setObject:[NSNumber numberWithInteger:fromPage] forKey:NSPrintFirstPage];
472    [printingDictionary setObject:[NSNumber numberWithInteger:toPage] forKey:NSPrintLastPage];
473
474    jobject page = (*env)->CallObjectMethod(env, srcPrinterJob, jm_getPageFormat);
475    CHECK_EXCEPTION();
476    if (page != NULL) {
477        javaPageFormatToNSPrintInfo(env, NULL, page, dst);
478    }
479}
480
481/*
482 * Class:     sun_lwawt_macosx_CPrinterJob
483 * Method:    abortDoc
484 * Signature: ()V
485 */
486JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_abortDoc
487  (JNIEnv *env, jobject jthis)
488{
489JNI_COCOA_ENTER(env);
490    // This is only called during the printLoop from the printLoop thread
491    NSPrintOperation* printLoop = [NSPrintOperation currentOperation];
492    NSPrintInfo* printInfo = [printLoop printInfo];
493    [printInfo setJobDisposition:NSPrintCancelJob];
494JNI_COCOA_EXIT(env);
495}
496
497/*
498 * Class:     sun_lwawt_macosx_CPrinterJob
499 * Method:    getDefaultPage
500 * Signature: (Ljava/awt/print/PageFormat;)V
501 */
502JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_getDefaultPage
503  (JNIEnv *env, jobject jthis, jobject page)
504{
505JNI_COCOA_ENTER(env);
506    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
507
508    nsPrintInfoToJavaPageFormat(env, printInfo, page);
509
510    [printInfo release];
511JNI_COCOA_EXIT(env);
512}
513
514/*
515 * Class:     sun_lwawt_macosx_CPrinterJob
516 * Method:    validatePaper
517 * Signature: (Ljava/awt/print/Paper;Ljava/awt/print/Paper;)V
518 */
519JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_validatePaper
520  (JNIEnv *env, jobject jthis, jobject origpaper, jobject newpaper)
521{
522JNI_COCOA_ENTER(env);
523
524
525    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
526    javaPaperToNSPrintInfo(env, origpaper, printInfo);
527    makeBestFit(printInfo);
528    nsPrintInfoToJavaPaper(env, printInfo, newpaper);
529    [printInfo release];
530
531JNI_COCOA_EXIT(env);
532}
533
534/*
535 * Class:     sun_lwawt_macosx_CPrinterJob
536 * Method:    createNSPrintInfo
537 * Signature: ()J
538 */
539JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPrinterJob_createNSPrintInfo
540  (JNIEnv *env, jobject jthis)
541{
542    jlong result = -1;
543JNI_COCOA_ENTER(env);
544    // This is used to create the NSPrintInfo for this PrinterJob. Thread
545    //  safety is assured by the java side of this call.
546
547    NSPrintInfo* printInfo = createDefaultNSPrintInfo(env, NULL);
548
549    result = ptr_to_jlong(printInfo);
550
551JNI_COCOA_EXIT(env);
552    return result;
553}
554
555/*
556 * Class:     sun_lwawt_macosx_CPrinterJob
557 * Method:    dispose
558 * Signature: (J)V
559 */
560JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPrinterJob_dispose
561  (JNIEnv *env, jobject jthis, jlong nsPrintInfo)
562{
563JNI_COCOA_ENTER(env);
564    if (nsPrintInfo != -1)
565    {
566        NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr(nsPrintInfo);
567        [printInfo release];
568    }
569JNI_COCOA_EXIT(env);
570}
571
572
573/*
574 * Class:     sun_lwawt_macosx_CPrinterJob
575 * Method:    printLoop
576 * Signature: ()V
577 */
578JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJob_printLoop
579  (JNIEnv *env, jobject jthis, jboolean blocks, jint firstPage, jint lastPage)
580{
581    AWT_ASSERT_NOT_APPKIT_THREAD;
582
583    GET_CPRINTERJOB_CLASS_RETURN(NO);
584    DECLARE_METHOD_RETURN(jm_getPageFormat, sjc_CPrinterJob, "getPageFormat", "(I)Ljava/awt/print/PageFormat;", NO);
585    DECLARE_METHOD_RETURN(jm_getPageFormatArea, sjc_CPrinterJob, "getPageFormatArea", "(Ljava/awt/print/PageFormat;)Ljava/awt/geom/Rectangle2D;", NO);
586    DECLARE_METHOD_RETURN(jm_getPrinterName, sjc_CPrinterJob, "getPrinterName", "()Ljava/lang/String;", NO);
587    DECLARE_METHOD_RETURN(jm_getPageable, sjc_CPrinterJob, "getPageable", "()Ljava/awt/print/Pageable;", NO);
588    DECLARE_METHOD_RETURN(jm_getPrinterTray, sjc_CPrinterJob, "getPrinterTray", "()Ljava/lang/String;", NO);
589
590    jboolean retVal = JNI_FALSE;
591
592JNI_COCOA_ENTER(env);
593    // Get the first page's PageFormat for setting things up (This introduces
594    //  and is a facet of the same problem in Radar 2818593/2708932).
595    jobject page = (*env)->CallObjectMethod(env, jthis, jm_getPageFormat, 0); // AWT_THREADING Safe (!appKit)
596    CHECK_EXCEPTION();
597    if (page != NULL) {
598        jobject pageFormatArea = (*env)->CallObjectMethod(env, jthis, jm_getPageFormatArea, page); // AWT_THREADING Safe (!appKit)
599        CHECK_EXCEPTION();
600
601        PrinterView* printerView = [[PrinterView alloc] initWithFrame:JavaToNSRect(env, pageFormatArea) withEnv:env withPrinterJob:jthis];
602        [printerView setFirstPage:firstPage lastPage:lastPage];
603
604        GET_NSPRINTINFO_METHOD_RETURN(NO)
605        NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, jthis, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
606        CHECK_EXCEPTION();
607        jobject printerTrayObj = (*env)->CallObjectMethod(env, jthis, jm_getPrinterTray);
608        CHECK_EXCEPTION();
609        if (printerTrayObj != NULL) {
610            NSString *printerTray = JavaStringToNSString(env, printerTrayObj);
611            if (printerTray != nil) {
612                [[printInfo printSettings] setObject:printerTray forKey:@"InputSlot"];
613            }
614        }
615
616        // <rdar://problem/4156975> passing jthis CPrinterJob as well, so we can extract the printer name from the current job
617        javaPageFormatToNSPrintInfo(env, jthis, page, printInfo);
618
619        // <rdar://problem/4093799> NSPrinterInfo is not correctly set to the selected printer
620        // from the Java side of CPrinterJob. Had always assumed the default printer was the one we wanted.
621        jobject printerNameObj = (*env)->CallObjectMethod(env, jthis, jm_getPrinterName);
622        CHECK_EXCEPTION();
623        if (printerNameObj != NULL) {
624            NSString *printerName = JavaStringToNSString(env, printerNameObj);
625            if (printerName != nil) {
626                NSPrinter *printer = [NSPrinter printerWithName:printerName];
627                if (printer != nil) [printInfo setPrinter:printer];
628            }
629        }
630
631        // <rdar://problem/4367998> JTable.print attributes are ignored
632        jobject pageable = (*env)->CallObjectMethod(env, jthis, jm_getPageable); // AWT_THREADING Safe (!appKit)
633        CHECK_EXCEPTION();
634        javaPrinterJobToNSPrintInfo(env, jthis, pageable, printInfo);
635
636        PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
637
638        (void)[printModel runPrintLoopWithView:printerView waitUntilDone:blocks withEnv:env];
639
640        // Only set this if we got far enough to call runPrintLoopWithView, or we will spin CPrinterJob.print() forever!
641        retVal = JNI_TRUE;
642
643        [printModel release];
644        [printerView release];
645
646        if (page != NULL)
647        {
648            (*env)->DeleteLocalRef(env, page);
649        }
650
651        if (pageFormatArea != NULL)
652        {
653            (*env)->DeleteLocalRef(env, pageFormatArea);
654        }
655    }
656JNI_COCOA_EXIT(env);
657    return retVal;
658}
659
660/*
661 * Class:     sun_lwawt_macosx_CPrinterPageDialog
662 * Method:    showDialog
663 * Signature: ()Z
664 */
665JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterPageDialog_showDialog
666  (JNIEnv *env, jobject jthis)
667{
668
669    DECLARE_CLASS_RETURN(jc_CPrinterPageDialog, "sun/lwawt/macosx/CPrinterPageDialog", NO);
670    DECLARE_FIELD_RETURN(jm_page, jc_CPrinterPageDialog, "fPage", "Ljava/awt/print/PageFormat;", NO);
671
672    jboolean result = JNI_FALSE;
673JNI_COCOA_ENTER(env);
674    GET_CPRINTERDIALOG_FIELD_RETURN(NO);
675    GET_NSPRINTINFO_METHOD_RETURN(NO)
676    jobject printerJob = (*env)->GetObjectField(env, jthis, sjm_printerJob);
677    if (printerJob == NULL) return NO;
678    NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
679    CHECK_EXCEPTION();
680    if (printInfo == NULL) return result;
681
682    jobject page = (*env)->GetObjectField(env, jthis, jm_page);
683    if (page == NULL) return NO;
684
685    // <rdar://problem/4156975> passing NULL, because only a CPrinterJob has a real printer associated with it
686    javaPageFormatToNSPrintInfo(env, NULL, page, printInfo);
687
688    PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
689    result = [printModel runPageSetup];
690    [printModel release];
691
692    if (result)
693    {
694        nsPrintInfoToJavaPageFormat(env, printInfo, page);
695    }
696
697    if (printerJob != NULL)
698    {
699        (*env)->DeleteLocalRef(env, printerJob);
700    }
701
702    if (page != NULL)
703    {
704        (*env)->DeleteLocalRef(env, page);
705    }
706
707JNI_COCOA_EXIT(env);
708    return result;
709}
710
711/*
712 * Class:     sun_lwawt_macosx_CPrinterJobDialog
713 * Method:    showDialog
714 * Signature: ()Z
715 */
716JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CPrinterJobDialog_showDialog
717  (JNIEnv *env, jobject jthis)
718{
719    DECLARE_CLASS_RETURN(jc_CPrinterJobDialog, "sun/lwawt/macosx/CPrinterJobDialog", NO);
720    DECLARE_FIELD_RETURN(jm_pageable, jc_CPrinterJobDialog, "fPageable", "Ljava/awt/print/Pageable;", NO);
721
722    jboolean result = JNI_FALSE;
723JNI_COCOA_ENTER(env);
724    GET_CPRINTERDIALOG_FIELD_RETURN(NO);
725    jobject printerJob = (*env)->GetObjectField(env, jthis, sjm_printerJob);
726    if (printerJob == NULL) return NO;
727    GET_NSPRINTINFO_METHOD_RETURN(NO)
728    NSPrintInfo* printInfo = (NSPrintInfo*)jlong_to_ptr((*env)->CallLongMethod(env, printerJob, sjm_getNSPrintInfo)); // AWT_THREADING Safe (known object)
729
730    jobject pageable = (*env)->GetObjectField(env, jthis, jm_pageable);
731    if (pageable == NULL) return NO;
732
733    javaPrinterJobToNSPrintInfo(env, printerJob, pageable, printInfo);
734
735    PrintModel* printModel = [[PrintModel alloc] initWithPrintInfo:printInfo];
736    result = [printModel runJobSetup];
737    [printModel release];
738
739    if (result)
740    {
741        nsPrintInfoToJavaPrinterJob(env, printInfo, printerJob, pageable);
742    }
743
744    if (printerJob != NULL)
745    {
746        (*env)->DeleteLocalRef(env, printerJob);
747    }
748
749    if (pageable != NULL)
750    {
751        (*env)->DeleteLocalRef(env, pageable);
752    }
753
754JNI_COCOA_EXIT(env);
755    return result;
756}
757