1 /*
2  * Copyright (c) 1997, 2014, 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.awt.windows;
27 
28 import java.awt.Color;
29 import java.awt.Font;
30 import java.awt.Graphics2D;
31 import java.awt.GraphicsEnvironment;
32 import java.awt.HeadlessException;
33 import java.awt.KeyboardFocusManager;
34 import java.awt.Toolkit;
35 import java.awt.BasicStroke;
36 import java.awt.Button;
37 import java.awt.Component;
38 import java.awt.Dimension;
39 import java.awt.Event;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ActionListener;
42 import java.awt.FileDialog;
43 import java.awt.Dialog;
44 import java.awt.Label;
45 import java.awt.Panel;
46 import java.awt.Rectangle;
47 import java.awt.Window;
48 
49 import java.awt.image.BufferedImage;
50 import java.awt.image.IndexColorModel;
51 
52 import java.awt.print.Pageable;
53 import java.awt.print.PageFormat;
54 import java.awt.print.Paper;
55 import java.awt.print.Printable;
56 import java.awt.print.PrinterJob;
57 import java.awt.print.PrinterException;
58 import javax.print.PrintService;
59 
60 import java.io.File;
61 
62 import java.util.MissingResourceException;
63 import java.util.ResourceBundle;
64 
65 import sun.print.PeekGraphics;
66 import sun.print.PeekMetrics;
67 
68 import java.net.URI;
69 import java.net.URISyntaxException;
70 
71 import javax.print.PrintServiceLookup;
72 import javax.print.attribute.PrintRequestAttributeSet;
73 import javax.print.attribute.HashPrintRequestAttributeSet;
74 import javax.print.attribute.Attribute;
75 import javax.print.attribute.standard.Sides;
76 import javax.print.attribute.standard.Chromaticity;
77 import javax.print.attribute.standard.PrintQuality;
78 import javax.print.attribute.standard.PrinterResolution;
79 import javax.print.attribute.standard.SheetCollate;
80 import javax.print.attribute.standard.Copies;
81 import javax.print.attribute.standard.Destination;
82 import javax.print.attribute.standard.OrientationRequested;
83 import javax.print.attribute.standard.Media;
84 import javax.print.attribute.standard.MediaSizeName;
85 import javax.print.attribute.standard.MediaSize;
86 import javax.print.attribute.standard.MediaTray;
87 import javax.print.attribute.standard.PageRanges;
88 
89 import sun.awt.Win32FontManager;
90 
91 import sun.print.RasterPrinterJob;
92 import sun.print.SunAlternateMedia;
93 import sun.print.SunPageSelection;
94 import sun.print.Win32MediaTray;
95 import sun.print.Win32PrintService;
96 import sun.print.PrintServiceLookupProvider;
97 import sun.print.ServiceDialog;
98 import sun.print.DialogOwner;
99 
100 import java.awt.Frame;
101 import java.io.FilePermission;
102 
103 import sun.java2d.Disposer;
104 import sun.java2d.DisposerRecord;
105 import sun.java2d.DisposerTarget;
106 
107 /**
108  * A class which initiates and executes a Win32 printer job.
109  *
110  * @author Richard Blanchard
111  */
112 public final class WPrinterJob extends RasterPrinterJob
113         implements DisposerTarget {
114 
115  /* Class Constants */
116 
117 
118 /* Instance Variables */
119 
120     /**
121      * These are Windows' ExtCreatePen End Cap Styles
122      * and must match the values in <WINGDI.h>
123      */
124     protected static final long PS_ENDCAP_ROUND  = 0x00000000;
125     protected static final long PS_ENDCAP_SQUARE   = 0x00000100;
126     protected static final long PS_ENDCAP_FLAT   =   0x00000200;
127 
128     /**
129      * These are Windows' ExtCreatePen Line Join Styles
130      * and must match the values in <WINGDI.h>
131      */
132     protected static final long PS_JOIN_ROUND   =    0x00000000;
133     protected static final long PS_JOIN_BEVEL   =    0x00001000;
134     protected static final long PS_JOIN_MITER   =    0x00002000;
135 
136     /**
137      * This is the Window's Polygon fill rule which
138      * Selects alternate mode (fills the area between odd-numbered
139      * and even-numbered polygon sides on each scan line).
140      * It must match the value in <WINGDI.h> It can be passed
141      * to setPolyFillMode().
142      */
143     protected static final int POLYFILL_ALTERNATE = 1;
144 
145     /**
146      * This is the Window's Polygon fill rule which
147      * Selects winding mode which fills any region
148      * with a nonzero winding value). It must match
149      * the value in <WINGDI.h> It can be passed
150      * to setPolyFillMode().
151      */
152     protected static final int POLYFILL_WINDING = 2;
153 
154     /**
155      * The maximum value for a Window's color component
156      * as passed to selectSolidBrush.
157      */
158     private static final int MAX_WCOLOR = 255;
159 
160     /**
161      * Flags for setting values from devmode in native code.
162      * Values must match those defined in awt_PrintControl.cpp
163      */
164     private static final int SET_DUP_VERTICAL = 0x00000010;
165     private static final int SET_DUP_HORIZONTAL = 0x00000020;
166     private static final int SET_RES_HIGH = 0x00000040;
167     private static final int SET_RES_LOW = 0x00000080;
168     private static final int SET_COLOR = 0x00000200;
169     private static final int SET_ORIENTATION = 0x00004000;
170     private static final int SET_COLLATED    = 0x00008000;
171 
172     /**
173      * Values must match those defined in wingdi.h & commdlg.h
174      */
175     private static final int PD_COLLATE = 0x00000010;
176     private static final int PD_PRINTTOFILE = 0x00000020;
177     private static final int DM_ORIENTATION   = 0x00000001;
178     private static final int DM_PAPERSIZE     = 0x00000002;
179     private static final int DM_COPIES        = 0x00000100;
180     private static final int DM_DEFAULTSOURCE = 0x00000200;
181     private static final int DM_PRINTQUALITY  = 0x00000400;
182     private static final int DM_COLOR         = 0x00000800;
183     private static final int DM_DUPLEX        = 0x00001000;
184     private static final int DM_YRESOLUTION   = 0x00002000;
185     private static final int DM_COLLATE       = 0x00008000;
186 
187     private static final short DMCOLLATE_FALSE  = 0;
188     private static final short DMCOLLATE_TRUE   = 1;
189 
190     private static final short DMORIENT_PORTRAIT  = 1;
191     private static final short DMORIENT_LANDSCAPE = 2;
192 
193     private static final short DMCOLOR_MONOCHROME = 1;
194     private static final short DMCOLOR_COLOR      = 2;
195 
196     private static final short DMRES_DRAFT  = -1;
197     private static final short DMRES_LOW    = -2;
198     private static final short DMRES_MEDIUM = -3;
199     private static final short DMRES_HIGH   = -4;
200 
201     private static final short DMDUP_SIMPLEX    = 1;
202     private static final short DMDUP_VERTICAL   = 2;
203     private static final short DMDUP_HORIZONTAL = 3;
204 
205     /**
206      * Pageable MAX pages
207      */
208     private static final int MAX_UNKNOWN_PAGES = 9999;
209 
210 
211     /* Collation and copy flags.
212      * The Windows PRINTDLG struct has a nCopies field which on return
213      * indicates how many copies of a print job an application must render.
214      * There is also a PD_COLLATE member of the flags field which if
215      * set on return indicates the application generated copies should be
216      * collated.
217      * Windows printer drivers typically - but not always - support
218      * generating multiple copies themselves, but uncollated is more
219      * universal than collated copies.
220      * When they do, they read the initial values from the PRINTDLG structure
221      * and set them into the driver's DEVMODE structure and intialise
222      * the printer DC based on that, so that when printed those settings
223      * will be used.
224      * For drivers supporting both these capabilities via DEVMODE, then on
225      * return from the Print Dialog, nCopies is set to 1 and the PD_COLLATE is
226      * cleared, so that the application will only render 1 copy and the
227      * driver takes care of the rest.
228      *
229      * Applications which want to know what's going on have to be DEVMODE
230      * savvy and peek at that.
231      * DM_COPIES flag indicates support for multiple driver copies
232      * and dmCopies is the number of copies the driver will print
233      * DM_COLLATE flag indicates support for collated driver copies and
234      * dmCollate == DMCOLLATE_TRUE indicates the option is in effect.
235      *
236      * Multiple copies from Java applications:
237      * We provide API to get & set the number of copies as well as allowing the
238      * user to choose it, so we need to be savvy about DEVMODE, so that
239      * we can accurately report back the number of copies selected by
240      * the user, as well as make use of the driver to render multiple copies.
241      *
242      * Collation and Java applications:
243      * We presently provide no API for specifying collation, but its
244      * present on the Windows Print Dialog, and when a user checks it
245      * they expect it to be obeyed.
246      * The best thing to do is to detect exactly the cases where the
247      * driver doesn't support this and render multiple copies ourselves.
248      * To support all this we need several flags which signal the
249      * printer's capabilities and the user's requests.
250      * Its questionable if we (yet) need to make a distinction between
251      * the user requesting collation and the driver supporting it.
252      * Since for now we only need to know whether we need to render the
253      * copies. However it allows the logic to be clearer.
254      * These fields are changed by native code which detects the driver's
255      * capabilities and the user's choices.
256      */
257 
258     //initialize to false because the Flags that we initialized in PRINTDLG
259     // tells GDI that we can handle our own collation and multiple copies
260      private boolean driverDoesMultipleCopies = false;
261      private boolean driverDoesCollation = false;
262      private boolean userRequestedCollation = false;
263      private boolean noDefaultPrinter = false;
264 
265     /* The HandleRecord holds the native resources that need to be freed
266      * when this WPrinterJob is GC'd.
267      */
268     static class HandleRecord implements DisposerRecord {
269         /**
270          * The Windows device context we will print into.
271          * This variable is set after the Print dialog
272          * is okayed by the user. If the user cancels
273          * the print dialog, then this variable is 0.
274          * Much of the configuration information for a printer is
275          * obtained through printer device specific handles.
276          * We need to associate these with, and free with, the mPrintDC.
277          */
278         private long mPrintDC;
279         private long mPrintHDevMode;
280         private long mPrintHDevNames;
281 
282         @Override
dispose()283         public void dispose() {
284             WPrinterJob.deleteDC(mPrintDC, mPrintHDevMode, mPrintHDevNames);
285         }
286     }
287 
288     private HandleRecord handleRecord = new HandleRecord();
289 
290     private int mPrintPaperSize;
291 
292     /* These fields are directly set in upcalls from the values
293      * obtained from calling DeviceCapabilities()
294      */
295     private int mPrintXRes;   // pixels per inch in x direction
296 
297     private int mPrintYRes;   // pixels per inch in y direction
298 
299     private int mPrintPhysX;  // x offset in pixels of printable area
300 
301     private int mPrintPhysY;  // y offset in pixels of printable area
302 
303     private int mPrintWidth;  // width in pixels of printable area
304 
305     private int mPrintHeight; // height in pixels of printable area
306 
307     private int mPageWidth;   // width in pixels of entire page
308 
309     private int mPageHeight;  // height in pixels of entire page
310 
311     /* The values of the following variables are pulled directly
312      * into native code (even bypassing getter methods) when starting a doc.
313      * So these need to be synced up from any resulting native changes
314      * by a user dialog.
315      * But the native changes call up to into the attributeset, and that
316      * should be sufficient, since before heading down to native either
317      * to (re-)display a dialog, or to print the doc, these are all
318      * re-populated from the AttributeSet,
319      * Nonetheless having them in sync with the attributeset and native
320      * state is probably safer.
321      * Also whereas the startDoc native code pulls the variables directly,
322      * the dialog code does use getter to pull some of these values.
323      * That's an inconsistency we should fix if it causes problems.
324      */
325     private int mAttSides;
326     private int mAttChromaticity;
327     private int mAttXRes;
328     private int mAttYRes;
329     private int mAttQuality;
330     private int mAttCollate;
331     private int mAttCopies;
332     private int mAttMediaSizeName;
333     private int mAttMediaTray;
334 
335     private String mDestination = null;
336 
337     /**
338      * The last color set into the print device context or
339      * <code>null</code> if no color has been set.
340      */
341     private Color mLastColor;
342 
343     /**
344      * The last text color set into the print device context or
345      * <code>null</code> if no color has been set.
346      */
347     private Color mLastTextColor;
348 
349     /**
350      * Define the most recent java font set as a GDI font in the printer
351      * device context. mLastFontFamily will be NULL if no
352      * GDI font has been set.
353      */
354     private String mLastFontFamily;
355     private float mLastFontSize;
356     private int mLastFontStyle;
357     private int mLastRotation;
358     private float mLastAwScale;
359 
360     // for AwtPrintControl::InitPrintDialog
361     private PrinterJob pjob;
362 
363     private java.awt.peer.ComponentPeer dialogOwnerPeer = null;
364 
365  /* Static Initializations */
366 
367     static {
368         // AWT has to be initialized for the native code to function correctly.
Toolkit.getDefaultToolkit()369         Toolkit.getDefaultToolkit();
370 
initIDs()371         initIDs();
372 
Win32FontManager.registerJREFontsForPrinting()373         Win32FontManager.registerJREFontsForPrinting();
374     }
375 
376     /* Constructors */
377 
WPrinterJob()378     public WPrinterJob()
379     {
380         Disposer.addRecord(disposerReferent,
381                            handleRecord = new HandleRecord());
382         initAttributeMembers();
383     }
384 
385     /* Implement DisposerTarget. Weak references to an Object can delay
386      * its storage reclaimation marginally.
387      * It won't make the native resources be release any more quickly, but
388      * by pointing the reference held by Disposer at an object which becomes
389      * no longer strongly reachable when this WPrinterJob is no longer
390      * strongly reachable, we allow the WPrinterJob to be freed more promptly
391      * than if it were the referenced object.
392      */
393     private Object disposerReferent = new Object();
394 
395     @Override
getDisposerReferent()396     public Object getDisposerReferent() {
397         return disposerReferent;
398     }
399 
400 /* Instance Methods */
401 
402     /**
403      * Display a dialog to the user allowing the modification of a
404      * PageFormat instance.
405      * The <code>page</code> argument is used to initialize controls
406      * in the page setup dialog.
407      * If the user cancels the dialog, then the method returns the
408      * original <code>page</code> object unmodified.
409      * If the user okays the dialog then the method returns a new
410      * PageFormat object with the indicated changes.
411      * In either case the original <code>page</code> object will
412      * not be modified.
413      * @param     page    the default PageFormat presented to the user
414      *                    for modification
415      * @return    the original <code>page</code> object if the dialog
416      *            is cancelled, or a new PageFormat object containing
417      *            the format indicated by the user if the dialog is
418      *            acknowledged
419      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
420      * returns true.
421      * @see java.awt.GraphicsEnvironment#isHeadless
422      * @since     JDK1.2
423      */
424     @Override
pageDialog(PageFormat page)425     public PageFormat pageDialog(PageFormat page) throws HeadlessException {
426         if (GraphicsEnvironment.isHeadless()) {
427             throw new HeadlessException();
428         }
429 
430         if (!(getPrintService() instanceof Win32PrintService)) {
431             return super.pageDialog(page);
432         }
433 
434         PageFormat pageClone = (PageFormat) page.clone();
435         boolean result = false;
436 
437         /*
438          * Fix for 4507585: show the native modal dialog the same way printDialog() does so
439          * that it won't block event dispatching when called on EventDispatchThread.
440          */
441         WPageDialog dialog = new WPageDialog((Frame)null, this,
442                                      pageClone, null);
443         dialog.setRetVal(false);
444         dialog.setVisible(true);
445         result = dialog.getRetVal();
446         dialog.dispose();
447 
448         // myService => current PrintService
449         if (result && (myService != null)) {
450             // It's possible that current printer is changed through
451             // the "Printer..." button so we query again from native.
452             String printerName = getNativePrintService();
453             if (!myService.getName().equals(printerName)) {
454                 // native printer is different !
455                 // we update the current PrintService
456                 try {
457                     setPrintService(PrintServiceLookupProvider.
458                                     getWin32PrintLUS().
459                                     getPrintServiceByName(printerName));
460                 } catch (PrinterException e) {
461                 }
462             }
463             // Update attributes, this will preserve the page settings.
464             //  - same code as in RasterPrinterJob.java
465             updatePageAttributes(myService, pageClone);
466 
467             return pageClone;
468         } else {
469             return page;
470         }
471     }
472 
473 
displayNativeDialog()474     private boolean displayNativeDialog() {
475         // "attributes" is required for getting the updated attributes
476         if (attributes == null) {
477             return false;
478         }
479 
480         DialogOwner dlgOwner = (DialogOwner)attributes.get(DialogOwner.class);
481         Frame ownerFrame = (dlgOwner != null) ? dlgOwner.getOwner() : null;
482 
483         WPrintDialog dialog = new WPrintDialog(ownerFrame, this);
484         dialog.setRetVal(false);
485         dialog.setVisible(true);
486         boolean prv = dialog.getRetVal();
487         dialog.dispose();
488 
489         Destination dest =
490                 (Destination)attributes.get(Destination.class);
491         if ((dest == null) || !prv){
492                 return prv;
493         } else {
494             String title = null;
495             String strBundle = "sun.print.resources.serviceui";
496             ResourceBundle rb = ResourceBundle.getBundle(strBundle);
497             try {
498                 title = rb.getString("dialog.printtofile");
499             } catch (MissingResourceException e) {
500             }
501             FileDialog fileDialog = new FileDialog(ownerFrame, title,
502                                                    FileDialog.SAVE);
503 
504             URI destURI = dest.getURI();
505             // Old code destURI.getPath() would return null for "file:out.prn"
506             // so we use getSchemeSpecificPart instead.
507             String pathName = (destURI != null) ?
508                 destURI.getSchemeSpecificPart() : null;
509             if (pathName != null) {
510                File file = new File(pathName);
511                fileDialog.setFile(file.getName());
512                File parent = file.getParentFile();
513                if (parent != null) {
514                    fileDialog.setDirectory(parent.getPath());
515                }
516             } else {
517                 fileDialog.setFile("out.prn");
518             }
519 
520             fileDialog.setVisible(true);
521             String fileName = fileDialog.getFile();
522             if (fileName == null) {
523                 fileDialog.dispose();
524                 return false;
525             }
526             String fullName = fileDialog.getDirectory() + fileName;
527             File f = new File(fullName);
528             File pFile = f.getParentFile();
529             while ((f.exists() &&
530                       (!f.isFile() || !f.canWrite())) ||
531                    ((pFile != null) &&
532                       (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {
533 
534                 (new PrintToFileErrorDialog(ownerFrame,
535                                 ServiceDialog.getMsg("dialog.owtitle"),
536                                 ServiceDialog.getMsg("dialog.writeerror")+" "+fullName,
537                                 ServiceDialog.getMsg("button.ok"))).setVisible(true);
538 
539                 fileDialog.setVisible(true);
540                 fileName = fileDialog.getFile();
541                 if (fileName == null) {
542                     fileDialog.dispose();
543                     return false;
544                 }
545                 fullName = fileDialog.getDirectory() + fileName;
546                 f = new File(fullName);
547                 pFile = f.getParentFile();
548             }
549             fileDialog.dispose();
550             attributes.add(new Destination(f.toURI()));
551             return true;
552         }
553 
554     }
555 
556     /**
557      * Presents the user a dialog for changing properties of the
558      * print job interactively.
559      * @returns false if the user cancels the dialog and
560      *          true otherwise.
561      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
562      * returns true.
563      * @see java.awt.GraphicsEnvironment#isHeadless
564      */
565     @Override
printDialog()566     public boolean printDialog() throws HeadlessException {
567 
568         if (GraphicsEnvironment.isHeadless()) {
569             throw new HeadlessException();
570         }
571         // current request attribute set should be reflected to the print dialog.
572         // If null, create new instance of HashPrintRequestAttributeSet.
573         if (attributes == null) {
574             attributes = new HashPrintRequestAttributeSet();
575         }
576 
577         if (!(getPrintService() instanceof Win32PrintService)) {
578             return super.printDialog(attributes);
579         }
580 
581         if (noDefaultPrinter == true) {
582             return false;
583         } else {
584             return displayNativeDialog();
585         }
586     }
587 
588      /**
589      * Associate this PrinterJob with a new PrintService.
590      *
591      * Throws <code>PrinterException</code> if the specified service
592      * cannot support the <code>Pageable</code> and
593      * </code>Printable</code> interfaces necessary to support 2D printing.
594      * @param a print service which supports 2D printing.
595      *
596      * @throws PrinterException if the specified service does not support
597      * 2D printing.
598      */
599     @Override
setPrintService(PrintService service)600     public void setPrintService(PrintService service)
601         throws PrinterException {
602         super.setPrintService(service);
603         if (!(service instanceof Win32PrintService)) {
604             return;
605         }
606         driverDoesMultipleCopies = false;
607         driverDoesCollation = false;
608         setNativePrintServiceIfNeeded(service.getName());
609     }
610 
611     /* associates this job with the specified native service */
setNativePrintService(String name)612     private native void setNativePrintService(String name)
613         throws PrinterException;
614 
615     private String lastNativeService = null;
setNativePrintServiceIfNeeded(String name)616     private void setNativePrintServiceIfNeeded(String name)
617         throws PrinterException {
618 
619         if (name != null && !(name.equals(lastNativeService))) {
620             setNativePrintService(name);
621             lastNativeService = name;
622         }
623     }
624 
625     @Override
getPrintService()626     public PrintService getPrintService() {
627         if (myService == null) {
628             String printerName = getNativePrintService();
629 
630             if (printerName != null) {
631                 myService = PrintServiceLookupProvider.getWin32PrintLUS().
632                     getPrintServiceByName(printerName);
633                 // no need to call setNativePrintService as this name is
634                 // currently set in native
635                 if (myService != null) {
636                     return myService;
637                 }
638             }
639 
640             myService = PrintServiceLookup.lookupDefaultPrintService();
641             if (myService instanceof Win32PrintService) {
642                 try {
643                     setNativePrintServiceIfNeeded(myService.getName());
644                 } catch (Exception e) {
645                     myService = null;
646                 }
647             }
648 
649           }
650           return myService;
651     }
652 
getNativePrintService()653     private native String getNativePrintService();
654 
initAttributeMembers()655     private void initAttributeMembers() {
656             mAttSides = 0;
657             mAttChromaticity = 0;
658             mAttXRes = 0;
659             mAttYRes = 0;
660             mAttQuality = 0;
661             mAttCollate = -1;
662             mAttCopies = 0;
663             mAttMediaTray = 0;
664             mAttMediaSizeName = 0;
665             mDestination = null;
666 
667     }
668 
669     /**
670      * copy the attributes to the native print job
671      * Note that this method, and hence the re-initialisation
672      * of the GDI values is done on each entry to the print dialog since
673      * an app could redisplay the print dialog for the same job and
674      * 1) the application may have changed attribute settings
675      * 2) the application may have changed the printer.
676      * In the event that the user changes the printer using the
677       dialog, then it is up to GDI to report back all changed values.
678      */
679     @Override
setAttributes(PrintRequestAttributeSet attributes)680     protected void setAttributes(PrintRequestAttributeSet attributes)
681         throws PrinterException {
682 
683         // initialize attribute values
684         initAttributeMembers();
685         super.setAttributes(attributes);
686 
687         mAttCopies = getCopiesInt();
688         mDestination = destinationAttr;
689 
690         if (attributes == null) {
691             return; // now always use attributes, so this shouldn't happen.
692         }
693         Attribute[] attrs = attributes.toArray();
694         for (int i=0; i< attrs.length; i++) {
695             Attribute attr = attrs[i];
696             try {
697                  if (attr.getCategory() == Sides.class) {
698                     setSidesAttrib(attr);
699                 }
700                 else if (attr.getCategory() == Chromaticity.class) {
701                     setColorAttrib(attr);
702                 }
703                 else if (attr.getCategory() == PrinterResolution.class) {
704                     setResolutionAttrib(attr);
705                 }
706                 else if (attr.getCategory() == PrintQuality.class) {
707                     setQualityAttrib(attr);
708                 }
709                 else if (attr.getCategory() == SheetCollate.class) {
710                     setCollateAttrib(attr);
711                 }  else if (attr.getCategory() == Media.class ||
712                             attr.getCategory() == SunAlternateMedia.class) {
713                     /* SunAlternateMedia is used if its a tray, and
714                      * any Media that is specified is not a tray.
715                      */
716                     if (attr.getCategory() == SunAlternateMedia.class) {
717                         Media media = (Media)attributes.get(Media.class);
718                         if (media == null ||
719                             !(media instanceof MediaTray)) {
720                             attr = ((SunAlternateMedia)attr).getMedia();
721                         }
722                     }
723                     if (attr instanceof MediaSizeName) {
724                         setWin32MediaAttrib(attr);
725                     }
726                     if (attr instanceof MediaTray) {
727                         setMediaTrayAttrib(attr);
728                     }
729                 }
730 
731             } catch (ClassCastException e) {
732             }
733         }
734     }
735 
736     /**
737      * Alters the orientation and Paper to match defaults obtained
738      * from a printer.
739      */
getDefaultPage(PageFormat page)740     private native void getDefaultPage(PageFormat page);
741 
742     /**
743      * The passed in PageFormat will be copied and altered to describe
744      * the default page size and orientation of the PrinterJob's
745      * current printer.
746      * Note: PageFormat.getPaper() returns a clone and getDefaultPage()
747      * gets that clone so it won't overwrite the original paper.
748      */
749     @Override
defaultPage(PageFormat page)750     public PageFormat defaultPage(PageFormat page) {
751         PageFormat newPage = (PageFormat)page.clone();
752         getDefaultPage(newPage);
753         return newPage;
754     }
755 
756     /**
757      * validate the paper size against the current printer.
758      */
759     @Override
validatePaper(Paper origPaper, Paper newPaper )760     protected native void validatePaper(Paper origPaper, Paper newPaper );
761 
762     /**
763      * Examine the metrics captured by the
764      * <code>PeekGraphics</code> instance and
765      * if capable of directly converting this
766      * print job to the printer's control language
767      * or the native OS's graphics primitives, then
768      * return a <code>PathGraphics</code> to perform
769      * that conversion. If there is not an object
770      * capable of the conversion then return
771      * <code>null</code>. Returning <code>null</code>
772      * causes the print job to be rasterized.
773      */
774 
775     @Override
createPathGraphics(PeekGraphics peekGraphics, PrinterJob printerJob, Printable painter, PageFormat pageFormat, int pageIndex)776     protected Graphics2D createPathGraphics(PeekGraphics peekGraphics,
777                                             PrinterJob printerJob,
778                                             Printable painter,
779                                             PageFormat pageFormat,
780                                             int pageIndex) {
781 
782         WPathGraphics pathGraphics;
783         PeekMetrics metrics = peekGraphics.getMetrics();
784 
785         /* If the application has drawn anything that
786          * out PathGraphics class can not handle then
787          * return a null PathGraphics. If the property
788          * to force the raster pipeline has been set then
789          * we also want to avoid the path (pdl) pipeline
790          * and return null.
791          */
792        if (forcePDL == false && (forceRaster == true
793                                   || metrics.hasNonSolidColors()
794                                   || metrics.hasCompositing()
795                                   )) {
796             pathGraphics = null;
797         } else {
798             BufferedImage bufferedImage = new BufferedImage(8, 8,
799                                             BufferedImage.TYPE_INT_RGB);
800             Graphics2D bufferedGraphics = bufferedImage.createGraphics();
801 
802             boolean canRedraw = peekGraphics.getAWTDrawingOnly() == false;
803             pathGraphics =  new WPathGraphics(bufferedGraphics, printerJob,
804                                               painter, pageFormat, pageIndex,
805                                               canRedraw);
806         }
807 
808         return pathGraphics;
809     }
810 
811 
812     @Override
getXRes()813     protected double getXRes() {
814         if (mAttXRes != 0) {
815             return mAttXRes;
816         } else {
817             return mPrintXRes;
818         }
819     }
820 
821     @Override
getYRes()822     protected double getYRes() {
823         if (mAttYRes != 0) {
824             return mAttYRes;
825         } else {
826             return mPrintYRes;
827         }
828     }
829 
830     @Override
getPhysicalPrintableX(Paper p)831     protected double getPhysicalPrintableX(Paper p) {
832         return mPrintPhysX;
833     }
834 
835     @Override
getPhysicalPrintableY(Paper p)836     protected double getPhysicalPrintableY(Paper p) {
837         return mPrintPhysY;
838     }
839 
840     @Override
getPhysicalPrintableWidth(Paper p)841     protected double getPhysicalPrintableWidth(Paper p) {
842         return mPrintWidth;
843     }
844 
845     @Override
getPhysicalPrintableHeight(Paper p)846     protected double getPhysicalPrintableHeight(Paper p) {
847         return mPrintHeight;
848     }
849 
850     @Override
getPhysicalPageWidth(Paper p)851     protected double getPhysicalPageWidth(Paper p) {
852         return mPageWidth;
853     }
854 
855     @Override
getPhysicalPageHeight(Paper p)856     protected double getPhysicalPageHeight(Paper p) {
857         return mPageHeight;
858     }
859 
860     /**
861      * We don't (yet) provide API to support collation, and
862      * when we do the logic here will require adjustment, but
863      * this method is currently necessary to honour user-originated
864      * collation requests - which can only originate from the print dialog.
865      * REMIND: check if this can be deleted already.
866      */
867     @Override
isCollated()868     protected boolean isCollated() {
869         return userRequestedCollation;
870     }
871 
872     /**
873      * Returns how many times the entire book should
874      * be printed by the PrintJob. If the printer
875      * itself supports collation then this method
876      * should return 1 indicating that the entire
877      * book need only be printed once and the copies
878      * will be collated and made in the printer.
879      */
880     @Override
getCollatedCopies()881     protected int getCollatedCopies() {
882         debug_println("driverDoesMultipleCopies="+driverDoesMultipleCopies
883                       +" driverDoesCollation="+driverDoesCollation);
884         if  (super.isCollated() && !driverDoesCollation) {
885             // we will do our own collation so we need to
886             // tell the printer to not collate
887             mAttCollate = 0;
888             mAttCopies = 1;
889             return getCopies();
890         }
891 
892         return 1;
893     }
894 
895     /**
896      * Returns how many times each page in the book
897      * should be consecutively printed by PrinterJob.
898      * If the underlying Window's driver will
899      * generate the copies, rather than having RasterPrinterJob
900      * iterate over the number of copies, this method always returns
901      * 1.
902      */
903     @Override
getNoncollatedCopies()904     protected int getNoncollatedCopies() {
905         if (driverDoesMultipleCopies || super.isCollated()) {
906             return 1;
907         } else {
908             return getCopies();
909         }
910     }
911 
912     /* These getter/setters are called from native code */
913 
914     /**
915      * Return the Window's device context that we are printing
916      * into.
917      */
getPrintDC()918     private long getPrintDC() {
919         return handleRecord.mPrintDC;
920     }
921 
setPrintDC(long mPrintDC)922     private void setPrintDC(long mPrintDC) {
923         handleRecord.mPrintDC = mPrintDC;
924     }
925 
getDevMode()926     private long getDevMode() {
927         return handleRecord.mPrintHDevMode;
928     }
929 
setDevMode(long mPrintHDevMode)930     private void setDevMode(long mPrintHDevMode) {
931         handleRecord.mPrintHDevMode = mPrintHDevMode;
932     }
933 
getDevNames()934     private long getDevNames() {
935         return handleRecord.mPrintHDevNames;
936     }
937 
setDevNames(long mPrintHDevNames)938     private void setDevNames(long mPrintHDevNames) {
939         handleRecord.mPrintHDevNames = mPrintHDevNames;
940     }
941 
beginPath()942     protected void beginPath() {
943         beginPath(getPrintDC());
944     }
945 
endPath()946     protected void endPath() {
947         endPath(getPrintDC());
948     }
949 
closeFigure()950     protected void closeFigure() {
951         closeFigure(getPrintDC());
952     }
953 
fillPath()954     protected void fillPath() {
955         fillPath(getPrintDC());
956     }
957 
moveTo(float x, float y)958     protected void moveTo(float x, float y) {
959         moveTo(getPrintDC(), x, y);
960     }
961 
lineTo(float x, float y)962     protected void lineTo(float x, float y) {
963         lineTo(getPrintDC(), x, y);
964     }
965 
polyBezierTo(float control1x, float control1y, float control2x, float control2y, float endX, float endY)966     protected void polyBezierTo(float control1x, float control1y,
967                                 float control2x, float control2y,
968                                 float endX, float endY) {
969 
970         polyBezierTo(getPrintDC(), control1x, control1y,
971                                control2x, control2y,
972                                endX, endY);
973     }
974 
975     /**
976      * Set the current polgon fill rule into the printer device context.
977      * The <code>fillRule</code> should
978      * be one of the following Windows constants:
979      * <code>ALTERNATE</code> or <code>WINDING</code>.
980      */
setPolyFillMode(int fillRule)981     protected void setPolyFillMode(int fillRule) {
982         setPolyFillMode(getPrintDC(), fillRule);
983     }
984 
985     /*
986      * Create a Window's solid brush for the color specified
987      * by <code>(red, green, blue)</code>. Once the brush
988      * is created, select it in the current printing device
989      * context and free the old brush.
990      */
selectSolidBrush(Color color)991     protected void selectSolidBrush(Color color) {
992 
993         /* We only need to select a brush if the color has changed.
994         */
995         if (color.equals(mLastColor) == false) {
996             mLastColor = color;
997             float[] rgb = color.getRGBColorComponents(null);
998 
999             selectSolidBrush(getPrintDC(),
1000                              (int) (rgb[0] * MAX_WCOLOR),
1001                              (int) (rgb[1] * MAX_WCOLOR),
1002                              (int) (rgb[2] * MAX_WCOLOR));
1003         }
1004     }
1005 
1006     /**
1007      * Return the x coordinate of the current pen
1008      * position in the print device context.
1009      */
getPenX()1010     protected int getPenX() {
1011 
1012         return getPenX(getPrintDC());
1013     }
1014 
1015 
1016     /**
1017      * Return the y coordinate of the current pen
1018      * position in the print device context.
1019      */
getPenY()1020     protected int getPenY() {
1021 
1022         return getPenY(getPrintDC());
1023     }
1024 
1025     /**
1026      * Set the current path in the printer device's
1027      * context to be clipping path.
1028      */
selectClipPath()1029     protected void selectClipPath() {
1030         selectClipPath(getPrintDC());
1031     }
1032 
1033 
frameRect(float x, float y, float width, float height)1034     protected void frameRect(float x, float y, float width, float height) {
1035         frameRect(getPrintDC(), x, y, width, height);
1036     }
1037 
fillRect(float x, float y, float width, float height, Color color)1038     protected void fillRect(float x, float y, float width, float height,
1039                             Color color) {
1040         float[] rgb = color.getRGBColorComponents(null);
1041 
1042         fillRect(getPrintDC(), x, y, width, height,
1043                  (int) (rgb[0] * MAX_WCOLOR),
1044                  (int) (rgb[1] * MAX_WCOLOR),
1045                  (int) (rgb[2] * MAX_WCOLOR));
1046     }
1047 
1048 
selectPen(float width, Color color)1049     protected void selectPen(float width, Color color) {
1050 
1051         float[] rgb = color.getRGBColorComponents(null);
1052 
1053         selectPen(getPrintDC(), width,
1054                   (int) (rgb[0] * MAX_WCOLOR),
1055                   (int) (rgb[1] * MAX_WCOLOR),
1056                   (int) (rgb[2] * MAX_WCOLOR));
1057     }
1058 
1059 
selectStylePen(int cap, int join, float width, Color color)1060     protected boolean selectStylePen(int cap, int join, float width,
1061                                      Color color) {
1062 
1063         long endCap;
1064         long lineJoin;
1065 
1066         float[] rgb = color.getRGBColorComponents(null);
1067 
1068         switch(cap) {
1069         case BasicStroke.CAP_BUTT: endCap = PS_ENDCAP_FLAT; break;
1070         case BasicStroke.CAP_ROUND: endCap = PS_ENDCAP_ROUND; break;
1071         default:
1072         case BasicStroke.CAP_SQUARE: endCap = PS_ENDCAP_SQUARE; break;
1073         }
1074 
1075         switch(join) {
1076         case BasicStroke.JOIN_BEVEL:lineJoin = PS_JOIN_BEVEL; break;
1077         default:
1078         case BasicStroke.JOIN_MITER:lineJoin = PS_JOIN_MITER; break;
1079         case BasicStroke.JOIN_ROUND:lineJoin = PS_JOIN_ROUND; break;
1080         }
1081 
1082         return (selectStylePen(getPrintDC(), endCap, lineJoin, width,
1083                                (int) (rgb[0] * MAX_WCOLOR),
1084                                (int) (rgb[1] * MAX_WCOLOR),
1085                                (int) (rgb[2] * MAX_WCOLOR)));
1086     }
1087 
1088     /**
1089      * Set a GDI font capable of drawing the java Font
1090      * passed in.
1091      */
setFont(String family, float size, int style, int rotation, float awScale)1092     protected boolean setFont(String family, float size, int style,
1093                               int rotation, float awScale) {
1094 
1095         boolean didSetFont = true;
1096 
1097         if (!family.equals(mLastFontFamily) ||
1098             size     != mLastFontSize       ||
1099             style    != mLastFontStyle      ||
1100             rotation != mLastRotation       ||
1101             awScale  != mLastAwScale) {
1102 
1103             didSetFont = setFont(getPrintDC(),
1104                                  family,
1105                                  size,
1106                                  (style & Font.BOLD) != 0,
1107                                  (style & Font.ITALIC) != 0,
1108                                  rotation, awScale);
1109             if (didSetFont) {
1110                 mLastFontFamily   = family;
1111                 mLastFontSize     = size;
1112                 mLastFontStyle    = style;
1113                 mLastRotation     = rotation;
1114                 mLastAwScale      = awScale;
1115             }
1116         }
1117         return didSetFont;
1118     }
1119 
1120     /**
1121      * Set the GDI color for text drawing.
1122      */
setTextColor(Color color)1123     protected void setTextColor(Color color) {
1124 
1125         /* We only need to select a brush if the color has changed.
1126         */
1127         if (color.equals(mLastTextColor) == false) {
1128             mLastTextColor = color;
1129             float[] rgb = color.getRGBColorComponents(null);
1130 
1131             setTextColor(getPrintDC(),
1132                          (int) (rgb[0] * MAX_WCOLOR),
1133                          (int) (rgb[1] * MAX_WCOLOR),
1134                          (int) (rgb[2] * MAX_WCOLOR));
1135         }
1136     }
1137 
1138     /**
1139      * Remove control characters.
1140      */
1141     @Override
removeControlChars(String str)1142     protected String removeControlChars(String str) {
1143         return super.removeControlChars(str);
1144     }
1145 
1146     /**
1147      * Draw the string <code>text</code> to the printer's
1148      * device context at the specified position.
1149      */
textOut(String str, float x, float y, float[] positions)1150     protected void textOut(String str, float x, float y,
1151                            float[] positions) {
1152         /* Don't leave handling of control chars to GDI.
1153          * If control chars are removed,  'positions' isn't valid.
1154          * This means the caller needs to be aware of this and remove
1155          * control chars up front if supplying positions. Since the
1156          * caller is tightly integrated here, that's acceptable.
1157          */
1158         String text = removeControlChars(str);
1159         assert (positions == null) || (text.length() == str.length());
1160         if (text.length() == 0) {
1161             return;
1162         }
1163         textOut(getPrintDC(), text, text.length(), false, x, y, positions);
1164     }
1165 
1166    /**
1167      * Draw the glyphs <code>glyphs</code> to the printer's
1168      * device context at the specified position.
1169      */
glyphsOut(int []glyphs, float x, float y, float[] positions)1170     protected void glyphsOut(int []glyphs, float x, float y,
1171                              float[] positions) {
1172 
1173         /* TrueType glyph codes are 16 bit values, so can be packed
1174          * in a unicode string, and that's how GDI expects them.
1175          * A flag bit is set to indicate to GDI that these are glyphs,
1176          * not characters. The positions array must always be non-null
1177          * here for our purposes, although if not supplied, GDI should
1178          * just use the default advances for the glyphs.
1179          * Mask out upper 16 bits to remove any slot from a composite.
1180          */
1181         char[] glyphCharArray = new char[glyphs.length];
1182         for (int i=0;i<glyphs.length;i++) {
1183             glyphCharArray[i] = (char)(glyphs[i] & 0xffff);
1184         }
1185         String glyphStr = new String(glyphCharArray);
1186         textOut(getPrintDC(), glyphStr, glyphs.length, true, x, y, positions);
1187     }
1188 
1189 
1190     /**
1191      * Get the advance of this text that GDI returns for the
1192      * font currently selected into the GDI device context for
1193      * this job. Note that the removed control characters are
1194      * interpreted as zero-width by JDK and we remove them for
1195      * rendering so also remove them for measurement so that
1196      * this measurement can be properly compared with JDK measurement.
1197      */
getGDIAdvance(String text)1198     protected int getGDIAdvance(String text) {
1199         /* Don't leave handling of control chars to GDI. */
1200         text = removeControlChars(text);
1201         if (text.length() == 0) {
1202             return 0;
1203         }
1204         return getGDIAdvance(getPrintDC(), text);
1205     }
1206 
1207      /**
1208      * Draw the 24 bit BGR image buffer represented by
1209      * <code>image</code> to the GDI device context
1210      * <code>printDC</code>. The image is drawn at
1211      * <code>(destX, destY)</code> in device coordinates.
1212      * The image is scaled into a square of size
1213      * specified by <code>destWidth</code> and
1214      * <code>destHeight</code>. The portion of the
1215      * source image copied into that square is specified
1216      * by <code>srcX</code>, <code>srcY</code>,
1217      * <code>srcWidth</code>, and srcHeight.
1218      */
drawImage3ByteBGR(byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, float srcWidth, float srcHeight)1219     protected void drawImage3ByteBGR(byte[] image,
1220                                      float destX, float destY,
1221                                      float destWidth, float destHeight,
1222                                      float srcX, float srcY,
1223                                      float srcWidth, float srcHeight) {
1224 
1225 
1226         drawDIBImage(getPrintDC(), image,
1227                      destX, destY,
1228                      destWidth, destHeight,
1229                      srcX, srcY,
1230                      srcWidth, srcHeight,
1231                      24, null);
1232 
1233     }
1234 
1235     /* If 'icm' is null we expect its 24 bit (ie 3BYTE_BGR).
1236      * If 'icm' is non-null we expect its no more than 8 bpp and
1237      * specifically must be a valid DIB sizes : 1, 4 or 8 bpp.
1238      * Then we need to extract the colours into a byte array of the
1239      * format required by GDI which is an array of 'RGBQUAD'
1240      * RGBQUAD looks like :
1241      * typedef struct tagRGBQUAD {
1242      *    BYTE    rgbBlue;
1243      *    BYTE    rgbGreen;
1244      *    BYTE    rgbRed;
1245      *    BYTE    rgbReserved; // must be zero.
1246      * } RGBQUAD;
1247      * There's no alignment problem as GDI expects this to be packed
1248      * and each struct will start on a 4 byte boundary anyway.
1249      */
drawDIBImage(byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, float srcWidth, float srcHeight, int sampleBitsPerPixel, IndexColorModel icm)1250     protected void drawDIBImage(byte[] image,
1251                                 float destX, float destY,
1252                                 float destWidth, float destHeight,
1253                                 float srcX, float srcY,
1254                                 float srcWidth, float srcHeight,
1255                                 int sampleBitsPerPixel,
1256                                 IndexColorModel icm) {
1257         int bitCount = 24;
1258         byte[] bmiColors = null;
1259 
1260         if (icm != null) {
1261             bitCount = sampleBitsPerPixel;
1262             bmiColors = new byte[(1<<icm.getPixelSize())*4];
1263             for (int i=0;i<icm.getMapSize(); i++) {
1264                 bmiColors[i*4+0]=(byte)(icm.getBlue(i)&0xff);
1265                 bmiColors[i*4+1]=(byte)(icm.getGreen(i)&0xff);
1266                 bmiColors[i*4+2]=(byte)(icm.getRed(i)&0xff);
1267             }
1268         }
1269 
1270         drawDIBImage(getPrintDC(), image,
1271                      destX, destY,
1272                      destWidth, destHeight,
1273                      srcX, srcY,
1274                      srcWidth, srcHeight,
1275                      bitCount, bmiColors);
1276     }
1277 
1278     /**
1279      * Begin a new page.
1280      */
1281     @Override
startPage(PageFormat format, Printable painter, int index, boolean paperChanged)1282     protected void startPage(PageFormat format, Printable painter,
1283                              int index, boolean paperChanged) {
1284 
1285         /* Invalidate any device state caches we are
1286          * maintaining. Win95/98 resets the device
1287          * context attributes to default values at
1288          * the start of each page.
1289          */
1290         invalidateCachedState();
1291 
1292         deviceStartPage(format, painter, index, paperChanged);
1293     }
1294 
1295     /**
1296      * End a page.
1297      */
1298     @Override
endPage(PageFormat format, Printable painter, int index)1299     protected void endPage(PageFormat format, Printable painter,
1300                            int index) {
1301 
1302         deviceEndPage(format, painter, index);
1303     }
1304 
1305     /**
1306      * Forget any device state we may have cached.
1307      */
invalidateCachedState()1308     private void invalidateCachedState() {
1309         mLastColor = null;
1310         mLastTextColor = null;
1311         mLastFontFamily = null;
1312     }
1313 
1314     private boolean defaultCopies = true;
1315     /**
1316      * Set the number of copies to be printed.
1317      */
1318     @Override
setCopies(int copies)1319     public void setCopies(int copies) {
1320         super.setCopies(copies);
1321         defaultCopies = false;
1322         mAttCopies = copies;
1323         setNativeCopies(copies);
1324     }
1325 
1326 
1327  /* Native Methods */
1328 
1329     /**
1330      * Set copies in device.
1331      */
setNativeCopies(int copies)1332     private native void setNativeCopies(int copies);
1333 
1334     /**
1335      * Displays the print dialog and records the user's settings
1336      * into this object. Return false if the user cancels the
1337      * dialog.
1338      * If the dialog is to use a set of attributes, useAttributes is true.
1339      */
jobSetup(Pageable doc, boolean allowPrintToFile)1340     private native boolean jobSetup(Pageable doc, boolean allowPrintToFile);
1341 
1342     /* Make sure printer DC is intialised and that info about the printer
1343      * is reflected back up to Java code
1344      */
1345     @Override
initPrinter()1346     protected native void initPrinter();
1347 
1348     /**
1349      * Call Window's StartDoc routine to begin a
1350      * print job. The DC from the print dialog is
1351      * used. If the print dialog was not displayed
1352      * then a DC for the default printer is created.
1353      * The native StartDoc returns false if the end-user cancelled
1354      * printing. This is possible if the printer is connected to FILE:
1355      * in which case windows queries the user for a destination and the
1356      * user may cancel out of it. Note that the implementation of
1357      * cancel() throws PrinterAbortException to indicate the user cancelled.
1358      */
_startDoc(String dest, String jobName)1359     private native boolean _startDoc(String dest, String jobName)
1360                                      throws PrinterException;
1361     @Override
startDoc()1362     protected void startDoc() throws PrinterException {
1363         if (!_startDoc(mDestination, getJobName())) {
1364             cancel();
1365         }
1366     }
1367 
1368     /**
1369      * Call Window's EndDoc routine to end a
1370      * print job.
1371      */
1372     @Override
endDoc()1373     protected native void endDoc();
1374 
1375     /**
1376      * Call Window's AbortDoc routine to abort a
1377      * print job.
1378      */
1379     @Override
abortDoc()1380     protected native void abortDoc();
1381 
1382     /**
1383      * Call Windows native resource freeing APIs
1384      */
deleteDC(long dc, long devmode, long devnames)1385     private static native void deleteDC(long dc, long devmode, long devnames);
1386 
1387     /**
1388      * Begin a new page. This call's Window's
1389      * StartPage routine.
1390      */
deviceStartPage(PageFormat format, Printable painter, int index, boolean paperChanged)1391     protected native void deviceStartPage(PageFormat format, Printable painter,
1392                                           int index, boolean paperChanged);
1393     /**
1394      * End a page. This call's Window's EndPage
1395      * routine.
1396      */
deviceEndPage(PageFormat format, Printable painter, int index)1397     protected native void deviceEndPage(PageFormat format, Printable painter,
1398                                         int index);
1399 
1400     /**
1401      * Prints the contents of the array of ints, 'data'
1402      * to the current page. The band is placed at the
1403      * location (x, y) in device coordinates on the
1404      * page. The width and height of the band is
1405      * specified by the caller.
1406      */
1407     @Override
printBand(byte[] data, int x, int y, int width, int height)1408     protected native void printBand(byte[] data, int x, int y,
1409                                     int width, int height);
1410 
1411     /**
1412      * Begin a Window's rendering path in the device
1413      * context <code>printDC</code>.
1414      */
beginPath(long printDC)1415     protected native void beginPath(long printDC);
1416 
1417     /**
1418      * End a Window's rendering path in the device
1419      * context <code>printDC</code>.
1420      */
endPath(long printDC)1421     protected native void endPath(long printDC);
1422 
1423     /**
1424      * Close a subpath in a Window's rendering path in the device
1425      * context <code>printDC</code>.
1426      */
closeFigure(long printDC)1427     protected native void closeFigure(long printDC);
1428 
1429     /**
1430      * Fill a defined Window's rendering path in the device
1431      * context <code>printDC</code>.
1432      */
fillPath(long printDC)1433     protected native void fillPath(long printDC);
1434 
1435     /**
1436      * Move the Window's pen position to <code>(x,y)</code>
1437      * in the device context <code>printDC</code>.
1438      */
moveTo(long printDC, float x, float y)1439     protected native void moveTo(long printDC, float x, float y);
1440 
1441     /**
1442      * Draw a line from the current pen position to
1443      * <code>(x,y)</code> in the device context <code>printDC</code>.
1444      */
lineTo(long printDC, float x, float y)1445     protected native void lineTo(long printDC, float x, float y);
1446 
polyBezierTo(long printDC, float control1x, float control1y, float control2x, float control2y, float endX, float endY)1447     protected native void polyBezierTo(long printDC,
1448                                        float control1x, float control1y,
1449                                        float control2x, float control2y,
1450                                        float endX, float endY);
1451 
1452     /**
1453      * Set the current polgon fill rule into the device context
1454      * <code>printDC</code>. The <code>fillRule</code> should
1455      * be one of the following Windows constants:
1456      * <code>ALTERNATE</code> or <code>WINDING</code>.
1457      */
setPolyFillMode(long printDC, int fillRule)1458     protected native void setPolyFillMode(long printDC, int fillRule);
1459 
1460     /**
1461      * Create a Window's solid brush for the color specified
1462      * by <code>(red, green, blue)</code>. Once the brush
1463      * is created, select it in the device
1464      * context <code>printDC</code> and free the old brush.
1465      */
selectSolidBrush(long printDC, int red, int green, int blue)1466     protected native void selectSolidBrush(long printDC,
1467                                            int red, int green, int blue);
1468 
1469     /**
1470      * Return the x coordinate of the current pen
1471      * position in the device context
1472      * <code>printDC</code>.
1473      */
getPenX(long printDC)1474     protected native int getPenX(long printDC);
1475 
1476     /**
1477      * Return the y coordinate of the current pen
1478      * position in the device context
1479      * <code>printDC</code>.
1480      */
getPenY(long printDC)1481     protected native int getPenY(long printDC);
1482 
1483     /**
1484      * Select the device context's current path
1485      * to be the clipping path.
1486      */
selectClipPath(long printDC)1487     protected native void selectClipPath(long printDC);
1488 
1489     /**
1490      * Draw a rectangle using specified brush.
1491      */
frameRect(long printDC, float x, float y, float width, float height)1492     protected native void frameRect(long printDC, float x, float y,
1493                                     float width, float height);
1494 
1495     /**
1496      * Fill a rectangle specified by the coordinates using
1497      * specified brush.
1498      */
fillRect(long printDC, float x, float y, float width, float height, int red, int green, int blue)1499     protected native void fillRect(long printDC, float x, float y,
1500                                    float width, float height,
1501                                    int red, int green, int blue);
1502 
1503     /**
1504      * Create a solid brush using the RG & B colors and width.
1505      * Select this brush and delete the old one.
1506      */
selectPen(long printDC, float width, int red, int green, int blue)1507     protected native void selectPen(long printDC, float width,
1508                                     int red, int green, int blue);
1509 
1510     /**
1511      * Create a solid brush using the RG & B colors and specified
1512      * pen styles.  Select this created brush and delete the old one.
1513      */
selectStylePen(long printDC, long cap, long join, float width, int red, int green, int blue)1514     protected native boolean selectStylePen(long printDC, long cap,
1515                                             long join, float width,
1516                                             int red, int green, int blue);
1517 
1518     /**
1519      * Set a GDI font capable of drawing the java Font
1520      * passed in.
1521      */
setFont(long printDC, String familyName, float fontSize, boolean bold, boolean italic, int rotation, float awScale)1522     protected native boolean setFont(long printDC, String familyName,
1523                                      float fontSize,
1524                                      boolean bold,
1525                                      boolean italic,
1526                                      int rotation,
1527                                      float awScale);
1528 
1529 
1530     /**
1531      * Set the GDI color for text drawing.
1532      */
setTextColor(long printDC, int red, int green, int blue)1533     protected native void setTextColor(long printDC,
1534                                        int red, int green, int blue);
1535 
1536 
1537     /**
1538      * Draw the string <code>text</code> into the device
1539      * context <code>printDC</code> at the specified
1540      * position.
1541      */
textOut(long printDC, String text, int strlen, boolean glyphs, float x, float y, float[] positions)1542     protected native void textOut(long printDC, String text,
1543                                   int strlen, boolean glyphs,
1544                                   float x, float y, float[] positions);
1545 
1546 
getGDIAdvance(long printDC, String text)1547     private native int getGDIAdvance(long printDC, String text);
1548 
1549      /**
1550      * Draw the DIB compatible image buffer represented by
1551      * <code>image</code> to the GDI device context
1552      * <code>printDC</code>. The image is drawn at
1553      * <code>(destX, destY)</code> in device coordinates.
1554      * The image is scaled into a square of size
1555      * specified by <code>destWidth</code> and
1556      * <code>destHeight</code>. The portion of the
1557      * source image copied into that square is specified
1558      * by <code>srcX</code>, <code>srcY</code>,
1559      * <code>srcWidth</code>, and srcHeight.
1560      * Note that the image isn't completely compatible with DIB format.
1561      * At the very least it needs to be padded so each scanline is
1562      * DWORD aligned. Also we "flip" the image to make it a bottom-up DIB.
1563      */
drawDIBImage(long printDC, byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, float srcWidth, float srcHeight, int bitCount, byte[] bmiColors)1564     private native void drawDIBImage(long printDC, byte[] image,
1565                                      float destX, float destY,
1566                                      float destWidth, float destHeight,
1567                                      float srcX, float srcY,
1568                                      float srcWidth, float srcHeight,
1569                                      int bitCount, byte[] bmiColors);
1570 
1571 
1572     //** BEGIN Functions called by native code for querying/updating attributes
1573 
getPrinterAttrib()1574     private final String getPrinterAttrib() {
1575         // getPrintService will get current print service or default if none
1576         PrintService service = this.getPrintService();
1577         String name = (service != null) ? service.getName() : null;
1578         return name;
1579     }
1580 
1581     /* SheetCollate */
getCollateAttrib()1582     private final int getCollateAttrib() {
1583         // -1 means unset, 0 uncollated, 1 collated.
1584         return mAttCollate;
1585     }
1586 
setCollateAttrib(Attribute attr)1587     private void setCollateAttrib(Attribute attr) {
1588         if (attr == SheetCollate.COLLATED) {
1589             mAttCollate = 1; // DMCOLLATE_TRUE
1590         } else {
1591             mAttCollate = 0; // DMCOLLATE_FALSE
1592         }
1593     }
1594 
setCollateAttrib(Attribute attr, PrintRequestAttributeSet set)1595     private void setCollateAttrib(Attribute attr,
1596                                   PrintRequestAttributeSet set) {
1597         setCollateAttrib(attr);
1598         set.add(attr);
1599     }
1600 
1601     /* Orientation */
1602 
getOrientAttrib()1603     private final int getOrientAttrib() {
1604         int orient = PageFormat.PORTRAIT;
1605         OrientationRequested orientReq = (attributes == null) ? null :
1606             (OrientationRequested)attributes.get(OrientationRequested.class);
1607         if (orientReq == null) {
1608             orientReq = (OrientationRequested)
1609                myService.getDefaultAttributeValue(OrientationRequested.class);
1610         }
1611         if (orientReq != null) {
1612             if (orientReq == OrientationRequested.REVERSE_LANDSCAPE) {
1613                 orient = PageFormat.REVERSE_LANDSCAPE;
1614             } else if (orientReq == OrientationRequested.LANDSCAPE) {
1615                 orient = PageFormat.LANDSCAPE;
1616             }
1617         }
1618 
1619         return orient;
1620     }
1621 
setOrientAttrib(Attribute attr, PrintRequestAttributeSet set)1622     private void setOrientAttrib(Attribute attr,
1623                                  PrintRequestAttributeSet set) {
1624         if (set != null) {
1625             set.add(attr);
1626         }
1627     }
1628 
1629     /* Copies and Page Range. */
getCopiesAttrib()1630     private final int getCopiesAttrib() {
1631         if (defaultCopies) {
1632             return 0;
1633         } else {
1634             return getCopiesInt();
1635         }
1636      }
1637 
setRangeCopiesAttribute(int from, int to, boolean isRangeSet, int copies)1638     private final void setRangeCopiesAttribute(int from, int to,
1639                                                boolean isRangeSet,
1640                                                int copies) {
1641         if (attributes != null) {
1642             if (isRangeSet) {
1643                 attributes.add(new PageRanges(from, to));
1644                 setPageRange(from, to);
1645             }
1646             defaultCopies = false;
1647             attributes.add(new Copies(copies));
1648             /* Since this is called from native to tell Java to sync
1649              * up with native, we don't call this class's own setCopies()
1650              * method which is mainly to send the value down to native
1651              */
1652             super.setCopies(copies);
1653             mAttCopies = copies;
1654         }
1655     }
1656 
1657 
1658 
getDestAttrib()1659     private final boolean getDestAttrib() {
1660         return (mDestination != null);
1661     }
1662 
1663     /* Quality */
getQualityAttrib()1664     private final int getQualityAttrib() {
1665         return mAttQuality;
1666     }
1667 
setQualityAttrib(Attribute attr)1668     private void setQualityAttrib(Attribute attr) {
1669         if (attr == PrintQuality.HIGH) {
1670             mAttQuality = -4; // DMRES_HIGH
1671         } else if (attr == PrintQuality.NORMAL) {
1672             mAttQuality = -3; // DMRES_MEDIUM
1673         } else {
1674             mAttQuality = -2; // DMRES_LOW
1675         }
1676     }
1677 
setQualityAttrib(Attribute attr, PrintRequestAttributeSet set)1678     private void setQualityAttrib(Attribute attr,
1679                                   PrintRequestAttributeSet set) {
1680         setQualityAttrib(attr);
1681         set.add(attr);
1682     }
1683 
1684     /* Color/Chromaticity */
getColorAttrib()1685     private final int getColorAttrib() {
1686         return mAttChromaticity;
1687     }
1688 
setColorAttrib(Attribute attr)1689     private void setColorAttrib(Attribute attr) {
1690         if (attr == Chromaticity.COLOR) {
1691             mAttChromaticity = 2; // DMCOLOR_COLOR
1692         } else {
1693             mAttChromaticity = 1; // DMCOLOR_MONOCHROME
1694         }
1695     }
1696 
setColorAttrib(Attribute attr, PrintRequestAttributeSet set)1697     private void setColorAttrib(Attribute attr,
1698                                   PrintRequestAttributeSet set) {
1699         setColorAttrib(attr);
1700         set.add(attr);
1701     }
1702 
1703     /* Sides */
getSidesAttrib()1704     private final int getSidesAttrib() {
1705         return mAttSides;
1706     }
1707 
setSidesAttrib(Attribute attr)1708     private void setSidesAttrib(Attribute attr) {
1709         if (attr == Sides.TWO_SIDED_LONG_EDGE) {
1710             mAttSides = 2; // DMDUP_VERTICAL
1711         } else if (attr == Sides.TWO_SIDED_SHORT_EDGE) {
1712             mAttSides = 3; // DMDUP_HORIZONTAL
1713         } else { // Sides.ONE_SIDED
1714             mAttSides = 1;
1715         }
1716     }
1717 
setSidesAttrib(Attribute attr, PrintRequestAttributeSet set)1718     private void setSidesAttrib(Attribute attr,
1719                                 PrintRequestAttributeSet set) {
1720         setSidesAttrib(attr);
1721         set.add(attr);
1722     }
1723 
1724     /** MediaSizeName / dmPaper */
getWin32MediaAttrib()1725     private final int[] getWin32MediaAttrib() {
1726         int wid_ht[] = {0, 0};
1727         if (attributes != null) {
1728             Media media = (Media)attributes.get(Media.class);
1729             if (media instanceof MediaSizeName) {
1730                 MediaSizeName msn = (MediaSizeName)media;
1731                 MediaSize ms = MediaSize.getMediaSizeForName(msn);
1732                 if (ms != null) {
1733                     wid_ht[0] = (int)(ms.getX(MediaSize.INCH) * 72.0);
1734                     wid_ht[1] = (int)(ms.getY(MediaSize.INCH) * 72.0);
1735                 }
1736             }
1737         }
1738         return wid_ht;
1739     }
1740 
setWin32MediaAttrib(Attribute attr)1741     private void setWin32MediaAttrib(Attribute attr) {
1742         if (!(attr instanceof MediaSizeName)) {
1743             return;
1744         }
1745         MediaSizeName msn = (MediaSizeName)attr;
1746         mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn);
1747     }
1748 
addPaperSize(PrintRequestAttributeSet aset, int dmIndex, int width, int length)1749     private void addPaperSize(PrintRequestAttributeSet aset,
1750                               int dmIndex, int width, int length) {
1751 
1752         if (aset == null) {
1753             return;
1754         }
1755         MediaSizeName msn =
1756            ((Win32PrintService)myService).findWin32Media(dmIndex);
1757         if (msn == null) {
1758             msn = ((Win32PrintService)myService).
1759                 findMatchingMediaSizeNameMM((float)width, (float)length);
1760         }
1761 
1762         if (msn != null) {
1763             aset.add(msn);
1764         }
1765     }
1766 
setWin32MediaAttrib(int dmIndex, int width, int length)1767     private void setWin32MediaAttrib(int dmIndex, int width, int length) {
1768         addPaperSize(attributes, dmIndex, width, length);
1769         mAttMediaSizeName = dmIndex;
1770     }
1771 
1772     /* MediaTray / dmTray */
setMediaTrayAttrib(Attribute attr)1773     private void setMediaTrayAttrib(Attribute attr) {
1774         if (attr == MediaTray.BOTTOM) {
1775             mAttMediaTray = 2;    // DMBIN_LOWER
1776         } else if (attr == MediaTray.ENVELOPE) {
1777             mAttMediaTray = 5;    // DMBIN_ENVELOPE
1778         } else if (attr == MediaTray.LARGE_CAPACITY) {
1779             mAttMediaTray = 11;      // DMBIN_LARGECAPACITY
1780         } else if (attr == MediaTray.MAIN) {
1781             mAttMediaTray =1;               // DMBIN_UPPER
1782         } else if (attr == MediaTray.MANUAL) {
1783             mAttMediaTray = 4;              // DMBIN_MANUAL
1784         } else if (attr == MediaTray.MIDDLE) {
1785             mAttMediaTray = 3;              // DMBIN_MIDDLE
1786         } else if (attr == MediaTray.SIDE) {
1787             // no equivalent predefined value
1788             mAttMediaTray = 7;              // DMBIN_AUTO
1789         } else if (attr == MediaTray.TOP) {
1790             mAttMediaTray = 1;              // DMBIN_UPPER
1791         } else {
1792             if (attr instanceof Win32MediaTray) {
1793                 mAttMediaTray = ((Win32MediaTray)attr).winID;
1794             } else {
1795                 mAttMediaTray = 1;  // default
1796             }
1797         }
1798     }
1799 
setMediaTrayAttrib(int dmBinID)1800     private void setMediaTrayAttrib(int dmBinID) {
1801         mAttMediaTray = dmBinID;
1802         MediaTray tray = ((Win32PrintService)myService).findMediaTray(dmBinID);
1803     }
1804 
getMediaTrayAttrib()1805     private int getMediaTrayAttrib() {
1806         return mAttMediaTray;
1807     }
1808 
1809 
1810 
getPrintToFileEnabled()1811     private final boolean getPrintToFileEnabled() {
1812         SecurityManager security = System.getSecurityManager();
1813         if (security != null) {
1814             FilePermission printToFilePermission =
1815                 new FilePermission("<<ALL FILES>>", "read,write");
1816             try {
1817                 security.checkPermission(printToFilePermission);
1818             } catch (SecurityException e) {
1819                 return false;
1820             }
1821         }
1822         return true;
1823     }
1824 
setNativeAttributes(int flags, int fields, int values)1825     private final void setNativeAttributes(int flags, int fields, int values) {
1826         if (attributes == null) {
1827             return;
1828         }
1829         if ((flags & PD_PRINTTOFILE) != 0) {
1830             Destination destPrn = (Destination)attributes.get(
1831                                                  Destination.class);
1832             if (destPrn == null) {
1833                 try {
1834                     attributes.add(new Destination(
1835                                                new File("./out.prn").toURI()));
1836                 } catch (SecurityException se) {
1837                     try {
1838                         attributes.add(new Destination(
1839                                                 new URI("file:out.prn")));
1840                     } catch (URISyntaxException e) {
1841                     }
1842                 }
1843             }
1844         } else {
1845             attributes.remove(Destination.class);
1846         }
1847 
1848         if ((flags & PD_COLLATE) != 0) {
1849             setCollateAttrib(SheetCollate.COLLATED, attributes);
1850         } else {
1851             setCollateAttrib(SheetCollate.UNCOLLATED, attributes);
1852         }
1853 
1854         if ((flags & PD_PAGENUMS) != 0) {
1855             attributes.add(SunPageSelection.RANGE);
1856         } else if ((flags & PD_SELECTION) != 0) {
1857             attributes.add(SunPageSelection.SELECTION);
1858         } else {
1859             attributes.add(SunPageSelection.ALL);
1860         }
1861 
1862         if ((fields & DM_ORIENTATION) != 0) {
1863             if ((values & SET_ORIENTATION) != 0) {
1864                 setOrientAttrib(OrientationRequested.LANDSCAPE, attributes);
1865             } else {
1866                 setOrientAttrib(OrientationRequested.PORTRAIT, attributes);
1867             }
1868         }
1869 
1870         if ((fields & DM_COLOR) != 0) {
1871             if ((values & SET_COLOR) != 0) {
1872                 setColorAttrib(Chromaticity.COLOR, attributes);
1873             } else {
1874                 setColorAttrib(Chromaticity.MONOCHROME, attributes);
1875             }
1876         }
1877 
1878         if ((fields & DM_PRINTQUALITY) != 0) {
1879             PrintQuality quality;
1880             if ((values & SET_RES_LOW) != 0) {
1881                 quality = PrintQuality.DRAFT;
1882             } else if ((fields & SET_RES_HIGH) != 0) {
1883                 quality = PrintQuality.HIGH;
1884             } else {
1885                 quality = PrintQuality.NORMAL;
1886             }
1887             setQualityAttrib(quality, attributes);
1888         }
1889 
1890         if ((fields & DM_DUPLEX) != 0) {
1891             Sides sides;
1892             if ((values & SET_DUP_VERTICAL) != 0) {
1893                 sides = Sides.TWO_SIDED_LONG_EDGE;
1894             } else if ((values & SET_DUP_HORIZONTAL) != 0) {
1895                 sides = Sides.TWO_SIDED_SHORT_EDGE;
1896             } else {
1897                 sides = Sides.ONE_SIDED;
1898             }
1899             setSidesAttrib(sides, attributes);
1900         }
1901     }
1902 
1903     private static final class DevModeValues {
1904         int dmFields;
1905         short copies;
1906         short collate;
1907         short color;
1908         short duplex;
1909         short orient;
1910         short paper;
1911         short bin;
1912         short xres_quality;
1913         short yres;
1914     }
1915 
getDevModeValues(PrintRequestAttributeSet aset, DevModeValues info)1916     private void getDevModeValues(PrintRequestAttributeSet aset,
1917                                   DevModeValues info) {
1918 
1919         Copies c = (Copies)aset.get(Copies.class);
1920         if (c != null) {
1921             info.dmFields |= DM_COPIES;
1922             info.copies = (short)c.getValue();
1923         }
1924 
1925         SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class);
1926         if (sc != null) {
1927             info.dmFields |= DM_COLLATE;
1928             info.collate = (sc == SheetCollate.COLLATED) ?
1929                 DMCOLLATE_TRUE : DMCOLLATE_FALSE;
1930         }
1931 
1932         Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class);
1933         if (ch != null) {
1934             info.dmFields |= DM_COLOR;
1935             if (ch == Chromaticity.COLOR) {
1936                 info.color = DMCOLOR_COLOR;
1937             } else {
1938                 info.color = DMCOLOR_MONOCHROME;
1939             }
1940         }
1941 
1942         Sides s = (Sides)aset.get(Sides.class);
1943         if (s != null) {
1944             info.dmFields |= DM_DUPLEX;
1945             if (s == Sides.TWO_SIDED_LONG_EDGE) {
1946                 info.duplex = DMDUP_VERTICAL;
1947             } else if (s == Sides.TWO_SIDED_SHORT_EDGE) {
1948                 info.duplex = DMDUP_HORIZONTAL;
1949             } else { // Sides.ONE_SIDED
1950                 info.duplex = DMDUP_SIMPLEX;
1951             }
1952         }
1953 
1954         OrientationRequested or =
1955             (OrientationRequested)aset.get(OrientationRequested.class);
1956         if (or != null) {
1957             info.dmFields |= DM_ORIENTATION;
1958             info.orient = (or == OrientationRequested.LANDSCAPE)
1959                 ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
1960         }
1961 
1962         Media m = (Media)aset.get(Media.class);
1963         if (m instanceof MediaSizeName) {
1964             info.dmFields |= DM_PAPERSIZE;
1965             MediaSizeName msn = (MediaSizeName)m;
1966             info.paper =
1967                 (short)((Win32PrintService)myService).findPaperID(msn);
1968         }
1969 
1970         MediaTray mt = null;
1971         if (m instanceof MediaTray) {
1972             mt = (MediaTray)m;
1973         }
1974         if (mt == null) {
1975             SunAlternateMedia sam =
1976                 (SunAlternateMedia)aset.get(SunAlternateMedia.class);
1977             if (sam != null && (sam.getMedia() instanceof MediaTray)) {
1978                 mt = (MediaTray)sam.getMedia();
1979             }
1980         }
1981 
1982         if (mt != null) {
1983             info.dmFields |= DM_DEFAULTSOURCE;
1984             info.bin = (short)(((Win32PrintService)myService).findTrayID(mt));
1985         }
1986 
1987         PrintQuality q = (PrintQuality)aset.get(PrintQuality.class);
1988         if (q != null) {
1989             info.dmFields |= DM_PRINTQUALITY;
1990             if (q == PrintQuality.DRAFT) {
1991                 info.xres_quality = DMRES_DRAFT;
1992             } else if (q == PrintQuality.HIGH) {
1993                 info.xres_quality = DMRES_HIGH;
1994             } else {
1995                 info.xres_quality = DMRES_MEDIUM;
1996             }
1997         }
1998 
1999         PrinterResolution r =
2000             (PrinterResolution)aset.get(PrinterResolution.class);
2001         if (r != null) {
2002             info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION;
2003             info.xres_quality =
2004                 (short)r.getCrossFeedResolution(PrinterResolution.DPI);
2005             info.yres = (short)r.getFeedResolution(PrinterResolution.DPI);
2006         }
2007     }
2008 
2009     /* This method is called from native to update the values in the
2010      * attribute set which originates from the cross-platform dialog,
2011      * but updated by the native DocumentPropertiesUI which updates the
2012      * devmode. This syncs the devmode back in to the attributes so that
2013      * we can update the cross-platform dialog.
2014      * The attribute set here is a temporary one installed whilst this
2015      * happens,
2016      */
setJobAttributes(PrintRequestAttributeSet attributes, int fields, int values, short copies, short dmPaperSize, short dmPaperWidth, short dmPaperLength, short dmDefaultSource, short xRes, short yRes)2017     private final void setJobAttributes(PrintRequestAttributeSet attributes,
2018                                         int fields, int values,
2019                                         short copies,
2020                                         short dmPaperSize,
2021                                         short dmPaperWidth,
2022                                         short dmPaperLength,
2023                                         short dmDefaultSource,
2024                                         short xRes,
2025                                         short yRes) {
2026 
2027         if (attributes == null) {
2028             return;
2029         }
2030 
2031         if ((fields & DM_COPIES) != 0) {
2032             attributes.add(new Copies(copies));
2033         }
2034 
2035         if ((fields & DM_COLLATE) != 0) {
2036             if ((values & SET_COLLATED) != 0) {
2037                 attributes.add(SheetCollate.COLLATED);
2038             } else {
2039                 attributes.add(SheetCollate.UNCOLLATED);
2040             }
2041         }
2042 
2043         if ((fields & DM_ORIENTATION) != 0) {
2044             if ((values & SET_ORIENTATION) != 0) {
2045                 attributes.add(OrientationRequested.LANDSCAPE);
2046             } else {
2047                 attributes.add(OrientationRequested.PORTRAIT);
2048             }
2049         }
2050 
2051         if ((fields & DM_COLOR) != 0) {
2052             if ((values & SET_COLOR) != 0) {
2053                 attributes.add(Chromaticity.COLOR);
2054             } else {
2055                 attributes.add(Chromaticity.MONOCHROME);
2056             }
2057         }
2058 
2059         if ((fields & DM_PRINTQUALITY) != 0) {
2060             /* value < 0 indicates quality setting.
2061              * value > 0 indicates X resolution. In that case
2062              * hopefully we will also find y-resolution specified.
2063              * If its not, assume its the same as x-res.
2064              * Maybe Java code should try to reconcile this against
2065              * the printers claimed set of supported resolutions.
2066              */
2067             if (xRes < 0) {
2068                 PrintQuality quality;
2069                 if ((values & SET_RES_LOW) != 0) {
2070                     quality = PrintQuality.DRAFT;
2071                 } else if ((fields & SET_RES_HIGH) != 0) {
2072                     quality = PrintQuality.HIGH;
2073                 } else {
2074                     quality = PrintQuality.NORMAL;
2075                 }
2076                 attributes.add(quality);
2077             } else if (xRes > 0 && yRes > 0) {
2078                 attributes.add(
2079                     new PrinterResolution(xRes, yRes, PrinterResolution.DPI));
2080             }
2081         }
2082 
2083         if ((fields & DM_DUPLEX) != 0) {
2084             Sides sides;
2085             if ((values & SET_DUP_VERTICAL) != 0) {
2086                 sides = Sides.TWO_SIDED_LONG_EDGE;
2087             } else if ((values & SET_DUP_HORIZONTAL) != 0) {
2088                 sides = Sides.TWO_SIDED_SHORT_EDGE;
2089             } else {
2090                 sides = Sides.ONE_SIDED;
2091             }
2092             attributes.add(sides);
2093         }
2094 
2095         if ((fields & DM_PAPERSIZE) != 0) {
2096             addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength);
2097         }
2098 
2099         if ((fields & DM_DEFAULTSOURCE) != 0) {
2100             MediaTray tray =
2101                 ((Win32PrintService)myService).findMediaTray(dmDefaultSource);
2102             attributes.add(new SunAlternateMedia(tray));
2103         }
2104     }
2105 
showDocProperties(long hWnd, PrintRequestAttributeSet aset, int dmFields, short copies, short collate, short color, short duplex, short orient, short paper, short bin, short xres_quality, short yres)2106     private native boolean showDocProperties(long hWnd,
2107                                              PrintRequestAttributeSet aset,
2108                                              int dmFields,
2109                                              short copies,
2110                                              short collate,
2111                                              short color,
2112                                              short duplex,
2113                                              short orient,
2114                                              short paper,
2115                                              short bin,
2116                                              short xres_quality,
2117                                              short yres);
2118 
2119     @SuppressWarnings("deprecation")
2120     public PrintRequestAttributeSet
showDocumentProperties(Window owner, PrintService service, PrintRequestAttributeSet aset)2121         showDocumentProperties(Window owner,
2122                                PrintService service,
2123                                PrintRequestAttributeSet aset)
2124     {
2125         try {
2126             setNativePrintServiceIfNeeded(service.getName());
2127         } catch (PrinterException e) {
2128         }
2129         long hWnd = ((WWindowPeer)(owner.getPeer())).getHWnd();
2130         DevModeValues info = new DevModeValues();
2131         getDevModeValues(aset, info);
2132         boolean ok =
2133             showDocProperties(hWnd, aset,
2134                               info.dmFields,
2135                               info.copies,
2136                               info.collate,
2137                               info.color,
2138                               info.duplex,
2139                               info.orient,
2140                               info.paper,
2141                               info.bin,
2142                               info.xres_quality,
2143                               info.yres);
2144 
2145         if (ok) {
2146             return aset;
2147         } else {
2148             return null;
2149         }
2150     }
2151 
2152     /* Printer Resolution. See also getXRes() and getYRes() */
setResolutionDPI(int xres, int yres)2153     private final void setResolutionDPI(int xres, int yres) {
2154         if (attributes != null) {
2155             PrinterResolution res =
2156                 new PrinterResolution(xres, yres, PrinterResolution.DPI);
2157             attributes.add(res);
2158         }
2159         mAttXRes = xres;
2160         mAttYRes = yres;
2161     }
2162 
setResolutionAttrib(Attribute attr)2163     private void setResolutionAttrib(Attribute attr) {
2164         PrinterResolution pr = (PrinterResolution)attr;
2165         mAttXRes = pr.getCrossFeedResolution(PrinterResolution.DPI);
2166         mAttYRes = pr.getFeedResolution(PrinterResolution.DPI);
2167     }
2168 
setPrinterNameAttrib(String printerName)2169     private void setPrinterNameAttrib(String printerName) {
2170         PrintService service = this.getPrintService();
2171 
2172         if (printerName == null) {
2173             return;
2174         }
2175 
2176         if (service != null && printerName.equals(service.getName())) {
2177             return;
2178         } else {
2179             PrintService []services = PrinterJob.lookupPrintServices();
2180             for (int i=0; i<services.length; i++) {
2181                 if (printerName.equals(services[i].getName())) {
2182 
2183                     try {
2184                         this.setPrintService(services[i]);
2185                     } catch (PrinterException e) {
2186                     }
2187                     return;
2188                 }
2189             }
2190         }
2191     //** END Functions called by native code for querying/updating attributes
2192 
2193     }
2194 
2195 class PrintToFileErrorDialog extends Dialog implements ActionListener{
PrintToFileErrorDialog(Frame parent, String title, String message, String buttonText)2196     public PrintToFileErrorDialog(Frame parent, String title, String message,
2197                            String buttonText) {
2198         super(parent, title, true);
2199         init (parent, title, message, buttonText);
2200     }
2201 
PrintToFileErrorDialog(Dialog parent, String title, String message, String buttonText)2202     public PrintToFileErrorDialog(Dialog parent, String title, String message,
2203                            String buttonText) {
2204         super(parent, title, true);
2205         init (parent, title, message, buttonText);
2206     }
2207 
init(Component parent, String title, String message, String buttonText)2208     private void init(Component parent, String  title, String message,
2209                       String buttonText) {
2210         Panel p = new Panel();
2211         add("Center", new Label(message));
2212         Button btn = new Button(buttonText);
2213         btn.addActionListener(this);
2214         p.add(btn);
2215         add("South", p);
2216         pack();
2217 
2218         Dimension dDim = getSize();
2219         if (parent != null) {
2220             Rectangle fRect = parent.getBounds();
2221             setLocation(fRect.x + ((fRect.width - dDim.width) / 2),
2222                         fRect.y + ((fRect.height - dDim.height) / 2));
2223         }
2224     }
2225 
2226     @Override
actionPerformed(ActionEvent event)2227     public void actionPerformed(ActionEvent event) {
2228         setVisible(false);
2229         dispose();
2230         return;
2231     }
2232 }
2233 
2234 
2235 
2236 
2237     /**
2238      * Initialize JNI field and method ids
2239      */
initIDs()2240     private static native void initIDs();
2241 
2242 }
2243