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