1 /*
   2  * Copyright (c) 2000, 2005, 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.io.OutputStream;
  29 import java.util.Iterator;
  30 import java.util.Locale;
  31 
  32 import javax.print.DocFlavor;
  33 import javax.print.DocPrintJob;
  34 import javax.print.StreamPrintService;
  35 import javax.print.StreamPrintServiceFactory;
  36 import javax.print.ServiceUIFactory;
  37 import javax.print.attribute.Attribute;
  38 import javax.print.attribute.AttributeSet;
  39 import javax.print.attribute.AttributeSetUtilities;
  40 import javax.print.attribute.HashAttributeSet;
  41 import javax.print.attribute.HashPrintServiceAttributeSet;
  42 import javax.print.attribute.PrintServiceAttribute;
  43 import javax.print.attribute.PrintServiceAttributeSet;
  44 import javax.print.attribute.Size2DSyntax;
  45 import javax.print.event.PrintServiceAttributeListener;
  46 import javax.print.attribute.standard.JobName;
  47 import javax.print.attribute.standard.RequestingUserName;
  48 import javax.print.attribute.standard.Chromaticity;
  49 import javax.print.attribute.standard.ColorSupported;
  50 import javax.print.attribute.standard.Copies;
  51 import javax.print.attribute.standard.CopiesSupported;
  52 import javax.print.attribute.standard.Fidelity;
  53 import javax.print.attribute.standard.Media;
  54 import javax.print.attribute.standard.MediaPrintableArea;
  55 import javax.print.attribute.standard.MediaSize;
  56 import javax.print.attribute.standard.MediaSizeName;
  57 import javax.print.attribute.standard.OrientationRequested;
  58 import javax.print.attribute.standard.PageRanges;
  59 import javax.print.attribute.standard.SheetCollate;
  60 import javax.print.attribute.standard.Sides;
  61 
  62 public class PSStreamPrintService extends StreamPrintService
  63     implements SunPrinterJobService {
  64 
  65     private static final Class[] suppAttrCats = {
  66         Chromaticity.class,
  67         Copies.class,
  68         Fidelity.class,
  69         JobName.class,
  70         Media.class,
  71         MediaPrintableArea.class,
  72         OrientationRequested.class,
  73         PageRanges.class,
  74         RequestingUserName.class,
  75         SheetCollate.class,
  76         Sides.class,
  77     };
  78 
  79     private static int MAXCOPIES = 1000;
  80 
  81     private static final MediaSizeName mediaSizes[] = {
  82         MediaSizeName.NA_LETTER,
  83         MediaSizeName.TABLOID,
  84         MediaSizeName.LEDGER,
  85         MediaSizeName.NA_LEGAL,
  86         MediaSizeName.EXECUTIVE,
  87         MediaSizeName.ISO_A3,
  88         MediaSizeName.ISO_A4,
  89         MediaSizeName.ISO_A5,
  90         MediaSizeName.ISO_B4,
  91         MediaSizeName.ISO_B5,
  92     };
  93 
  94     public PSStreamPrintService(OutputStream out) {
  95         super(out);
  96     }
  97 
  98     public String getOutputFormat() {
  99         return PSStreamPrinterFactory.psMimeType;
 100     }
 101 
 102 
 103     public DocFlavor[] getSupportedDocFlavors() {
 104         return PSStreamPrinterFactory.getFlavors();
 105     }
 106 
 107     public DocPrintJob createPrintJob() {
 108         return new PSStreamPrintJob(this);
 109     }
 110 
 111     public boolean usesClass(Class c) {
 112         return (c == sun.print.PSPrinterJob.class);
 113     }
 114 
 115     public String getName() {
 116         return "Postscript output";
 117     }
 118 
 119     public void addPrintServiceAttributeListener(
 120                          PrintServiceAttributeListener listener) {
 121         return;
 122     }
 123 
 124     public void removePrintServiceAttributeListener(
 125                             PrintServiceAttributeListener listener) {
 126         return;
 127     }
 128 
 129 
 130     public <T extends PrintServiceAttribute>
 131         T getAttribute(Class<T> category)
 132     {
 133         if (category == null) {
 134             throw new NullPointerException("category");
 135         }
 136         if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {
 137             throw new IllegalArgumentException("Not a PrintServiceAttribute");
 138         }
 139         if (category == ColorSupported.class) {
 140             return (T)ColorSupported.SUPPORTED;
 141         } else {
 142             return null;
 143         }
 144     }
 145     public PrintServiceAttributeSet getAttributes() {
 146         PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
 147         attrs.add(ColorSupported.SUPPORTED);
 148 
 149         return AttributeSetUtilities.unmodifiableView(attrs);
 150     }
 151 
 152     public boolean isDocFlavorSupported(DocFlavor flavor) {
 153         DocFlavor [] flavors = getSupportedDocFlavors();
 154         for (int f=0; f<flavors.length; f++) {
 155             if (flavor.equals(flavors[f])) {
 156                 return true;
 157             }
 158         }
 159         return false;
 160     }
 161 
 162 
 163     public Class<?>[] getSupportedAttributeCategories() {
 164         Class []cats = new Class[suppAttrCats.length];
 165         System.arraycopy(suppAttrCats, 0, cats, 0, cats.length);
 166         return cats;
 167     }
 168 
 169     public boolean
 170         isAttributeCategorySupported(Class<? extends Attribute> category)
 171     {
 172         if (category == null) {
 173             throw new NullPointerException("null category");
 174         }
 175         if (!(Attribute.class.isAssignableFrom(category))) {
 176             throw new IllegalArgumentException(category +
 177                                              " is not an Attribute");
 178         }
 179 
 180         for (int i=0;i<suppAttrCats.length;i++) {
 181             if (category == suppAttrCats[i]) {
 182                 return true;
 183             }
 184         }
 185         return false;
 186     }
 187 
 188 
 189     public Object
 190         getDefaultAttributeValue(Class<? extends Attribute> category)
 191     {
 192         if (category == null) {
 193             throw new NullPointerException("null category");
 194         }
 195         if (!Attribute.class.isAssignableFrom(category)) {
 196             throw new IllegalArgumentException(category +
 197                                              " is not an Attribute");
 198         }
 199 
 200         if (!isAttributeCategorySupported(category)) {
 201             return null;
 202         }
 203 
 204         if (category == Copies.class) {
 205             return new Copies(1);
 206         } else if (category == Chromaticity.class) {
 207             return Chromaticity.COLOR;
 208         } else if (category == Fidelity.class) {
 209             return Fidelity.FIDELITY_FALSE;
 210         } else if (category == Media.class) {
 211             String defaultCountry = Locale.getDefault().getCountry();
 212             if (defaultCountry != null &&
 213                 (defaultCountry.equals("") ||
 214                  defaultCountry.equals(Locale.US.getCountry()) ||
 215                  defaultCountry.equals(Locale.CANADA.getCountry()))) {
 216                 return MediaSizeName.NA_LETTER;
 217             } else {
 218                  return MediaSizeName.ISO_A4;
 219             }
 220         } else if (category == MediaPrintableArea.class) {
 221             String defaultCountry = Locale.getDefault().getCountry();
 222             float iw, ih;
 223             float margin = 0.5f; // both these papers > 5" in all dimensions
 224             if (defaultCountry != null &&
 225                 (defaultCountry.equals("") ||
 226                  defaultCountry.equals(Locale.US.getCountry()) ||
 227                  defaultCountry.equals(Locale.CANADA.getCountry()))) {
 228                 iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 2*margin;
 229                 ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 2*margin;
 230             } else {
 231                 iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 2*margin;
 232                 ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 2*margin;
 233             }
 234             return new MediaPrintableArea(margin, margin, iw, ih,
 235                                           MediaPrintableArea.INCH);
 236         } else if (category == OrientationRequested.class) {
 237             return OrientationRequested.PORTRAIT;
 238         } else if (category == PageRanges.class) {
 239             return new PageRanges(1, Integer.MAX_VALUE);
 240         } else if (category == SheetCollate.class) {
 241             return SheetCollate.UNCOLLATED;
 242         } else if (category == Sides.class) {
 243             return Sides.ONE_SIDED;
 244 
 245         } else
 246             return null;
 247     }
 248 
 249 
 250     public Object
 251         getSupportedAttributeValues(Class<? extends Attribute> category,
 252                                     DocFlavor flavor,
 253                                     AttributeSet attributes)
 254     {
 255 
 256         if (category == null) {
 257             throw new NullPointerException("null category");
 258         }
 259         if (!Attribute.class.isAssignableFrom(category)) {
 260             throw new IllegalArgumentException(category +
 261                                              " does not implement Attribute");
 262         }
 263         if (flavor != null && !isDocFlavorSupported(flavor)) {
 264             throw new IllegalArgumentException(flavor +
 265                                                " is an unsupported flavor");
 266         }
 267 
 268         if (!isAttributeCategorySupported(category)) {
 269             return null;
 270         }
 271 
 272         if (category == Chromaticity.class) {
 273             Chromaticity[]arr = new Chromaticity[1];
 274             arr[0] = Chromaticity.COLOR;
 275             //arr[1] = Chromaticity.MONOCHROME;
 276             return (arr);
 277         } else if (category == JobName.class) {
 278             return new JobName("", null);
 279         } else if (category == RequestingUserName.class) {
 280             return new RequestingUserName("", null);
 281         } else if (category == OrientationRequested.class) {
 282             if (flavor == null ||
 283                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 284                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
 285                 OrientationRequested []arr = new OrientationRequested[3];
 286                 arr[0] = OrientationRequested.PORTRAIT;
 287                 arr[1] = OrientationRequested.LANDSCAPE;
 288                 arr[2] = OrientationRequested.REVERSE_LANDSCAPE;
 289                 return arr;
 290             } else {
 291                 return null;
 292             }
 293         } else if ((category == Copies.class) ||
 294                    (category == CopiesSupported.class)) {
 295             return new CopiesSupported(1, MAXCOPIES);
 296         } else if (category == Media.class) {
 297             Media []arr = new Media[mediaSizes.length];
 298             System.arraycopy(mediaSizes, 0, arr, 0, mediaSizes.length);
 299             return arr;
 300         } else if (category == Fidelity.class) {
 301             Fidelity []arr = new Fidelity[2];
 302             arr[0] = Fidelity.FIDELITY_FALSE;
 303             arr[1] = Fidelity.FIDELITY_TRUE;
 304             return arr;
 305         } else if (category == MediaPrintableArea.class) {
 306             if (attributes == null) {
 307                 return null;
 308             }
 309             MediaSize mediaSize = (MediaSize)attributes.get(MediaSize.class);
 310             if (mediaSize == null) {
 311                 Media media = (Media)attributes.get(Media.class);
 312                 if (media != null && media instanceof MediaSizeName) {
 313                     MediaSizeName msn = (MediaSizeName)media;
 314                     mediaSize = MediaSize.getMediaSizeForName(msn);
 315                 }
 316             }
 317             if (mediaSize == null) {
 318                 return null;
 319             } else {
 320                 MediaPrintableArea []arr = new MediaPrintableArea[1];
 321                 float w = mediaSize.getX(MediaSize.INCH);
 322                 float h = mediaSize.getY(MediaSize.INCH);
 323                 /* For dimensions >= 5 inches use 0.5 inch margins.
 324                  * For smaller dimensions, use 10% margins.
 325                  */
 326                 float xmargin = 0.5f;
 327                 float ymargin = 0.5f;
 328                 if (w < 5f) {
 329                     xmargin = w/10;
 330                 }
 331                 if (h < 5f) {
 332                     ymargin = h/10;
 333                 }
 334                 arr[0] = new MediaPrintableArea(xmargin, ymargin,
 335                                                 w - 2*xmargin,
 336                                                 h - 2*ymargin,
 337                                                 MediaSize.INCH);
 338                 return arr;
 339             }
 340         } else if (category == PageRanges.class) {
 341             if (flavor == null ||
 342                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 343                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
 344                 PageRanges []arr = new PageRanges[1];
 345                 arr[0] = new PageRanges(1, Integer.MAX_VALUE);
 346                 return arr;
 347             } else {
 348                 return null;
 349             }
 350         } else if (category == SheetCollate.class) {
 351             if (flavor == null ||
 352                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 353                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
 354                 SheetCollate []arr = new SheetCollate[2];
 355                 arr[0] = SheetCollate.UNCOLLATED;
 356                 arr[1] = SheetCollate.COLLATED;
 357                 return arr;
 358             } else {
 359                 SheetCollate []arr = new SheetCollate[1];
 360                 arr[0] = SheetCollate.UNCOLLATED;
 361                 return arr;
 362             }
 363         } else if (category == Sides.class) {
 364             if (flavor == null ||
 365                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 366                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
 367                 Sides []arr = new Sides[3];
 368                 arr[0] = Sides.ONE_SIDED;
 369                 arr[1] = Sides.TWO_SIDED_LONG_EDGE;
 370                 arr[2] = Sides.TWO_SIDED_SHORT_EDGE;
 371                 return arr;
 372             } else {
 373                 return null;
 374             }
 375         } else {
 376             return null;
 377         }
 378     }
 379 
 380     private boolean isSupportedCopies(Copies copies) {
 381         int numCopies = copies.getValue();
 382         return (numCopies > 0 && numCopies < MAXCOPIES);
 383     }
 384 
 385     private boolean isSupportedMedia(MediaSizeName msn) {
 386         for (int i=0; i<mediaSizes.length; i++) {
 387             if (msn.equals(mediaSizes[i])) {
 388                 return true;
 389             }
 390         }
 391         return false;
 392     }
 393 
 394     public boolean isAttributeValueSupported(Attribute attr,
 395                                              DocFlavor flavor,
 396                                              AttributeSet attributes) {
 397         if (attr == null) {
 398             throw new NullPointerException("null attribute");
 399         }
 400         if (flavor != null && !isDocFlavorSupported(flavor)) {
 401             throw new IllegalArgumentException(flavor +
 402                                                " is an unsupported flavor");
 403         }
 404         Class category = attr.getCategory();
 405         if (!isAttributeCategorySupported(category)) {
 406             return false;
 407         }
 408         else if (attr.getCategory() == Chromaticity.class) {
 409             return attr == Chromaticity.COLOR;
 410         }
 411         else if (attr.getCategory() == Copies.class) {
 412             return isSupportedCopies((Copies)attr);
 413         } else if (attr.getCategory() == Media.class &&
 414                    attr instanceof MediaSizeName) {
 415             return isSupportedMedia((MediaSizeName)attr);
 416         } else if (attr.getCategory() == OrientationRequested.class) {
 417             if (attr == OrientationRequested.REVERSE_PORTRAIT ||
 418                 (flavor != null) &&
 419                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 420                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
 421                 return false;
 422             }
 423         } else if (attr.getCategory() == PageRanges.class) {
 424             if (flavor != null &&
 425                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 426                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
 427                 return false;
 428             }
 429         } else if (attr.getCategory() == SheetCollate.class) {
 430             if (flavor != null &&
 431                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 432                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
 433                 return false;
 434             }
 435         } else if (attr.getCategory() == Sides.class) {
 436             if (flavor != null &&
 437                 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
 438                 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
 439                 return false;
 440             }
 441         }
 442         return true;
 443     }
 444 
 445     public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
 446                                                  AttributeSet attributes) {
 447 
 448         if (flavor != null && !isDocFlavorSupported(flavor)) {
 449             throw new IllegalArgumentException("flavor " + flavor +
 450                                                "is not supported");
 451         }
 452 
 453         if (attributes == null) {
 454             return null;
 455         }
 456 
 457         Attribute attr;
 458         AttributeSet unsupp = new HashAttributeSet();
 459         Attribute[] attrs = attributes.toArray();
 460         for (int i=0; i<attrs.length; i++) {
 461             try {
 462                 attr = attrs[i];
 463                 if (!isAttributeCategorySupported(attr.getCategory())) {
 464                     unsupp.add(attr);
 465                 } else if (!isAttributeValueSupported(attr, flavor,
 466                                                       attributes)) {
 467                     unsupp.add(attr);
 468                 }
 469             } catch (ClassCastException e) {
 470             }
 471         }
 472         if (unsupp.isEmpty()) {
 473             return null;
 474         } else {
 475             return unsupp;
 476         }
 477     }
 478 
 479     public ServiceUIFactory getServiceUIFactory() {
 480         return null;
 481     }
 482 
 483     public String toString() {
 484         return "PSStreamPrintService: " + getName();
 485     }
 486 
 487     /* Stream services have an output stream which cannot be shared,
 488      * so two services are equal only if they are the same object.
 489      */
 490     public boolean equals(Object obj) {
 491         return (obj == this ||
 492                  (obj instanceof PSStreamPrintService &&
 493                  ((PSStreamPrintService)obj).getName().equals(getName())));
 494     }
 495 
 496    public int hashCode() {
 497         return this.getClass().hashCode()+getName().hashCode();
 498     }
 499 
 500 }