From 5d0b6737b50458f021be480c086b90d9826ee0f7 Mon Sep 17 00:00:00 2001 From: prrace Date: Tue, 22 Jul 2025 14:42:13 -0700 Subject: [PATCH 1/4] 8363889 --- .../share/classes/sun/print/PrintJob2D.java | 1149 +-------------- .../classes/sun/print/PrintJobDelegate.java | 1233 +++++++++++++++++ 2 files changed, 1253 insertions(+), 1129 deletions(-) create mode 100644 src/java.desktop/share/classes/sun/print/PrintJobDelegate.java diff --git a/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/src/java.desktop/share/classes/sun/print/PrintJob2D.java index b3811e363676d..17fa99c49c2fa 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,47 +28,14 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.PrintJob; import java.awt.JobAttributes; import java.awt.JobAttributes.*; import java.awt.PageAttributes; import java.awt.PageAttributes.*; - -import java.awt.print.PageFormat; -import java.awt.print.Paper; -import java.awt.print.Printable; -import java.awt.print.PrinterException; -import java.awt.print.PrinterJob; - -import java.io.File; -import java.io.IOException; - -import java.net.URI; -import java.net.URISyntaxException; - -import java.util.ArrayList; import java.util.Properties; - -import javax.print.PrintService; -import javax.print.attribute.HashPrintRequestAttributeSet; -import javax.print.attribute.PrintRequestAttributeSet; -import javax.print.attribute.Size2DSyntax; -import javax.print.attribute.standard.Chromaticity; -import javax.print.attribute.standard.Copies; -import javax.print.attribute.standard.Destination; -import javax.print.attribute.standard.DialogTypeSelection; -import javax.print.attribute.standard.DialogOwner; -import javax.print.attribute.standard.JobName; -import javax.print.attribute.standard.MediaSize; -import javax.print.attribute.standard.PrintQuality; -import javax.print.attribute.standard.SheetCollate; -import javax.print.attribute.standard.Sides; -import javax.print.attribute.standard.Media; -import javax.print.attribute.standard.OrientationRequested; -import javax.print.attribute.standard.MediaSizeName; -import javax.print.attribute.standard.PageRanges; - +import sun.java2d.Disposer; +import sun.java2d.DisposerRecord; /** * A class which initiates and executes a print job using @@ -77,667 +44,26 @@ * @see java.awt.Toolkit#getPrintJob * */ -public class PrintJob2D extends PrintJob implements Printable, Runnable { - - private static final MediaType[] SIZES = { - MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0, - MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3, - MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6, - MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9, - MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1, - MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4, - MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7, - MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10, - MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2, - MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5, - MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8, - MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0, - MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3, - MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6, - MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9, - MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG, - MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE, - MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL, - MediaType.QUARTO, MediaType.A, MediaType.B, - MediaType.C, MediaType.D, MediaType.E, - MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE, - MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE, - MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE, - MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE, - MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE, - MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE, - MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE, - MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE - }; - - /* This array maps the above array to the objects used by the - * javax.print APIs - */ - private static final MediaSizeName[] JAVAXSIZES = { - null, null, MediaSizeName.ISO_A0, - MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3, - MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6, - MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9, - MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1, - MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4, - MediaSizeName.ISO_B5, MediaSizeName.ISO_B6, MediaSizeName.ISO_B7, - MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10, - MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2, - MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5, - MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8, - MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0, - MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3, - MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6, - null, null, null, null, - MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE, - MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER, - MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL, - MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B, - MediaSizeName.C, MediaSizeName.D, MediaSizeName.E, - MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE, - MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE, - MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE, - MediaSizeName.NA_6X9_ENVELOPE, - MediaSizeName.NA_NUMBER_9_ENVELOPE, - MediaSizeName.NA_NUMBER_10_ENVELOPE, - MediaSizeName.NA_NUMBER_11_ENVELOPE, - MediaSizeName.NA_NUMBER_12_ENVELOPE, - MediaSizeName.NA_NUMBER_14_ENVELOPE, - null, MediaSizeName.ITALY_ENVELOPE, - MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE, - }; +public class PrintJob2D extends PrintJob { - - // widths and lengths in PostScript points (1/72 in.) - private static final int[] WIDTHS = { - /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684, - /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420, - /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105, - /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417, - /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354, - /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88, - /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032, - /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258, - /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599, - /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649, - /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162, - /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312, - /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792, - /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612, - /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448, - /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720, - /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648, - /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504, - /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279, - /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324, - /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360, - /*invite-envelope*/ 624, /*italy-envelope*/ 312, - /*monarch-envelope*/ 279, /*personal-envelope*/ 261 - }; - private static final int[] LENGTHS = { - /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384, - /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595, - /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147, - /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004, - /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499, - /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125, - /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460, - /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363, - /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677, - /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918, - /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230, - /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624, - /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224, - /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792, - /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168, - /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008, - /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864, - /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648, - /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639, - /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747, - /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828, - /*invite-envelope*/ 624, /*italy-envelope*/ 652, - /*monarch-envelope*/ 540, /*personal-envelope*/ 468 - }; - - - private Frame frame; - private String docTitle = ""; - private JobAttributes jobAttributes; - private PageAttributes pageAttributes; - private PrintRequestAttributeSet attributes; - - /* - * Displays the native or cross-platform dialog and allows the - * user to update job & page attributes - */ - - /** - * The PrinterJob being uses to implement the PrintJob. - */ - private PrinterJob printerJob; - - /** - * The size of the page being used for the PrintJob. - */ - private PageFormat pageFormat; - - /** - * The PrinterJob and the application run on different - * threads and communicate through a pair of message - * queues. This queue is the list of Graphics that - * the PrinterJob has requested rendering for, but - * for which the application has not yet called getGraphics(). - * In practice the length of this message queue is always - * 0 or 1. - */ - private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn"); - - /** - * Used to communicate between the application's thread - * and the PrinterJob's thread this message queue holds - * the list of Graphics into which the application has - * finished drawing, but that have not yet been returned - * to the PrinterJob thread. Again, in practice, the - * length of this message queue is always 0 or 1. - */ - private MessageQ graphicsDrawn = new MessageQ("drawn"); - - /** - * The last Graphics returned to the application via - * getGraphics. This is the Graphics into which the - * application is currently drawing. - */ - private Graphics2D currentGraphics; - - /** - * The zero based index of the page currently being rendered - * by the application. - */ - private int pageIndex = -1; - - // The following Strings are maintained for backward-compatibility with - // Properties based print control. - private static final String DEST_PROP = "awt.print.destination"; - private static final String PRINTER = "printer"; - private static final String FILE = "file"; - - private static final String PRINTER_PROP = "awt.print.printer"; - - private static final String FILENAME_PROP = "awt.print.fileName"; - - private static final String NUMCOPIES_PROP = "awt.print.numCopies"; - - private static final String OPTIONS_PROP = "awt.print.options"; - - private static final String ORIENT_PROP = "awt.print.orientation"; - private static final String PORTRAIT = "portrait"; - private static final String LANDSCAPE = "landscape"; - - private static final String PAPERSIZE_PROP = "awt.print.paperSize"; - private static final String LETTER = "letter"; - private static final String LEGAL = "legal"; - private static final String EXECUTIVE = "executive"; - private static final String A4 = "a4"; - - private Properties props; - - private String options = ""; // REMIND: needs implementation - - /** - * The thread on which PrinterJob is running. - * This is different than the applications thread. - */ - private Thread printerJobThread; + private final PrintJobDelegate printJobDelegate; public PrintJob2D(Frame frame, String doctitle, final Properties props) { - this.props = props; - this.jobAttributes = new JobAttributes(); - this.pageAttributes = new PageAttributes(); - translateInputProps(); - initPrintJob2D(frame, doctitle, - this.jobAttributes, this.pageAttributes); + printJobDelegate = new PrintJobDelegate(frame, doctitle, props); } public PrintJob2D(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { - initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes); + printJobDelegate = new PrintJobDelegate(frame, doctitle, jobAttributes, pageAttributes); + Disposer.addRecord(this, new PrintJobDisposerRecord(printJobDelegate)); } - private void initPrintJob2D(Frame frame, String doctitle, - JobAttributes jobAttributes, - PageAttributes pageAttributes) { - - if (frame == null && - (jobAttributes == null || - jobAttributes.getDialog() == DialogType.NATIVE)) { - throw new NullPointerException("Frame must not be null"); - } - this.frame = frame; - - this.docTitle = (doctitle == null) ? "" : doctitle; - this.jobAttributes = (jobAttributes != null) - ? jobAttributes : new JobAttributes(); - this.pageAttributes = (pageAttributes != null) - ? pageAttributes : new PageAttributes(); - - // Currently, we always reduce page ranges to xxx or xxx-xxx - int[][] pageRanges = this.jobAttributes.getPageRanges(); - int first = pageRanges[0][0]; - int last = pageRanges[pageRanges.length - 1][1]; - this.jobAttributes.setPageRanges(new int[][] { - new int[] { first, last } - }); - this.jobAttributes.setToPage(last); - this.jobAttributes.setFromPage(first); - - - // Verify that the cross feed and feed resolutions are the same - int[] res = this.pageAttributes.getPrinterResolution(); - if (res[0] != res[1]) { - throw new IllegalArgumentException("Differing cross feed and feed"+ - " resolutions not supported."); - } - - // Verify that the app has access to the file system - DestinationType dest= this.jobAttributes.getDestination(); - if (dest == DestinationType.FILE) { - - // check if given filename is valid - String destStr = jobAttributes.getFileName(); - if ((destStr != null) && - (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) { - - File f = new File(destStr); - try { - // check if this is a new file and if filename chars are valid - // createNewFile returns false if file exists - if (f.createNewFile()) { - f.delete(); - } - } catch (IOException ioe) { - throw new IllegalArgumentException("Cannot write to file:"+ - destStr); - } - - File pFile = f.getParentFile(); - if ((f.exists() && - (!f.isFile() || !f.canWrite())) || - ((pFile != null) && - (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { - throw new IllegalArgumentException("Cannot write to file:"+ - destStr); - } - } - } - } + // PrintJob2D API, not PrintJob public boolean printDialog() { - - boolean proceedWithPrint = false; - - printerJob = PrinterJob.getPrinterJob(); - if (printerJob == null) { - return false; - } - DialogType d = this.jobAttributes.getDialog(); - PrintService pServ = printerJob.getPrintService(); - if ((pServ == null) && (d == DialogType.NONE)){ - return false; - } - copyAttributes(pServ); - - DefaultSelectionType select = - this.jobAttributes.getDefaultSelection(); - if (select == DefaultSelectionType.RANGE) { - attributes.add(SunPageSelection.RANGE); - } else if (select == DefaultSelectionType.SELECTION) { - attributes.add(SunPageSelection.SELECTION); - } else { - attributes.add(SunPageSelection.ALL); - } - - if (frame != null) { - attributes.add(new DialogOwner(frame)); - } - - if ( d == DialogType.NONE) { - proceedWithPrint = true; - } else { - if (d == DialogType.NATIVE) { - attributes.add(DialogTypeSelection.NATIVE); - } else { // (d == DialogType.COMMON) - attributes.add(DialogTypeSelection.COMMON); - } - if (proceedWithPrint = printerJob.printDialog(attributes)) { - if (pServ == null) { - // Windows gives an option to install a service - // when it detects there are no printers so - // we make sure we get the updated print service. - pServ = printerJob.getPrintService(); - if (pServ == null) { - return false; - } - } - updateAttributes(); - translateOutputProps(); - } - } - - if (proceedWithPrint) { - - JobName jname = (JobName)attributes.get(JobName.class); - if (jname != null) { - printerJob.setJobName(jname.toString()); - } - - pageFormat = new PageFormat(); - - Media media = (Media)attributes.get(Media.class); - MediaSize mediaSize = null; - if (media instanceof MediaSizeName msn) { - mediaSize = MediaSize.getMediaSizeForName(msn); - } - - Paper p = pageFormat.getPaper(); - if (mediaSize != null) { - p.setSize(mediaSize.getX(MediaSize.INCH)*72.0, - mediaSize.getY(MediaSize.INCH)*72.0); - } - - if (pageAttributes.getOrigin()==OriginType.PRINTABLE) { - // AWT uses 1/4" borders by default - p.setImageableArea(18.0, 18.0, - p.getWidth()-36.0, - p.getHeight()-36.0); - } else { - p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight()); - } - - pageFormat.setPaper(p); - - OrientationRequested orient = - (OrientationRequested)attributes.get(OrientationRequested.class); - if (orient!= null && - orient == OrientationRequested.REVERSE_LANDSCAPE) { - pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE); - } else if (orient == OrientationRequested.LANDSCAPE) { - pageFormat.setOrientation(PageFormat.LANDSCAPE); - } else { - pageFormat.setOrientation(PageFormat.PORTRAIT); - } - - PageRanges pageRangesAttr - = (PageRanges) attributes.get(PageRanges.class); - if (pageRangesAttr != null) { - // Get the PageRanges from print dialog. - int[][] range = pageRangesAttr.getMembers(); - - int prevFromPage = this.jobAttributes.getFromPage(); - int prevToPage = this.jobAttributes.getToPage(); - - int currFromPage = range[0][0]; - int currToPage = range[range.length - 1][1]; - - // if from < to update fromPage first followed by toPage - // else update toPage first followed by fromPage - if (currFromPage < prevToPage) { - this.jobAttributes.setFromPage(currFromPage); - this.jobAttributes.setToPage(currToPage); - } else { - this.jobAttributes.setToPage(currToPage); - this.jobAttributes.setFromPage(currFromPage); - } - } - printerJob.setPrintable(this, pageFormat); - - } - - return proceedWithPrint; - } - - private void updateAttributes() { - Copies c = (Copies)attributes.get(Copies.class); - jobAttributes.setCopies(c.getValue()); - - SunPageSelection sel = - (SunPageSelection)attributes.get(SunPageSelection.class); - if (sel == SunPageSelection.RANGE) { - jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE); - } else if (sel == SunPageSelection.SELECTION) { - jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION); - } else { - jobAttributes.setDefaultSelection(DefaultSelectionType.ALL); - } - - Destination dest = (Destination)attributes.get(Destination.class); - if (dest != null) { - jobAttributes.setDestination(DestinationType.FILE); - jobAttributes.setFileName(dest.getURI().getPath()); - } else { - jobAttributes.setDestination(DestinationType.PRINTER); - } - - PrintService serv = printerJob.getPrintService(); - if (serv != null) { - jobAttributes.setPrinter(serv.getName()); - } - - PageRanges range = (PageRanges)attributes.get(PageRanges.class); - int[][] members = range.getMembers(); - jobAttributes.setPageRanges(members); - - SheetCollate collation = - (SheetCollate)attributes.get(SheetCollate.class); - if (collation == SheetCollate.COLLATED) { - jobAttributes.setMultipleDocumentHandling( - MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES); - } else { - jobAttributes.setMultipleDocumentHandling( - MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES); - } - - Sides sides = (Sides)attributes.get(Sides.class); - if (sides == Sides.TWO_SIDED_LONG_EDGE) { - jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE); - } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) { - jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE); - } else { - jobAttributes.setSides(SidesType.ONE_SIDED); - } - - // PageAttributes - - Chromaticity color = - (Chromaticity)attributes.get(Chromaticity.class); - if (color == Chromaticity.COLOR) { - pageAttributes.setColor(ColorType.COLOR); - } else { - pageAttributes.setColor(ColorType.MONOCHROME); - } - - OrientationRequested orient = - (OrientationRequested)attributes.get(OrientationRequested.class); - if (orient == OrientationRequested.LANDSCAPE) { - pageAttributes.setOrientationRequested( - OrientationRequestedType.LANDSCAPE); - } else { - pageAttributes.setOrientationRequested( - OrientationRequestedType.PORTRAIT); - } - - PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class); - if (qual == PrintQuality.DRAFT) { - pageAttributes.setPrintQuality(PrintQualityType.DRAFT); - } else if (qual == PrintQuality.HIGH) { - pageAttributes.setPrintQuality(PrintQualityType.HIGH); - } else { // NORMAL - pageAttributes.setPrintQuality(PrintQualityType.NORMAL); - } - - Media media = (Media)attributes.get(Media.class); - if (media instanceof MediaSizeName msn) { - MediaType mType = unMapMedia(msn); - - if (mType != null) { - pageAttributes.setMedia(mType); - } - } - debugPrintAttributes(false, false); - } - - private void debugPrintAttributes(boolean ja, boolean pa ) { - if (ja) { - System.out.println("new Attributes\ncopies = "+ - jobAttributes.getCopies()+ - "\nselection = "+ - jobAttributes.getDefaultSelection()+ - "\ndest "+jobAttributes.getDestination()+ - "\nfile "+jobAttributes.getFileName()+ - "\nfromPage "+jobAttributes.getFromPage()+ - "\ntoPage "+jobAttributes.getToPage()+ - "\ncollation "+ - jobAttributes.getMultipleDocumentHandling()+ - "\nPrinter "+jobAttributes.getPrinter()+ - "\nSides2 "+jobAttributes.getSides() - ); - } - - if (pa) { - System.out.println("new Attributes\ncolor = "+ - pageAttributes.getColor()+ - "\norientation = "+ - pageAttributes.getOrientationRequested()+ - "\nquality "+pageAttributes.getPrintQuality()+ - "\nMedia2 "+pageAttributes.getMedia() - ); - } - } - - - /* From JobAttributes we will copy job name and duplex printing - * and destination. - * The majority of the rest of the attributes are reflected - * attributes. - * - * From PageAttributes we copy color, media size, orientation, - * origin type, resolution and print quality. - * We use the media, orientation in creating the page format, and - * the origin type to set its imageable area. - * - * REMIND: Interpretation of resolution, additional media sizes. - */ - private void copyAttributes(PrintService printServ) { - - attributes = new HashPrintRequestAttributeSet(); - attributes.add(new JobName(docTitle, null)); - PrintService pServ = printServ; - - String printerName = jobAttributes.getPrinter(); - if (printerName != null && printerName != "" - && pServ != null && !printerName.equals(pServ.getName())) { - - // Search for the given printerName in the list of PrintServices - PrintService []services = PrinterJob.lookupPrintServices(); - try { - for (int i=0; i queue = new ArrayList<>(); - - MessageQ(String id) { - qid = id; - } - - synchronized void closeWhenEmpty() { - - while (queue != null && queue.size() > 0) { - try { - wait(1000); - } catch (InterruptedException e) { - // do nothing. - } - } - - queue = null; - notifyAll(); - } - - synchronized void close() { - queue = null; - notifyAll(); - } - - synchronized boolean append(Graphics2D g) { - - boolean queued = false; - - if (queue != null) { - queue.add(g); - queued = true; - notify(); - } - - return queued; - } - - synchronized Graphics2D pop() { - Graphics2D g = null; - - while (g == null && queue != null) { - - if (queue.size() > 0) { - g = queue.remove(0); - notify(); - - } else { - try { - wait(2000); - } catch (InterruptedException e) { - // do nothing. - } - } - } - - return g; - } - - synchronized boolean isClosed() { - return queue == null; - } - - } - - - private static int[] getSize(MediaType mType) { - int []dim = new int[2]; - dim[0] = 612; - dim[1] = 792; - - for (int i=0; i < SIZES.length; i++) { - if (SIZES[i] == mType) { - dim[0] = WIDTHS[i]; - dim[1] = LENGTHS[i]; - break; - } - } - return dim; - } - - public static MediaSizeName mapMedia(MediaType mType) { - MediaSizeName media = null; - - // JAVAXSIZES.length and SIZES.length must be equal! - // Attempt to recover by getting the smaller size. - int length = Math.min(SIZES.length, JAVAXSIZES.length); - - for (int i=0; i < length; i++) { - if (SIZES[i] == mType) { - if ((JAVAXSIZES[i] != null) && - MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) { - media = JAVAXSIZES[i]; - break; - } else { - /* create Custom Media */ - media = new CustomMediaSizeName(SIZES[i].toString()); - - float w = (float)Math.rint(WIDTHS[i] / 72.0); - float h = (float)Math.rint(LENGTHS[i] / 72.0); - if (w > 0.0 && h > 0.0) { - // add new created MediaSize to our static map - // so it will be found when we call findMedia - new MediaSize(w, h, Size2DSyntax.INCH, media); - } - - break; - } - } - } - return media; - } - - - public static MediaType unMapMedia(MediaSizeName mSize) { - MediaType media = null; - - // JAVAXSIZES.length and SIZES.length must be equal! - // Attempt to recover by getting the smaller size. - int length = Math.min(SIZES.length, JAVAXSIZES.length); - - for (int i=0; i < length; i++) { - if (JAVAXSIZES[i] == mSize) { - if (SIZES[i] != null) { - media = SIZES[i]; - break; - } - } - } - return media; - } - - private void translateInputProps() { - if (props == null) { - return; - } - - String str; - - str = props.getProperty(DEST_PROP); - if (str != null) { - if (str.equals(PRINTER)) { - jobAttributes.setDestination(DestinationType.PRINTER); - } else if (str.equals(FILE)) { - jobAttributes.setDestination(DestinationType.FILE); - } - } - str = props.getProperty(PRINTER_PROP); - if (str != null) { - jobAttributes.setPrinter(str); - } - str = props.getProperty(FILENAME_PROP); - if (str != null) { - jobAttributes.setFileName(str); - } - str = props.getProperty(NUMCOPIES_PROP); - if (str != null) { - jobAttributes.setCopies(Integer.parseInt(str)); - } - - this.options = props.getProperty(OPTIONS_PROP, ""); - - str = props.getProperty(ORIENT_PROP); - if (str != null) { - if (str.equals(PORTRAIT)) { - pageAttributes.setOrientationRequested( - OrientationRequestedType.PORTRAIT); - } else if (str.equals(LANDSCAPE)) { - pageAttributes.setOrientationRequested( - OrientationRequestedType.LANDSCAPE); - } - } - str = props.getProperty(PAPERSIZE_PROP); - if (str != null) { - if (str.equals(LETTER)) { - pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]); - } else if (str.equals(LEGAL)) { - pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]); - } else if (str.equals(EXECUTIVE)) { - pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]); - } else if (str.equals(A4)) { - pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]); - } - } - } - - private void translateOutputProps() { - if (props == null) { - return; - } - - String str; - - props.setProperty(DEST_PROP, - (jobAttributes.getDestination() == DestinationType.PRINTER) ? - PRINTER : FILE); - str = jobAttributes.getPrinter(); - if (str != null && !str.isEmpty()) { - props.setProperty(PRINTER_PROP, str); - } - str = jobAttributes.getFileName(); - if (str != null && !str.isEmpty()) { - props.setProperty(FILENAME_PROP, str); - } - int copies = jobAttributes.getCopies(); - if (copies > 0) { - props.setProperty(NUMCOPIES_PROP, "" + copies); - } - str = this.options; - if (str != null && !str.isEmpty()) { - props.setProperty(OPTIONS_PROP, str); - } - props.setProperty(ORIENT_PROP, - (pageAttributes.getOrientationRequested() == - OrientationRequestedType.PORTRAIT) - ? PORTRAIT : LANDSCAPE); - MediaType media = SIZES[pageAttributes.getMedia().hashCode()]; - if (media == MediaType.LETTER) { - str = LETTER; - } else if (media == MediaType.LEGAL) { - str = LEGAL; - } else if (media == MediaType.EXECUTIVE) { - str = EXECUTIVE; - } else if (media == MediaType.A4) { - str = A4; - } else { - str = media.toString(); - } - props.setProperty(PAPERSIZE_PROP, str); - } - } diff --git a/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java b/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java new file mode 100644 index 0000000000000..c516c20ca0f79 --- /dev/null +++ b/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java @@ -0,0 +1,1233 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.print; + +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.PrintJob; +import java.awt.JobAttributes; +import java.awt.JobAttributes.*; +import java.awt.PageAttributes; +import java.awt.PageAttributes.*; + +import java.awt.print.PageFormat; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; + +import java.io.File; +import java.io.IOException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Properties; + +import javax.print.PrintService; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.Size2DSyntax; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.Destination; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.print.attribute.standard.DialogOwner; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.MediaSize; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.PageRanges; + + +/** + * A class which initiates and executes a print job using + * the underlying PrinterJob graphics conversions. + * + * @see java.awt.Toolkit#getPrintJob + * + */ +public class PrintJobDelegate implements Printable, Runnable { + + private static final MediaType[] SIZES = { + MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0, + MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3, + MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6, + MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9, + MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1, + MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4, + MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7, + MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10, + MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2, + MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5, + MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8, + MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0, + MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3, + MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6, + MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9, + MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG, + MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE, + MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL, + MediaType.QUARTO, MediaType.A, MediaType.B, + MediaType.C, MediaType.D, MediaType.E, + MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE, + MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE, + MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE, + MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE, + MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE, + MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE, + MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE, + MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE + }; + + /* This array maps the above array to the objects used by the + * javax.print APIs + */ + private static final MediaSizeName[] JAVAXSIZES = { + null, null, MediaSizeName.ISO_A0, + MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3, + MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6, + MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9, + MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1, + MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4, + MediaSizeName.ISO_B5, MediaSizeName.ISO_B6, MediaSizeName.ISO_B7, + MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10, + MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2, + MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5, + MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8, + MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0, + MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3, + MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6, + null, null, null, null, + MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE, + MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER, + MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL, + MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B, + MediaSizeName.C, MediaSizeName.D, MediaSizeName.E, + MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE, + MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE, + MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE, + MediaSizeName.NA_6X9_ENVELOPE, + MediaSizeName.NA_NUMBER_9_ENVELOPE, + MediaSizeName.NA_NUMBER_10_ENVELOPE, + MediaSizeName.NA_NUMBER_11_ENVELOPE, + MediaSizeName.NA_NUMBER_12_ENVELOPE, + MediaSizeName.NA_NUMBER_14_ENVELOPE, + null, MediaSizeName.ITALY_ENVELOPE, + MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE, + }; + + + // widths and lengths in PostScript points (1/72 in.) + private static final int[] WIDTHS = { + /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684, + /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420, + /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105, + /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417, + /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354, + /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88, + /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032, + /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258, + /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599, + /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649, + /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162, + /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312, + /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792, + /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612, + /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448, + /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720, + /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648, + /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504, + /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279, + /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324, + /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360, + /*invite-envelope*/ 624, /*italy-envelope*/ 312, + /*monarch-envelope*/ 279, /*personal-envelope*/ 261 + }; + private static final int[] LENGTHS = { + /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384, + /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595, + /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147, + /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004, + /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499, + /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125, + /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460, + /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363, + /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677, + /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918, + /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230, + /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624, + /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224, + /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792, + /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168, + /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008, + /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864, + /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648, + /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639, + /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747, + /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828, + /*invite-envelope*/ 624, /*italy-envelope*/ 652, + /*monarch-envelope*/ 540, /*personal-envelope*/ 468 + }; + + + private Frame frame; + private String docTitle = ""; + private JobAttributes jobAttributes; + private PageAttributes pageAttributes; + private PrintRequestAttributeSet attributes; + + /* + * Displays the native or cross-platform dialog and allows the + * user to update job & page attributes + */ + + /** + * The PrinterJob being uses to implement the PrintJob. + */ + private PrinterJob printerJob; + + /** + * The size of the page being used for the PrintJob. + */ + private PageFormat pageFormat; + + /** + * The PrinterJob and the application run on different + * threads and communicate through a pair of message + * queues. This queue is the list of Graphics that + * the PrinterJob has requested rendering for, but + * for which the application has not yet called getGraphics(). + * In practice the length of this message queue is always + * 0 or 1. + */ + private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn"); + + /** + * Used to communicate between the application's thread + * and the PrinterJob's thread this message queue holds + * the list of Graphics into which the application has + * finished drawing, but that have not yet been returned + * to the PrinterJob thread. Again, in practice, the + * length of this message queue is always 0 or 1. + */ + private MessageQ graphicsDrawn = new MessageQ("drawn"); + + /** + * The last Graphics returned to the application via + * getGraphics. This is the Graphics into which the + * application is currently drawing. + */ + private Graphics2D currentGraphics; + + /** + * The zero based index of the page currently being rendered + * by the application. + */ + private int pageIndex = -1; + + // The following Strings are maintained for backward-compatibility with + // Properties based print control. + private static final String DEST_PROP = "awt.print.destination"; + private static final String PRINTER = "printer"; + private static final String FILE = "file"; + + private static final String PRINTER_PROP = "awt.print.printer"; + + private static final String FILENAME_PROP = "awt.print.fileName"; + + private static final String NUMCOPIES_PROP = "awt.print.numCopies"; + + private static final String OPTIONS_PROP = "awt.print.options"; + + private static final String ORIENT_PROP = "awt.print.orientation"; + private static final String PORTRAIT = "portrait"; + private static final String LANDSCAPE = "landscape"; + + private static final String PAPERSIZE_PROP = "awt.print.paperSize"; + private static final String LETTER = "letter"; + private static final String LEGAL = "legal"; + private static final String EXECUTIVE = "executive"; + private static final String A4 = "a4"; + + private Properties props; + + private String options = ""; // REMIND: needs implementation + + /** + * The thread on which PrinterJob is running. + * This is different than the applications thread. + */ + private Thread printerJobThread; + + public PrintJobDelegate(Frame frame, String doctitle, + final Properties props) { + this.props = props; + this.jobAttributes = new JobAttributes(); + this.pageAttributes = new PageAttributes(); + translateInputProps(); + initPrintJob2D(frame, doctitle, + this.jobAttributes, this.pageAttributes); + } + + public PrintJobDelegate(Frame frame, String doctitle, + JobAttributes jobAttributes, + PageAttributes pageAttributes) { + initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes); + } + + private void initPrintJob2D(Frame frame, String doctitle, + JobAttributes jobAttributes, + PageAttributes pageAttributes) { + + if (frame == null && + (jobAttributes == null || + jobAttributes.getDialog() == DialogType.NATIVE)) { + throw new NullPointerException("Frame must not be null"); + } + this.frame = frame; + + this.docTitle = (doctitle == null) ? "" : doctitle; + this.jobAttributes = (jobAttributes != null) + ? jobAttributes : new JobAttributes(); + this.pageAttributes = (pageAttributes != null) + ? pageAttributes : new PageAttributes(); + + // Currently, we always reduce page ranges to xxx or xxx-xxx + int[][] pageRanges = this.jobAttributes.getPageRanges(); + int first = pageRanges[0][0]; + int last = pageRanges[pageRanges.length - 1][1]; + this.jobAttributes.setPageRanges(new int[][] { + new int[] { first, last } + }); + this.jobAttributes.setToPage(last); + this.jobAttributes.setFromPage(first); + + + // Verify that the cross feed and feed resolutions are the same + int[] res = this.pageAttributes.getPrinterResolution(); + if (res[0] != res[1]) { + throw new IllegalArgumentException("Differing cross feed and feed"+ + " resolutions not supported."); + } + + // Verify that the app has access to the file system + DestinationType dest= this.jobAttributes.getDestination(); + if (dest == DestinationType.FILE) { + + // check if given filename is valid + String destStr = jobAttributes.getFileName(); + if ((destStr != null) && + (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) { + + File f = new File(destStr); + try { + // check if this is a new file and if filename chars are valid + // createNewFile returns false if file exists + if (f.createNewFile()) { + f.delete(); + } + } catch (IOException ioe) { + throw new IllegalArgumentException("Cannot write to file:"+ + destStr); + } + + File pFile = f.getParentFile(); + if ((f.exists() && + (!f.isFile() || !f.canWrite())) || + ((pFile != null) && + (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { + throw new IllegalArgumentException("Cannot write to file:"+ + destStr); + } + } + } + } + + public boolean printDialog() { + + boolean proceedWithPrint = false; + + printerJob = PrinterJob.getPrinterJob(); + if (printerJob == null) { + return false; + } + DialogType d = this.jobAttributes.getDialog(); + PrintService pServ = printerJob.getPrintService(); + if ((pServ == null) && (d == DialogType.NONE)){ + return false; + } + copyAttributes(pServ); + + DefaultSelectionType select = + this.jobAttributes.getDefaultSelection(); + if (select == DefaultSelectionType.RANGE) { + attributes.add(SunPageSelection.RANGE); + } else if (select == DefaultSelectionType.SELECTION) { + attributes.add(SunPageSelection.SELECTION); + } else { + attributes.add(SunPageSelection.ALL); + } + + if (frame != null) { + attributes.add(new DialogOwner(frame)); + } + + if ( d == DialogType.NONE) { + proceedWithPrint = true; + } else { + if (d == DialogType.NATIVE) { + attributes.add(DialogTypeSelection.NATIVE); + } else { // (d == DialogType.COMMON) + attributes.add(DialogTypeSelection.COMMON); + } + if (proceedWithPrint = printerJob.printDialog(attributes)) { + if (pServ == null) { + // Windows gives an option to install a service + // when it detects there are no printers so + // we make sure we get the updated print service. + pServ = printerJob.getPrintService(); + if (pServ == null) { + return false; + } + } + updateAttributes(); + translateOutputProps(); + } + } + + if (proceedWithPrint) { + + JobName jname = (JobName)attributes.get(JobName.class); + if (jname != null) { + printerJob.setJobName(jname.toString()); + } + + pageFormat = new PageFormat(); + + Media media = (Media)attributes.get(Media.class); + MediaSize mediaSize = null; + if (media instanceof MediaSizeName msn) { + mediaSize = MediaSize.getMediaSizeForName(msn); + } + + Paper p = pageFormat.getPaper(); + if (mediaSize != null) { + p.setSize(mediaSize.getX(MediaSize.INCH)*72.0, + mediaSize.getY(MediaSize.INCH)*72.0); + } + + if (pageAttributes.getOrigin()==OriginType.PRINTABLE) { + // AWT uses 1/4" borders by default + p.setImageableArea(18.0, 18.0, + p.getWidth()-36.0, + p.getHeight()-36.0); + } else { + p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight()); + } + + pageFormat.setPaper(p); + + OrientationRequested orient = + (OrientationRequested)attributes.get(OrientationRequested.class); + if (orient!= null && + orient == OrientationRequested.REVERSE_LANDSCAPE) { + pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE); + } else if (orient == OrientationRequested.LANDSCAPE) { + pageFormat.setOrientation(PageFormat.LANDSCAPE); + } else { + pageFormat.setOrientation(PageFormat.PORTRAIT); + } + + PageRanges pageRangesAttr + = (PageRanges) attributes.get(PageRanges.class); + if (pageRangesAttr != null) { + // Get the PageRanges from print dialog. + int[][] range = pageRangesAttr.getMembers(); + + int prevFromPage = this.jobAttributes.getFromPage(); + int prevToPage = this.jobAttributes.getToPage(); + + int currFromPage = range[0][0]; + int currToPage = range[range.length - 1][1]; + + // if from < to update fromPage first followed by toPage + // else update toPage first followed by fromPage + if (currFromPage < prevToPage) { + this.jobAttributes.setFromPage(currFromPage); + this.jobAttributes.setToPage(currToPage); + } else { + this.jobAttributes.setToPage(currToPage); + this.jobAttributes.setFromPage(currFromPage); + } + } + printerJob.setPrintable(this, pageFormat); + + } + + return proceedWithPrint; + } + + private void updateAttributes() { + Copies c = (Copies)attributes.get(Copies.class); + jobAttributes.setCopies(c.getValue()); + + SunPageSelection sel = + (SunPageSelection)attributes.get(SunPageSelection.class); + if (sel == SunPageSelection.RANGE) { + jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE); + } else if (sel == SunPageSelection.SELECTION) { + jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION); + } else { + jobAttributes.setDefaultSelection(DefaultSelectionType.ALL); + } + + Destination dest = (Destination)attributes.get(Destination.class); + if (dest != null) { + jobAttributes.setDestination(DestinationType.FILE); + jobAttributes.setFileName(dest.getURI().getPath()); + } else { + jobAttributes.setDestination(DestinationType.PRINTER); + } + + PrintService serv = printerJob.getPrintService(); + if (serv != null) { + jobAttributes.setPrinter(serv.getName()); + } + + PageRanges range = (PageRanges)attributes.get(PageRanges.class); + int[][] members = range.getMembers(); + jobAttributes.setPageRanges(members); + + SheetCollate collation = + (SheetCollate)attributes.get(SheetCollate.class); + if (collation == SheetCollate.COLLATED) { + jobAttributes.setMultipleDocumentHandling( + MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES); + } else { + jobAttributes.setMultipleDocumentHandling( + MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES); + } + + Sides sides = (Sides)attributes.get(Sides.class); + if (sides == Sides.TWO_SIDED_LONG_EDGE) { + jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE); + } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) { + jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE); + } else { + jobAttributes.setSides(SidesType.ONE_SIDED); + } + + // PageAttributes + + Chromaticity color = + (Chromaticity)attributes.get(Chromaticity.class); + if (color == Chromaticity.COLOR) { + pageAttributes.setColor(ColorType.COLOR); + } else { + pageAttributes.setColor(ColorType.MONOCHROME); + } + + OrientationRequested orient = + (OrientationRequested)attributes.get(OrientationRequested.class); + if (orient == OrientationRequested.LANDSCAPE) { + pageAttributes.setOrientationRequested( + OrientationRequestedType.LANDSCAPE); + } else { + pageAttributes.setOrientationRequested( + OrientationRequestedType.PORTRAIT); + } + + PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class); + if (qual == PrintQuality.DRAFT) { + pageAttributes.setPrintQuality(PrintQualityType.DRAFT); + } else if (qual == PrintQuality.HIGH) { + pageAttributes.setPrintQuality(PrintQualityType.HIGH); + } else { // NORMAL + pageAttributes.setPrintQuality(PrintQualityType.NORMAL); + } + + Media media = (Media)attributes.get(Media.class); + if (media instanceof MediaSizeName msn) { + MediaType mType = unMapMedia(msn); + + if (mType != null) { + pageAttributes.setMedia(mType); + } + } + debugPrintAttributes(false, false); + } + + private void debugPrintAttributes(boolean ja, boolean pa ) { + if (ja) { + System.out.println("new Attributes\ncopies = "+ + jobAttributes.getCopies()+ + "\nselection = "+ + jobAttributes.getDefaultSelection()+ + "\ndest "+jobAttributes.getDestination()+ + "\nfile "+jobAttributes.getFileName()+ + "\nfromPage "+jobAttributes.getFromPage()+ + "\ntoPage "+jobAttributes.getToPage()+ + "\ncollation "+ + jobAttributes.getMultipleDocumentHandling()+ + "\nPrinter "+jobAttributes.getPrinter()+ + "\nSides2 "+jobAttributes.getSides() + ); + } + + if (pa) { + System.out.println("new Attributes\ncolor = "+ + pageAttributes.getColor()+ + "\norientation = "+ + pageAttributes.getOrientationRequested()+ + "\nquality "+pageAttributes.getPrintQuality()+ + "\nMedia2 "+pageAttributes.getMedia() + ); + } + } + + + /* From JobAttributes we will copy job name and duplex printing + * and destination. + * The majority of the rest of the attributes are reflected + * attributes. + * + * From PageAttributes we copy color, media size, orientation, + * origin type, resolution and print quality. + * We use the media, orientation in creating the page format, and + * the origin type to set its imageable area. + * + * REMIND: Interpretation of resolution, additional media sizes. + */ + private void copyAttributes(PrintService printServ) { + + attributes = new HashPrintRequestAttributeSet(); + attributes.add(new JobName(docTitle, null)); + PrintService pServ = printServ; + + String printerName = jobAttributes.getPrinter(); + if (printerName != null && printerName != "" + && pServ != null && !printerName.equals(pServ.getName())) { + + // Search for the given printerName in the list of PrintServices + PrintService []services = PrinterJob.lookupPrintServices(); + try { + for (int i=0; i queue = new ArrayList<>(); + + MessageQ(String id) { + qid = id; + } + + synchronized void closeWhenEmpty() { + + while (queue != null && queue.size() > 0) { + try { + wait(1000); + } catch (InterruptedException e) { + // do nothing. + } + } + + queue = null; + notifyAll(); + } + + synchronized void close() { + queue = null; + notifyAll(); + } + + synchronized boolean append(Graphics2D g) { + + boolean queued = false; + + if (queue != null) { + queue.add(g); + queued = true; + notify(); + } + + return queued; + } + + synchronized Graphics2D pop() { + Graphics2D g = null; + + while (g == null && queue != null) { + + if (queue.size() > 0) { + g = queue.remove(0); + notify(); + + } else { + try { + wait(2000); + } catch (InterruptedException e) { + // do nothing. + } + } + } + + return g; + } + + synchronized boolean isClosed() { + return queue == null; + } + + } + + + private static int[] getSize(MediaType mType) { + int []dim = new int[2]; + dim[0] = 612; + dim[1] = 792; + + for (int i=0; i < SIZES.length; i++) { + if (SIZES[i] == mType) { + dim[0] = WIDTHS[i]; + dim[1] = LENGTHS[i]; + break; + } + } + return dim; + } + + public static MediaSizeName mapMedia(MediaType mType) { + MediaSizeName media = null; + + // JAVAXSIZES.length and SIZES.length must be equal! + // Attempt to recover by getting the smaller size. + int length = Math.min(SIZES.length, JAVAXSIZES.length); + + for (int i=0; i < length; i++) { + if (SIZES[i] == mType) { + if ((JAVAXSIZES[i] != null) && + MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) { + media = JAVAXSIZES[i]; + break; + } else { + /* create Custom Media */ + media = new CustomMediaSizeName(SIZES[i].toString()); + + float w = (float)Math.rint(WIDTHS[i] / 72.0); + float h = (float)Math.rint(LENGTHS[i] / 72.0); + if (w > 0.0 && h > 0.0) { + // add new created MediaSize to our static map + // so it will be found when we call findMedia + new MediaSize(w, h, Size2DSyntax.INCH, media); + } + + break; + } + } + } + return media; + } + + + public static MediaType unMapMedia(MediaSizeName mSize) { + MediaType media = null; + + // JAVAXSIZES.length and SIZES.length must be equal! + // Attempt to recover by getting the smaller size. + int length = Math.min(SIZES.length, JAVAXSIZES.length); + + for (int i=0; i < length; i++) { + if (JAVAXSIZES[i] == mSize) { + if (SIZES[i] != null) { + media = SIZES[i]; + break; + } + } + } + return media; + } + + private void translateInputProps() { + if (props == null) { + return; + } + + String str; + + str = props.getProperty(DEST_PROP); + if (str != null) { + if (str.equals(PRINTER)) { + jobAttributes.setDestination(DestinationType.PRINTER); + } else if (str.equals(FILE)) { + jobAttributes.setDestination(DestinationType.FILE); + } + } + str = props.getProperty(PRINTER_PROP); + if (str != null) { + jobAttributes.setPrinter(str); + } + str = props.getProperty(FILENAME_PROP); + if (str != null) { + jobAttributes.setFileName(str); + } + str = props.getProperty(NUMCOPIES_PROP); + if (str != null) { + jobAttributes.setCopies(Integer.parseInt(str)); + } + + this.options = props.getProperty(OPTIONS_PROP, ""); + + str = props.getProperty(ORIENT_PROP); + if (str != null) { + if (str.equals(PORTRAIT)) { + pageAttributes.setOrientationRequested( + OrientationRequestedType.PORTRAIT); + } else if (str.equals(LANDSCAPE)) { + pageAttributes.setOrientationRequested( + OrientationRequestedType.LANDSCAPE); + } + } + str = props.getProperty(PAPERSIZE_PROP); + if (str != null) { + if (str.equals(LETTER)) { + pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]); + } else if (str.equals(LEGAL)) { + pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]); + } else if (str.equals(EXECUTIVE)) { + pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]); + } else if (str.equals(A4)) { + pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]); + } + } + } + + private void translateOutputProps() { + if (props == null) { + return; + } + + String str; + + props.setProperty(DEST_PROP, + (jobAttributes.getDestination() == DestinationType.PRINTER) ? + PRINTER : FILE); + str = jobAttributes.getPrinter(); + if (str != null && !str.isEmpty()) { + props.setProperty(PRINTER_PROP, str); + } + str = jobAttributes.getFileName(); + if (str != null && !str.isEmpty()) { + props.setProperty(FILENAME_PROP, str); + } + int copies = jobAttributes.getCopies(); + if (copies > 0) { + props.setProperty(NUMCOPIES_PROP, "" + copies); + } + str = this.options; + if (str != null && !str.isEmpty()) { + props.setProperty(OPTIONS_PROP, str); + } + props.setProperty(ORIENT_PROP, + (pageAttributes.getOrientationRequested() == + OrientationRequestedType.PORTRAIT) + ? PORTRAIT : LANDSCAPE); + MediaType media = SIZES[pageAttributes.getMedia().hashCode()]; + if (media == MediaType.LETTER) { + str = LETTER; + } else if (media == MediaType.LEGAL) { + str = LEGAL; + } else if (media == MediaType.EXECUTIVE) { + str = EXECUTIVE; + } else if (media == MediaType.A4) { + str = A4; + } else { + str = media.toString(); + } + props.setProperty(PAPERSIZE_PROP, str); + } + +} From 45a5aa7cb7bb96ad53419ccd73591e9dcfa30814 Mon Sep 17 00:00:00 2001 From: prrace Date: Tue, 22 Jul 2025 15:07:37 -0700 Subject: [PATCH 2/4] 8363889 --- src/java.desktop/share/classes/sun/print/PrintJob2D.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 17fa99c49c2fa..9813347e603cf 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -51,6 +51,7 @@ public class PrintJob2D extends PrintJob { public PrintJob2D(Frame frame, String doctitle, final Properties props) { printJobDelegate = new PrintJobDelegate(frame, doctitle, props); + Disposer.addRecord(this, new PrintJobDisposerRecord(printJobDelegate)); } public PrintJob2D(Frame frame, String doctitle, From b70e147ecd03ffdf20dfc6e26cdaf324d357abac Mon Sep 17 00:00:00 2001 From: prrace Date: Fri, 1 Aug 2025 14:41:39 -0700 Subject: [PATCH 3/4] 8363889 --- .../share/classes/sun/print/PrintJob2D.java | 11 ++++++++--- .../share/classes/sun/print/PrintJobDelegate.java | 8 +------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 9813347e603cf..5f6372241de93 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -30,9 +30,7 @@ import java.awt.Graphics; import java.awt.PrintJob; import java.awt.JobAttributes; -import java.awt.JobAttributes.*; import java.awt.PageAttributes; -import java.awt.PageAttributes.*; import java.util.Properties; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; @@ -75,6 +73,12 @@ public boolean printDialog() { * @see java.awt.PrintGraphics */ public Graphics getGraphics() { + /* The caller wants a Graphics instance but we do + * not want them to make 2D calls. We can't hand + * back a Graphics2D. The returned Graphics also + * needs to implement PrintGraphics, so we wrap + * the Graphics2D instance. + */ return new ProxyPrintGraphics(printJobDelegate.getGraphics(), this); } @@ -102,7 +106,7 @@ public int getPageResolution() { * Returns true if the last page will be printed first. */ public boolean lastPageFirst() { - return false; + return printJobDelegate.lastPageFirst(); } /** @@ -120,6 +124,7 @@ private static class PrintJobDisposerRecord implements DisposerRecord { } public void dispose() { + Thread.dumpStack(); printJobDelegate.end(); } } diff --git a/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java b/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java index c516c20ca0f79..5a88d4b9d45f5 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java +++ b/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java @@ -812,15 +812,9 @@ public Graphics getGraphics() { double awtScale = 72.0/getPageResolutionInternal(); currentGraphics.scale(awtScale, awtScale); - /* The caller wants a Graphics instance but we do - * not want them to make 2D calls. We can't hand - * back a Graphics2D. The returned Graphics also - * needs to implement PrintGraphics, so we wrap - * the Graphics2D instance. The PrintJob API has - * the application dispose of the Graphics so + /* The PrintJob API has the application dispose of the Graphics so * we create a copy of the one returned by PrinterJob. */ - //printGraphics = new ProxyPrintGraphics(currentGraphics.create(), this); printGraphics = currentGraphics.create(); } From 312840fce427fd842638e05fccc0ceacd5d60dc3 Mon Sep 17 00:00:00 2001 From: prrace Date: Sat, 2 Aug 2025 12:40:05 -0700 Subject: [PATCH 4/4] 8363889 --- src/java.desktop/share/classes/sun/print/PrintJob2D.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 5f6372241de93..8128dae1057db 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -124,7 +124,6 @@ private static class PrintJobDisposerRecord implements DisposerRecord { } public void dispose() { - Thread.dumpStack(); printJobDelegate.end(); } }