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 package sun.lwawt.macosx; 27 28 29 import java.awt.*; 30 import java.awt.geom.Rectangle2D; 31 import java.awt.image.BufferedImage; 32 import java.awt.print.*; 33 import java.security.AccessController; 34 import java.security.PrivilegedAction; 35 36 import javax.print.*; 37 import javax.print.attribute.PrintRequestAttributeSet; 38 import javax.print.attribute.HashPrintRequestAttributeSet; 39 import javax.print.attribute.standard.Media; 40 import javax.print.attribute.standard.MediaPrintableArea; 41 import javax.print.attribute.standard.MediaSize; 42 import javax.print.attribute.standard.MediaSizeName; 43 import javax.print.attribute.standard.PageRanges; 44 45 import sun.java2d.*; 46 import sun.print.*; 47 48 public final class CPrinterJob extends RasterPrinterJob { 49 // NOTE: This uses RasterPrinterJob as a base, but it doesn't use 50 // all of the RasterPrinterJob functions. RasterPrinterJob will 51 // break down printing to pieces that aren't necessary under MacOSX 52 // printing, such as controlling the # of copies and collating. These 53 // are handled by the native printing. RasterPrinterJob is kept for 54 // future compatibility and the state keeping that it handles. 55 56 private static String sShouldNotReachHere = "Should not reach here."; 57 58 private volatile SecondaryLoop printingLoop; 59 60 private boolean noDefaultPrinter = false; 61 62 private static Font defaultFont; 63 64 // This is the NSPrintInfo for this PrinterJob. Protect multi thread 65 // access to it. It is used by the pageDialog, jobDialog, and printLoop. 66 // This way the state of these items is shared across these calls. 67 // PageFormat data is passed in and set on the fNSPrintInfo on a per call 68 // basis. 69 private long fNSPrintInfo = -1; 70 private Object fNSPrintInfoLock = new Object(); 71 72 static { 73 // AWT has to be initialized for the native code to function correctly. Toolkit.getDefaultToolkit()74 Toolkit.getDefaultToolkit(); 75 } 76 77 /** 78 * Presents a dialog to the user for changing the properties of 79 * the print job. 80 * This method will display a native dialog if a native print 81 * service is selected, and user choice of printers will be restricted 82 * to these native print services. 83 * To present the cross platform print dialog for all services, 84 * including native ones instead use 85 * <code>printDialog(PrintRequestAttributeSet)</code>. 86 * <p> 87 * PrinterJob implementations which can use PrintService's will update 88 * the PrintService for this PrinterJob to reflect the new service 89 * selected by the user. 90 * @return <code>true</code> if the user does not cancel the dialog; 91 * <code>false</code> otherwise. 92 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 93 * returns true. 94 * @see java.awt.GraphicsEnvironment#isHeadless 95 */ 96 @Override printDialog()97 public boolean printDialog() throws HeadlessException { 98 if (GraphicsEnvironment.isHeadless()) { 99 throw new HeadlessException(); 100 } 101 102 if (noDefaultPrinter) { 103 return false; 104 } 105 106 if (attributes == null) { 107 attributes = new HashPrintRequestAttributeSet(); 108 } 109 110 if (getPrintService() instanceof StreamPrintService) { 111 return super.printDialog(attributes); 112 } 113 114 return jobSetup(getPageable(), checkAllowedToPrintToFile()); 115 } 116 117 /** 118 * Displays a dialog that allows modification of a 119 * <code>PageFormat</code> instance. 120 * The <code>page</code> argument is used to initialize controls 121 * in the page setup dialog. 122 * If the user cancels the dialog then this method returns the 123 * original <code>page</code> object unmodified. 124 * If the user okays the dialog then this method returns a new 125 * <code>PageFormat</code> object with the indicated changes. 126 * In either case, the original <code>page</code> object is 127 * not modified. 128 * @param page the default <code>PageFormat</code> presented to the 129 * user for modification 130 * @return the original <code>page</code> object if the dialog 131 * is cancelled; a new <code>PageFormat</code> object 132 * containing the format indicated by the user if the 133 * dialog is acknowledged. 134 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 135 * returns true. 136 * @see java.awt.GraphicsEnvironment#isHeadless 137 * @since 1.2 138 */ 139 @Override pageDialog(PageFormat page)140 public PageFormat pageDialog(PageFormat page) throws HeadlessException { 141 if (GraphicsEnvironment.isHeadless()) { 142 throw new HeadlessException(); 143 } 144 145 if (noDefaultPrinter) { 146 return page; 147 } 148 149 if (getPrintService() instanceof StreamPrintService) { 150 return super.pageDialog(page); 151 } 152 153 PageFormat pageClone = (PageFormat) page.clone(); 154 boolean doIt = pageSetup(pageClone, null); 155 return doIt ? pageClone : page; 156 } 157 158 /** 159 * Clones the <code>PageFormat</code> argument and alters the 160 * clone to describe a default page size and orientation. 161 * @param page the <code>PageFormat</code> to be cloned and altered 162 * @return clone of <code>page</code>, altered to describe a default 163 * <code>PageFormat</code>. 164 */ 165 @Override defaultPage(PageFormat page)166 public PageFormat defaultPage(PageFormat page) { 167 PageFormat newPage = (PageFormat)page.clone(); 168 getDefaultPage(newPage); 169 return newPage; 170 } 171 172 @Override setAttributes(PrintRequestAttributeSet attributes)173 protected void setAttributes(PrintRequestAttributeSet attributes) throws PrinterException { 174 super.setAttributes(attributes); 175 176 if (attributes == null) { 177 return; 178 } 179 180 PageRanges pageRangesAttr = (PageRanges)attributes.get(PageRanges.class); 181 if (isSupportedValue(pageRangesAttr, attributes)) { 182 SunPageSelection rangeSelect = (SunPageSelection)attributes.get(SunPageSelection.class); 183 // If rangeSelect is not null, we are using AWT's print dialog that has 184 // All, Selection, and Range radio buttons 185 if (rangeSelect == null || rangeSelect == SunPageSelection.RANGE) { 186 int[][] range = pageRangesAttr.getMembers(); 187 // setPageRange will set firstPage and lastPage as called in getFirstPage 188 // and getLastPage 189 setPageRange(range[0][0] - 1, range[0][1] - 1); 190 } 191 } 192 } 193 194 volatile boolean onEventThread; 195 196 @Override cancelDoc()197 protected void cancelDoc() throws PrinterAbortException { 198 super.cancelDoc(); 199 if (printingLoop != null) { 200 printingLoop.exit(); 201 } 202 } 203 completePrintLoop()204 private void completePrintLoop() { 205 Runnable r = new Runnable() { public void run() { 206 synchronized(this) { 207 performingPrinting = false; 208 } 209 if (printingLoop != null) { 210 printingLoop.exit(); 211 } 212 }}; 213 214 if (onEventThread) { 215 try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); } 216 } else { 217 r.run(); 218 } 219 } 220 221 @Override print(PrintRequestAttributeSet attributes)222 public void print(PrintRequestAttributeSet attributes) throws PrinterException { 223 // NOTE: Some of this code is copied from RasterPrinterJob. 224 225 226 // this code uses javax.print APIs 227 // this will make it print directly to the printer 228 // this will not work if the user clicks on the "Preview" button 229 // However if the printer is a StreamPrintService, its the right path. 230 PrintService psvc = getPrintService(); 231 232 if (psvc == null) { 233 throw new PrinterException("No print service found."); 234 } 235 236 if (psvc instanceof StreamPrintService) { 237 spoolToService(psvc, attributes); 238 return; 239 } 240 241 242 setAttributes(attributes); 243 // throw exception for invalid destination 244 if (destinationAttr != null) { 245 validateDestination(destinationAttr); 246 } 247 248 /* Get the range of pages we are to print. If the 249 * last page to print is unknown, then we print to 250 * the end of the document. Note that firstPage 251 * and lastPage are 0 based page indices. 252 */ 253 254 int firstPage = getFirstPage(); 255 int lastPage = getLastPage(); 256 if(lastPage == Pageable.UNKNOWN_NUMBER_OF_PAGES) { 257 int totalPages = mDocument.getNumberOfPages(); 258 if (totalPages != Pageable.UNKNOWN_NUMBER_OF_PAGES) { 259 lastPage = mDocument.getNumberOfPages() - 1; 260 } 261 } 262 263 try { 264 synchronized (this) { 265 performingPrinting = true; 266 userCancelled = false; 267 } 268 269 //Add support for PageRange 270 PageRanges pr = (attributes == null) ? null 271 : (PageRanges)attributes.get(PageRanges.class); 272 int[][] prMembers = (pr == null) ? new int[0][0] : pr.getMembers(); 273 int loopi = 0; 274 do { 275 if (EventQueue.isDispatchThread()) { 276 // This is an AWT EventQueue, and this print rendering loop needs to block it. 277 278 onEventThread = true; 279 280 printingLoop = AccessController.doPrivileged(new PrivilegedAction<SecondaryLoop>() { 281 @Override 282 public SecondaryLoop run() { 283 return Toolkit.getDefaultToolkit() 284 .getSystemEventQueue() 285 .createSecondaryLoop(); 286 } 287 }); 288 289 try { 290 // Fire off the print rendering loop on the AppKit thread, and don't have 291 // it wait and block this thread. 292 if (printLoop(false, firstPage, lastPage)) { 293 // Start a secondary loop on EDT until printing operation is finished or cancelled 294 printingLoop.enter(); 295 } 296 } catch (Exception e) { 297 e.printStackTrace(); 298 } 299 } else { 300 // Fire off the print rendering loop on the AppKit, and block this thread 301 // until it is done. 302 // But don't actually block... we need to come back here! 303 onEventThread = false; 304 305 try { 306 printLoop(true, firstPage, lastPage); 307 } catch (Exception e) { 308 e.printStackTrace(); 309 } 310 } 311 if (++loopi < prMembers.length) { 312 firstPage = prMembers[loopi][0]-1; 313 lastPage = prMembers[loopi][1] -1; 314 } 315 } while (loopi < prMembers.length); 316 } finally { 317 synchronized (this) { 318 // NOTE: Native code shouldn't allow exceptions out while 319 // printing. They should cancel the print loop. 320 performingPrinting = false; 321 notify(); 322 } 323 if (printingLoop != null) { 324 printingLoop.exit(); 325 } 326 } 327 328 // Normalize the collated, # copies, numPages, first/last pages. Need to 329 // make note of pageRangesAttr. 330 331 // Set up NSPrintInfo with the java settings (PageFormat & Paper). 332 333 // Create an NSView for printing. Have knowsPageRange return YES, and give the correct 334 // range, or MAX? if unknown. Have rectForPage do a peekGraphics check before returning 335 // the rectangle. Have drawRect do the real render of the page. Have printJobTitle do 336 // the right thing. 337 338 // Call NSPrintOperation, it will call NSView.drawRect: for each page. 339 340 // NSView.drawRect: will create a CPrinterGraphics with the current CGContextRef, and then 341 // pass this Graphics onto the Printable with the appropriate PageFormat and index. 342 343 // Need to be able to cancel the NSPrintOperation (using code from RasterPrinterJob, be 344 // sure to initialize userCancelled and performingPrinting member variables). 345 346 // Extensions available from AppKit: Print to PDF or EPS file! 347 } 348 349 /** 350 * Returns the resolution in dots per inch across the width 351 * of the page. 352 */ 353 @Override getXRes()354 protected double getXRes() { 355 // NOTE: This is not used in the CPrinterJob code path. 356 return 0; 357 } 358 359 /** 360 * Returns the resolution in dots per inch down the height 361 * of the page. 362 */ 363 @Override getYRes()364 protected double getYRes() { 365 // NOTE: This is not used in the CPrinterJob code path. 366 return 0; 367 } 368 369 /** 370 * Must be obtained from the current printer. 371 * Value is in device pixels. 372 * Not adjusted for orientation of the paper. 373 */ 374 @Override getPhysicalPrintableX(Paper p)375 protected double getPhysicalPrintableX(Paper p) { 376 // NOTE: This is not used in the CPrinterJob code path. 377 return 0; 378 } 379 380 /** 381 * Must be obtained from the current printer. 382 * Value is in device pixels. 383 * Not adjusted for orientation of the paper. 384 */ 385 @Override getPhysicalPrintableY(Paper p)386 protected double getPhysicalPrintableY(Paper p) { 387 // NOTE: This is not used in the CPrinterJob code path. 388 return 0; 389 } 390 391 /** 392 * Must be obtained from the current printer. 393 * Value is in device pixels. 394 * Not adjusted for orientation of the paper. 395 */ 396 @Override getPhysicalPrintableWidth(Paper p)397 protected double getPhysicalPrintableWidth(Paper p) { 398 // NOTE: This is not used in the CPrinterJob code path. 399 return 0; 400 } 401 402 /** 403 * Must be obtained from the current printer. 404 * Value is in device pixels. 405 * Not adjusted for orientation of the paper. 406 */ 407 @Override getPhysicalPrintableHeight(Paper p)408 protected double getPhysicalPrintableHeight(Paper p) { 409 // NOTE: This is not used in the CPrinterJob code path. 410 return 0; 411 } 412 413 /** 414 * Must be obtained from the current printer. 415 * Value is in device pixels. 416 * Not adjusted for orientation of the paper. 417 */ 418 @Override getPhysicalPageWidth(Paper p)419 protected double getPhysicalPageWidth(Paper p) { 420 // NOTE: This is not used in the CPrinterJob code path. 421 return 0; 422 } 423 424 /** 425 * Must be obtained from the current printer. 426 * Value is in device pixels. 427 * Not adjusted for orientation of the paper. 428 */ 429 @Override getPhysicalPageHeight(Paper p)430 protected double getPhysicalPageHeight(Paper p) { 431 // NOTE: This is not used in the CPrinterJob code path. 432 return 0; 433 } 434 435 /** 436 * Begin a new page. This call's Window's 437 * StartPage routine. 438 */ startPage(PageFormat format, Printable painter, int index)439 protected void startPage(PageFormat format, Printable painter, int index) throws PrinterException { 440 // NOTE: This is not used in the CPrinterJob code path. 441 throw new PrinterException(sShouldNotReachHere); 442 } 443 444 /** 445 * End a page. 446 */ 447 @Override endPage(PageFormat format, Printable painter, int index)448 protected void endPage(PageFormat format, Printable painter, int index) throws PrinterException { 449 // NOTE: This is not used in the CPrinterJob code path. 450 throw new PrinterException(sShouldNotReachHere); 451 } 452 453 /** 454 * Prints the contents of the array of ints, 'data' 455 * to the current page. The band is placed at the 456 * location (x, y) in device coordinates on the 457 * page. The width and height of the band is 458 * specified by the caller. 459 */ 460 @Override printBand(byte[] data, int x, int y, int width, int height)461 protected void printBand(byte[] data, int x, int y, int width, int height) throws PrinterException { 462 // NOTE: This is not used in the CPrinterJob code path. 463 throw new PrinterException(sShouldNotReachHere); 464 } 465 466 /** 467 * Called by the print() method at the start of 468 * a print job. 469 */ 470 @Override startDoc()471 protected void startDoc() throws PrinterException { 472 // NOTE: This is not used in the CPrinterJob code path. 473 throw new PrinterException(sShouldNotReachHere); 474 } 475 476 /** 477 * Called by the print() method at the end of 478 * a print job. 479 */ 480 @Override endDoc()481 protected void endDoc() throws PrinterException { 482 // NOTE: This is not used in the CPrinterJob code path. 483 throw new PrinterException(sShouldNotReachHere); 484 } 485 486 /* Called by cancelDoc */ 487 @Override abortDoc()488 protected native void abortDoc(); 489 490 /** 491 * Displays the page setup dialog placing the user's 492 * settings into 'page'. 493 */ pageSetup(PageFormat page, Printable painter)494 public boolean pageSetup(PageFormat page, Printable painter) { 495 CPrinterDialog printerDialog = new CPrinterPageDialog(null, this, page, painter); 496 printerDialog.setVisible(true); 497 boolean result = printerDialog.getRetVal(); 498 printerDialog.dispose(); 499 return result; 500 } 501 502 /** 503 * Displays the print dialog and records the user's settings 504 * into this object. Return false if the user cancels the 505 * dialog. 506 * If the dialog is to use a set of attributes, useAttributes is true. 507 */ jobSetup(Pageable doc, boolean allowPrintToFile)508 private boolean jobSetup(Pageable doc, boolean allowPrintToFile) { 509 CPrinterDialog printerDialog = new CPrinterJobDialog(null, this, doc, allowPrintToFile); 510 printerDialog.setVisible(true); 511 boolean result = printerDialog.getRetVal(); 512 printerDialog.dispose(); 513 return result; 514 } 515 516 /** 517 * Alters the orientation and Paper to match defaults obtained 518 * from a printer. 519 */ getDefaultPage(PageFormat page)520 private native void getDefaultPage(PageFormat page); 521 522 /** 523 * validate the paper size against the current printer. 524 */ 525 @Override validatePaper(Paper origPaper, Paper newPaper )526 protected native void validatePaper(Paper origPaper, Paper newPaper ); 527 528 // The following methods are CPrinterJob specific. 529 530 @Override finalize()531 protected void finalize() { 532 synchronized (fNSPrintInfoLock) { 533 if (fNSPrintInfo != -1) { 534 dispose(fNSPrintInfo); 535 } 536 fNSPrintInfo = -1; 537 } 538 } 539 createNSPrintInfo()540 private native long createNSPrintInfo(); dispose(long printInfo)541 private native void dispose(long printInfo); 542 getNSPrintInfo()543 private long getNSPrintInfo() { 544 // This is called from the native side. 545 synchronized (fNSPrintInfoLock) { 546 if (fNSPrintInfo == -1) { 547 fNSPrintInfo = createNSPrintInfo(); 548 } 549 return fNSPrintInfo; 550 } 551 } 552 printLoop(boolean waitUntilDone, int firstPage, int lastPage)553 private native boolean printLoop(boolean waitUntilDone, int firstPage, int lastPage) throws PrinterException; 554 getPageFormat(int pageIndex)555 private PageFormat getPageFormat(int pageIndex) { 556 // This is called from the native side. 557 PageFormat page; 558 try { 559 page = getPageable().getPageFormat(pageIndex); 560 } catch (Exception e) { 561 return null; 562 } 563 return page; 564 } 565 getPrintable(int pageIndex)566 private Printable getPrintable(int pageIndex) { 567 // This is called from the native side. 568 Printable painter; 569 try { 570 painter = getPageable().getPrintable(pageIndex); 571 } catch (Exception e) { 572 return null; 573 } 574 return painter; 575 } 576 getPrinterName()577 private String getPrinterName(){ 578 // This is called from the native side. 579 PrintService service = getPrintService(); 580 if (service == null) return null; 581 return service.getName(); 582 } 583 setPrinterServiceFromNative(String printerName)584 private void setPrinterServiceFromNative(String printerName) { 585 // This is called from the native side. 586 PrintService[] services = PrintServiceLookup.lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); 587 588 for (int i = 0; i < services.length; i++) { 589 PrintService service = services[i]; 590 591 if (printerName.equals(service.getName())) { 592 try { 593 setPrintService(service); 594 } catch (PrinterException e) { 595 // ignored 596 } 597 return; 598 } 599 } 600 } 601 getPageFormatArea(PageFormat page)602 private Rectangle2D getPageFormatArea(PageFormat page) { 603 Rectangle2D.Double pageFormatArea = 604 new Rectangle2D.Double(page.getImageableX(), 605 page.getImageableY(), 606 page.getImageableWidth(), 607 page.getImageableHeight()); 608 return pageFormatArea; 609 } 610 cancelCheck()611 private boolean cancelCheck() { 612 // This is called from the native side. 613 614 // This is used to avoid deadlock 615 // We would like to just call if isCancelled(), 616 // but that will block the AppKit thread against whomever is holding the synchronized lock 617 boolean cancelled = (performingPrinting && userCancelled); 618 if (cancelled) { 619 try { 620 LWCToolkit.invokeLater(new Runnable() { public void run() { 621 try { 622 cancelDoc(); 623 } catch (PrinterAbortException pae) { 624 // no-op, let the native side handle it 625 } 626 }}, null); 627 } catch (java.lang.reflect.InvocationTargetException ite) {} 628 } 629 return cancelled; 630 } 631 createFirstPassGraphics(PrinterJob printerJob, PageFormat page)632 private PeekGraphics createFirstPassGraphics(PrinterJob printerJob, PageFormat page) { 633 // This is called from the native side. 634 BufferedImage bimg = new BufferedImage((int)Math.round(page.getWidth()), (int)Math.round(page.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE); 635 PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob); 636 Rectangle2D pageFormatArea = getPageFormatArea(page); 637 initPrinterGraphics(peekGraphics, pageFormatArea); 638 return peekGraphics; 639 } 640 printToPathGraphics( final PeekGraphics graphics, final PrinterJob printerJob, final Printable painter, final PageFormat page, final int pageIndex, final long context)641 private void printToPathGraphics( final PeekGraphics graphics, // Always an actual PeekGraphics 642 final PrinterJob printerJob, // Always an actual CPrinterJob 643 final Printable painter, // Client class 644 final PageFormat page, // Client class 645 final int pageIndex, 646 final long context) throws PrinterException { 647 // This is called from the native side. 648 Runnable r = new Runnable() { public void run() { 649 try { 650 SurfaceData sd = CPrinterSurfaceData.createData(page, context); // Just stores page into an ivar 651 if (defaultFont == null) { 652 defaultFont = new Font("Dialog", Font.PLAIN, 12); 653 } 654 Graphics2D delegate = new SunGraphics2D(sd, Color.black, Color.white, defaultFont); 655 656 Graphics2D pathGraphics = new CPrinterGraphics(delegate, printerJob); // Just stores delegate into an ivar 657 Rectangle2D pageFormatArea = getPageFormatArea(page); 658 initPrinterGraphics(pathGraphics, pageFormatArea); 659 painter.print(pathGraphics, page, pageIndex); 660 delegate.dispose(); 661 delegate = null; 662 } catch (PrinterException pe) { throw new java.lang.reflect.UndeclaredThrowableException(pe); } 663 }}; 664 665 if (onEventThread) { 666 try { EventQueue.invokeAndWait(r); 667 } catch (java.lang.reflect.InvocationTargetException ite) { 668 Throwable te = (Throwable)ite.getTargetException(); 669 if (te instanceof PrinterException) throw (PrinterException)te; 670 else te.printStackTrace(); 671 } catch (Exception e) { e.printStackTrace(); } 672 } else { 673 r.run(); 674 } 675 676 } 677 678 // Returns either 1. an array of 3 object (PageFormat, Printable, PeekGraphics) or 2. null getPageformatPrintablePeekgraphics(final int pageIndex)679 private Object[] getPageformatPrintablePeekgraphics(final int pageIndex) { 680 final Object[] ret = new Object[3]; 681 final PrinterJob printerJob = this; 682 683 Runnable r = new Runnable() { public void run() { synchronized(ret) { 684 try { 685 Pageable pageable = getPageable(); 686 PageFormat pageFormat = pageable.getPageFormat(pageIndex); 687 if (pageFormat != null) { 688 Printable printable = pageable.getPrintable(pageIndex); 689 if (printable != null) { 690 BufferedImage bimg = new BufferedImage((int)Math.round(pageFormat.getWidth()), (int)Math.round(pageFormat.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE); 691 PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob); 692 Rectangle2D pageFormatArea = getPageFormatArea(pageFormat); 693 initPrinterGraphics(peekGraphics, pageFormatArea); 694 695 // Do the assignment here! 696 ret[0] = pageFormat; 697 ret[1] = printable; 698 ret[2] = peekGraphics; 699 } 700 } 701 } catch (Exception e) {} // Original code bailed on any exception 702 }}}; 703 704 if (onEventThread) { 705 try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); } 706 } else { 707 r.run(); 708 } 709 710 synchronized(ret) { 711 if (ret[2] != null) 712 return ret; 713 return null; 714 } 715 } 716 printAndGetPageFormatArea(final Printable printable, final Graphics graphics, final PageFormat pageFormat, final int pageIndex)717 private Rectangle2D printAndGetPageFormatArea(final Printable printable, final Graphics graphics, final PageFormat pageFormat, final int pageIndex) { 718 final Rectangle2D[] ret = new Rectangle2D[1]; 719 720 Runnable r = new Runnable() { public void run() { synchronized(ret) { 721 try { 722 int pageResult = printable.print(graphics, pageFormat, pageIndex); 723 if (pageResult != Printable.NO_SUCH_PAGE) { 724 ret[0] = getPageFormatArea(pageFormat); 725 } 726 } catch (Exception e) {} // Original code bailed on any exception 727 }}}; 728 729 if (onEventThread) { 730 try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); } 731 } else { 732 r.run(); 733 } 734 735 synchronized(ret) { return ret[0]; } 736 } 737 738 // upcall from native detachPrintLoop(final long target, final long arg)739 private static void detachPrintLoop(final long target, final long arg) { 740 new Thread() { public void run() { 741 _safePrintLoop(target, arg); 742 }}.start(); 743 } _safePrintLoop(long target, long arg)744 private static native void _safePrintLoop(long target, long arg); 745 746 @Override startPage(PageFormat arg0, Printable arg1, int arg2, boolean arg3)747 protected void startPage(PageFormat arg0, Printable arg1, int arg2, boolean arg3) throws PrinterException { 748 // TODO Auto-generated method stub 749 } 750 751 @Override getMediaSize(Media media, PrintService service, PageFormat page)752 protected MediaSize getMediaSize(Media media, PrintService service, 753 PageFormat page) { 754 if (media == null || !(media instanceof MediaSizeName)) { 755 return getDefaultMediaSize(page); 756 } 757 MediaSize size = MediaSize.getMediaSizeForName((MediaSizeName) media); 758 return size != null ? size : getDefaultMediaSize(page); 759 } 760 getDefaultMediaSize(PageFormat page)761 private MediaSize getDefaultMediaSize(PageFormat page){ 762 final int inch = 72; 763 Paper paper = page.getPaper(); 764 float width = (float) (paper.getWidth() / inch); 765 float height = (float) (paper.getHeight() / inch); 766 return new MediaSize(width, height, MediaSize.INCH); 767 } 768 769 @Override getDefaultPrintableArea(PageFormat page, double w, double h)770 protected MediaPrintableArea getDefaultPrintableArea(PageFormat page, double w, double h) { 771 final float dpi = 72.0f; 772 Paper paper = page.getPaper(); 773 return new MediaPrintableArea( 774 (float) (paper.getImageableX() / dpi), 775 (float) (paper.getImageableY() / dpi), 776 (float) (paper.getImageableWidth() / dpi), 777 (float) (paper.getImageableHeight() / dpi), 778 MediaPrintableArea.INCH); 779 } 780 } 781