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

Save This Page
Home » openjdk-7 » sun » awt » windows » [javadoc | source]