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