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