1/*
2 * Copyright (c) 2011, 2013, 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#import "PrinterView.h"
27
28#import "java_awt_print_Pageable.h"
29#import "java_awt_print_PageFormat.h"
30
31#import <JavaNativeFoundation/JavaNativeFoundation.h>
32
33#import "ThreadUtilities.h"
34#import "GeomUtilities.h"
35
36
37static JNF_CLASS_CACHE(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
38static JNF_CLASS_CACHE(sjc_PageFormat, "java/awt/print/PageFormat");
39
40@implementation PrinterView
41
42- (id)initWithFrame:(NSRect)aRect withEnv:(JNIEnv*)env withPrinterJob:(jobject)printerJob
43{
44    self = [super initWithFrame:aRect];
45    if (self)
46    {
47        fPrinterJob = JNFNewGlobalRef(env, printerJob);
48        fCurPageFormat = NULL;
49        fCurPainter = NULL;
50        fCurPeekGraphics = NULL;
51    }
52    return self;
53}
54
55- (void)releaseReferences:(JNIEnv*)env
56{
57    if (fCurPageFormat != NULL)
58    {
59        JNFDeleteGlobalRef(env, fCurPageFormat);
60        fCurPageFormat = NULL;
61    }
62    if (fCurPainter != NULL)
63    {
64        JNFDeleteGlobalRef(env, fCurPainter);
65        fCurPainter = NULL;
66    }
67    if (fCurPeekGraphics != NULL)
68    {
69        JNFDeleteGlobalRef(env, fCurPeekGraphics);
70        fCurPeekGraphics = NULL;
71    }
72}
73
74- (void)setFirstPage:(jint)firstPage lastPage:(jint)lastPage {
75    fFirstPage = firstPage;
76    fLastPage = lastPage;
77}
78
79- (void)drawRect:(NSRect)aRect
80{
81    AWT_ASSERT_NOT_APPKIT_THREAD;
82
83    static JNF_MEMBER_CACHE(jm_printToPathGraphics, sjc_CPrinterJob, "printToPathGraphics", "(Lsun/print/PeekGraphics;Ljava/awt/print/PrinterJob;Ljava/awt/print/Printable;Ljava/awt/print/PageFormat;IJ)V");
84
85    // Create and draw into a new CPrinterGraphics with the current Context.
86    assert(fCurPageFormat != NULL);
87    assert(fCurPainter != NULL);
88    assert(fCurPeekGraphics != NULL);
89
90    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
91
92    if ([self cancelCheck:env])
93    {
94        [self releaseReferences:env];
95        return;
96    }
97
98    NSPrintOperation* printLoop = [NSPrintOperation currentOperation];
99    jint jPageIndex = [printLoop currentPage] - 1;
100
101    jlong context = ptr_to_jlong([printLoop context]);
102    CGContextRef cgRef = (CGContextRef)[[printLoop context] graphicsPort];
103    CGContextSaveGState(cgRef); //04/28/2004: state needs to be saved here due to addition of lazy state management
104
105    JNFCallVoidMethod(env, fPrinterJob, jm_printToPathGraphics, fCurPeekGraphics, fPrinterJob, fCurPainter, fCurPageFormat, jPageIndex, context); // AWT_THREADING Safe (AWTRunLoop)
106
107    CGContextRestoreGState(cgRef);
108
109    [self releaseReferences:env];
110}
111
112- (NSString*)printJobTitle
113{
114    AWT_ASSERT_NOT_APPKIT_THREAD;
115
116    static JNF_MEMBER_CACHE(jm_getJobName, sjc_CPrinterJob, "getJobName", "()Ljava/lang/String;");
117
118    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
119
120    jobject o = JNFCallObjectMethod(env, fPrinterJob, jm_getJobName); // AWT_THREADING Safe (known object)
121    id result = JNFJavaToNSString(env, o);
122    (*env)->DeleteLocalRef(env, o);
123    return result;
124}
125
126- (BOOL)knowsPageRange:(NSRangePointer)aRange
127{
128    AWT_ASSERT_NOT_APPKIT_THREAD;
129
130    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
131    if ([self cancelCheck:env])
132    {
133        return NO;
134    }
135
136    aRange->location = fFirstPage + 1;
137
138    if (fLastPage == java_awt_print_Pageable_UNKNOWN_NUMBER_OF_PAGES)
139    {
140        aRange->length = NSIntegerMax;
141    }
142    else
143    {
144        aRange->length = (fLastPage + 1) - fFirstPage;
145    }
146
147    return YES;
148}
149
150- (NSRect)rectForPage:(NSInteger)pageNumber
151{
152    AWT_ASSERT_NOT_APPKIT_THREAD;
153
154    static JNF_MEMBER_CACHE(jm_getPageformatPrintablePeekgraphics, sjc_CPrinterJob, "getPageformatPrintablePeekgraphics", "(I)[Ljava/lang/Object;");
155    static JNF_MEMBER_CACHE(jm_printAndGetPageFormatArea, sjc_CPrinterJob, "printAndGetPageFormatArea", "(Ljava/awt/print/Printable;Ljava/awt/Graphics;Ljava/awt/print/PageFormat;I)Ljava/awt/geom/Rectangle2D;");
156    static JNF_MEMBER_CACHE(jm_getOrientation, sjc_PageFormat, "getOrientation", "()I");
157
158    // Assertions removed, and corresponding JNFDeleteGlobalRefs added, for radr://3962543
159    // Actual fix that will keep these assertions from being true is radr://3205462 ,
160    // which will hopefully be fixed by the blocking AppKit bug radr://3056694
161    //assert(fCurPageFormat == NULL);
162    //assert(fCurPainter == NULL);
163    //assert(fCurPeekGraphics == NULL);
164
165    JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
166    if(fCurPageFormat != NULL) {
167        JNFDeleteGlobalRef(env, fCurPageFormat);
168    }
169    if(fCurPainter != NULL) {
170        JNFDeleteGlobalRef(env, fCurPainter);
171    }
172    if(fCurPeekGraphics != NULL) {
173        JNFDeleteGlobalRef(env, fCurPeekGraphics);
174    }
175
176    //+++gdb Check the pageNumber for validity (PageAttrs)
177
178    jint jPageNumber = pageNumber - 1;
179
180    NSRect result;
181
182    if ([self cancelCheck:env])
183    {
184        return NSZeroRect;
185    }
186
187    jobjectArray objectArray = JNFCallObjectMethod(env, fPrinterJob, jm_getPageformatPrintablePeekgraphics, jPageNumber); // AWT_THREADING Safe (AWTRunLoopMode)
188    if (objectArray != NULL) {
189        // Get references to the return objects -> PageFormat, Printable, PeekGraphics
190        // Cheat - we know we either got NULL or a 3 element array
191        jobject pageFormat = (*env)->GetObjectArrayElement(env, objectArray, 0);
192        fCurPageFormat = JNFNewGlobalRef(env, pageFormat);
193        (*env)->DeleteLocalRef(env, pageFormat);
194
195        jobject painter = (*env)->GetObjectArrayElement(env, objectArray, 1);
196        fCurPainter = JNFNewGlobalRef(env, painter);
197        (*env)->DeleteLocalRef(env, painter);
198
199        jobject peekGraphics = (*env)->GetObjectArrayElement(env, objectArray, 2);
200        fCurPeekGraphics = JNFNewGlobalRef(env, peekGraphics);
201        (*env)->DeleteLocalRef(env, peekGraphics);
202
203        // Actually print and get the PageFormatArea
204        jobject pageFormatArea = JNFCallObjectMethod(env, fPrinterJob, jm_printAndGetPageFormatArea, fCurPainter, fCurPeekGraphics, fCurPageFormat, jPageNumber); // AWT_THREADING Safe (AWTRunLoopMode)
205        if (pageFormatArea != NULL) {
206            NSPrintingOrientation currentOrientation = 
207                    [[[NSPrintOperation currentOperation] printInfo] orientation];
208            // set page orientation
209            switch (JNFCallIntMethod(env, fCurPageFormat, jm_getOrientation)) { 
210                case java_awt_print_PageFormat_PORTRAIT:
211                default:
212                    if (currentOrientation != NSPortraitOrientation) {
213                        [[[NSPrintOperation currentOperation] printInfo] 
214                                            setOrientation:NSPortraitOrientation];
215                    }
216                    break;
217
218                case java_awt_print_PageFormat_LANDSCAPE:
219                case java_awt_print_PageFormat_REVERSE_LANDSCAPE:
220                    if (currentOrientation != NSLandscapeOrientation) {
221                        [[[NSPrintOperation currentOperation] printInfo] 
222                                            setOrientation:NSLandscapeOrientation];
223                    }
224                    break;
225                }
226            result = JavaToNSRect(env, pageFormatArea);
227            (*env)->DeleteLocalRef(env, pageFormatArea);
228        } else {
229            [self releaseReferences:env];
230            result = NSZeroRect;
231        }
232
233        (*env)->DeleteLocalRef(env, objectArray);
234    } else {
235        [self releaseReferences:env];
236        result = NSZeroRect;
237    }
238
239    return result;
240}
241
242- (BOOL)cancelCheck:(JNIEnv*)env
243{
244    AWT_ASSERT_NOT_APPKIT_THREAD;
245
246    static JNF_MEMBER_CACHE(jm_cancelCheck, sjc_CPrinterJob, "cancelCheck", "()Z");
247
248    return JNFCallBooleanMethod(env, fPrinterJob, jm_cancelCheck); // AWT_THREADING Safe (known object)
249}
250
251// This is called by -[PrintModel safePrintLoop]
252- (void)complete:(JNIEnv*)env
253{
254    AWT_ASSERT_NOT_APPKIT_THREAD;
255
256    static JNF_MEMBER_CACHE(jf_completePrintLoop, sjc_CPrinterJob, "completePrintLoop", "()V");
257    JNFCallVoidMethod(env, fPrinterJob, jf_completePrintLoop);
258
259    // Clean up after ourselves
260    // Can't put these into -dealloc since that happens (potentially) after the JNIEnv is stale
261    [self releaseReferences:env];
262    if (fPrinterJob != NULL)
263    {
264        JNFDeleteGlobalRef(env, fPrinterJob);
265        fPrinterJob = NULL;
266    }
267}
268
269- (BOOL)isFlipped
270{
271    return TRUE;
272}
273
274@end
275