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