| /* |
| * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.lwawt.macosx; |
| |
| |
| import java.awt.*; |
| import java.awt.geom.Rectangle2D; |
| import java.awt.image.BufferedImage; |
| import java.awt.print.*; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| |
| import javax.print.*; |
| import javax.print.attribute.PrintRequestAttributeSet; |
| import javax.print.attribute.HashPrintRequestAttributeSet; |
| import javax.print.attribute.standard.Media; |
| import javax.print.attribute.standard.MediaPrintableArea; |
| import javax.print.attribute.standard.MediaSize; |
| import javax.print.attribute.standard.MediaSizeName; |
| import javax.print.attribute.standard.PageRanges; |
| |
| import sun.java2d.*; |
| import sun.print.*; |
| |
| public final class CPrinterJob extends RasterPrinterJob { |
| // NOTE: This uses RasterPrinterJob as a base, but it doesn't use |
| // all of the RasterPrinterJob functions. RasterPrinterJob will |
| // break down printing to pieces that aren't necessary under MacOSX |
| // printing, such as controlling the # of copies and collating. These |
| // are handled by the native printing. RasterPrinterJob is kept for |
| // future compatibility and the state keeping that it handles. |
| |
| private static String sShouldNotReachHere = "Should not reach here."; |
| |
| private volatile SecondaryLoop printingLoop; |
| |
| private boolean noDefaultPrinter = false; |
| |
| private static Font defaultFont; |
| |
| // This is the NSPrintInfo for this PrinterJob. Protect multi thread |
| // access to it. It is used by the pageDialog, jobDialog, and printLoop. |
| // This way the state of these items is shared across these calls. |
| // PageFormat data is passed in and set on the fNSPrintInfo on a per call |
| // basis. |
| private long fNSPrintInfo = -1; |
| private Object fNSPrintInfoLock = new Object(); |
| |
| static { |
| // AWT has to be initialized for the native code to function correctly. |
| Toolkit.getDefaultToolkit(); |
| } |
| |
| /** |
| * Presents a dialog to the user for changing the properties of |
| * the print job. |
| * This method will display a native dialog if a native print |
| * service is selected, and user choice of printers will be restricted |
| * to these native print services. |
| * To present the cross platform print dialog for all services, |
| * including native ones instead use |
| * <code>printDialog(PrintRequestAttributeSet)</code>. |
| * <p> |
| * PrinterJob implementations which can use PrintService's will update |
| * the PrintService for this PrinterJob to reflect the new service |
| * selected by the user. |
| * @return <code>true</code> if the user does not cancel the dialog; |
| * <code>false</code> otherwise. |
| * @exception HeadlessException if GraphicsEnvironment.isHeadless() |
| * returns true. |
| * @see java.awt.GraphicsEnvironment#isHeadless |
| */ |
| @Override |
| public boolean printDialog() throws HeadlessException { |
| if (GraphicsEnvironment.isHeadless()) { |
| throw new HeadlessException(); |
| } |
| |
| if (noDefaultPrinter) { |
| return false; |
| } |
| |
| if (attributes == null) { |
| attributes = new HashPrintRequestAttributeSet(); |
| } |
| |
| if (getPrintService() instanceof StreamPrintService) { |
| return super.printDialog(attributes); |
| } |
| |
| return jobSetup(getPageable(), checkAllowedToPrintToFile()); |
| } |
| |
| /** |
| * Displays a dialog that allows modification of a |
| * <code>PageFormat</code> instance. |
| * The <code>page</code> argument is used to initialize controls |
| * in the page setup dialog. |
| * If the user cancels the dialog then this method returns the |
| * original <code>page</code> object unmodified. |
| * If the user okays the dialog then this method returns a new |
| * <code>PageFormat</code> object with the indicated changes. |
| * In either case, the original <code>page</code> object is |
| * not modified. |
| * @param page the default <code>PageFormat</code> presented to the |
| * user for modification |
| * @return the original <code>page</code> object if the dialog |
| * is cancelled; a new <code>PageFormat</code> object |
| * containing the format indicated by the user if the |
| * dialog is acknowledged. |
| * @exception HeadlessException if GraphicsEnvironment.isHeadless() |
| * returns true. |
| * @see java.awt.GraphicsEnvironment#isHeadless |
| * @since 1.2 |
| */ |
| @Override |
| public PageFormat pageDialog(PageFormat page) throws HeadlessException { |
| if (GraphicsEnvironment.isHeadless()) { |
| throw new HeadlessException(); |
| } |
| |
| if (noDefaultPrinter) { |
| return page; |
| } |
| |
| if (getPrintService() instanceof StreamPrintService) { |
| return super.pageDialog(page); |
| } |
| |
| PageFormat pageClone = (PageFormat) page.clone(); |
| boolean doIt = pageSetup(pageClone, null); |
| return doIt ? pageClone : page; |
| } |
| |
| /** |
| * Clones the <code>PageFormat</code> argument and alters the |
| * clone to describe a default page size and orientation. |
| * @param page the <code>PageFormat</code> to be cloned and altered |
| * @return clone of <code>page</code>, altered to describe a default |
| * <code>PageFormat</code>. |
| */ |
| @Override |
| public PageFormat defaultPage(PageFormat page) { |
| PageFormat newPage = (PageFormat)page.clone(); |
| getDefaultPage(newPage); |
| return newPage; |
| } |
| |
| @Override |
| protected void setAttributes(PrintRequestAttributeSet attributes) throws PrinterException { |
| super.setAttributes(attributes); |
| |
| if (attributes == null) { |
| return; |
| } |
| |
| // See if this has an NSPrintInfo in it. |
| NSPrintInfo nsPrintInfo = (NSPrintInfo)attributes.get(NSPrintInfo.class); |
| if (nsPrintInfo != null) { |
| fNSPrintInfo = nsPrintInfo.getValue(); |
| } |
| |
| PageRanges pageRangesAttr = (PageRanges)attributes.get(PageRanges.class); |
| if (isSupportedValue(pageRangesAttr, attributes)) { |
| SunPageSelection rangeSelect = (SunPageSelection)attributes.get(SunPageSelection.class); |
| // If rangeSelect is not null, we are using AWT's print dialog that has |
| // All, Selection, and Range radio buttons |
| if (rangeSelect == null || rangeSelect == SunPageSelection.RANGE) { |
| int[][] range = pageRangesAttr.getMembers(); |
| // setPageRange will set firstPage and lastPage as called in getFirstPage |
| // and getLastPage |
| setPageRange(range[0][0] - 1, range[0][1] - 1); |
| } |
| } |
| } |
| |
| volatile boolean onEventThread; |
| |
| @Override |
| protected void cancelDoc() throws PrinterAbortException { |
| super.cancelDoc(); |
| if (printingLoop != null) { |
| printingLoop.exit(); |
| } |
| } |
| |
| private void completePrintLoop() { |
| Runnable r = new Runnable() { public void run() { |
| synchronized(this) { |
| performingPrinting = false; |
| } |
| if (printingLoop != null) { |
| printingLoop.exit(); |
| } |
| }}; |
| |
| if (onEventThread) { |
| try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); } |
| } else { |
| r.run(); |
| } |
| } |
| |
| @Override |
| public void print(PrintRequestAttributeSet attributes) throws PrinterException { |
| // NOTE: Some of this code is copied from RasterPrinterJob. |
| |
| |
| // this code uses javax.print APIs |
| // this will make it print directly to the printer |
| // this will not work if the user clicks on the "Preview" button |
| // However if the printer is a StreamPrintService, its the right path. |
| PrintService psvc = getPrintService(); |
| |
| if (psvc == null) { |
| throw new PrinterException("No print service found."); |
| } |
| |
| if (psvc instanceof StreamPrintService) { |
| spoolToService(psvc, attributes); |
| return; |
| } |
| |
| |
| setAttributes(attributes); |
| // throw exception for invalid destination |
| if (destinationAttr != null) { |
| validateDestination(destinationAttr); |
| } |
| |
| /* Get the range of pages we are to print. If the |
| * last page to print is unknown, then we print to |
| * the end of the document. Note that firstPage |
| * and lastPage are 0 based page indices. |
| */ |
| |
| int firstPage = getFirstPage(); |
| int lastPage = getLastPage(); |
| if(lastPage == Pageable.UNKNOWN_NUMBER_OF_PAGES) { |
| int totalPages = mDocument.getNumberOfPages(); |
| if (totalPages != Pageable.UNKNOWN_NUMBER_OF_PAGES) { |
| lastPage = mDocument.getNumberOfPages() - 1; |
| } |
| } |
| |
| try { |
| synchronized (this) { |
| performingPrinting = true; |
| userCancelled = false; |
| } |
| |
| //Add support for PageRange |
| PageRanges pr = (attributes == null) ? null |
| : (PageRanges)attributes.get(PageRanges.class); |
| int[][] prMembers = (pr == null) ? new int[0][0] : pr.getMembers(); |
| int loopi = 0; |
| do { |
| if (EventQueue.isDispatchThread()) { |
| // This is an AWT EventQueue, and this print rendering loop needs to block it. |
| |
| onEventThread = true; |
| |
| printingLoop = AccessController.doPrivileged(new PrivilegedAction<SecondaryLoop>() { |
| @Override |
| public SecondaryLoop run() { |
| return Toolkit.getDefaultToolkit() |
| .getSystemEventQueue() |
| .createSecondaryLoop(); |
| } |
| }); |
| |
| try { |
| // Fire off the print rendering loop on the AppKit thread, and don't have |
| // it wait and block this thread. |
| if (printLoop(false, firstPage, lastPage)) { |
| // Start a secondary loop on EDT until printing operation is finished or cancelled |
| printingLoop.enter(); |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } else { |
| // Fire off the print rendering loop on the AppKit, and block this thread |
| // until it is done. |
| // But don't actually block... we need to come back here! |
| onEventThread = false; |
| |
| try { |
| printLoop(true, firstPage, lastPage); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } |
| if (++loopi < prMembers.length) { |
| firstPage = prMembers[loopi][0]-1; |
| lastPage = prMembers[loopi][1] -1; |
| } |
| } while (loopi < prMembers.length); |
| } finally { |
| synchronized (this) { |
| // NOTE: Native code shouldn't allow exceptions out while |
| // printing. They should cancel the print loop. |
| performingPrinting = false; |
| notify(); |
| } |
| if (printingLoop != null) { |
| printingLoop.exit(); |
| } |
| } |
| |
| // Normalize the collated, # copies, numPages, first/last pages. Need to |
| // make note of pageRangesAttr. |
| |
| // Set up NSPrintInfo with the java settings (PageFormat & Paper). |
| |
| // Create an NSView for printing. Have knowsPageRange return YES, and give the correct |
| // range, or MAX? if unknown. Have rectForPage do a peekGraphics check before returning |
| // the rectangle. Have drawRect do the real render of the page. Have printJobTitle do |
| // the right thing. |
| |
| // Call NSPrintOperation, it will call NSView.drawRect: for each page. |
| |
| // NSView.drawRect: will create a CPrinterGraphics with the current CGContextRef, and then |
| // pass this Graphics onto the Printable with the appropriate PageFormat and index. |
| |
| // Need to be able to cancel the NSPrintOperation (using code from RasterPrinterJob, be |
| // sure to initialize userCancelled and performingPrinting member variables). |
| |
| // Extensions available from AppKit: Print to PDF or EPS file! |
| } |
| |
| /** |
| * Returns the resolution in dots per inch across the width |
| * of the page. |
| */ |
| @Override |
| protected double getXRes() { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Returns the resolution in dots per inch down the height |
| * of the page. |
| */ |
| @Override |
| protected double getYRes() { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Must be obtained from the current printer. |
| * Value is in device pixels. |
| * Not adjusted for orientation of the paper. |
| */ |
| @Override |
| protected double getPhysicalPrintableX(Paper p) { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Must be obtained from the current printer. |
| * Value is in device pixels. |
| * Not adjusted for orientation of the paper. |
| */ |
| @Override |
| protected double getPhysicalPrintableY(Paper p) { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Must be obtained from the current printer. |
| * Value is in device pixels. |
| * Not adjusted for orientation of the paper. |
| */ |
| @Override |
| protected double getPhysicalPrintableWidth(Paper p) { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Must be obtained from the current printer. |
| * Value is in device pixels. |
| * Not adjusted for orientation of the paper. |
| */ |
| @Override |
| protected double getPhysicalPrintableHeight(Paper p) { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Must be obtained from the current printer. |
| * Value is in device pixels. |
| * Not adjusted for orientation of the paper. |
| */ |
| @Override |
| protected double getPhysicalPageWidth(Paper p) { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Must be obtained from the current printer. |
| * Value is in device pixels. |
| * Not adjusted for orientation of the paper. |
| */ |
| @Override |
| protected double getPhysicalPageHeight(Paper p) { |
| // NOTE: This is not used in the CPrinterJob code path. |
| return 0; |
| } |
| |
| /** |
| * Begin a new page. This call's Window's |
| * StartPage routine. |
| */ |
| protected void startPage(PageFormat format, Printable painter, int index) throws PrinterException { |
| // NOTE: This is not used in the CPrinterJob code path. |
| throw new PrinterException(sShouldNotReachHere); |
| } |
| |
| /** |
| * End a page. |
| */ |
| @Override |
| protected void endPage(PageFormat format, Printable painter, int index) throws PrinterException { |
| // NOTE: This is not used in the CPrinterJob code path. |
| throw new PrinterException(sShouldNotReachHere); |
| } |
| |
| /** |
| * Prints the contents of the array of ints, 'data' |
| * to the current page. The band is placed at the |
| * location (x, y) in device coordinates on the |
| * page. The width and height of the band is |
| * specified by the caller. |
| */ |
| @Override |
| protected void printBand(byte[] data, int x, int y, int width, int height) throws PrinterException { |
| // NOTE: This is not used in the CPrinterJob code path. |
| throw new PrinterException(sShouldNotReachHere); |
| } |
| |
| /** |
| * Called by the print() method at the start of |
| * a print job. |
| */ |
| @Override |
| protected void startDoc() throws PrinterException { |
| // NOTE: This is not used in the CPrinterJob code path. |
| throw new PrinterException(sShouldNotReachHere); |
| } |
| |
| /** |
| * Called by the print() method at the end of |
| * a print job. |
| */ |
| @Override |
| protected void endDoc() throws PrinterException { |
| // NOTE: This is not used in the CPrinterJob code path. |
| throw new PrinterException(sShouldNotReachHere); |
| } |
| |
| /* Called by cancelDoc */ |
| @Override |
| protected native void abortDoc(); |
| |
| /** |
| * Displays the page setup dialog placing the user's |
| * settings into 'page'. |
| */ |
| public boolean pageSetup(PageFormat page, Printable painter) { |
| CPrinterDialog printerDialog = new CPrinterPageDialog(null, this, page, painter); |
| printerDialog.setVisible(true); |
| boolean result = printerDialog.getRetVal(); |
| printerDialog.dispose(); |
| return result; |
| } |
| |
| /** |
| * Displays the print dialog and records the user's settings |
| * into this object. Return false if the user cancels the |
| * dialog. |
| * If the dialog is to use a set of attributes, useAttributes is true. |
| */ |
| private boolean jobSetup(Pageable doc, boolean allowPrintToFile) { |
| CPrinterDialog printerDialog = new CPrinterJobDialog(null, this, doc, allowPrintToFile); |
| printerDialog.setVisible(true); |
| boolean result = printerDialog.getRetVal(); |
| printerDialog.dispose(); |
| return result; |
| } |
| |
| /** |
| * Alters the orientation and Paper to match defaults obtained |
| * from a printer. |
| */ |
| private native void getDefaultPage(PageFormat page); |
| |
| /** |
| * validate the paper size against the current printer. |
| */ |
| @Override |
| protected native void validatePaper(Paper origPaper, Paper newPaper ); |
| |
| // The following methods are CPrinterJob specific. |
| |
| @Override |
| protected void finalize() { |
| if (fNSPrintInfo != -1) { |
| dispose(fNSPrintInfo); |
| } |
| } |
| |
| private native long createNSPrintInfo(); |
| private native void dispose(long printInfo); |
| |
| private long getNSPrintInfo() { |
| // This is called from the native side. |
| synchronized (fNSPrintInfoLock) { |
| if (fNSPrintInfo == -1) { |
| fNSPrintInfo = createNSPrintInfo(); |
| } |
| return fNSPrintInfo; |
| } |
| } |
| |
| private native boolean printLoop(boolean waitUntilDone, int firstPage, int lastPage) throws PrinterException; |
| |
| private PageFormat getPageFormat(int pageIndex) { |
| // This is called from the native side. |
| PageFormat page; |
| try { |
| page = getPageable().getPageFormat(pageIndex); |
| } catch (Exception e) { |
| return null; |
| } |
| return page; |
| } |
| |
| private Printable getPrintable(int pageIndex) { |
| // This is called from the native side. |
| Printable painter; |
| try { |
| painter = getPageable().getPrintable(pageIndex); |
| } catch (Exception e) { |
| return null; |
| } |
| return painter; |
| } |
| |
| private String getPrinterName(){ |
| // This is called from the native side. |
| PrintService service = getPrintService(); |
| if (service == null) return null; |
| return service.getName(); |
| } |
| |
| private void setPrinterServiceFromNative(String printerName) { |
| // This is called from the native side. |
| PrintService[] services = PrintServiceLookup.lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); |
| |
| for (int i = 0; i < services.length; i++) { |
| PrintService service = services[i]; |
| |
| if (printerName.equals(service.getName())) { |
| try { |
| setPrintService(service); |
| } catch (PrinterException e) { |
| // ignored |
| } |
| return; |
| } |
| } |
| } |
| |
| private Rectangle2D getPageFormatArea(PageFormat page) { |
| Rectangle2D.Double pageFormatArea = |
| new Rectangle2D.Double(page.getImageableX(), |
| page.getImageableY(), |
| page.getImageableWidth(), |
| page.getImageableHeight()); |
| return pageFormatArea; |
| } |
| |
| private boolean cancelCheck() { |
| // This is called from the native side. |
| |
| // This is used to avoid deadlock |
| // We would like to just call if isCancelled(), |
| // but that will block the AppKit thread against whomever is holding the synchronized lock |
| boolean cancelled = (performingPrinting && userCancelled); |
| if (cancelled) { |
| try { |
| LWCToolkit.invokeLater(new Runnable() { public void run() { |
| try { |
| cancelDoc(); |
| } catch (PrinterAbortException pae) { |
| // no-op, let the native side handle it |
| } |
| }}, null); |
| } catch (java.lang.reflect.InvocationTargetException ite) {} |
| } |
| return cancelled; |
| } |
| |
| private PeekGraphics createFirstPassGraphics(PrinterJob printerJob, PageFormat page) { |
| // This is called from the native side. |
| BufferedImage bimg = new BufferedImage((int)Math.round(page.getWidth()), (int)Math.round(page.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE); |
| PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob); |
| Rectangle2D pageFormatArea = getPageFormatArea(page); |
| initPrinterGraphics(peekGraphics, pageFormatArea); |
| return peekGraphics; |
| } |
| |
| private void printToPathGraphics( final PeekGraphics graphics, // Always an actual PeekGraphics |
| final PrinterJob printerJob, // Always an actual CPrinterJob |
| final Printable painter, // Client class |
| final PageFormat page, // Client class |
| final int pageIndex, |
| final long context) throws PrinterException { |
| // This is called from the native side. |
| Runnable r = new Runnable() { public void run() { |
| try { |
| SurfaceData sd = CPrinterSurfaceData.createData(page, context); // Just stores page into an ivar |
| if (defaultFont == null) { |
| defaultFont = new Font("Dialog", Font.PLAIN, 12); |
| } |
| Graphics2D delegate = new SunGraphics2D(sd, Color.black, Color.white, defaultFont); |
| |
| Graphics2D pathGraphics = new CPrinterGraphics(delegate, printerJob); // Just stores delegate into an ivar |
| Rectangle2D pageFormatArea = getPageFormatArea(page); |
| initPrinterGraphics(pathGraphics, pageFormatArea); |
| painter.print(pathGraphics, page, pageIndex); |
| delegate.dispose(); |
| delegate = null; |
| } catch (PrinterException pe) { throw new java.lang.reflect.UndeclaredThrowableException(pe); } |
| }}; |
| |
| if (onEventThread) { |
| try { EventQueue.invokeAndWait(r); |
| } catch (java.lang.reflect.InvocationTargetException ite) { |
| Throwable te = (Throwable)ite.getTargetException(); |
| if (te instanceof PrinterException) throw (PrinterException)te; |
| else te.printStackTrace(); |
| } catch (Exception e) { e.printStackTrace(); } |
| } else { |
| r.run(); |
| } |
| |
| } |
| |
| // Returns either 1. an array of 3 object (PageFormat, Printable, PeekGraphics) or 2. null |
| private Object[] getPageformatPrintablePeekgraphics(final int pageIndex) { |
| final Object[] ret = new Object[3]; |
| final PrinterJob printerJob = this; |
| |
| Runnable r = new Runnable() { public void run() { synchronized(ret) { |
| try { |
| Pageable pageable = getPageable(); |
| PageFormat pageFormat = pageable.getPageFormat(pageIndex); |
| if (pageFormat != null) { |
| Printable printable = pageable.getPrintable(pageIndex); |
| if (printable != null) { |
| BufferedImage bimg = new BufferedImage((int)Math.round(pageFormat.getWidth()), (int)Math.round(pageFormat.getHeight()), BufferedImage.TYPE_INT_ARGB_PRE); |
| PeekGraphics peekGraphics = createPeekGraphics(bimg.createGraphics(), printerJob); |
| Rectangle2D pageFormatArea = getPageFormatArea(pageFormat); |
| initPrinterGraphics(peekGraphics, pageFormatArea); |
| |
| // Do the assignment here! |
| ret[0] = pageFormat; |
| ret[1] = printable; |
| ret[2] = peekGraphics; |
| } |
| } |
| } catch (Exception e) {} // Original code bailed on any exception |
| }}}; |
| |
| if (onEventThread) { |
| try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); } |
| } else { |
| r.run(); |
| } |
| |
| synchronized(ret) { |
| if (ret[2] != null) |
| return ret; |
| return null; |
| } |
| } |
| |
| private Rectangle2D printAndGetPageFormatArea(final Printable printable, final Graphics graphics, final PageFormat pageFormat, final int pageIndex) { |
| final Rectangle2D[] ret = new Rectangle2D[1]; |
| |
| Runnable r = new Runnable() { public void run() { synchronized(ret) { |
| try { |
| int pageResult = printable.print(graphics, pageFormat, pageIndex); |
| if (pageResult != Printable.NO_SUCH_PAGE) { |
| ret[0] = getPageFormatArea(pageFormat); |
| } |
| } catch (Exception e) {} // Original code bailed on any exception |
| }}}; |
| |
| if (onEventThread) { |
| try { EventQueue.invokeAndWait(r); } catch (Exception e) { e.printStackTrace(); } |
| } else { |
| r.run(); |
| } |
| |
| synchronized(ret) { return ret[0]; } |
| } |
| |
| // upcall from native |
| private static void detachPrintLoop(final long target, final long arg) { |
| new Thread() { public void run() { |
| _safePrintLoop(target, arg); |
| }}.start(); |
| } |
| private static native void _safePrintLoop(long target, long arg); |
| |
| @Override |
| protected void startPage(PageFormat arg0, Printable arg1, int arg2, boolean arg3) throws PrinterException { |
| // TODO Auto-generated method stub |
| } |
| |
| @Override |
| protected MediaSize getMediaSize(Media media, PrintService service, |
| PageFormat page) { |
| if (media == null || !(media instanceof MediaSizeName)) { |
| return getDefaultMediaSize(page); |
| } |
| MediaSize size = MediaSize.getMediaSizeForName((MediaSizeName) media); |
| return size != null ? size : getDefaultMediaSize(page); |
| } |
| |
| private MediaSize getDefaultMediaSize(PageFormat page){ |
| final int inch = 72; |
| Paper paper = page.getPaper(); |
| float width = (float) (paper.getWidth() / inch); |
| float height = (float) (paper.getHeight() / inch); |
| return new MediaSize(width, height, MediaSize.INCH); |
| } |
| |
| @Override |
| protected MediaPrintableArea getDefaultPrintableArea(PageFormat page, double w, double h) { |
| final float dpi = 72.0f; |
| Paper paper = page.getPaper(); |
| return new MediaPrintableArea( |
| (float) (paper.getImageableX() / dpi), |
| (float) (paper.getImageableY() / dpi), |
| (float) (paper.getImageableWidth() / dpi), |
| (float) (paper.getImageableHeight() / dpi), |
| MediaPrintableArea.INCH); |
| } |
| } |