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