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 
  37 static JNF_CLASS_CACHE(sjc_CPrinterJob, "sun/lwawt/macosx/CPrinterJob");
  38 static 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