Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/print/PrintJob2D.java
38829 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.print;2627import java.awt.Dimension;28import java.awt.Frame;29import java.awt.Graphics;30import java.awt.Graphics2D;31import java.awt.PrintJob;32import java.awt.JobAttributes;33import java.awt.JobAttributes.*;34import java.awt.PageAttributes;35import java.awt.PageAttributes.*;3637import java.awt.print.PageFormat;38import java.awt.print.Paper;39import java.awt.print.Printable;40import java.awt.print.PrinterException;41import java.awt.print.PrinterJob;4243import java.io.File;44import java.io.FilePermission;45import java.io.IOException;4647import java.net.URI;48import java.net.URISyntaxException;4950import java.util.ArrayList;51import java.util.Properties;5253import javax.print.PrintService;54import javax.print.attribute.HashPrintRequestAttributeSet;55import javax.print.attribute.PrintRequestAttributeSet;56import javax.print.attribute.ResolutionSyntax;57import javax.print.attribute.Size2DSyntax;58import javax.print.attribute.standard.Chromaticity;59import javax.print.attribute.standard.Copies;60import javax.print.attribute.standard.Destination;61import javax.print.attribute.standard.DialogTypeSelection;62import javax.print.attribute.standard.JobName;63import javax.print.attribute.standard.MediaSize;64import javax.print.attribute.standard.PrintQuality;65import javax.print.attribute.standard.PrinterResolution;66import javax.print.attribute.standard.SheetCollate;67import javax.print.attribute.standard.Sides;68import javax.print.attribute.standard.Media;69import javax.print.attribute.standard.OrientationRequested;70import javax.print.attribute.standard.MediaSizeName;71import javax.print.attribute.standard.PageRanges;7273import sun.print.SunPageSelection;74import sun.print.SunMinMaxPage;7576/**77* A class which initiates and executes a print job using78* the underlying PrinterJob graphics conversions.79*80* @see Toolkit#getPrintJob81*82*/83public class PrintJob2D extends PrintJob implements Printable, Runnable {8485private static final MediaType SIZES[] = {86MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0,87MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3,88MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6,89MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9,90MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1,91MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4,92MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7,93MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10,94MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2,95MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5,96MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8,97MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0,98MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3,99MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6,100MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9,101MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG,102MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE,103MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL,104MediaType.QUARTO, MediaType.A, MediaType.B,105MediaType.C, MediaType.D, MediaType.E,106MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE,107MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE,108MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE,109MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE,110MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE,111MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE,112MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE,113MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE114};115116/* This array maps the above array to the objects used by the117* javax.print APIs118*/119private static final MediaSizeName JAVAXSIZES[] = {120null, null, MediaSizeName.ISO_A0,121MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3,122MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6,123MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9,124MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1,125MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4,126MediaSizeName.ISO_B5, MediaSizeName.ISO_B6, MediaSizeName.ISO_B7,127MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10,128MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2,129MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5,130MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8,131MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0,132MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3,133MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6,134null, null, null, null,135MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE,136MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER,137MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL,138MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B,139MediaSizeName.C, MediaSizeName.D, MediaSizeName.E,140MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE,141MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,142MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE,143MediaSizeName.NA_6X9_ENVELOPE,144MediaSizeName.NA_NUMBER_9_ENVELOPE,145MediaSizeName.NA_NUMBER_10_ENVELOPE,146MediaSizeName.NA_NUMBER_11_ENVELOPE,147MediaSizeName.NA_NUMBER_12_ENVELOPE,148MediaSizeName.NA_NUMBER_14_ENVELOPE,149null, MediaSizeName.ITALY_ENVELOPE,150MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,151};152153154// widths and lengths in PostScript points (1/72 in.)155private static final int WIDTHS[] = {156/*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684,157/*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420,158/*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105,159/*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417,160/*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354,161/*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88,162/*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032,163/*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258,164/*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599,165/*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649,166/*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162,167/*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312,168/*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792,169/*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612,170/*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448,171/*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720,172/*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648,173/*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504,174/*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279,175/*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324,176/*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360,177/*invite-envelope*/ 624, /*italy-envelope*/ 312,178/*monarch-envelope*/ 279, /*personal-envelope*/ 261179};180private static final int LENGTHS[] = {181/*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384,182/*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595,183/*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147,184/*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004,185/*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499,186/*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125,187/*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460,188/*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363,189/*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677,190/*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918,191/*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230,192/*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624,193/*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224,194/*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792,195/*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168,196/*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008,197/*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864,198/*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648,199/*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639,200/*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747,201/*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828,202/*invite-envelope*/ 624, /*italy-envelope*/ 652,203/*monarch-envelope*/ 540, /*personal-envelope*/ 468204};205206207private Frame frame;208private String docTitle = "";209private JobAttributes jobAttributes;210private PageAttributes pageAttributes;211private PrintRequestAttributeSet attributes;212213/*214* Displays the native or cross-platform dialog and allows the215* user to update job & page attributes216*/217218/**219* The PrinterJob being uses to implement the PrintJob.220*/221private PrinterJob printerJob;222223/**224* The size of the page being used for the PrintJob.225*/226private PageFormat pageFormat;227228/**229* The PrinterJob and the application run on different230* threads and communicate through a pair of message231* queues. This queue is the list of Graphics that232* the PrinterJob has requested rendering for, but233* for which the application has not yet called getGraphics().234* In practice the length of this message queue is always235* 0 or 1.236*/237private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn");238239/**240* Used to communicate between the application's thread241* and the PrinterJob's thread this message queue holds242* the list of Graphics into which the application has243* finished drawing, but that have not yet been returned244* to the PrinterJob thread. Again, in practice, the245* length of this message queue is always 0 or 1.246*/247private MessageQ graphicsDrawn = new MessageQ("drawn");248249/**250* The last Graphics returned to the application via251* getGraphics. This is the Graphics into which the252* application is currently drawing.253*/254private Graphics2D currentGraphics;255256/**257* The zero based index of the page currently being rendered258* by the application.259*/260private int pageIndex = -1;261262// The following Strings are maintained for backward-compatibility with263// Properties based print control.264private final static String DEST_PROP = "awt.print.destination";265private final static String PRINTER = "printer";266private final static String FILE = "file";267268private final static String PRINTER_PROP = "awt.print.printer";269270private final static String FILENAME_PROP = "awt.print.fileName";271272private final static String NUMCOPIES_PROP = "awt.print.numCopies";273274private final static String OPTIONS_PROP = "awt.print.options";275276private final static String ORIENT_PROP = "awt.print.orientation";277private final static String PORTRAIT = "portrait";278private final static String LANDSCAPE = "landscape";279280private final static String PAPERSIZE_PROP = "awt.print.paperSize";281private final static String LETTER = "letter";282private final static String LEGAL = "legal";283private final static String EXECUTIVE = "executive";284private final static String A4 = "a4";285286private Properties props;287288private String options = ""; // REMIND: needs implementation289290/**291* The thread on which PrinterJob is running.292* This is different than the applications thread.293*/294private Thread printerJobThread;295296public PrintJob2D(Frame frame, String doctitle,297final Properties props) {298this.props = props;299this.jobAttributes = new JobAttributes();300this.pageAttributes = new PageAttributes();301translateInputProps();302initPrintJob2D(frame, doctitle,303this.jobAttributes, this.pageAttributes);304}305306public PrintJob2D(Frame frame, String doctitle,307JobAttributes jobAttributes,308PageAttributes pageAttributes) {309initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes);310}311312private void initPrintJob2D(Frame frame, String doctitle,313JobAttributes jobAttributes,314PageAttributes pageAttributes) {315316SecurityManager security = System.getSecurityManager();317if (security != null) {318security.checkPrintJobAccess();319}320321if (frame == null &&322(jobAttributes == null ||323jobAttributes.getDialog() == DialogType.NATIVE)) {324throw new NullPointerException("Frame must not be null");325}326this.frame = frame;327328this.docTitle = (doctitle == null) ? "" : doctitle;329this.jobAttributes = (jobAttributes != null)330? jobAttributes : new JobAttributes();331this.pageAttributes = (pageAttributes != null)332? pageAttributes : new PageAttributes();333334// Currently, we always reduce page ranges to xxx or xxx-xxx335int[][] pageRanges = this.jobAttributes.getPageRanges();336int first = pageRanges[0][0];337int last = pageRanges[pageRanges.length - 1][1];338this.jobAttributes.setPageRanges(new int[][] {339new int[] { first, last }340});341this.jobAttributes.setToPage(last);342this.jobAttributes.setFromPage(first);343344345// Verify that the cross feed and feed resolutions are the same346int[] res = this.pageAttributes.getPrinterResolution();347if (res[0] != res[1]) {348throw new IllegalArgumentException("Differing cross feed and feed"+349" resolutions not supported.");350}351352// Verify that the app has access to the file system353DestinationType dest= this.jobAttributes.getDestination();354if (dest == DestinationType.FILE) {355throwPrintToFile();356357// check if given filename is valid358String destStr = jobAttributes.getFileName();359if ((destStr != null) &&360(jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) {361362File f = new File(destStr);363try {364// check if this is a new file and if filename chars are valid365// createNewFile returns false if file exists366if (f.createNewFile()) {367f.delete();368}369} catch (IOException ioe) {370throw new IllegalArgumentException("Cannot write to file:"+371destStr);372} catch (SecurityException se) {373//There is already file read/write access so at this point374// only delete access is denied. Just ignore it because in375// most cases the file created in createNewFile gets overwritten376// anyway.377}378379File pFile = f.getParentFile();380if ((f.exists() &&381(!f.isFile() || !f.canWrite())) ||382((pFile != null) &&383(!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {384throw new IllegalArgumentException("Cannot write to file:"+385destStr);386}387}388}389}390391public boolean printDialog() {392393boolean proceedWithPrint = false;394395printerJob = PrinterJob.getPrinterJob();396if (printerJob == null) {397return false;398}399DialogType d = this.jobAttributes.getDialog();400PrintService pServ = printerJob.getPrintService();401if ((pServ == null) && (d == DialogType.NONE)){402return false;403}404copyAttributes(pServ);405406DefaultSelectionType select =407this.jobAttributes.getDefaultSelection();408if (select == DefaultSelectionType.RANGE) {409attributes.add(SunPageSelection.RANGE);410} else if (select == DefaultSelectionType.SELECTION) {411attributes.add(SunPageSelection.SELECTION);412} else {413attributes.add(SunPageSelection.ALL);414}415416if (frame != null) {417attributes.add(new DialogOwner(frame));418}419420if ( d == DialogType.NONE) {421proceedWithPrint = true;422} else {423if (d == DialogType.NATIVE) {424attributes.add(DialogTypeSelection.NATIVE);425} else { // (d == DialogType.COMMON)426attributes.add(DialogTypeSelection.COMMON);427}428if (proceedWithPrint = printerJob.printDialog(attributes)) {429if (pServ == null) {430// Windows gives an option to install a service431// when it detects there are no printers so432// we make sure we get the updated print service.433pServ = printerJob.getPrintService();434if (pServ == null) {435return false;436}437}438updateAttributes();439translateOutputProps();440}441}442443if (proceedWithPrint) {444445JobName jname = (JobName)attributes.get(JobName.class);446if (jname != null) {447printerJob.setJobName(jname.toString());448}449450pageFormat = new PageFormat();451452Media media = (Media)attributes.get(Media.class);453MediaSize mediaSize = null;454if (media != null && media instanceof MediaSizeName) {455mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)media);456}457458Paper p = pageFormat.getPaper();459if (mediaSize != null) {460p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,461mediaSize.getY(MediaSize.INCH)*72.0);462}463464if (pageAttributes.getOrigin()==OriginType.PRINTABLE) {465// AWT uses 1/4" borders by default466p.setImageableArea(18.0, 18.0,467p.getWidth()-36.0,468p.getHeight()-36.0);469} else {470p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight());471}472473pageFormat.setPaper(p);474475OrientationRequested orient =476(OrientationRequested)attributes.get(OrientationRequested.class);477if (orient!= null &&478orient == OrientationRequested.REVERSE_LANDSCAPE) {479pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);480} else if (orient == OrientationRequested.LANDSCAPE) {481pageFormat.setOrientation(PageFormat.LANDSCAPE);482} else {483pageFormat.setOrientation(PageFormat.PORTRAIT);484}485486printerJob.setPrintable(this, pageFormat);487488}489490return proceedWithPrint;491}492493private void updateAttributes() {494Copies c = (Copies)attributes.get(Copies.class);495jobAttributes.setCopies(c.getValue());496497SunPageSelection sel =498(SunPageSelection)attributes.get(SunPageSelection.class);499if (sel == SunPageSelection.RANGE) {500jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE);501} else if (sel == SunPageSelection.SELECTION) {502jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION);503} else {504jobAttributes.setDefaultSelection(DefaultSelectionType.ALL);505}506507Destination dest = (Destination)attributes.get(Destination.class);508if (dest != null) {509jobAttributes.setDestination(DestinationType.FILE);510jobAttributes.setFileName(dest.getURI().getPath());511} else {512jobAttributes.setDestination(DestinationType.PRINTER);513}514515PrintService serv = printerJob.getPrintService();516if (serv != null) {517jobAttributes.setPrinter(serv.getName());518}519520PageRanges range = (PageRanges)attributes.get(PageRanges.class);521int[][] members = range.getMembers();522jobAttributes.setPageRanges(members);523524SheetCollate collation =525(SheetCollate)attributes.get(SheetCollate.class);526if (collation == SheetCollate.COLLATED) {527jobAttributes.setMultipleDocumentHandling(528MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES);529} else {530jobAttributes.setMultipleDocumentHandling(531MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);532}533534Sides sides = (Sides)attributes.get(Sides.class);535if (sides == Sides.TWO_SIDED_LONG_EDGE) {536jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE);537} else if (sides == Sides.TWO_SIDED_SHORT_EDGE) {538jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE);539} else {540jobAttributes.setSides(SidesType.ONE_SIDED);541}542543// PageAttributes544545Chromaticity color =546(Chromaticity)attributes.get(Chromaticity.class);547if (color == Chromaticity.COLOR) {548pageAttributes.setColor(ColorType.COLOR);549} else {550pageAttributes.setColor(ColorType.MONOCHROME);551}552553OrientationRequested orient =554(OrientationRequested)attributes.get(OrientationRequested.class);555if (orient == OrientationRequested.LANDSCAPE) {556pageAttributes.setOrientationRequested(557OrientationRequestedType.LANDSCAPE);558} else {559pageAttributes.setOrientationRequested(560OrientationRequestedType.PORTRAIT);561}562563PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class);564if (qual == PrintQuality.DRAFT) {565pageAttributes.setPrintQuality(PrintQualityType.DRAFT);566} else if (qual == PrintQuality.HIGH) {567pageAttributes.setPrintQuality(PrintQualityType.HIGH);568} else { // NORMAL569pageAttributes.setPrintQuality(PrintQualityType.NORMAL);570}571572Media msn = (Media)attributes.get(Media.class);573if (msn != null && msn instanceof MediaSizeName) {574MediaType mType = unMapMedia((MediaSizeName)msn);575576if (mType != null) {577pageAttributes.setMedia(mType);578}579}580debugPrintAttributes(false, false);581}582583private void debugPrintAttributes(boolean ja, boolean pa ) {584if (ja) {585System.out.println("new Attributes\ncopies = "+586jobAttributes.getCopies()+587"\nselection = "+588jobAttributes.getDefaultSelection()+589"\ndest "+jobAttributes.getDestination()+590"\nfile "+jobAttributes.getFileName()+591"\nfromPage "+jobAttributes.getFromPage()+592"\ntoPage "+jobAttributes.getToPage()+593"\ncollation "+594jobAttributes.getMultipleDocumentHandling()+595"\nPrinter "+jobAttributes.getPrinter()+596"\nSides2 "+jobAttributes.getSides()597);598}599600if (pa) {601System.out.println("new Attributes\ncolor = "+602pageAttributes.getColor()+603"\norientation = "+604pageAttributes.getOrientationRequested()+605"\nquality "+pageAttributes.getPrintQuality()+606"\nMedia2 "+pageAttributes.getMedia()607);608}609}610611612/* From JobAttributes we will copy job name and duplex printing613* and destination.614* The majority of the rest of the attributes are reflected615* attributes.616*617* From PageAttributes we copy color, media size, orientation,618* origin type, resolution and print quality.619* We use the media, orientation in creating the page format, and620* the origin type to set its imageable area.621*622* REMIND: Interpretation of resolution, additional media sizes.623*/624private void copyAttributes(PrintService printServ) {625626attributes = new HashPrintRequestAttributeSet();627attributes.add(new JobName(docTitle, null));628PrintService pServ = printServ;629630String printerName = jobAttributes.getPrinter();631if (printerName != null && printerName != ""632&& !printerName.equals(pServ.getName())) {633634// Search for the given printerName in the list of PrintServices635PrintService []services = PrinterJob.lookupPrintServices();636try {637for (int i=0; i<services.length; i++) {638if (printerName.equals(services[i].getName())) {639printerJob.setPrintService(services[i]);640pServ = services[i];641break;642}643}644} catch (PrinterException pe) {645}646}647648DestinationType dest = jobAttributes.getDestination();649if (dest == DestinationType.FILE &&650pServ.isAttributeCategorySupported(Destination.class)) {651652String fileName = jobAttributes.getFileName();653654Destination defaultDest;655if (fileName == null && (defaultDest = (Destination)pServ.656getDefaultAttributeValue(Destination.class)) != null) {657attributes.add(defaultDest);658} else {659URI uri = null;660try {661if (fileName != null) {662if (fileName.equals("")) {663fileName = ".";664}665} else {666// defaultDest should not be null. The following code667// is only added to safeguard against a possible668// buggy implementation of a PrintService having a669// null default Destination.670fileName = "out.prn";671}672uri = (new File(fileName)).toURI();673} catch (SecurityException se) {674try {675// '\\' file separator is illegal character in opaque676// part and causes URISyntaxException, so we replace677// it with '/'678fileName = fileName.replace('\\', '/');679uri = new URI("file:"+fileName);680} catch (URISyntaxException e) {681}682}683if (uri != null) {684attributes.add(new Destination(uri));685}686}687}688attributes.add(new SunMinMaxPage(jobAttributes.getMinPage(),689jobAttributes.getMaxPage()));690SidesType sType = jobAttributes.getSides();691if (sType == SidesType.TWO_SIDED_LONG_EDGE) {692attributes.add(Sides.TWO_SIDED_LONG_EDGE);693} else if (sType == SidesType.TWO_SIDED_SHORT_EDGE) {694attributes.add(Sides.TWO_SIDED_SHORT_EDGE);695} else if (sType == SidesType.ONE_SIDED) {696attributes.add(Sides.ONE_SIDED);697}698699MultipleDocumentHandlingType hType =700jobAttributes.getMultipleDocumentHandling();701if (hType ==702MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES) {703attributes.add(SheetCollate.COLLATED);704} else {705attributes.add(SheetCollate.UNCOLLATED);706}707708attributes.add(new Copies(jobAttributes.getCopies()));709710attributes.add(new PageRanges(jobAttributes.getFromPage(),711jobAttributes.getToPage()));712713if (pageAttributes.getColor() == ColorType.COLOR) {714attributes.add(Chromaticity.COLOR);715} else {716attributes.add(Chromaticity.MONOCHROME);717}718719pageFormat = printerJob.defaultPage();720if (pageAttributes.getOrientationRequested() ==721OrientationRequestedType.LANDSCAPE) {722pageFormat.setOrientation(PageFormat.LANDSCAPE);723attributes.add(OrientationRequested.LANDSCAPE);724} else {725pageFormat.setOrientation(PageFormat.PORTRAIT);726attributes.add(OrientationRequested.PORTRAIT);727}728729MediaType media = pageAttributes.getMedia();730MediaSizeName msn = mapMedia(media);731if (msn != null) {732attributes.add(msn);733}734735PrintQualityType qType =736pageAttributes.getPrintQuality();737if (qType == PrintQualityType.DRAFT) {738attributes.add(PrintQuality.DRAFT);739} else if (qType == PrintQualityType.NORMAL) {740attributes.add(PrintQuality.NORMAL);741} else if (qType == PrintQualityType.HIGH) {742attributes.add(PrintQuality.HIGH);743}744}745746/**747* Gets a Graphics object that will draw to the next page.748* The page is sent to the printer when the graphics749* object is disposed. This graphics object will also implement750* the PrintGraphics interface.751* @see PrintGraphics752*/753public Graphics getGraphics() {754755Graphics printGraphics = null;756757synchronized (this) {758++pageIndex;759760// Thread should not be created after end has been called.761// One way to detect this is if any of the graphics queue762// has been closed.763if (pageIndex == 0 && !graphicsToBeDrawn.isClosed()) {764765/* We start a thread on which the PrinterJob will run.766* The PrinterJob will ask for pages on that thread767* and will use a message queue to fulfill the application's768* requests for a Graphics on the application's769* thread.770*/771772startPrinterJobThread();773774}775notify();776}777778/* If the application has already been handed back779* a graphics then we need to put that graphics into780* the drawn queue so that the PrinterJob thread can781* return to the print system.782*/783if (currentGraphics != null) {784graphicsDrawn.append(currentGraphics);785currentGraphics = null;786}787788/* We'll block here until a new graphics becomes789* available.790*/791792currentGraphics = graphicsToBeDrawn.pop();793794if (currentGraphics instanceof PeekGraphics) {795( (PeekGraphics) currentGraphics).setAWTDrawingOnly();796graphicsDrawn.append(currentGraphics);797currentGraphics = graphicsToBeDrawn.pop();798}799800801if (currentGraphics != null) {802803/* In the PrintJob API, the origin is at the upper-804* left of the imageable area when using the new "printable"805* origin attribute, otherwise its the physical origin (for806* backwards compatibility. We emulate this by createing807* a PageFormat which matches and then performing the808* translate to the origin. This is a no-op if physical809* origin is specified.810*/811currentGraphics.translate(pageFormat.getImageableX(),812pageFormat.getImageableY());813814/* Scale to accommodate AWT's notion of printer resolution */815double awtScale = 72.0/getPageResolutionInternal();816currentGraphics.scale(awtScale, awtScale);817818/* The caller wants a Graphics instance but we do819* not want them to make 2D calls. We can't hand820* back a Graphics2D. The returned Graphics also821* needs to implement PrintGraphics, so we wrap822* the Graphics2D instance. The PrintJob API has823* the application dispose of the Graphics so824* we create a copy of the one returned by PrinterJob.825*/826printGraphics = new ProxyPrintGraphics(currentGraphics.create(),827this);828829}830831return printGraphics;832}833834/**835* Returns the dimensions of the page in pixels.836* The resolution of the page is chosen so that it837* is similar to the screen resolution.838* Except (since 1.3) when the application specifies a resolution.839* In that case it it scaled accordingly.840*/841public Dimension getPageDimension() {842double wid, hgt, scale;843if (pageAttributes != null &&844pageAttributes.getOrigin()==OriginType.PRINTABLE) {845wid = pageFormat.getImageableWidth();846hgt = pageFormat.getImageableHeight();847} else {848wid = pageFormat.getWidth();849hgt = pageFormat.getHeight();850}851scale = getPageResolutionInternal() / 72.0;852return new Dimension((int)(wid * scale), (int)(hgt * scale));853}854855private double getPageResolutionInternal() {856if (pageAttributes != null) {857int []res = pageAttributes.getPrinterResolution();858if (res[2] == 3) {859return res[0];860} else /* if (res[2] == 4) */ {861return (res[0] * 2.54);862}863} else {864return 72.0;865}866}867868/**869* Returns the resolution of the page in pixels per inch.870* Note that this doesn't have to correspond to the physical871* resolution of the printer.872*/873public int getPageResolution() {874return (int)getPageResolutionInternal();875}876877/**878* Returns true if the last page will be printed first.879*/880public boolean lastPageFirst() {881return false;882}883884/**885* Ends the print job and does any necessary cleanup.886*/887public synchronized void end() {888889/* Prevent the PrinterJob thread from appending any more890* graphics to the to-be-drawn queue891*/892graphicsToBeDrawn.close();893894/* If we have a currentGraphics it was the last one returned to the895* PrintJob client. Append it to the drawn queue so that print()896* will return allowing the page to be flushed.897* This really ought to happen in dispose() but for whatever reason898* that isn't how the old PrintJob worked even though its spec899* said dispose() flushed the page.900*/901if (currentGraphics != null) {902graphicsDrawn.append(currentGraphics);903}904graphicsDrawn.closeWhenEmpty();905906/* Wait for the PrinterJob.print() thread to terminate, ensuring907* that RasterPrinterJob has made its end doc call, and resources908* are released, files closed etc.909*/910if( printerJobThread != null && printerJobThread.isAlive() ){911try {912printerJobThread.join();913} catch (InterruptedException e) {914}915}916}917918/**919* Ends this print job once it is no longer referenced.920* @see #end921*/922public void finalize() {923end();924}925926/**927* Prints the page at the specified index into the specified928* {@link Graphics} context in the specified929* format. A <code>PrinterJob</code> calls the930* <code>Printable</code> interface to request that a page be931* rendered into the context specified by932* <code>graphics</code>. The format of the page to be drawn is933* specified by <code>pageFormat</code>. The zero based index934* of the requested page is specified by <code>pageIndex</code>.935* If the requested page does not exist then this method returns936* NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.937* The <code>Graphics</code> class or subclass implements the938* {@link PrinterGraphics} interface to provide additional939* information. If the <code>Printable</code> object940* aborts the print job then it throws a {@link PrinterException}.941* @param graphics the context into which the page is drawn942* @param pageFormat the size and orientation of the page being drawn943* @param pageIndex the zero based index of the page to be drawn944* @return PAGE_EXISTS if the page is rendered successfully945* or NO_SUCH_PAGE if <code>pageIndex</code> specifies a946* non-existent page.947* @exception java.awt.print.PrinterException948* thrown when the print job is terminated.949*/950public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)951throws PrinterException {952953int result;954955/* This method will be called by the PrinterJob on a thread other956* that the application's thread. We hold on to the graphics957* until we can rendevous with the application's thread and958* hand over the graphics. The application then does all the959* drawing. When the application is done drawing we rendevous960* again with the PrinterJob thread and release the Graphics961* so that it knows we are done.962*/963964/* Add the graphics to the message queue of graphics to965* be rendered. This is really a one slot queue. The966* application's thread will come along and remove the967* graphics from the queue when the app asks for a graphics.968*/969graphicsToBeDrawn.append( (Graphics2D) graphics);970971/* We now wait for the app's thread to finish drawing on972* the Graphics. This thread will sleep until the application973* release the graphics by placing it in the graphics drawn974* message queue. If the application signals that it is975* finished drawing the entire document then we'll get null976* returned when we try and pop a finished graphic.977*/978if (graphicsDrawn.pop() != null) {979result = PAGE_EXISTS;980} else {981result = NO_SUCH_PAGE;982}983984return result;985}986987private void startPrinterJobThread() {988989printerJobThread = new Thread(this, "printerJobThread");990printerJobThread.start();991}992993994public void run() {995996try {997printerJob.print(attributes);998} catch (PrinterException e) {999//REMIND: need to store this away and not rethrow it.1000}10011002/* Close the message queues so that nobody is stuck1003* waiting for one.1004*/1005graphicsToBeDrawn.closeWhenEmpty();1006graphicsDrawn.close();1007}10081009private class MessageQ {10101011private String qid="noname";10121013private ArrayList queue = new ArrayList();10141015MessageQ(String id) {1016qid = id;1017}10181019synchronized void closeWhenEmpty() {10201021while (queue != null && queue.size() > 0) {1022try {1023wait(1000);1024} catch (InterruptedException e) {1025// do nothing.1026}1027}10281029queue = null;1030notifyAll();1031}10321033synchronized void close() {1034queue = null;1035notifyAll();1036}10371038synchronized boolean append(Graphics2D g) {10391040boolean queued = false;10411042if (queue != null) {1043queue.add(g);1044queued = true;1045notify();1046}10471048return queued;1049}10501051synchronized Graphics2D pop() {1052Graphics2D g = null;10531054while (g == null && queue != null) {10551056if (queue.size() > 0) {1057g = (Graphics2D) queue.remove(0);1058notify();10591060} else {1061try {1062wait(2000);1063} catch (InterruptedException e) {1064// do nothing.1065}1066}1067}10681069return g;1070}10711072synchronized boolean isClosed() {1073return queue == null;1074}10751076}107710781079private static int[] getSize(MediaType mType) {1080int []dim = new int[2];1081dim[0] = 612;1082dim[1] = 792;10831084for (int i=0; i < SIZES.length; i++) {1085if (SIZES[i] == mType) {1086dim[0] = WIDTHS[i];1087dim[1] = LENGTHS[i];1088break;1089}1090}1091return dim;1092}10931094public static MediaSizeName mapMedia(MediaType mType) {1095MediaSizeName media = null;10961097// JAVAXSIZES.length and SIZES.length must be equal!1098// Attempt to recover by getting the smaller size.1099int length = Math.min(SIZES.length, JAVAXSIZES.length);11001101for (int i=0; i < length; i++) {1102if (SIZES[i] == mType) {1103if ((JAVAXSIZES[i] != null) &&1104MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) {1105media = JAVAXSIZES[i];1106break;1107} else {1108/* create Custom Media */1109media = new CustomMediaSizeName(SIZES[i].toString());11101111float w = (float)Math.rint(WIDTHS[i] / 72.0);1112float h = (float)Math.rint(LENGTHS[i] / 72.0);1113if (w > 0.0 && h > 0.0) {1114// add new created MediaSize to our static map1115// so it will be found when we call findMedia1116new MediaSize(w, h, Size2DSyntax.INCH, media);1117}11181119break;1120}1121}1122}1123return media;1124}112511261127public static MediaType unMapMedia(MediaSizeName mSize) {1128MediaType media = null;11291130// JAVAXSIZES.length and SIZES.length must be equal!1131// Attempt to recover by getting the smaller size.1132int length = Math.min(SIZES.length, JAVAXSIZES.length);11331134for (int i=0; i < length; i++) {1135if (JAVAXSIZES[i] == mSize) {1136if (SIZES[i] != null) {1137media = SIZES[i];1138break;1139}1140}1141}1142return media;1143}11441145private void translateInputProps() {1146if (props == null) {1147return;1148}11491150String str;11511152str = props.getProperty(DEST_PROP);1153if (str != null) {1154if (str.equals(PRINTER)) {1155jobAttributes.setDestination(DestinationType.PRINTER);1156} else if (str.equals(FILE)) {1157jobAttributes.setDestination(DestinationType.FILE);1158}1159}1160str = props.getProperty(PRINTER_PROP);1161if (str != null) {1162jobAttributes.setPrinter(str);1163}1164str = props.getProperty(FILENAME_PROP);1165if (str != null) {1166jobAttributes.setFileName(str);1167}1168str = props.getProperty(NUMCOPIES_PROP);1169if (str != null) {1170jobAttributes.setCopies(Integer.parseInt(str));1171}11721173this.options = props.getProperty(OPTIONS_PROP, "");11741175str = props.getProperty(ORIENT_PROP);1176if (str != null) {1177if (str.equals(PORTRAIT)) {1178pageAttributes.setOrientationRequested(1179OrientationRequestedType.PORTRAIT);1180} else if (str.equals(LANDSCAPE)) {1181pageAttributes.setOrientationRequested(1182OrientationRequestedType.LANDSCAPE);1183}1184}1185str = props.getProperty(PAPERSIZE_PROP);1186if (str != null) {1187if (str.equals(LETTER)) {1188pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]);1189} else if (str.equals(LEGAL)) {1190pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]);1191} else if (str.equals(EXECUTIVE)) {1192pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]);1193} else if (str.equals(A4)) {1194pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]);1195}1196}1197}11981199private void translateOutputProps() {1200if (props == null) {1201return;1202}12031204String str;12051206props.setProperty(DEST_PROP,1207(jobAttributes.getDestination() == DestinationType.PRINTER) ?1208PRINTER : FILE);1209str = jobAttributes.getPrinter();1210if (str != null && !str.equals("")) {1211props.setProperty(PRINTER_PROP, str);1212}1213str = jobAttributes.getFileName();1214if (str != null && !str.equals("")) {1215props.setProperty(FILENAME_PROP, str);1216}1217int copies = jobAttributes.getCopies();1218if (copies > 0) {1219props.setProperty(NUMCOPIES_PROP, "" + copies);1220}1221str = this.options;1222if (str != null && !str.equals("")) {1223props.setProperty(OPTIONS_PROP, str);1224}1225props.setProperty(ORIENT_PROP,1226(pageAttributes.getOrientationRequested() ==1227OrientationRequestedType.PORTRAIT)1228? PORTRAIT : LANDSCAPE);1229MediaType media = SIZES[pageAttributes.getMedia().hashCode()];1230if (media == MediaType.LETTER) {1231str = LETTER;1232} else if (media == MediaType.LEGAL) {1233str = LEGAL;1234} else if (media == MediaType.EXECUTIVE) {1235str = EXECUTIVE;1236} else if (media == MediaType.A4) {1237str = A4;1238} else {1239str = media.toString();1240}1241props.setProperty(PAPERSIZE_PROP, str);1242}12431244private void throwPrintToFile() {1245SecurityManager security = System.getSecurityManager();1246FilePermission printToFilePermission = null;1247if (security != null) {1248if (printToFilePermission == null) {1249printToFilePermission =1250new FilePermission("<<ALL FILES>>", "read,write");1251}1252security.checkPermission(printToFilePermission);1253}1254}12551256}125712581259