View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.print;
27  
28  import java.awt.Window;
29  import java.awt.print.PrinterJob;
30  import java.io.File;
31  import java.net.URI;
32  import java.net.URISyntaxException;
33  import java.util.ArrayList;
34  import java.util.HashMap;
35  import javax.print.DocFlavor;
36  import javax.print.DocPrintJob;
37  import javax.print.PrintService;
38  import javax.print.ServiceUIFactory;
39  import javax.print.attribute.Attribute;
40  import javax.print.attribute.AttributeSet;
41  import javax.print.attribute.AttributeSetUtilities;
42  import javax.print.attribute.EnumSyntax;
43  import javax.print.attribute.HashAttributeSet;
44  import javax.print.attribute.PrintRequestAttributeSet;
45  import javax.print.attribute.PrintServiceAttribute;
46  import javax.print.attribute.PrintServiceAttributeSet;
47  import javax.print.attribute.HashPrintServiceAttributeSet;
48  import javax.print.attribute.standard.PrinterName;
49  import javax.print.attribute.standard.PrinterIsAcceptingJobs;
50  import javax.print.attribute.standard.QueuedJobCount;
51  import javax.print.attribute.standard.JobName;
52  import javax.print.attribute.standard.RequestingUserName;
53  import javax.print.attribute.standard.Chromaticity;
54  import javax.print.attribute.standard.Copies;
55  import javax.print.attribute.standard.CopiesSupported;
56  import javax.print.attribute.standard.Destination;
57  import javax.print.attribute.standard.Fidelity;
58  import javax.print.attribute.standard.Media;
59  import javax.print.attribute.standard.MediaSizeName;
60  import javax.print.attribute.standard.MediaSize;
61  import javax.print.attribute.standard.MediaTray;
62  import javax.print.attribute.standard.MediaPrintableArea;
63  import javax.print.attribute.standard.OrientationRequested;
64  import javax.print.attribute.standard.PageRanges;
65  import javax.print.attribute.standard.PrinterState;
66  import javax.print.attribute.standard.PrinterStateReason;
67  import javax.print.attribute.standard.PrinterStateReasons;
68  import javax.print.attribute.standard.Severity;
69  import javax.print.attribute.standard.Sides;
70  import javax.print.attribute.standard.ColorSupported;
71  import javax.print.attribute.standard.PrintQuality;
72  import javax.print.attribute.standard.PrinterResolution;
73  import javax.print.attribute.standard.SheetCollate;
74  import javax.print.event.PrintServiceAttributeListener;
75  import sun.awt.windows.WPrinterJob;
76  
77  public class Win32PrintService implements PrintService, AttributeUpdater,
78                                            SunPrinterJobService {
79  
80      public static MediaSize[] predefMedia = Win32MediaSize.getPredefMedia();
81  
82      private static final DocFlavor[] supportedFlavors = {
83          DocFlavor.BYTE_ARRAY.GIF,
84          DocFlavor.INPUT_STREAM.GIF,
85          DocFlavor.URL.GIF,
86          DocFlavor.BYTE_ARRAY.JPEG,
87          DocFlavor.INPUT_STREAM.JPEG,
88          DocFlavor.URL.JPEG,
89          DocFlavor.BYTE_ARRAY.PNG,
90          DocFlavor.INPUT_STREAM.PNG,
91          DocFlavor.URL.PNG,
92          DocFlavor.SERVICE_FORMATTED.PAGEABLE,
93          DocFlavor.SERVICE_FORMATTED.PRINTABLE,
94          DocFlavor.BYTE_ARRAY.AUTOSENSE,
95          DocFlavor.URL.AUTOSENSE,
96          DocFlavor.INPUT_STREAM.AUTOSENSE
97      };
98  
99      /* let's try to support a few of these */
100     private static final Class[] serviceAttrCats = {
101         PrinterName.class,
102         PrinterIsAcceptingJobs.class,
103         QueuedJobCount.class,
104         ColorSupported.class,
105     };
106 
107     /*  it turns out to be inconvenient to store the other categories
108      *  separately because many attributes are in multiple categories.
109      */
110     private static Class[] otherAttrCats = {
111         JobName.class,
112         RequestingUserName.class,
113         Copies.class,
114         Destination.class,
115         OrientationRequested.class,
116         PageRanges.class,
117         Media.class,
118         MediaPrintableArea.class,
119         Fidelity.class,
120         // We support collation on 2D printer jobs, even if the driver can't.
121         SheetCollate.class,
122         SunAlternateMedia.class,
123         Chromaticity.class
124     };
125 
126 
127     /*
128      * This table together with methods findWin32Media and
129      * findMatchingMediaSizeNameMM are declared public as these are also
130      * used in WPrinterJob.java.
131      */
132     public static final MediaSizeName[] dmPaperToPrintService = {
133       MediaSizeName.NA_LETTER, MediaSizeName.NA_LETTER,
134       MediaSizeName.TABLOID, MediaSizeName.LEDGER,
135       MediaSizeName.NA_LEGAL, MediaSizeName.INVOICE,
136       MediaSizeName.EXECUTIVE, MediaSizeName.ISO_A3,
137       MediaSizeName.ISO_A4, MediaSizeName.ISO_A4,
138       MediaSizeName.ISO_A5, MediaSizeName.JIS_B4,
139       MediaSizeName.JIS_B5, MediaSizeName.FOLIO,
140       MediaSizeName.QUARTO, MediaSizeName.NA_10X14_ENVELOPE,
141       MediaSizeName.B, MediaSizeName.NA_LETTER,
142       MediaSizeName.NA_NUMBER_9_ENVELOPE, MediaSizeName.NA_NUMBER_10_ENVELOPE,
143       MediaSizeName.NA_NUMBER_11_ENVELOPE, MediaSizeName.NA_NUMBER_12_ENVELOPE,
144       MediaSizeName.NA_NUMBER_14_ENVELOPE, MediaSizeName.C,
145       MediaSizeName.D, MediaSizeName.E,
146       MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.ISO_C5,
147       MediaSizeName.ISO_C3, MediaSizeName.ISO_C4,
148       MediaSizeName.ISO_C6, MediaSizeName.ITALY_ENVELOPE,
149       MediaSizeName.ISO_B4, MediaSizeName.ISO_B5,
150       MediaSizeName.ISO_B6, MediaSizeName.ITALY_ENVELOPE,
151       MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,
152       MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,
153       MediaSizeName.FOLIO, MediaSizeName.ISO_B4,
154       MediaSizeName.JAPANESE_POSTCARD, MediaSizeName.NA_9X11_ENVELOPE,
155     };
156 
157     private static final MediaTray[] dmPaperBinToPrintService = {
158       MediaTray.TOP, MediaTray.BOTTOM, MediaTray.MIDDLE,
159       MediaTray.MANUAL, MediaTray.ENVELOPE, Win32MediaTray.ENVELOPE_MANUAL,
160       Win32MediaTray.AUTO, Win32MediaTray.TRACTOR,
161       Win32MediaTray.SMALL_FORMAT, Win32MediaTray.LARGE_FORMAT,
162       MediaTray.LARGE_CAPACITY, null, null,
163       MediaTray.MAIN, Win32MediaTray.FORMSOURCE,
164     };
165 
166     // from wingdi.h
167     private static int DM_PAPERSIZE = 0x2;
168     private static int DM_PRINTQUALITY = 0x400;
169     private static int DM_YRESOLUTION = 0x2000;
170     private static final int DMRES_MEDIUM = -3;
171     private static final int DMRES_HIGH = -4;
172     private static final int DMORIENT_LANDSCAPE = 2;
173     private static final int DMDUP_VERTICAL = 2;
174     private static final int DMDUP_HORIZONTAL = 3;
175     private static final int DMCOLLATE_TRUE = 1;
176     private static final int DMCOLOR_MONOCHROME = 1;
177     private static final int DMCOLOR_COLOR = 2;
178 
179 
180     // media sizes with indices above dmPaperToPrintService' length
181     private static final int DMPAPER_A2 = 66;
182     private static final int DMPAPER_A6 = 70;
183     private static final int DMPAPER_B6_JIS = 88;
184 
185 
186     // Bit settings for getPrinterCapabilities which matches that
187     // of native getCapabilities in WPrinterJob.cpp
188     private static final int DEVCAP_COLOR = 0x0001;
189     private static final int DEVCAP_DUPLEX = 0x0002;
190     private static final int DEVCAP_COLLATE = 0x0004;
191     private static final int DEVCAP_QUALITY = 0x0008;
192     private static final int DEVCAP_POSTSCRIPT = 0x0010;
193 
194     private String printer;
195     private PrinterName name;
196     private String port;
197 
198     transient private PrintServiceAttributeSet lastSet;
199     transient private ServiceNotifier notifier = null;
200 
201     private MediaSizeName[] mediaSizeNames;
202     private MediaPrintableArea[] mediaPrintables;
203     private MediaTray[] mediaTrays;
204     private PrinterResolution[] printRes;
205     private HashMap mpaMap;
206     private int nCopies;
207     private int prnCaps;
208     private int[] defaultSettings;
209 
210     private boolean gotTrays;
211     private boolean gotCopies;
212     private boolean mediaInitialized;
213     private boolean mpaListInitialized;
214 
215     private ArrayList idList;
216     private MediaSize[] mediaSizes;
217 
218     private boolean isInvalid;
219 
220     Win32PrintService(String name) {
221         if (name == null) {
222             throw new IllegalArgumentException("null printer name");
223         }
224         printer = name;
225 
226         // initialize flags
227         mediaInitialized = false;
228         gotTrays = false;
229         gotCopies = false;
230         isInvalid = false;
231         printRes = null;
232         prnCaps = 0;
233         defaultSettings = null;
234         port = null;
235     }
236 
237     public void invalidateService() {
238         isInvalid = true;
239     }
240 
241     public String getName() {
242         return printer;
243     }
244 
245     private PrinterName getPrinterName() {
246         if (name == null) {
247             name = new PrinterName(printer, null);
248         }
249         return name;
250     }
251 
252     public int findPaperID(MediaSizeName msn) {
253         if (msn instanceof Win32MediaSize) {
254             Win32MediaSize winMedia = (Win32MediaSize)msn;
255             return winMedia.getDMPaper();
256         } else {
257             for (int id=0; id<dmPaperToPrintService.length;id++) {
258                 if (dmPaperToPrintService[id].equals(msn)) {
259                     return id+1; // DMPAPER_LETTER == 1
260                 }
261             }
262             if (msn.equals(MediaSizeName.ISO_A2)) {
263                 return DMPAPER_A2;
264             }
265             else if (msn.equals(MediaSizeName.ISO_A6)) {
266                 return DMPAPER_A6;
267             }
268             else if (msn.equals(MediaSizeName.JIS_B6)) {
269                 return DMPAPER_B6_JIS;
270             }
271         }
272 
273         // If not found in predefined Windows ID, then we search through
274         // the returned IDs of the driver because they can define their own
275         // unique IDs.
276         initMedia();
277 
278         if ((idList != null) && (mediaSizes != null) &&
279             (idList.size() == mediaSizes.length)) {
280             for (int i=0; i< idList.size(); i++) {
281                 if (mediaSizes[i].getMediaSizeName() == msn) {
282                     return ((Integer)idList.get(i)).intValue();
283                 }
284             }
285         }
286         return 0;
287     }
288 
289     public int findTrayID(MediaTray tray) {
290 
291         getMediaTrays(); // make sure they are initialised.
292 
293         if (tray instanceof Win32MediaTray) {
294             Win32MediaTray winTray = (Win32MediaTray)tray;
295             return winTray.getDMBinID();
296         }
297         for (int id=0; id<dmPaperBinToPrintService.length; id++) {
298             if (tray.equals(dmPaperBinToPrintService[id])) {
299                 return id+1; // DMBIN_FIRST = 1;
300             }
301         }
302         return 0; // didn't find the tray
303     }
304 
305     public MediaTray findMediaTray(int dmBin) {
306         if (dmBin >= 1 && dmBin <= dmPaperBinToPrintService.length) {
307             return dmPaperBinToPrintService[dmBin-1];
308         }
309         MediaTray[] trays = getMediaTrays();
310         if (trays != null) {
311             for (int i=0;i<trays.length;i++) {
312                 if(trays[i] instanceof Win32MediaTray) {
313                     Win32MediaTray win32Tray = (Win32MediaTray)trays[i];
314                     if (win32Tray.winID == dmBin) {
315                         return win32Tray;
316                     }
317                 }
318             }
319         }
320         return Win32MediaTray.AUTO;
321     }
322 
323     public MediaSizeName findWin32Media(int dmIndex) {
324         if (dmIndex >= 1 && dmIndex <= dmPaperToPrintService.length) {
325             return dmPaperToPrintService[dmIndex - 1];
326         }
327         switch(dmIndex) {
328             /* matching media sizes with indices beyond
329                dmPaperToPrintService's length */
330             case DMPAPER_A2:
331                 return MediaSizeName.ISO_A2;
332             case DMPAPER_A6:
333                 return MediaSizeName.ISO_A6;
334             case DMPAPER_B6_JIS:
335                 return MediaSizeName.JIS_B6;
336             default:
337                 return null;
338         }
339     }
340 
341     private boolean addToUniqueList(ArrayList msnList, MediaSizeName mediaName) {
342         MediaSizeName msn;
343         for (int i=0; i< msnList.size(); i++) {
344             msn = (MediaSizeName)msnList.get(i);
345             if (msn == mediaName) {
346                 return false;
347             }
348         }
349         msnList.add(mediaName);
350         return true;
351     }
352 
353     private synchronized void initMedia() {
354         if (mediaInitialized == true) {
355             return;
356         }
357         mediaInitialized = true;
358         int[] media = getAllMediaIDs(printer, getPort());
359         if (media == null) {
360             return;
361         }
362 
363         ArrayList msnList = new ArrayList();
364         ArrayList<Win32MediaSize> trailingWmsList = new ArrayList<Win32MediaSize>();
365         ArrayList printableList = new ArrayList();
366         MediaSizeName mediaName;
367         boolean added;
368         boolean queryFailure = false;
369         float[] prnArea;
370 
371         // Get all mediaSizes supported by the printer.
372         // We convert media to ArrayList idList and pass this to the
373         // function for getting mediaSizes.
374         // This is to ensure that mediaSizes and media IDs have 1-1 correspondence.
375         // We remove from ID list any invalid mediaSize.  Though this is rare,
376         // it happens in HP 4050 German driver.
377 
378         idList = new ArrayList();
379         for (int i=0; i < media.length; i++) {
380             idList.add(Integer.valueOf(media[i]));
381         }
382 
383         ArrayList<String> dmPaperNameList = new ArrayList<String>();
384         mediaSizes = getMediaSizes(idList, media, dmPaperNameList);
385         for (int i = 0; i < idList.size(); i++) {
386 
387             // match Win ID with our predefined ID using table
388             mediaName = findWin32Media(((Integer)idList.get(i)).intValue());
389             // Verify that this standard size is the same size as that
390             // reported by the driver. This should be the case except when
391             // the driver is mis-using a standard windows paper ID.
392             if (mediaName != null &&
393                 idList.size() == mediaSizes.length) {
394                 MediaSize win32Size = MediaSize.getMediaSizeForName(mediaName);
395                 MediaSize driverSize = mediaSizes[i];
396                 int error = 2540; // == 1/10"
397                 if (Math.abs(win32Size.getX(1)-driverSize.getX(1)) > error ||
398                     Math.abs(win32Size.getY(1)-driverSize.getY(1)) > error)
399                 {
400                    mediaName = null;
401                 }
402             }
403             boolean dmPaperIDMatched = (mediaName != null);
404 
405             // No match found, then we get the MediaSizeName out of the MediaSize
406             // This requires 1-1 correspondence, lengths must be checked.
407             if ((mediaName == null) && (idList.size() == mediaSizes.length)) {
408                 mediaName = mediaSizes[i].getMediaSizeName();
409             }
410 
411             // Add mediaName to the msnList
412             added = false;
413             if (mediaName != null) {
414                 added = addToUniqueList(msnList, mediaName);
415             }
416             if ((!dmPaperIDMatched || !added) && (idList.size() == dmPaperNameList.size())) {
417                 /* The following block allows to add such media names to the list, whose sizes
418                  * matched with media sizes predefined in JDK, while whose paper IDs did not,
419                  * or whose sizes and paper IDs both did not match with any predefined in JDK.
420                  */
421                 Win32MediaSize wms = Win32MediaSize.findMediaName(dmPaperNameList.get(i));
422                 if ((wms == null) && (idList.size() == mediaSizes.length)) {
423                     wms = new Win32MediaSize(dmPaperNameList.get(i), (Integer)idList.get(i));
424                     mediaSizes[i] = new MediaSize(mediaSizes[i].getX(MediaSize.MM),
425                         mediaSizes[i].getY(MediaSize.MM), MediaSize.MM, wms);
426                 }
427                 if ((wms != null) && (wms != mediaName)) {
428                     if (!added) {
429                         added = addToUniqueList(msnList, mediaName = wms);
430                     } else {
431                         trailingWmsList.add(wms);
432                     }
433                 }
434             }
435         }
436         for (Win32MediaSize wms : trailingWmsList) {
437             added = addToUniqueList(msnList, wms);
438         }
439 
440         // init mediaSizeNames
441         mediaSizeNames = new MediaSizeName[msnList.size()];
442         msnList.toArray(mediaSizeNames);
443     }
444 
445 
446     /*
447      * Gets a list of MediaPrintableAreas using a call to native function.
448      *  msn is MediaSizeName used to get a specific printable area.  If null,
449      *  it will get all the supported MediPrintableAreas.
450      */
451     private synchronized MediaPrintableArea[] getMediaPrintables(MediaSizeName msn)
452     {
453         if (msn == null)  {
454             if (mpaListInitialized == true) {
455                 return mediaPrintables;
456             }
457         } else {
458             // get from cached mapping of MPAs
459             if (mpaMap != null && (mpaMap.get(msn) != null)) {
460                 MediaPrintableArea[] mpaArr = new MediaPrintableArea[1];
461                 mpaArr[0] = (MediaPrintableArea)mpaMap.get(msn);
462                 return mpaArr;
463             }
464         }
465 
466         initMedia();
467 
468         if ((mediaSizeNames == null) || (mediaSizeNames.length == 0)) {
469             return null;
470         }
471 
472         MediaSizeName[] loopNames;
473         if (msn != null) {
474             loopNames = new MediaSizeName[1];
475             loopNames[0] = msn;
476         } else {
477             loopNames = mediaSizeNames;
478         }
479 
480         if (mpaMap == null) {
481             mpaMap = new HashMap();
482         }
483 
484         for (int i=0; i < loopNames.length; i++) {
485             MediaSizeName mediaName = loopNames[i];
486 
487             if (mpaMap.get(mediaName) != null) {
488                 continue;
489              }
490 
491             if (mediaName != null) {
492                 int defPaper = findPaperID(mediaName);
493                 float[] prnArea = (defPaper != 0) ? getMediaPrintableArea(printer, defPaper) : null;
494                 MediaPrintableArea printableArea = null;
495                 if (prnArea != null) {
496                     try {
497                         printableArea = new MediaPrintableArea(prnArea[0],
498                                                                prnArea[1],
499                                                                prnArea[2],
500                                                                prnArea[3],
501                                                  MediaPrintableArea.INCH);
502 
503                         mpaMap.put(mediaName, printableArea);
504                     }
505                     catch (IllegalArgumentException e) {
506                     }
507                 } else {
508                     // if getting  MPA failed, we use MediaSize
509                     MediaSize ms =
510                         MediaSize.getMediaSizeForName((MediaSizeName)mediaName);
511 
512                     if (ms != null) {
513                         try {
514                             printableArea = new MediaPrintableArea(0, 0,
515                                                      ms.getX(MediaSize.INCH),
516                                                      ms.getY(MediaSize.INCH),
517                                                      MediaPrintableArea.INCH);
518                             mpaMap.put(mediaName, printableArea);
519                         } catch (IllegalArgumentException e) {
520                         }
521                     }
522                 }
523             } //mediaName != null
524         }
525 
526        if (mpaMap.size() == 0) {
527            return null;
528        }
529 
530        if (msn != null) {
531            if (mpaMap.get(msn) == null) {
532                return null;
533            }
534            MediaPrintableArea[] mpaArr = new MediaPrintableArea[1];
535            // by this time, we've already gotten the desired MPA
536            mpaArr[0] = (MediaPrintableArea)mpaMap.get(msn);
537            return mpaArr;
538        } else {
539            mediaPrintables = (MediaPrintableArea[])mpaMap.values().toArray(new MediaPrintableArea[0]);
540            mpaListInitialized = true;
541            return mediaPrintables;
542        }
543     }
544 
545 
546     private synchronized MediaTray[] getMediaTrays() {
547         if (gotTrays == true && mediaTrays != null) {
548             return mediaTrays;
549         }
550         String prnPort = getPort();
551         int[] mediaTr = getAllMediaTrays(printer, prnPort);
552         String[] winMediaTrayNames = getAllMediaTrayNames(printer, prnPort);
553 
554         if ((mediaTr == null) || (winMediaTrayNames == null)){
555             return null;
556         }
557 
558         /* first count how many valid bins there are so we can allocate
559          * an array of the correct size
560          */
561         int nTray = 0;
562         for (int i=0; i < mediaTr.length ; i++) {
563             if (mediaTr[i] > 0) nTray++;
564         }
565 
566         MediaTray[] arr = new MediaTray[nTray];
567         int dmBin;
568 
569         /* Some drivers in Win 7 don't have the same length for DC_BINS and
570          * DC_BINNAMES so there is no guarantee that lengths of mediaTr and
571          * winMediaTrayNames are equal. To avoid getting ArrayIndexOutOfBounds,
572          * we need to make sure we get the minimum of the two.
573          */
574 
575         for (int i = 0, j=0; i < Math.min(mediaTr.length, winMediaTrayNames.length); i++) {
576             dmBin = mediaTr[i];
577             if (dmBin > 0) {
578                 // check for unsupported DMBINs and create new Win32MediaTray
579                 if ((dmBin > dmPaperBinToPrintService.length)
580                     || (dmPaperBinToPrintService[dmBin-1] == null)) {
581                     arr[j++] = new Win32MediaTray(dmBin, winMediaTrayNames[i]);
582                 } else {
583                     arr[j++] = dmPaperBinToPrintService[dmBin-1];
584                 }
585             }
586             // no else - For invalid ids, just ignore it because assigning a "default"
587             // value may result in duplicate trays.
588         }
589         mediaTrays = arr;
590         gotTrays = true;
591         return mediaTrays;
592     }
593 
594     private boolean isSameSize(float w1, float h1, float w2, float h2) {
595         float diffX = w1 - w2;
596         float diffY = h1 - h2;
597         // Get diff of reverse dimensions
598         // EPSON Stylus COLOR 860 reverses envelope's width & height
599         float diffXrev = w1 - h2;
600         float diffYrev = h1 - w2;
601 
602         if (((Math.abs(diffX)<=1) && (Math.abs(diffY)<=1)) ||
603             ((Math.abs(diffXrev)<=1) && (Math.abs(diffYrev)<=1))){
604           return true;
605         } else {
606           return false;
607         }
608     }
609 
610     public MediaSizeName findMatchingMediaSizeNameMM (float w, float h){
611         if (predefMedia != null) {
612             for (int k=0; k<predefMedia.length;k++) {
613                 if (predefMedia[k] == null) {
614                     continue;
615                 }
616 
617                 if (isSameSize(predefMedia[k].getX(MediaSize.MM),
618                                predefMedia[k].getY(MediaSize.MM),
619                                w, h)) {
620                   return predefMedia[k].getMediaSizeName();
621                 }
622             }
623         }
624         return null;
625     }
626 
627 
628     private MediaSize[] getMediaSizes(ArrayList idList, int[] media, ArrayList<String> dmPaperNameList) {
629         if (dmPaperNameList == null) {
630             dmPaperNameList = new ArrayList<String>();
631         }
632 
633         String prnPort = getPort();
634         int[] mediaSz = getAllMediaSizes(printer, prnPort);
635         String[] winMediaNames = getAllMediaNames(printer, prnPort);
636         MediaSizeName msn = null;
637         MediaSize ms = null;
638         float wid, ht;
639 
640         if ((mediaSz == null) || (winMediaNames == null)) {
641             return null;
642         }
643 
644         int nMedia = mediaSz.length/2;
645         ArrayList msList = new ArrayList();
646 
647         for (int i = 0; i < nMedia; i++, ms=null) {
648             wid = mediaSz[i*2]/10f;
649             ht = mediaSz[i*2+1]/10f;
650 
651             // Make sure to validate wid & ht.
652             // HP LJ 4050 (german) causes IAE in Sonderformat paper, wid & ht
653             // returned is not constant.
654             if ((wid <= 0) || (ht <= 0)) {
655                 //Remove corresponding ID from list
656                 if (nMedia == media.length) {
657                     Integer remObj = Integer.valueOf(media[i]);
658                     idList.remove(idList.indexOf(remObj));
659                 }
660                 continue;
661             }
662             // Find matching media using dimensions.
663             // This call matches only with our own predefined sizes.
664             msn = findMatchingMediaSizeNameMM(wid, ht);
665             if (msn != null) {
666                 ms = MediaSize.getMediaSizeForName(msn);
667             }
668 
669             if (ms != null) {
670                 msList.add(ms);
671                 dmPaperNameList.add(winMediaNames[i]);
672             } else {
673                 Win32MediaSize wms = Win32MediaSize.findMediaName(winMediaNames[i]);
674                 if (wms == null) {
675                     wms = new Win32MediaSize(winMediaNames[i], media[i]);
676                 }
677                 try {
678                     ms = new MediaSize(wid, ht, MediaSize.MM, wms);
679                     msList.add(ms);
680                     dmPaperNameList.add(winMediaNames[i]);
681                 } catch(IllegalArgumentException e) {
682                     if (nMedia == media.length) {
683                         Integer remObj = Integer.valueOf(media[i]);
684                         idList.remove(idList.indexOf(remObj));
685                     }
686                 }
687             }
688         }
689 
690         MediaSize[] arr2 = new MediaSize[msList.size()];
691         msList.toArray(arr2);
692 
693         return arr2;
694     }
695 
696     private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
697         if (getJobStatus(printer, 2) != 1) {
698             return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;
699         }
700         else {
701             return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
702         }
703     }
704 
705     private PrinterState getPrinterState() {
706         if (isInvalid) {
707             return PrinterState.STOPPED;
708         } else {
709             return null;
710         }
711     }
712 
713     private PrinterStateReasons getPrinterStateReasons() {
714         if (isInvalid) {
715             PrinterStateReasons psr = new PrinterStateReasons();
716             psr.put(PrinterStateReason.SHUTDOWN, Severity.ERROR);
717             return psr;
718         } else {
719             return null;
720         }
721     }
722 
723     private QueuedJobCount getQueuedJobCount() {
724 
725         int count = getJobStatus(printer, 1);
726         if (count != -1) {
727             return new QueuedJobCount(count);
728         }
729         else {
730             return new QueuedJobCount(0);
731         }
732     }
733 
734     private boolean isSupportedCopies(Copies copies) {
735         synchronized (this) {
736             if (gotCopies == false) {
737                 nCopies = getCopiesSupported(printer, getPort());
738                 gotCopies = true;
739             }
740         }
741         int numCopies = copies.getValue();
742         return (numCopies > 0 && numCopies <= nCopies);
743     }
744 
745     private boolean isSupportedMedia(MediaSizeName msn) {
746 
747         initMedia();
748 
749         if (mediaSizeNames != null) {
750             for (int i=0; i<mediaSizeNames.length; i++) {
751                 if (msn.equals(mediaSizeNames[i])) {
752                     return true;
753                 }
754             }
755         }
756         return false;
757     }
758 
759     private boolean isSupportedMediaPrintableArea(MediaPrintableArea mpa) {
760 
761         getMediaPrintables(null);
762 
763         if (mediaPrintables != null) {
764             for (int i=0; i<mediaPrintables.length; i++) {
765                 if (mpa.equals(mediaPrintables[i])) {
766                     return true;
767                 }
768             }
769         }
770         return false;
771     }
772 
773     private boolean isSupportedMediaTray(MediaTray msn) {
774         MediaTray[] trays = getMediaTrays();
775 
776         if (trays != null) {
777             for (int i=0; i<trays.length; i++) {
778                 if (msn.equals(trays[i])) {
779                     return true;
780                 }
781             }
782         }
783         return false;
784     }
785 
786     private int getPrinterCapabilities() {
787         if (prnCaps == 0) {
788             prnCaps = getCapabilities(printer, getPort());
789         }
790         return prnCaps;
791     }
792 
793     private String getPort() {
794         if (port == null) {
795             port = getPrinterPort(printer);
796         }
797         return port;
798     }
799 
800    /*
801     * NOTE: defaults indices must match those in WPrinterJob.cpp
802     */
803     private int[] getDefaultPrinterSettings() {
804         if (defaultSettings == null) {
805             defaultSettings = getDefaultSettings(printer, getPort());
806         }
807         return defaultSettings;
808     }
809 
810     private PrinterResolution[] getPrintResolutions() {
811         if (printRes == null) {
812             int[] prnRes = getAllResolutions(printer, getPort());
813             if (prnRes == null) {
814                 printRes = new PrinterResolution[0];
815             } else {
816                 int nRes = prnRes.length/2;
817 
818                 ArrayList arrList = new ArrayList();
819                 PrinterResolution pr;
820 
821                 for (int i=0; i<nRes; i++) {
822                   try {
823                         pr = new PrinterResolution(prnRes[i*2],
824                                        prnRes[i*2+1], PrinterResolution.DPI);
825                         arrList.add(pr);
826                     } catch (IllegalArgumentException e) {
827                     }
828                 }
829 
830                 printRes = (PrinterResolution[])arrList.toArray(
831                                         new PrinterResolution[arrList.size()]);
832             }
833         }
834         return printRes;
835     }
836 
837     private boolean isSupportedResolution(PrinterResolution res) {
838         PrinterResolution[] supportedRes = getPrintResolutions();
839         if (supportedRes != null) {
840             for (int i=0; i<supportedRes.length; i++) {
841                 if (res.equals(supportedRes[i])) {
842                     return true;
843                 }
844             }
845         }
846         return false;
847     }
848 
849     public DocPrintJob createPrintJob() {
850       SecurityManager security = System.getSecurityManager();
851       if (security != null) {
852         security.checkPrintJobAccess();
853       }
854         return new Win32PrintJob(this);
855     }
856 
857     private PrintServiceAttributeSet getDynamicAttributes() {
858         PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
859         attrs.add(getPrinterIsAcceptingJobs());
860         attrs.add(getQueuedJobCount());
861         return attrs;
862     }
863 
864     public PrintServiceAttributeSet getUpdatedAttributes() {
865         PrintServiceAttributeSet currSet = getDynamicAttributes();
866         if (lastSet == null) {
867             lastSet = currSet;
868             return AttributeSetUtilities.unmodifiableView(currSet);
869         } else {
870             PrintServiceAttributeSet updates =
871                 new HashPrintServiceAttributeSet();
872             Attribute []attrs =  currSet.toArray();
873             for (int i=0; i<attrs.length; i++) {
874                 Attribute attr = attrs[i];
875                 if (!lastSet.containsValue(attr)) {
876                     updates.add(attr);
877                 }
878             }
879             lastSet = currSet;
880             return AttributeSetUtilities.unmodifiableView(updates);
881         }
882     }
883 
884     public void wakeNotifier() {
885         synchronized (this) {
886             if (notifier != null) {
887                 notifier.wake();
888             }
889         }
890     }
891 
892     public void addPrintServiceAttributeListener(PrintServiceAttributeListener
893                                                  listener) {
894         synchronized (this) {
895             if (listener == null) {
896                 return;
897             }
898             if (notifier == null) {
899                 notifier = new ServiceNotifier(this);
900             }
901             notifier.addListener(listener);
902         }
903     }
904 
905     public void removePrintServiceAttributeListener(
906                                       PrintServiceAttributeListener listener) {
907         synchronized (this) {
908             if (listener == null || notifier == null ) {
909                 return;
910             }
911             notifier.removeListener(listener);
912             if (notifier.isEmpty()) {
913                 notifier.stopNotifier();
914                 notifier = null;
915             }
916         }
917     }
918 
919     public <T extends PrintServiceAttribute> T
920         getAttribute(Class<T> category)
921     {
922         if (category == null) {
923             throw new NullPointerException("category");
924         }
925         if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {
926             throw new IllegalArgumentException("Not a PrintServiceAttribute");
927         }
928         if (category == ColorSupported.class) {
929             int caps = getPrinterCapabilities();
930             if ((caps & DEVCAP_COLOR) != 0) {
931                 return (T)ColorSupported.SUPPORTED;
932             } else {
933                 return (T)ColorSupported.NOT_SUPPORTED;
934             }
935         } else if (category == PrinterName.class) {
936             return (T)getPrinterName();
937         } else if (category == PrinterState.class) {
938             return (T)getPrinterState();
939         } else if (category == PrinterStateReasons.class) {
940             return (T)getPrinterStateReasons();
941         } else if (category == QueuedJobCount.class) {
942             return (T)getQueuedJobCount();
943         } else if (category == PrinterIsAcceptingJobs.class) {
944             return (T)getPrinterIsAcceptingJobs();
945         } else {
946             return null;
947         }
948     }
949 
950     public PrintServiceAttributeSet getAttributes() {
951 
952         PrintServiceAttributeSet attrs = new  HashPrintServiceAttributeSet();
953         attrs.add(getPrinterName());
954         attrs.add(getPrinterIsAcceptingJobs());
955         PrinterState prnState = getPrinterState();
956         if (prnState != null) {
957             attrs.add(prnState);
958         }
959         PrinterStateReasons prnStateReasons = getPrinterStateReasons();
960         if (prnStateReasons != null) {
961             attrs.add(prnStateReasons);
962         }
963         attrs.add(getQueuedJobCount());
964         int caps = getPrinterCapabilities();
965         if ((caps & DEVCAP_COLOR) != 0) {
966             attrs.add(ColorSupported.SUPPORTED);
967         } else {
968             attrs.add(ColorSupported.NOT_SUPPORTED);
969         }
970 
971         return AttributeSetUtilities.unmodifiableView(attrs);
972     }
973 
974     public DocFlavor[] getSupportedDocFlavors() {
975         int len = supportedFlavors.length;
976         DocFlavor[] supportedDocFlavors;
977         int caps = getPrinterCapabilities();
978         // doc flavors supported
979         // if PostScript is supported
980         if ((caps & DEVCAP_POSTSCRIPT) != 0) {
981             supportedDocFlavors = new DocFlavor[len+3];
982             System.arraycopy(supportedFlavors, 0, supportedDocFlavors, 0, len);
983             supportedDocFlavors[len] = DocFlavor.BYTE_ARRAY.POSTSCRIPT;
984             supportedDocFlavors[len+1] = DocFlavor.INPUT_STREAM.POSTSCRIPT;
985             supportedDocFlavors[len+2] = DocFlavor.URL.POSTSCRIPT;
986         } else {
987             supportedDocFlavors = new DocFlavor[len];
988             System.arraycopy(supportedFlavors, 0, supportedDocFlavors, 0, len);
989         }
990         return supportedDocFlavors;
991     }
992 
993     public boolean isDocFlavorSupported(DocFlavor flavor) {
994         /* To avoid a native query which may be time-consuming
995          * do not invoke native unless postscript support is being queried.
996          * Instead just check the ones we 'always' support
997          */
998         DocFlavor[] supportedDocFlavors;
999         if (isPostScriptFlavor(flavor)) {
1000             supportedDocFlavors = getSupportedDocFlavors();
1001         } else {
1002             supportedDocFlavors = supportedFlavors;
1003         }
1004         for (int f=0; f<supportedDocFlavors.length; f++) {
1005             if (flavor.equals(supportedDocFlavors[f])) {
1006                 return true;
1007             }
1008         }
1009         return false;
1010     }
1011 
1012     public Class<?>[] getSupportedAttributeCategories() {
1013         ArrayList categList = new ArrayList(otherAttrCats.length+3);
1014         for (int i=0; i < otherAttrCats.length; i++) {
1015             categList.add(otherAttrCats[i]);
1016         }
1017 
1018         int caps = getPrinterCapabilities();
1019 
1020         if ((caps & DEVCAP_DUPLEX) != 0) {
1021             categList.add(Sides.class);
1022         }
1023 
1024         if ((caps & DEVCAP_QUALITY) != 0) {
1025             int[] defaults = getDefaultPrinterSettings();
1026             // Added check: if supported, we should be able to get the default.
1027             if ((defaults[3] >= DMRES_HIGH) && (defaults[3] < 0)) {
1028                 categList.add(PrintQuality.class);
1029             }
1030         }
1031 
1032         PrinterResolution[] supportedRes = getPrintResolutions();
1033         if ((supportedRes!=null) && (supportedRes.length>0)) {
1034             categList.add(PrinterResolution.class);
1035         }
1036 
1037         return (Class[])categList.toArray(new Class[categList.size()]);
1038     }
1039 
1040     public boolean
1041         isAttributeCategorySupported(Class<? extends Attribute> category)
1042     {
1043 
1044         if (category == null) {
1045             throw new NullPointerException("null category");
1046         }
1047 
1048         if (!(Attribute.class.isAssignableFrom(category))) {
1049             throw new IllegalArgumentException(category +
1050                                                " is not an Attribute");
1051         }
1052 
1053         Class[] classList = getSupportedAttributeCategories();
1054         for (int i = 0; i < classList.length; i++) {
1055             if (category.equals(classList[i])) {
1056                 return true;
1057             }
1058         }
1059 
1060         return false;
1061     }
1062 
1063     public Object
1064         getDefaultAttributeValue(Class<? extends Attribute> category)
1065     {
1066         if (category == null) {
1067             throw new NullPointerException("null category");
1068         }
1069         if (!Attribute.class.isAssignableFrom(category)) {
1070             throw new IllegalArgumentException(category +
1071                                                " is not an Attribute");
1072         }
1073 
1074         if (!isAttributeCategorySupported(category)) {
1075             return null;
1076         }
1077 
1078         int[] defaults = getDefaultPrinterSettings();
1079         // indices must match those in WPrinterJob.cpp
1080         int defPaper = defaults[0];
1081         int defYRes = defaults[2];
1082         int defQuality = defaults[3];
1083         int defCopies = defaults[4];
1084         int defOrient = defaults[5];
1085         int defSides = defaults[6];
1086         int defCollate = defaults[7];
1087         int defColor = defaults[8];
1088 
1089         if (category == Copies.class) {
1090             if (defCopies > 0) {
1091                 return new Copies(defCopies);
1092             } else {
1093                 return new Copies(1);
1094             }
1095         } else if (category == Chromaticity.class) {
1096             if (defColor == DMCOLOR_COLOR) {
1097                 return Chromaticity.COLOR;
1098             } else {
1099                 return Chromaticity.MONOCHROME;
1100             }
1101         } else if (category == JobName.class) {
1102             return new JobName("Java Printing", null);
1103         } else if (category == OrientationRequested.class) {
1104             if (defOrient == DMORIENT_LANDSCAPE) {
1105                 return OrientationRequested.LANDSCAPE;
1106             } else {
1107                 return OrientationRequested.PORTRAIT;
1108             }
1109         } else if (category == PageRanges.class) {
1110             return new PageRanges(1, Integer.MAX_VALUE);
1111         } else if (category == Media.class) {
1112             MediaSizeName msn = findWin32Media(defPaper);
1113             if (msn != null) {
1114                 if (!isSupportedMedia(msn) && mediaSizeNames != null) {
1115                     msn = mediaSizeNames[0];
1116                     defPaper = findPaperID(msn);
1117                 }
1118                 return msn;
1119              } else {
1120                  initMedia();
1121                  if ((mediaSizeNames != null) && (mediaSizeNames.length > 0)) {
1122                      // if 'mediaSizeNames' is not null, idList and mediaSizes
1123                      // cannot be null but to be safe, add a check
1124                      if ((idList != null) && (mediaSizes != null) &&
1125                          (idList.size() == mediaSizes.length)) {
1126                          Integer defIdObj = Integer.valueOf(defPaper);
1127                          int index = idList.indexOf(defIdObj);
1128                          if (index>=0 && index<mediaSizes.length) {
1129                              return mediaSizes[index].getMediaSizeName();
1130                          }
1131                      }
1132 
1133                      return mediaSizeNames[0];
1134                  }
1135              }
1136         } else if (category == MediaPrintableArea.class) {
1137             /* Verify defPaper */
1138             MediaSizeName msn = findWin32Media(defPaper);
1139             if (msn != null &&
1140                 !isSupportedMedia(msn) && mediaSizeNames != null) {
1141                 defPaper = findPaperID(mediaSizeNames[0]);
1142             }
1143             float[] prnArea = getMediaPrintableArea(printer, defPaper);
1144             if (prnArea != null) {
1145                 MediaPrintableArea printableArea = null;
1146                 try {
1147                     printableArea = new MediaPrintableArea(prnArea[0],
1148                                                            prnArea[1],
1149                                                            prnArea[2],
1150                                                            prnArea[3],
1151                                                            MediaPrintableArea.INCH);
1152                 } catch (IllegalArgumentException e) {
1153                 }
1154                 return printableArea;
1155             }
1156             return null;
1157         } else if (category == SunAlternateMedia.class) {
1158             return null;
1159         } else if (category == Destination.class) {
1160             try {
1161                 return new Destination((new File("out.prn")).toURI());
1162             } catch (SecurityException se) {
1163                 try {
1164                     return new Destination(new URI("file:out.prn"));
1165                 } catch (URISyntaxException e) {
1166                     return null;
1167                 }
1168             }
1169         } else if (category == Sides.class) {
1170             switch(defSides) {
1171             case DMDUP_VERTICAL :
1172                 return Sides.TWO_SIDED_LONG_EDGE;
1173             case DMDUP_HORIZONTAL :
1174                 return Sides.TWO_SIDED_SHORT_EDGE;
1175             default :
1176                 return Sides.ONE_SIDED;
1177             }
1178         } else if (category == PrinterResolution.class) {
1179             int yRes = defYRes;
1180             int xRes = defQuality;
1181             if ((xRes < 0) || (yRes < 0)) {
1182                 int res = (yRes > xRes) ? yRes : xRes;
1183                 if (res > 0) {
1184                  return new PrinterResolution(res, res, PrinterResolution.DPI);
1185                 }
1186             }
1187             else {
1188                return new PrinterResolution(xRes, yRes, PrinterResolution.DPI);
1189             }
1190         } else if (category == ColorSupported.class) {
1191             int caps = getPrinterCapabilities();
1192             if ((caps & DEVCAP_COLOR) != 0) {
1193                 return ColorSupported.SUPPORTED;
1194             } else {
1195                 return ColorSupported.NOT_SUPPORTED;
1196             }
1197         } else if (category == PrintQuality.class) {
1198             if ((defQuality < 0) && (defQuality >= DMRES_HIGH)) {
1199                 switch (defQuality) {
1200                 case DMRES_HIGH:
1201                     return PrintQuality.HIGH;
1202                 case DMRES_MEDIUM:
1203                     return PrintQuality.NORMAL;
1204                 default:
1205                     return PrintQuality.DRAFT;
1206                 }
1207             }
1208         } else if (category == RequestingUserName.class) {
1209             String userName = "";
1210             try {
1211               userName = System.getProperty("user.name", "");
1212             } catch (SecurityException se) {
1213             }
1214             return new RequestingUserName(userName, null);
1215         } else if (category == SheetCollate.class) {
1216             if (defCollate == DMCOLLATE_TRUE) {
1217                 return SheetCollate.COLLATED;
1218             } else {
1219                 return SheetCollate.UNCOLLATED;
1220             }
1221         } else if (category == Fidelity.class) {
1222             return Fidelity.FIDELITY_FALSE;
1223         }
1224         return null;
1225     }
1226 
1227     private boolean isPostScriptFlavor(DocFlavor flavor) {
1228         if (flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT) ||
1229             flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||
1230             flavor.equals(DocFlavor.URL.POSTSCRIPT)) {
1231             return true;
1232         }
1233         else {
1234             return false;
1235         }
1236     }
1237 
1238     private boolean isPSDocAttr(Class category) {
1239         if (category == OrientationRequested.class || category == Copies.class) {
1240                 return true;
1241         }
1242         else {
1243             return false;
1244         }
1245     }
1246 
1247     private boolean isAutoSense(DocFlavor flavor) {
1248         if (flavor.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE) ||
1249             flavor.equals(DocFlavor.INPUT_STREAM.AUTOSENSE) ||
1250             flavor.equals(DocFlavor.URL.AUTOSENSE)) {
1251             return true;
1252         }
1253         else {
1254             return false;
1255         }
1256     }
1257 
1258     public Object
1259         getSupportedAttributeValues(Class<? extends Attribute> category,
1260                                     DocFlavor flavor,
1261                                     AttributeSet attributes)
1262     {
1263         if (category == null) {
1264             throw new NullPointerException("null category");
1265         }
1266         if (!Attribute.class.isAssignableFrom(category)) {
1267             throw new IllegalArgumentException(category +
1268                                              " does not implement Attribute");
1269         }
1270         if (flavor != null) {
1271             if (!isDocFlavorSupported(flavor)) {
1272                 throw new IllegalArgumentException(flavor +
1273                                                   " is an unsupported flavor");
1274                 // if postscript & category is already specified within the
1275                 //  PostScript data we return null
1276             } else if (isAutoSense(flavor) ||(isPostScriptFlavor(flavor) &&
1277                        (isPSDocAttr(category)))){
1278                 return null;
1279             }
1280         }
1281         if (!isAttributeCategorySupported(category)) {
1282             return null;
1283         }
1284 
1285         if (category == JobName.class) {
1286             return new JobName("Java Printing", null);
1287         } else if (category == RequestingUserName.class) {
1288           String userName = "";
1289           try {
1290             userName = System.getProperty("user.name", "");
1291           } catch (SecurityException se) {
1292           }
1293             return new RequestingUserName(userName, null);
1294         } else if (category == ColorSupported.class) {
1295             int caps = getPrinterCapabilities();
1296             if ((caps & DEVCAP_COLOR) != 0) {
1297                 return ColorSupported.SUPPORTED;
1298             } else {
1299                 return ColorSupported.NOT_SUPPORTED;
1300             }
1301         } else if (category == Chromaticity.class) {
1302             if (flavor == null ||
1303                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1304                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1305                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1306                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1307                 flavor.equals(DocFlavor.URL.GIF) ||
1308                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1309                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1310                 flavor.equals(DocFlavor.URL.JPEG) ||
1311                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1312                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1313                 flavor.equals(DocFlavor.URL.PNG)) {
1314                 int caps = getPrinterCapabilities();
1315                 if ((caps & DEVCAP_COLOR) == 0) {
1316                     Chromaticity []arr = new Chromaticity[1];
1317                     arr[0] = Chromaticity.MONOCHROME;
1318                     return (arr);
1319                 } else {
1320                     Chromaticity []arr = new Chromaticity[2];
1321                     arr[0] = Chromaticity.MONOCHROME;
1322                     arr[1] = Chromaticity.COLOR;
1323                     return (arr);
1324                 }
1325             } else {
1326                 return null;
1327             }
1328         } else if (category == Destination.class) {
1329             try {
1330                 return new Destination((new File("out.prn")).toURI());
1331             } catch (SecurityException se) {
1332                 try {
1333                     return new Destination(new URI("file:out.prn"));
1334                 } catch (URISyntaxException e) {
1335                     return null;
1336                 }
1337             }
1338         } else if (category == OrientationRequested.class) {
1339             if (flavor == null ||
1340                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1341                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1342                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1343                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1344                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1345                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1346                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1347                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1348                 flavor.equals(DocFlavor.URL.GIF) ||
1349                 flavor.equals(DocFlavor.URL.JPEG) ||
1350                 flavor.equals(DocFlavor.URL.PNG)) {
1351                 OrientationRequested []arr = new OrientationRequested[3];
1352                 arr[0] = OrientationRequested.PORTRAIT;
1353                 arr[1] = OrientationRequested.LANDSCAPE;
1354                 arr[2] = OrientationRequested.REVERSE_LANDSCAPE;
1355                 return arr;
1356             } else {
1357                 return null;
1358             }
1359         } else if ((category == Copies.class) ||
1360                    (category == CopiesSupported.class)) {
1361             synchronized (this) {
1362                 if (gotCopies == false) {
1363                     nCopies = getCopiesSupported(printer, getPort());
1364                     gotCopies = true;
1365                 }
1366             }
1367             return new CopiesSupported(1, nCopies);
1368         } else if (category == Media.class) {
1369 
1370             initMedia();
1371 
1372             int len = (mediaSizeNames == null) ? 0 : mediaSizeNames.length;
1373 
1374             MediaTray[] trays = getMediaTrays();
1375 
1376             len += (trays == null) ? 0 : trays.length;
1377 
1378             Media []arr = new Media[len];
1379             if (mediaSizeNames != null) {
1380                 System.arraycopy(mediaSizeNames, 0, arr,
1381                                  0, mediaSizeNames.length);
1382             }
1383             if (trays != null) {
1384                 System.arraycopy(trays, 0, arr,
1385                                  len - trays.length, trays.length);
1386             }
1387             return arr;
1388         } else if (category == MediaPrintableArea.class) {
1389             // if getting printable area for a specific media size
1390             Media mediaName = null;
1391             if ((attributes != null) &&
1392                 ((mediaName =
1393                   (Media)attributes.get(Media.class)) != null)) {
1394 
1395                 if (!(mediaName instanceof MediaSizeName)) {
1396                     // if an instance of MediaTray, fall thru returning
1397                     // all MediaPrintableAreas
1398                     mediaName = null;
1399                 }
1400             }
1401 
1402             MediaPrintableArea[] mpas =
1403                                   getMediaPrintables((MediaSizeName)mediaName);
1404             if (mpas != null) {
1405                 MediaPrintableArea[] arr = new MediaPrintableArea[mpas.length];
1406                 System.arraycopy(mpas, 0, arr, 0, mpas.length);
1407                 return arr;
1408             } else {
1409                 return null;
1410             }
1411         } else if (category == SunAlternateMedia.class) {
1412             return new SunAlternateMedia(
1413                               (Media)getDefaultAttributeValue(Media.class));
1414         } else if (category == PageRanges.class) {
1415             if (flavor == null ||
1416                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1417                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
1418                 PageRanges []arr = new PageRanges[1];
1419                 arr[0] = new PageRanges(1, Integer.MAX_VALUE);
1420                 return arr;
1421             } else {
1422                 return null;
1423             }
1424         } else if (category == PrinterResolution.class) {
1425             PrinterResolution[] supportedRes = getPrintResolutions();
1426             if (supportedRes == null) {
1427                 return null;
1428             }
1429             PrinterResolution []arr =
1430                 new PrinterResolution[supportedRes.length];
1431             System.arraycopy(supportedRes, 0, arr, 0, supportedRes.length);
1432             return arr;
1433         } else if (category == Sides.class) {
1434             if (flavor == null ||
1435                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1436                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
1437                 Sides []arr = new Sides[3];
1438                 arr[0] = Sides.ONE_SIDED;
1439                 arr[1] = Sides.TWO_SIDED_LONG_EDGE;
1440                 arr[2] = Sides.TWO_SIDED_SHORT_EDGE;
1441                 return arr;
1442             } else {
1443                 return null;
1444             }
1445         } else if (category == PrintQuality.class) {
1446             PrintQuality []arr = new PrintQuality[3];
1447             arr[0] = PrintQuality.DRAFT;
1448             arr[1] = PrintQuality.HIGH;
1449             arr[2] = PrintQuality.NORMAL;
1450             return arr;
1451         } else if (category == SheetCollate.class) {
1452             if (flavor == null ||
1453                 (flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1454                  flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1455                 SheetCollate []arr = new SheetCollate[2];
1456                 arr[0] = SheetCollate.COLLATED;
1457                 arr[1] = SheetCollate.UNCOLLATED;
1458                 return arr;
1459             } else {
1460                 return null;
1461             }
1462         } else if (category == Fidelity.class) {
1463             Fidelity []arr = new Fidelity[2];
1464             arr[0] = Fidelity.FIDELITY_FALSE;
1465             arr[1] = Fidelity.FIDELITY_TRUE;
1466             return arr;
1467         } else {
1468             return null;
1469         }
1470     }
1471 
1472     public boolean isAttributeValueSupported(Attribute attr,
1473                                              DocFlavor flavor,
1474                                              AttributeSet attributes) {
1475 
1476         if (attr == null) {
1477             throw new NullPointerException("null attribute");
1478         }
1479         Class category = attr.getCategory();
1480         if (flavor != null) {
1481             if (!isDocFlavorSupported(flavor)) {
1482                 throw new IllegalArgumentException(flavor +
1483                                                    " is an unsupported flavor");
1484                 // if postscript & category is already specified within the PostScript data
1485                 // we return false
1486             } else if (isAutoSense(flavor) || (isPostScriptFlavor(flavor) &&
1487                        (isPSDocAttr(category)))) {
1488                 return false;
1489             }
1490         }
1491 
1492         if (!isAttributeCategorySupported(category)) {
1493             return false;
1494         }
1495         else if (category == Chromaticity.class) {
1496             if ((flavor == null) ||
1497                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1498                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1499                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1500                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1501                 flavor.equals(DocFlavor.URL.GIF) ||
1502                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1503                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1504                 flavor.equals(DocFlavor.URL.JPEG) ||
1505                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1506                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1507                 flavor.equals(DocFlavor.URL.PNG)) {
1508                 int caps = getPrinterCapabilities();
1509                 if ((caps & DEVCAP_COLOR) != 0) {
1510                     return true;
1511                 } else {
1512                     return attr == Chromaticity.MONOCHROME;
1513                 }
1514             } else {
1515                 return false;
1516             }
1517         } else if (category == Copies.class) {
1518             return isSupportedCopies((Copies)attr);
1519 
1520         } else if (category == Destination.class) {
1521             URI uri = ((Destination)attr).getURI();
1522             if ("file".equals(uri.getScheme()) &&
1523                 !(uri.getSchemeSpecificPart().equals(""))) {
1524                 return true;
1525             } else {
1526             return false;
1527             }
1528 
1529         } else if (category == Media.class) {
1530             if (attr instanceof MediaSizeName) {
1531                 return isSupportedMedia((MediaSizeName)attr);
1532             }
1533             if (attr instanceof MediaTray) {
1534                 return isSupportedMediaTray((MediaTray)attr);
1535             }
1536 
1537         } else if (category == MediaPrintableArea.class) {
1538             return isSupportedMediaPrintableArea((MediaPrintableArea)attr);
1539 
1540         } else if (category == SunAlternateMedia.class) {
1541             Media media = ((SunAlternateMedia)attr).getMedia();
1542             return isAttributeValueSupported(media, flavor, attributes);
1543 
1544         } else if (category == PageRanges.class ||
1545                    category == SheetCollate.class ||
1546                    category == Sides.class) {
1547             if (flavor != null &&
1548                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1549                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1550                 return false;
1551             }
1552         } else if (category == PrinterResolution.class) {
1553             if (attr instanceof PrinterResolution) {
1554                 return isSupportedResolution((PrinterResolution)attr);
1555             }
1556         } else if (category == OrientationRequested.class) {
1557             if (attr == OrientationRequested.REVERSE_PORTRAIT ||
1558                 (flavor != null) &&
1559                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1560                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1561                 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
1562                 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
1563                 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
1564                 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
1565                 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
1566                 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
1567                 flavor.equals(DocFlavor.URL.GIF) ||
1568                 flavor.equals(DocFlavor.URL.JPEG) ||
1569                 flavor.equals(DocFlavor.URL.PNG))) {
1570                 return false;
1571             }
1572 
1573         } else if (category == ColorSupported.class) {
1574             int caps = getPrinterCapabilities();
1575             boolean isColorSup = ((caps & DEVCAP_COLOR) != 0);
1576             if  ((!isColorSup && (attr == ColorSupported.SUPPORTED)) ||
1577                 (isColorSup && (attr == ColorSupported.NOT_SUPPORTED))) {
1578                 return false;
1579             }
1580         }
1581         return true;
1582     }
1583 
1584     public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
1585                                                  AttributeSet attributes) {
1586 
1587         if (flavor != null && !isDocFlavorSupported(flavor)) {
1588             throw new IllegalArgumentException("flavor " + flavor +
1589                                                "is not supported");
1590         }
1591 
1592         if (attributes == null) {
1593             return null;
1594         }
1595 
1596         Attribute attr;
1597         AttributeSet unsupp = new HashAttributeSet();
1598         Attribute []attrs = attributes.toArray();
1599         for (int i=0; i<attrs.length; i++) {
1600             try {
1601                 attr = attrs[i];
1602                 if (!isAttributeCategorySupported(attr.getCategory())) {
1603                     unsupp.add(attr);
1604                 }
1605                 else if (!isAttributeValueSupported(attr, flavor, attributes)) {
1606                     unsupp.add(attr);
1607                 }
1608             } catch (ClassCastException e) {
1609             }
1610         }
1611         if (unsupp.isEmpty()) {
1612             return null;
1613         } else {
1614             return unsupp;
1615         }
1616     }
1617 
1618     private Win32DocumentPropertiesUI docPropertiesUI = null;
1619 
1620     private static class Win32DocumentPropertiesUI
1621         extends DocumentPropertiesUI {
1622 
1623         Win32PrintService service;
1624 
1625         private Win32DocumentPropertiesUI(Win32PrintService s) {
1626             service = s;
1627         }
1628 
1629         public PrintRequestAttributeSet
1630             showDocumentProperties(PrinterJob job,
1631                                    Window owner,
1632                                    PrintService service,
1633                                    PrintRequestAttributeSet aset) {
1634 
1635             if (!(job instanceof WPrinterJob)) {
1636                 return null;
1637             }
1638             WPrinterJob wJob = (WPrinterJob)job;
1639             return wJob.showDocumentProperties(owner, service, aset);
1640         }
1641     }
1642 
1643     private synchronized DocumentPropertiesUI getDocumentPropertiesUI() {
1644         return new Win32DocumentPropertiesUI(this);
1645     }
1646 
1647     private static class Win32ServiceUIFactory extends ServiceUIFactory {
1648 
1649         Win32PrintService service;
1650 
1651         Win32ServiceUIFactory(Win32PrintService s) {
1652             service = s;
1653         }
1654 
1655         public Object getUI(int role, String ui) {
1656             if (role <= ServiceUIFactory.MAIN_UIROLE) {
1657                 return null;
1658             }
1659             if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE &&
1660                 DocumentPropertiesUI.DOCPROPERTIESCLASSNAME.equals(ui))
1661             {
1662                 return service.getDocumentPropertiesUI();
1663             }
1664             throw new IllegalArgumentException("Unsupported role");
1665         }
1666 
1667         public String[] getUIClassNamesForRole(int role) {
1668 
1669             if (role <= ServiceUIFactory.MAIN_UIROLE) {
1670                 return null;
1671             }
1672             if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE) {
1673                 String[] names = new String[0];
1674                 names[0] = DocumentPropertiesUI.DOCPROPERTIESCLASSNAME;
1675                 return names;
1676             }
1677             throw new IllegalArgumentException("Unsupported role");
1678         }
1679     }
1680 
1681     private Win32ServiceUIFactory uiFactory = null;
1682 
1683     public synchronized ServiceUIFactory getServiceUIFactory() {
1684         if (uiFactory == null) {
1685             uiFactory = new Win32ServiceUIFactory(this);
1686         }
1687         return uiFactory;
1688     }
1689 
1690     public String toString() {
1691         return "Win32 Printer : " + getName();
1692     }
1693 
1694     public boolean equals(Object obj) {
1695         return  (obj == this ||
1696                  (obj instanceof Win32PrintService &&
1697                   ((Win32PrintService)obj).getName().equals(getName())));
1698     }
1699 
1700    public int hashCode() {
1701         return this.getClass().hashCode()+getName().hashCode();
1702     }
1703 
1704     public boolean usesClass(Class c) {
1705         return (c == sun.awt.windows.WPrinterJob.class);
1706     }
1707 
1708     private native int[] getAllMediaIDs(String printerName, String port);
1709     private native int[] getAllMediaSizes(String printerName, String port);
1710     private native int[] getAllMediaTrays(String printerName, String port);
1711     private native float[] getMediaPrintableArea(String printerName,
1712                                                  int paperSize);
1713     private native String[] getAllMediaNames(String printerName, String port);
1714     private native String[] getAllMediaTrayNames(String printerName, String port);
1715     private native int getCopiesSupported(String printerName, String port);
1716     private native int[] getAllResolutions(String printerName, String port);
1717     private native int getCapabilities(String printerName, String port);
1718 
1719     private native int[] getDefaultSettings(String printerName, String port);
1720     private native int getJobStatus(String printerName, int type);
1721     private native String getPrinterPort(String printerName);
1722 }
1723 
1724 
1725 class Win32MediaSize extends MediaSizeName {
1726     private static ArrayList winStringTable = new ArrayList();
1727     private static ArrayList winEnumTable = new ArrayList();
1728     private static MediaSize[] predefMedia;
1729 
1730     private int dmPaperID; // driver ID for this paper.
1731 
1732     private Win32MediaSize(int x) {
1733         super(x);
1734 
1735     }
1736 
1737     private synchronized static int nextValue(String name) {
1738       winStringTable.add(name);
1739       return (winStringTable.size()-1);
1740     }
1741 
1742     public static synchronized Win32MediaSize findMediaName(String name) {
1743         int nameIndex = winStringTable.indexOf(name);
1744         if (nameIndex != -1) {
1745             return (Win32MediaSize)winEnumTable.get(nameIndex);
1746         }
1747         return null;
1748     }
1749 
1750     public static MediaSize[] getPredefMedia() {
1751         return predefMedia;
1752     }
1753 
1754     public Win32MediaSize(String name, int dmPaper) {
1755         super(nextValue(name));
1756         dmPaperID = dmPaper;
1757         winEnumTable.add(this);
1758     }
1759 
1760     private MediaSizeName[] getSuperEnumTable() {
1761       return (MediaSizeName[])super.getEnumValueTable();
1762     }
1763 
1764     static {
1765          /* initialize predefMedia */
1766         {
1767             Win32MediaSize winMedia = new Win32MediaSize(-1);
1768 
1769             // cannot call getSuperEnumTable directly because of static context
1770             MediaSizeName[] enumMedia = winMedia.getSuperEnumTable();
1771             if (enumMedia != null) {
1772                 predefMedia = new MediaSize[enumMedia.length];
1773 
1774                 for (int i=0; i<enumMedia.length; i++) {
1775                     predefMedia[i] = MediaSize.getMediaSizeForName(enumMedia[i]);
1776                 }
1777             }
1778         }
1779     }
1780 
1781     int getDMPaper() {
1782         return dmPaperID;
1783     }
1784 
1785     protected String[] getStringTable() {
1786       String[] nameTable = new String[winStringTable.size()];
1787       return (String[])winStringTable.toArray(nameTable);
1788     }
1789 
1790     protected EnumSyntax[] getEnumValueTable() {
1791       MediaSizeName[] enumTable = new MediaSizeName[winEnumTable.size()];
1792       return (MediaSizeName[])winEnumTable.toArray(enumTable);
1793     }
1794 
1795 }