1 /*
   2  * Copyright (c) 2000, 2017, 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.print;
  27 
  28 import java.awt.Dimension;
  29 import java.awt.Frame;
  30 import java.awt.Graphics;
  31 import java.awt.Graphics2D;
  32 import java.awt.PrintJob;
  33 import java.awt.JobAttributes;
  34 import java.awt.JobAttributes.*;
  35 import java.awt.PageAttributes;
  36 import java.awt.PageAttributes.*;
  37 
  38 import java.awt.print.PageFormat;
  39 import java.awt.print.Paper;
  40 import java.awt.print.Printable;
  41 import java.awt.print.PrinterException;
  42 import java.awt.print.PrinterJob;
  43 
  44 import java.io.File;
  45 import java.io.FilePermission;
  46 import java.io.IOException;
  47 
  48 import java.net.URI;
  49 import java.net.URISyntaxException;
  50 
  51 import java.util.ArrayList;
  52 import java.util.Properties;
  53 
  54 import javax.print.PrintService;
  55 import javax.print.attribute.HashPrintRequestAttributeSet;
  56 import javax.print.attribute.PrintRequestAttributeSet;
  57 import javax.print.attribute.ResolutionSyntax;
  58 import javax.print.attribute.Size2DSyntax;
  59 import javax.print.attribute.standard.Chromaticity;
  60 import javax.print.attribute.standard.Copies;
  61 import javax.print.attribute.standard.Destination;
  62 import javax.print.attribute.standard.DialogTypeSelection;
  63 import javax.print.attribute.standard.JobName;
  64 import javax.print.attribute.standard.MediaSize;
  65 import javax.print.attribute.standard.PrintQuality;
  66 import javax.print.attribute.standard.PrinterResolution;
  67 import javax.print.attribute.standard.SheetCollate;
  68 import javax.print.attribute.standard.Sides;
  69 import javax.print.attribute.standard.Media;
  70 import javax.print.attribute.standard.OrientationRequested;
  71 import javax.print.attribute.standard.MediaSizeName;
  72 import javax.print.attribute.standard.PageRanges;
  73 
  74 import sun.print.SunPageSelection;
  75 import sun.print.SunMinMaxPage;
  76 
  77 /**
  78  * A class which initiates and executes a print job using
  79  * the underlying PrinterJob graphics conversions.
  80  *
  81  * @see java.awt.Toolkit#getPrintJob
  82  *
  83  */
  84 public class PrintJob2D extends PrintJob implements Printable, Runnable {
  85 
  86     private static final MediaType SIZES[] = {
  87         MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0,
  88         MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3,
  89         MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6,
  90         MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9,
  91         MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1,
  92         MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4,
  93         MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7,
  94         MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10,
  95         MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2,
  96         MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5,
  97         MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8,
  98         MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0,
  99         MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3,
 100         MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6,
 101         MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9,
 102         MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG,
 103         MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE,
 104         MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL,
 105         MediaType.QUARTO, MediaType.A, MediaType.B,
 106         MediaType.C, MediaType.D, MediaType.E,
 107         MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE,
 108         MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE,
 109         MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE,
 110         MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE,
 111         MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE,
 112         MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE,
 113         MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE,
 114         MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE
 115     };
 116 
 117     /* This array maps the above array to the objects used by the
 118      * javax.print APIs
 119          */
 120     private static final MediaSizeName JAVAXSIZES[] = {
 121         null, null, MediaSizeName.ISO_A0,
 122         MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3,
 123         MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6,
 124         MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9,
 125         MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1,
 126         MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4,
 127         MediaSizeName.ISO_B5,  MediaSizeName.ISO_B6, MediaSizeName.ISO_B7,
 128         MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10,
 129         MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2,
 130         MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5,
 131         MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8,
 132         MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0,
 133         MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3,
 134         MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6,
 135         null, null, null, null,
 136         MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE,
 137         MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER,
 138         MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL,
 139         MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B,
 140         MediaSizeName.C, MediaSizeName.D, MediaSizeName.E,
 141         MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE,
 142         MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,
 143         MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE,
 144         MediaSizeName.NA_6X9_ENVELOPE,
 145         MediaSizeName.NA_NUMBER_9_ENVELOPE,
 146         MediaSizeName.NA_NUMBER_10_ENVELOPE,
 147         MediaSizeName.NA_NUMBER_11_ENVELOPE,
 148         MediaSizeName.NA_NUMBER_12_ENVELOPE,
 149         MediaSizeName.NA_NUMBER_14_ENVELOPE,
 150         null, MediaSizeName.ITALY_ENVELOPE,
 151         MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,
 152     };
 153 
 154 
 155     // widths and lengths in PostScript points (1/72 in.)
 156     private static final int WIDTHS[] = {
 157         /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684,
 158         /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420,
 159         /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105,
 160         /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417,
 161         /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354,
 162         /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88,
 163         /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032,
 164         /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258,
 165         /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599,
 166         /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649,
 167         /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162,
 168         /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312,
 169         /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792,
 170         /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612,
 171         /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448,
 172         /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720,
 173         /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648,
 174         /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504,
 175         /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279,
 176         /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324,
 177         /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360,
 178         /*invite-envelope*/ 624, /*italy-envelope*/ 312,
 179         /*monarch-envelope*/ 279, /*personal-envelope*/ 261
 180     };
 181     private static final int LENGTHS[] = {
 182         /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384,
 183         /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595,
 184         /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147,
 185         /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004,
 186         /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499,
 187         /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125,
 188         /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460,
 189         /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363,
 190         /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677,
 191         /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918,
 192         /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230,
 193         /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624,
 194         /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224,
 195         /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792,
 196         /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168,
 197         /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008,
 198         /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864,
 199         /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648,
 200         /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639,
 201         /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747,
 202         /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828,
 203         /*invite-envelope*/ 624, /*italy-envelope*/ 652,
 204         /*monarch-envelope*/ 540, /*personal-envelope*/ 468
 205     };
 206 
 207 
 208     private Frame frame;
 209     private String docTitle = "";
 210     private JobAttributes jobAttributes;
 211     private PageAttributes pageAttributes;
 212     private PrintRequestAttributeSet attributes;
 213 
 214     /*
 215      * Displays the native or cross-platform dialog and allows the
 216      * user to update job & page attributes
 217      */
 218 
 219     /**
 220      * The PrinterJob being uses to implement the PrintJob.
 221      */
 222     private PrinterJob printerJob;
 223 
 224     /**
 225      * The size of the page being used for the PrintJob.
 226      */
 227     private PageFormat pageFormat;
 228 
 229     /**
 230      * The PrinterJob and the application run on different
 231      * threads and communicate through a pair of message
 232      * queues. This queue is the list of Graphics that
 233      * the PrinterJob has requested rendering for, but
 234      * for which the application has not yet called getGraphics().
 235      * In practice the length of this message queue is always
 236      * 0 or 1.
 237      */
 238     private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn");
 239 
 240     /**
 241      * Used to communicate between the application's thread
 242      * and the PrinterJob's thread this message queue holds
 243      * the list of Graphics into which the application has
 244      * finished drawing, but that have not yet been returned
 245      * to the PrinterJob thread. Again, in practice, the
 246      * length of this message queue is always 0 or 1.
 247      */
 248     private MessageQ graphicsDrawn = new MessageQ("drawn");
 249 
 250     /**
 251      * The last Graphics returned to the application via
 252      * getGraphics. This is the Graphics into which the
 253      * application is currently drawing.
 254      */
 255     private Graphics2D currentGraphics;
 256 
 257     /**
 258      * The zero based index of the page currently being rendered
 259      * by the application.
 260      */
 261     private int pageIndex = -1;
 262 
 263     // The following Strings are maintained for backward-compatibility with
 264     // Properties based print control.
 265     private static final String DEST_PROP = "awt.print.destination";
 266     private static final String PRINTER = "printer";
 267     private static final String FILE = "file";
 268 
 269     private static final String PRINTER_PROP = "awt.print.printer";
 270 
 271     private static final String FILENAME_PROP = "awt.print.fileName";
 272 
 273     private static final String NUMCOPIES_PROP = "awt.print.numCopies";
 274 
 275     private static final String OPTIONS_PROP = "awt.print.options";
 276 
 277     private static final String ORIENT_PROP = "awt.print.orientation";
 278     private static final String PORTRAIT = "portrait";
 279     private static final String LANDSCAPE = "landscape";
 280 
 281     private static final String PAPERSIZE_PROP = "awt.print.paperSize";
 282     private static final String LETTER = "letter";
 283     private static final String LEGAL = "legal";
 284     private static final String EXECUTIVE = "executive";
 285     private static final String A4 = "a4";
 286 
 287     private Properties props;
 288 
 289     private String options = ""; // REMIND: needs implementation
 290 
 291     /**
 292      * The thread on which PrinterJob is running.
 293      * This is different than the applications thread.
 294      */
 295     private Thread printerJobThread;
 296 
 297     public PrintJob2D(Frame frame,  String doctitle,
 298                       final Properties props) {
 299         this.props = props;
 300         this.jobAttributes = new JobAttributes();
 301         this.pageAttributes = new PageAttributes();
 302         translateInputProps();
 303         initPrintJob2D(frame, doctitle,
 304                        this.jobAttributes, this.pageAttributes);
 305     }
 306 
 307     public PrintJob2D(Frame frame,  String doctitle,
 308                       JobAttributes jobAttributes,
 309                       PageAttributes pageAttributes) {
 310         initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
 311     }
 312 
 313     private void initPrintJob2D(Frame frame,  String doctitle,
 314                                 JobAttributes jobAttributes,
 315                                 PageAttributes pageAttributes) {
 316 
 317         SecurityManager security = System.getSecurityManager();
 318         if (security != null) {
 319             security.checkPrintJobAccess();
 320         }
 321 
 322         if (frame == null &&
 323             (jobAttributes == null ||
 324              jobAttributes.getDialog() == DialogType.NATIVE)) {
 325             throw new NullPointerException("Frame must not be null");
 326         }
 327         this.frame = frame;
 328 
 329         this.docTitle = (doctitle == null) ? "" : doctitle;
 330         this.jobAttributes = (jobAttributes != null)
 331             ? jobAttributes : new JobAttributes();
 332         this.pageAttributes = (pageAttributes != null)
 333             ? pageAttributes : new PageAttributes();
 334 
 335         // Currently, we always reduce page ranges to xxx or xxx-xxx
 336         int[][] pageRanges = this.jobAttributes.getPageRanges();
 337         int first = pageRanges[0][0];
 338         int last = pageRanges[pageRanges.length - 1][1];
 339         this.jobAttributes.setPageRanges(new int[][] {
 340             new int[] { first, last }
 341         });
 342         this.jobAttributes.setToPage(last);
 343         this.jobAttributes.setFromPage(first);
 344 
 345 
 346         // Verify that the cross feed and feed resolutions are the same
 347         int[] res = this.pageAttributes.getPrinterResolution();
 348         if (res[0] != res[1]) {
 349             throw new IllegalArgumentException("Differing cross feed and feed"+
 350                                                " resolutions not supported.");
 351         }
 352 
 353         // Verify that the app has access to the file system
 354         DestinationType dest= this.jobAttributes.getDestination();
 355         if (dest == DestinationType.FILE) {
 356             throwPrintToFile();
 357 
 358             // check if given filename is valid
 359             String destStr = jobAttributes.getFileName();
 360             if ((destStr != null) &&
 361                 (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) {
 362 
 363                 File f = new File(destStr);
 364                 try {
 365                     // check if this is a new file and if filename chars are valid
 366                     // createNewFile returns false if file exists
 367                     if (f.createNewFile()) {
 368                         f.delete();
 369                     }
 370                 } catch (IOException ioe) {
 371                     throw new IllegalArgumentException("Cannot write to file:"+
 372                                                        destStr);
 373                 } catch (SecurityException se) {
 374                     //There is already file read/write access so at this point
 375                     // only delete access is denied.  Just ignore it because in
 376                     // most cases the file created in createNewFile gets overwritten
 377                     // anyway.
 378                 }
 379 
 380                  File pFile = f.getParentFile();
 381                  if ((f.exists() &&
 382                       (!f.isFile() || !f.canWrite())) ||
 383                      ((pFile != null) &&
 384                       (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {
 385                      throw new IllegalArgumentException("Cannot write to file:"+
 386                                                         destStr);
 387                  }
 388             }
 389         }
 390     }
 391 
 392     public boolean printDialog() {
 393 
 394         boolean proceedWithPrint = false;
 395 
 396         printerJob = PrinterJob.getPrinterJob();
 397         if (printerJob == null) {
 398             return false;
 399         }
 400         DialogType d = this.jobAttributes.getDialog();
 401         PrintService pServ = printerJob.getPrintService();
 402         if ((pServ == null) &&  (d == DialogType.NONE)){
 403             return false;
 404         }
 405         copyAttributes(pServ);
 406 
 407         DefaultSelectionType select =
 408             this.jobAttributes.getDefaultSelection();
 409         if (select == DefaultSelectionType.RANGE) {
 410             attributes.add(SunPageSelection.RANGE);
 411         } else if (select == DefaultSelectionType.SELECTION) {
 412             attributes.add(SunPageSelection.SELECTION);
 413         } else {
 414             attributes.add(SunPageSelection.ALL);
 415         }
 416 
 417         if (frame != null) {
 418              attributes.add(new DialogOwner(frame));
 419          }
 420 
 421         if ( d == DialogType.NONE) {
 422             proceedWithPrint = true;
 423         } else {
 424             if (d == DialogType.NATIVE) {
 425                 attributes.add(DialogTypeSelection.NATIVE);
 426             }  else { //  (d == DialogType.COMMON)
 427                 attributes.add(DialogTypeSelection.COMMON);
 428             }
 429             if (proceedWithPrint = printerJob.printDialog(attributes)) {
 430                 if (pServ == null) {
 431                     // Windows gives an option to install a service
 432                     // when it detects there are no printers so
 433                     // we make sure we get the updated print service.
 434                     pServ = printerJob.getPrintService();
 435                     if (pServ == null) {
 436                         return false;
 437                     }
 438                 }
 439                 updateAttributes();
 440                 translateOutputProps();
 441             }
 442         }
 443 
 444         if (proceedWithPrint) {
 445 
 446             JobName jname = (JobName)attributes.get(JobName.class);
 447             if (jname != null) {
 448                 printerJob.setJobName(jname.toString());
 449             }
 450 
 451             pageFormat = new PageFormat();
 452 
 453             Media media = (Media)attributes.get(Media.class);
 454             MediaSize mediaSize =  null;
 455             if (media != null  && media instanceof MediaSizeName) {
 456                 mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)media);
 457             }
 458 
 459             Paper p = pageFormat.getPaper();
 460             if (mediaSize != null) {
 461                 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
 462                           mediaSize.getY(MediaSize.INCH)*72.0);
 463             }
 464 
 465             if (pageAttributes.getOrigin()==OriginType.PRINTABLE) {
 466                 // AWT uses 1/4" borders by default
 467                 p.setImageableArea(18.0, 18.0,
 468                                    p.getWidth()-36.0,
 469                                    p.getHeight()-36.0);
 470             } else {
 471                 p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight());
 472             }
 473 
 474             pageFormat.setPaper(p);
 475 
 476             OrientationRequested orient =
 477                (OrientationRequested)attributes.get(OrientationRequested.class);
 478             if (orient!= null &&
 479                 orient == OrientationRequested.REVERSE_LANDSCAPE) {
 480                 pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
 481             } else if (orient == OrientationRequested.LANDSCAPE) {
 482                 pageFormat.setOrientation(PageFormat.LANDSCAPE);
 483             } else {
 484                 pageFormat.setOrientation(PageFormat.PORTRAIT);
 485             }
 486 
 487             PageRanges pageRangesAttr
 488                     = (PageRanges) attributes.get(PageRanges.class);
 489             if (pageRangesAttr != null) {
 490                 // Get the PageRanges from print dialog.
 491                 int[][] range = pageRangesAttr.getMembers();
 492 
 493                 int prevFromPage = this.jobAttributes.getFromPage();
 494                 int prevToPage = this.jobAttributes.getToPage();
 495 
 496                 int currFromPage = range[0][0];
 497                 int currToPage = range[range.length - 1][1];
 498 
 499                 // if from < to update fromPage first followed by toPage
 500                 // else update toPage first followed by fromPage
 501                 if (currFromPage < prevToPage) {
 502                     this.jobAttributes.setFromPage(currFromPage);
 503                     this.jobAttributes.setToPage(currToPage);
 504                 } else {
 505                     this.jobAttributes.setToPage(currToPage);
 506                     this.jobAttributes.setFromPage(currFromPage);
 507                 }
 508             }
 509             printerJob.setPrintable(this, pageFormat);
 510 
 511         }
 512 
 513         return proceedWithPrint;
 514     }
 515 
 516     private void updateAttributes() {
 517         Copies c = (Copies)attributes.get(Copies.class);
 518         jobAttributes.setCopies(c.getValue());
 519 
 520         SunPageSelection sel =
 521             (SunPageSelection)attributes.get(SunPageSelection.class);
 522         if (sel == SunPageSelection.RANGE) {
 523             jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE);
 524         } else if (sel == SunPageSelection.SELECTION) {
 525             jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION);
 526         } else {
 527             jobAttributes.setDefaultSelection(DefaultSelectionType.ALL);
 528         }
 529 
 530         Destination dest = (Destination)attributes.get(Destination.class);
 531         if (dest != null) {
 532             jobAttributes.setDestination(DestinationType.FILE);
 533             jobAttributes.setFileName(dest.getURI().getPath());
 534         } else {
 535             jobAttributes.setDestination(DestinationType.PRINTER);
 536         }
 537 
 538         PrintService serv = printerJob.getPrintService();
 539         if (serv != null) {
 540             jobAttributes.setPrinter(serv.getName());
 541         }
 542 
 543         PageRanges range = (PageRanges)attributes.get(PageRanges.class);
 544         int[][] members = range.getMembers();
 545         jobAttributes.setPageRanges(members);
 546 
 547         SheetCollate collation =
 548             (SheetCollate)attributes.get(SheetCollate.class);
 549         if (collation == SheetCollate.COLLATED) {
 550             jobAttributes.setMultipleDocumentHandling(
 551             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES);
 552         } else {
 553             jobAttributes.setMultipleDocumentHandling(
 554             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);
 555         }
 556 
 557         Sides sides = (Sides)attributes.get(Sides.class);
 558         if (sides == Sides.TWO_SIDED_LONG_EDGE) {
 559             jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE);
 560         } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) {
 561             jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE);
 562         } else {
 563             jobAttributes.setSides(SidesType.ONE_SIDED);
 564         }
 565 
 566         // PageAttributes
 567 
 568         Chromaticity color =
 569             (Chromaticity)attributes.get(Chromaticity.class);
 570         if (color == Chromaticity.COLOR) {
 571             pageAttributes.setColor(ColorType.COLOR);
 572         } else {
 573             pageAttributes.setColor(ColorType.MONOCHROME);
 574         }
 575 
 576         OrientationRequested orient =
 577             (OrientationRequested)attributes.get(OrientationRequested.class);
 578         if (orient == OrientationRequested.LANDSCAPE) {
 579             pageAttributes.setOrientationRequested(
 580                                        OrientationRequestedType.LANDSCAPE);
 581         } else {
 582             pageAttributes.setOrientationRequested(
 583                                        OrientationRequestedType.PORTRAIT);
 584         }
 585 
 586         PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class);
 587         if (qual == PrintQuality.DRAFT) {
 588             pageAttributes.setPrintQuality(PrintQualityType.DRAFT);
 589         } else if (qual == PrintQuality.HIGH) {
 590             pageAttributes.setPrintQuality(PrintQualityType.HIGH);
 591         } else { // NORMAL
 592             pageAttributes.setPrintQuality(PrintQualityType.NORMAL);
 593         }
 594 
 595         Media msn = (Media)attributes.get(Media.class);
 596         if (msn != null && msn instanceof MediaSizeName) {
 597             MediaType mType = unMapMedia((MediaSizeName)msn);
 598 
 599             if (mType != null) {
 600                 pageAttributes.setMedia(mType);
 601             }
 602         }
 603         debugPrintAttributes(false, false);
 604     }
 605 
 606     private void debugPrintAttributes(boolean ja, boolean pa ) {
 607         if (ja) {
 608             System.out.println("new Attributes\ncopies = "+
 609                                jobAttributes.getCopies()+
 610                                "\nselection = "+
 611                                jobAttributes.getDefaultSelection()+
 612                                "\ndest "+jobAttributes.getDestination()+
 613                                "\nfile "+jobAttributes.getFileName()+
 614                                "\nfromPage "+jobAttributes.getFromPage()+
 615                                "\ntoPage "+jobAttributes.getToPage()+
 616                                "\ncollation "+
 617                                jobAttributes.getMultipleDocumentHandling()+
 618                                "\nPrinter "+jobAttributes.getPrinter()+
 619                                "\nSides2 "+jobAttributes.getSides()
 620                                );
 621         }
 622 
 623         if (pa) {
 624             System.out.println("new Attributes\ncolor = "+
 625                                pageAttributes.getColor()+
 626                                "\norientation = "+
 627                                pageAttributes.getOrientationRequested()+
 628                                "\nquality "+pageAttributes.getPrintQuality()+
 629                                "\nMedia2 "+pageAttributes.getMedia()
 630                                );
 631         }
 632     }
 633 
 634 
 635     /* From JobAttributes we will copy job name and duplex printing
 636      * and destination.
 637      * The majority of the rest of the attributes are reflected
 638      * attributes.
 639      *
 640      * From PageAttributes we copy color, media size, orientation,
 641      * origin type, resolution and print quality.
 642      * We use the media, orientation in creating the page format, and
 643      * the origin type to set its imageable area.
 644      *
 645      * REMIND: Interpretation of resolution, additional media sizes.
 646      */
 647     private void copyAttributes(PrintService printServ) {
 648 
 649         attributes = new HashPrintRequestAttributeSet();
 650         attributes.add(new JobName(docTitle, null));
 651         PrintService pServ = printServ;
 652 
 653         String printerName = jobAttributes.getPrinter();
 654         if (printerName != null && printerName != ""
 655             && pServ != null && !printerName.equals(pServ.getName())) {
 656 
 657             // Search for the given printerName in the list of PrintServices
 658             PrintService []services = PrinterJob.lookupPrintServices();
 659             try {
 660                 for (int i=0; i<services.length; i++) {
 661                     if (printerName.equals(services[i].getName())) {
 662                         printerJob.setPrintService(services[i]);
 663                         pServ = services[i];
 664                         break;
 665                     }
 666                 }
 667             } catch (PrinterException pe) {
 668             }
 669         }
 670 
 671         DestinationType dest = jobAttributes.getDestination();
 672         if (dest == DestinationType.FILE && pServ != null &&
 673             pServ.isAttributeCategorySupported(Destination.class)) {
 674 
 675             String fileName = jobAttributes.getFileName();
 676 
 677             Destination defaultDest;
 678             if (fileName == null && (defaultDest = (Destination)pServ.
 679                     getDefaultAttributeValue(Destination.class)) != null) {
 680                 attributes.add(defaultDest);
 681             } else {
 682                 URI uri = null;
 683                 try {
 684                     if (fileName != null) {
 685                         if (fileName.equals("")) {
 686                             fileName = ".";
 687                         }
 688                     } else {
 689                         // defaultDest should not be null.  The following code
 690                         // is only added to safeguard against a possible
 691                         // buggy implementation of a PrintService having a
 692                         // null default Destination.
 693                         fileName = "out.prn";
 694                     }
 695                     uri = (new File(fileName)).toURI();
 696                 } catch (SecurityException se) {
 697                     try {
 698                         // '\\' file separator is illegal character in opaque
 699                         // part and causes URISyntaxException, so we replace
 700                         // it with '/'
 701                         fileName = fileName.replace('\\', '/');
 702                         uri = new URI("file:"+fileName);
 703                     } catch (URISyntaxException e) {
 704                     }
 705                 }
 706                 if (uri != null) {
 707                     attributes.add(new Destination(uri));
 708                 }
 709             }
 710         }
 711         attributes.add(new SunMinMaxPage(jobAttributes.getMinPage(),
 712                                          jobAttributes.getMaxPage()));
 713         SidesType sType = jobAttributes.getSides();
 714         if (sType == SidesType.TWO_SIDED_LONG_EDGE) {
 715             attributes.add(Sides.TWO_SIDED_LONG_EDGE);
 716         } else if (sType == SidesType.TWO_SIDED_SHORT_EDGE) {
 717             attributes.add(Sides.TWO_SIDED_SHORT_EDGE);
 718         } else if (sType == SidesType.ONE_SIDED) {
 719             attributes.add(Sides.ONE_SIDED);
 720         }
 721 
 722         MultipleDocumentHandlingType hType =
 723           jobAttributes.getMultipleDocumentHandling();
 724         if (hType ==
 725             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES) {
 726           attributes.add(SheetCollate.COLLATED);
 727         } else {
 728           attributes.add(SheetCollate.UNCOLLATED);
 729         }
 730 
 731         attributes.add(new Copies(jobAttributes.getCopies()));
 732 
 733         attributes.add(new PageRanges(jobAttributes.getFromPage(),
 734                                       jobAttributes.getToPage()));
 735 
 736         if (pageAttributes.getColor() == ColorType.COLOR) {
 737             attributes.add(Chromaticity.COLOR);
 738         } else {
 739             attributes.add(Chromaticity.MONOCHROME);
 740         }
 741 
 742         pageFormat = printerJob.defaultPage();
 743         if (pageAttributes.getOrientationRequested() ==
 744             OrientationRequestedType.LANDSCAPE) {
 745             pageFormat.setOrientation(PageFormat.LANDSCAPE);
 746                 attributes.add(OrientationRequested.LANDSCAPE);
 747         } else {
 748                 pageFormat.setOrientation(PageFormat.PORTRAIT);
 749                 attributes.add(OrientationRequested.PORTRAIT);
 750         }
 751 
 752         MediaType media = pageAttributes.getMedia();
 753         MediaSizeName msn = mapMedia(media);
 754         if (msn != null) {
 755             attributes.add(msn);
 756         }
 757 
 758         PrintQualityType qType =
 759             pageAttributes.getPrintQuality();
 760         if (qType == PrintQualityType.DRAFT) {
 761             attributes.add(PrintQuality.DRAFT);
 762         } else if (qType == PrintQualityType.NORMAL) {
 763             attributes.add(PrintQuality.NORMAL);
 764         } else if (qType == PrintQualityType.HIGH) {
 765             attributes.add(PrintQuality.HIGH);
 766         }
 767     }
 768 
 769     /**
 770      * Gets a Graphics object that will draw to the next page.
 771      * The page is sent to the printer when the graphics
 772      * object is disposed.  This graphics object will also implement
 773      * the PrintGraphics interface.
 774      * @see java.awt.PrintGraphics
 775      */
 776     public Graphics getGraphics() {
 777 
 778         Graphics printGraphics = null;
 779 
 780         synchronized (this) {
 781             ++pageIndex;
 782 
 783             // Thread should not be created after end has been called.
 784             // One way to detect this is if any of the graphics queue
 785             //  has been closed.
 786             if (pageIndex == 0 && !graphicsToBeDrawn.isClosed()) {
 787 
 788             /* We start a thread on which the PrinterJob will run.
 789              * The PrinterJob will ask for pages on that thread
 790              * and will use a message queue to fulfill the application's
 791              * requests for a Graphics on the application's
 792              * thread.
 793              */
 794 
 795                 startPrinterJobThread();
 796 
 797             }
 798             notify();
 799         }
 800 
 801         /* If the application has already been handed back
 802          * a graphics then we need to put that graphics into
 803          * the drawn queue so that the PrinterJob thread can
 804          * return to the print system.
 805          */
 806         if (currentGraphics != null) {
 807             graphicsDrawn.append(currentGraphics);
 808             currentGraphics = null;
 809         }
 810 
 811         /* We'll block here until a new graphics becomes
 812          * available.
 813          */
 814 
 815         currentGraphics = graphicsToBeDrawn.pop();
 816 
 817         if (currentGraphics instanceof PeekGraphics) {
 818             ( (PeekGraphics) currentGraphics).setAWTDrawingOnly();
 819             graphicsDrawn.append(currentGraphics);
 820             currentGraphics = graphicsToBeDrawn.pop();
 821         }
 822 
 823 
 824         if (currentGraphics != null) {
 825 
 826             /* In the PrintJob API, the origin is at the upper-
 827              * left of the imageable area when using the new "printable"
 828              * origin attribute, otherwise its the physical origin (for
 829              * backwards compatibility. We emulate this by createing
 830              * a PageFormat which matches and then performing the
 831              * translate to the origin. This is a no-op if physical
 832              * origin is specified.
 833              */
 834             currentGraphics.translate(pageFormat.getImageableX(),
 835                                       pageFormat.getImageableY());
 836 
 837             /* Scale to accommodate AWT's notion of printer resolution */
 838             double awtScale = 72.0/getPageResolutionInternal();
 839             currentGraphics.scale(awtScale, awtScale);
 840 
 841             /* The caller wants a Graphics instance but we do
 842              * not want them to make 2D calls. We can't hand
 843              * back a Graphics2D. The returned Graphics also
 844              * needs to implement PrintGraphics, so we wrap
 845              * the Graphics2D instance. The PrintJob API has
 846              * the application dispose of the Graphics so
 847              * we create a copy of the one returned by PrinterJob.
 848              */
 849             printGraphics = new ProxyPrintGraphics(currentGraphics.create(),
 850                                                    this);
 851 
 852         }
 853 
 854         return printGraphics;
 855     }
 856 
 857     /**
 858      * Returns the dimensions of the page in pixels.
 859      * The resolution of the page is chosen so that it
 860      * is similar to the screen resolution.
 861      * Except (since 1.3) when the application specifies a resolution.
 862      * In that case it is scaled accordingly.
 863      */
 864     public Dimension getPageDimension() {
 865         double wid, hgt, scale;
 866         if (pageAttributes != null &&
 867             pageAttributes.getOrigin()==OriginType.PRINTABLE) {
 868             wid = pageFormat.getImageableWidth();
 869             hgt = pageFormat.getImageableHeight();
 870         } else {
 871             wid = pageFormat.getWidth();
 872             hgt = pageFormat.getHeight();
 873         }
 874         scale = getPageResolutionInternal() / 72.0;
 875         return new Dimension((int)(wid * scale), (int)(hgt * scale));
 876     }
 877 
 878      private double getPageResolutionInternal() {
 879         if (pageAttributes != null) {
 880             int []res = pageAttributes.getPrinterResolution();
 881             if (res[2] == 3) {
 882                 return res[0];
 883             } else /* if (res[2] == 4) */ {
 884                 return (res[0] * 2.54);
 885             }
 886         } else {
 887             return 72.0;
 888         }
 889     }
 890 
 891     /**
 892      * Returns the resolution of the page in pixels per inch.
 893      * Note that this doesn't have to correspond to the physical
 894      * resolution of the printer.
 895      */
 896     public int getPageResolution() {
 897         return (int)getPageResolutionInternal();
 898     }
 899 
 900     /**
 901      * Returns true if the last page will be printed first.
 902      */
 903     public boolean lastPageFirst() {
 904         return false;
 905     }
 906 
 907     /**
 908      * Ends the print job and does any necessary cleanup.
 909      */
 910     public synchronized void end() {
 911 
 912         /* Prevent the PrinterJob thread from appending any more
 913          * graphics to the to-be-drawn queue
 914          */
 915         graphicsToBeDrawn.close();
 916 
 917         /* If we have a currentGraphics it was the last one returned to the
 918          * PrintJob client. Append it to the drawn queue so that print()
 919          * will return allowing the page to be flushed.
 920          * This really ought to happen in dispose() but for whatever reason
 921          * that isn't how the old PrintJob worked even though its spec
 922          * said dispose() flushed the page.
 923          */
 924         if (currentGraphics != null) {
 925             graphicsDrawn.append(currentGraphics);
 926         }
 927         graphicsDrawn.closeWhenEmpty();
 928 
 929         /* Wait for the PrinterJob.print() thread to terminate, ensuring
 930          * that RasterPrinterJob has made its end doc call, and resources
 931          * are released, files closed etc.
 932          */
 933         if( printerJobThread != null && printerJobThread.isAlive() ){
 934             try {
 935                 printerJobThread.join();
 936             } catch (InterruptedException e) {
 937             }
 938         }
 939     }
 940 
 941     /**
 942      * Ends this print job once it is no longer referenced.
 943      * @see #end
 944      */
 945     @SuppressWarnings("deprecation")
 946     public void finalize() {
 947         end();
 948     }
 949 
 950     /**
 951      * Prints the page at the specified index into the specified
 952      * {@link Graphics} context in the specified
 953      * format.  A {@code PrinterJob} calls the
 954      * {@code Printable} interface to request that a page be
 955      * rendered into the context specified by
 956      * {@code graphics}.  The format of the page to be drawn is
 957      * specified by {@code pageFormat}.  The zero based index
 958      * of the requested page is specified by {@code pageIndex}.
 959      * If the requested page does not exist then this method returns
 960      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
 961      * The {@code Graphics} class or subclass implements the
 962      * {@link java.awt.PrintGraphics} interface to provide additional
 963      * information.  If the {@code Printable} object
 964      * aborts the print job then it throws a {@link PrinterException}.
 965      * @param graphics the context into which the page is drawn
 966      * @param pageFormat the size and orientation of the page being drawn
 967      * @param pageIndex the zero based index of the page to be drawn
 968      * @return PAGE_EXISTS if the page is rendered successfully
 969      *         or NO_SUCH_PAGE if {@code pageIndex} specifies a
 970      *         non-existent page.
 971      * @exception java.awt.print.PrinterException
 972      *         thrown when the print job is terminated.
 973      */
 974     public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
 975                  throws PrinterException {
 976 
 977         int result;
 978 
 979         /* This method will be called by the PrinterJob on a thread other
 980          * that the application's thread. We hold on to the graphics
 981          * until we can rendevous with the application's thread and
 982          * hand over the graphics. The application then does all the
 983          * drawing. When the application is done drawing we rendevous
 984          * again with the PrinterJob thread and release the Graphics
 985          * so that it knows we are done.
 986          */
 987 
 988         /* Add the graphics to the message queue of graphics to
 989          * be rendered. This is really a one slot queue. The
 990          * application's thread will come along and remove the
 991          * graphics from the queue when the app asks for a graphics.
 992          */
 993         graphicsToBeDrawn.append( (Graphics2D) graphics);
 994 
 995         /* We now wait for the app's thread to finish drawing on
 996          * the Graphics. This thread will sleep until the application
 997          * release the graphics by placing it in the graphics drawn
 998          * message queue. If the application signals that it is
 999          * finished drawing the entire document then we'll get null
1000          * returned when we try and pop a finished graphic.
1001          */
1002         if (graphicsDrawn.pop() != null) {
1003             result = PAGE_EXISTS;
1004         } else {
1005             result = NO_SUCH_PAGE;
1006         }
1007 
1008         return result;
1009     }
1010 
1011     private void startPrinterJobThread() {
1012         printerJobThread =
1013             new Thread(null, this, "printerJobThread", 0, false);
1014         printerJobThread.start();
1015     }
1016 
1017 
1018     public void run() {
1019 
1020         try {
1021             attributes.remove(PageRanges.class);
1022             printerJob.print(attributes);
1023         } catch (PrinterException e) {
1024             //REMIND: need to store this away and not rethrow it.
1025         }
1026 
1027         /* Close the message queues so that nobody is stuck
1028          * waiting for one.
1029          */
1030         graphicsToBeDrawn.closeWhenEmpty();
1031         graphicsDrawn.close();
1032     }
1033 
1034     private class MessageQ {
1035 
1036         private String qid="noname";
1037 
1038         private ArrayList<Graphics2D> queue = new ArrayList<>();
1039 
1040         MessageQ(String id) {
1041           qid = id;
1042         }
1043 
1044         synchronized void closeWhenEmpty() {
1045 
1046             while (queue != null && queue.size() > 0) {
1047                 try {
1048                     wait(1000);
1049                 } catch (InterruptedException e) {
1050                     // do nothing.
1051                 }
1052             }
1053 
1054             queue = null;
1055             notifyAll();
1056         }
1057 
1058         synchronized void close() {
1059             queue = null;
1060             notifyAll();
1061         }
1062 
1063         synchronized boolean append(Graphics2D g) {
1064 
1065             boolean queued = false;
1066 
1067             if (queue != null) {
1068                 queue.add(g);
1069                 queued = true;
1070                 notify();
1071             }
1072 
1073             return queued;
1074         }
1075 
1076         synchronized Graphics2D pop() {
1077             Graphics2D g = null;
1078 
1079             while (g == null && queue != null) {
1080 
1081                 if (queue.size() > 0) {
1082                     g = queue.remove(0);
1083                     notify();
1084 
1085                 } else {
1086                     try {
1087                         wait(2000);
1088                     } catch (InterruptedException e) {
1089                         // do nothing.
1090                     }
1091                 }
1092             }
1093 
1094             return g;
1095         }
1096 
1097         synchronized boolean isClosed() {
1098             return queue == null;
1099         }
1100 
1101     }
1102 
1103 
1104     private static int[] getSize(MediaType mType) {
1105         int []dim = new int[2];
1106         dim[0] = 612;
1107         dim[1] = 792;
1108 
1109         for (int i=0; i < SIZES.length; i++) {
1110             if (SIZES[i] == mType) {
1111                 dim[0] = WIDTHS[i];
1112                 dim[1] = LENGTHS[i];
1113                 break;
1114             }
1115         }
1116         return dim;
1117     }
1118 
1119     public static MediaSizeName mapMedia(MediaType mType) {
1120         MediaSizeName media = null;
1121 
1122         // JAVAXSIZES.length and SIZES.length must be equal!
1123         // Attempt to recover by getting the smaller size.
1124         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1125 
1126         for (int i=0; i < length; i++) {
1127             if (SIZES[i] == mType) {
1128                 if ((JAVAXSIZES[i] != null) &&
1129                     MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) {
1130                     media = JAVAXSIZES[i];
1131                     break;
1132                 } else {
1133                     /* create Custom Media */
1134                     media = new CustomMediaSizeName(SIZES[i].toString());
1135 
1136                     float w = (float)Math.rint(WIDTHS[i]  / 72.0);
1137                     float h = (float)Math.rint(LENGTHS[i] / 72.0);
1138                     if (w > 0.0 && h > 0.0) {
1139                         // add new created MediaSize to our static map
1140                         // so it will be found when we call findMedia
1141                         new MediaSize(w, h, Size2DSyntax.INCH, media);
1142                     }
1143 
1144                     break;
1145                 }
1146             }
1147         }
1148         return media;
1149     }
1150 
1151 
1152     public static MediaType unMapMedia(MediaSizeName mSize) {
1153         MediaType media = null;
1154 
1155         // JAVAXSIZES.length and SIZES.length must be equal!
1156         // Attempt to recover by getting the smaller size.
1157         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1158 
1159         for (int i=0; i < length; i++) {
1160             if (JAVAXSIZES[i] == mSize) {
1161                 if (SIZES[i] != null) {
1162                     media = SIZES[i];
1163                     break;
1164                 }
1165             }
1166         }
1167         return media;
1168     }
1169 
1170     private void translateInputProps() {
1171         if (props == null) {
1172             return;
1173         }
1174 
1175         String str;
1176 
1177         str = props.getProperty(DEST_PROP);
1178         if (str != null) {
1179             if (str.equals(PRINTER)) {
1180                 jobAttributes.setDestination(DestinationType.PRINTER);
1181             } else if (str.equals(FILE)) {
1182                 jobAttributes.setDestination(DestinationType.FILE);
1183             }
1184         }
1185         str = props.getProperty(PRINTER_PROP);
1186         if (str != null) {
1187             jobAttributes.setPrinter(str);
1188         }
1189         str = props.getProperty(FILENAME_PROP);
1190         if (str != null) {
1191             jobAttributes.setFileName(str);
1192         }
1193         str = props.getProperty(NUMCOPIES_PROP);
1194         if (str != null) {
1195             jobAttributes.setCopies(Integer.parseInt(str));
1196         }
1197 
1198         this.options = props.getProperty(OPTIONS_PROP, "");
1199 
1200         str = props.getProperty(ORIENT_PROP);
1201         if (str != null) {
1202             if (str.equals(PORTRAIT)) {
1203                 pageAttributes.setOrientationRequested(
1204                                         OrientationRequestedType.PORTRAIT);
1205             } else if (str.equals(LANDSCAPE)) {
1206                 pageAttributes.setOrientationRequested(
1207                                         OrientationRequestedType.LANDSCAPE);
1208             }
1209         }
1210         str = props.getProperty(PAPERSIZE_PROP);
1211         if (str != null) {
1212             if (str.equals(LETTER)) {
1213                 pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]);
1214             } else if (str.equals(LEGAL)) {
1215                 pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]);
1216             } else if (str.equals(EXECUTIVE)) {
1217                 pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]);
1218             } else if (str.equals(A4)) {
1219                 pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]);
1220             }
1221         }
1222     }
1223 
1224     private void translateOutputProps() {
1225         if (props == null) {
1226             return;
1227         }
1228 
1229         String str;
1230 
1231         props.setProperty(DEST_PROP,
1232             (jobAttributes.getDestination() == DestinationType.PRINTER) ?
1233                           PRINTER : FILE);
1234         str = jobAttributes.getPrinter();
1235         if (str != null && !str.equals("")) {
1236             props.setProperty(PRINTER_PROP, str);
1237         }
1238         str = jobAttributes.getFileName();
1239         if (str != null && !str.equals("")) {
1240             props.setProperty(FILENAME_PROP, str);
1241         }
1242         int copies = jobAttributes.getCopies();
1243         if (copies > 0) {
1244             props.setProperty(NUMCOPIES_PROP, "" + copies);
1245         }
1246         str = this.options;
1247         if (str != null && !str.equals("")) {
1248             props.setProperty(OPTIONS_PROP, str);
1249         }
1250         props.setProperty(ORIENT_PROP,
1251             (pageAttributes.getOrientationRequested() ==
1252              OrientationRequestedType.PORTRAIT)
1253                           ? PORTRAIT : LANDSCAPE);
1254         MediaType media = SIZES[pageAttributes.getMedia().hashCode()];
1255         if (media == MediaType.LETTER) {
1256             str = LETTER;
1257         } else if (media == MediaType.LEGAL) {
1258             str = LEGAL;
1259         } else if (media == MediaType.EXECUTIVE) {
1260             str = EXECUTIVE;
1261         } else if (media == MediaType.A4) {
1262             str = A4;
1263         } else {
1264             str = media.toString();
1265         }
1266         props.setProperty(PAPERSIZE_PROP, str);
1267     }
1268 
1269     private void throwPrintToFile() {
1270         SecurityManager security = System.getSecurityManager();
1271         FilePermission printToFilePermission = null;
1272         if (security != null) {
1273             if (printToFilePermission == null) {
1274                 printToFilePermission =
1275                     new FilePermission("<<ALL FILES>>", "read,write");
1276             }
1277             security.checkPermission(printToFilePermission);
1278         }
1279     }
1280 
1281 }