/* * This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com> * Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/) */ /* * @(#)WPrinterJob.java 1.44 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package sun.awt.windows; import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.KeyboardFocusManager; import java.awt.Toolkit; import java.awt.BasicStroke; import java.awt.image.BufferedImage; import java.awt.peer.ComponentPeer; import java.awt.print.Pageable; import java.awt.print.PageFormat; import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterJob; import java.awt.print.PrinterException; import javax.print.PrintService; import java.io.IOException; import java.util.Properties; import sun.awt.EmbeddedFrame; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.awt.image.Image; import sun.awt.image.ImageRepresentation; import sun.print.PeekGraphics; import sun.print.PeekMetrics; import java.net.URL; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.Attribute; import javax.print.attribute.standard.Sides; import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.PrintQuality; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.standard.SheetCollate; import javax.print.attribute.IntegerSyntax; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.MediaTray; import sun.print.RasterPrinterJob; import sun.print.SunAlternateMedia; import sun.print.Win32MediaTray; /** * A class which initiates and executes a Win32 printer job. * * @version 1.0 07 Nov 1997 * @author Richard Blanchard */ public class WPrinterJob extends RasterPrinterJob { static final class HandleRecord extends DisposerRecord { private long mPrintDC; private long mPrintHDevMode; private long mPrintHDevNames; public void dispose() { WPrinterJob.deleteDC(mPrintDC, mPrintHDevMode, mPrintHDevNames); mPrintDC = mPrintHDevMode = mPrintHDevNames = 0L; } } /* Class Constants */ /* Instance Variables */ /** * These are Windows' ExtCreatePen End Cap Styles * and must match the values in <WINGDI.h> */ protected static final long PS_ENDCAP_ROUND = 0x00000000; protected static final long PS_ENDCAP_SQUARE = 0x00000100; protected static final long PS_ENDCAP_FLAT = 0x00000200; /** * These are Windows' ExtCreatePen Line Join Styles * and must match the values in <WINGDI.h> */ protected static final long PS_JOIN_ROUND = 0x00000000; protected static final long PS_JOIN_BEVEL = 0x00001000; protected static final long PS_JOIN_MITER = 0x00002000; /** * This is the Window's Polygon fill rule which * Selects alternate mode (fills the area between odd-numbered * and even-numbered polygon sides on each scan line). * It must match the value in <WINGDI.h> It can be passed * to setPolyFillMode(). */ protected static final int POLYFILL_ALTERNATE = 1; /** * This is the Window's Polygon fill rule which * Selects winding mode which fills any region * with a nonzero winding value). It must match * the value in <WINGDI.h> It can be passed * to setPolyFillMode(). */ protected static final int POLYFILL_WINDING = 2; /** * The maximum value for a Window's color component * as passed to selectSolidBrush. */ private static final int MAX_WCOLOR = 255; /** * Useful mainly for debugging, this system property * can be used to force the printing code to print * using a particular pipeline. The two currently * supported values are FORCE_RASTER and FORCE_PDL. */ private static final String FORCE_PIPE_PROP = "sun.java2d.print.pipeline"; /** * When the system property FORCE_PIPE_PROP has this value * then each page of a print job will be rendered through * the raster pipeline. */ private static final String FORCE_RASTER = "raster"; /** * When the system property FORCE_PIPE_PROP has this value * then each page of a print job will be rendered through * the PDL pipeline. */ private static final String FORCE_PDL = "pdl"; /** * When the system property SHAPE_TEXT_PROP has this value * then text is always rendered as a shape, and no attempt is made * to match the font through GDI */ private static final String SHAPE_TEXT_PROP = "sun.java2d.print.shapetext"; /** * values obtained from System properties in static initialiser block */ private static boolean forcePDL; private static boolean forceRaster; static boolean shapeTextProp; private static final String boldNames[] = { "bold", "demibold", "demi-bold", "demi bold", "negreta", "demi" }; private static final String italicNames[] = { "italic", "cursiva", "oblique", "inclined" }; private static final String boldItalicNames[] = { "bolditalic", "bold-italic", "bold italic", "boldoblique", "bold-oblique", "bold oblique", "demibold italic", "negreta cursiva", "demi oblique" }; /* Collation and copy flags. * The Windows PRINTDLG struct has a nCopies field which on return * indicates how many copies of a print job an application must render. * There is also a PD_COLLATE member of the flags field which if * set on return indicates the application generated copies should be * collated. * Windows printer drivers typically - but not always - support * generating multiple copies themselves, but uncollated is more * universal than collated copies. * When they do, they read the initial values from the PRINTDLG structure * and set them into the driver's DEVMODE structure and intialise * the printer DC based on that, so that when printed those settings * will be used. * For drivers supporting both these capabilities via DEVMODE, then on * return from the Print Dialog, nCopies is set to 1 and the PD_COLLATE is * cleared, so that the application will only render 1 copy and the * driver takes care of the rest. * * Applications which want to know what's going on have to be DEVMODE * savvy and peek at that. * DM_COPIES flag indicates support for multiple driver copies * and dmCopies is the number of copies the driver will print * DM_COLLATE flag indicates support for collated driver copies and * dmCollate == DMCOLLATE_TRUE indicates the option is in effect. * * Multiple copies from Java applications: * We provide API to get & set the number of copies as well as allowing the * user to choose it, so we need to be savvy about DEVMODE, so that * we can accurately report back the number of copies selected by * the user, as well as make use of the driver to render multiple copies. * * Collation and Java applications: * We presently provide no API for specifying collation, but its * present on the Windows Print Dialog, and when a user checks it * they expect it to be obeyed. * The best thing to do is to detect exactly the cases where the * driver doesn't support this and render multiple copies ourselves. * To support all this we need several flags which signal the * printer's capabilities and the user's requests. * Its questionable if we (yet) need to make a distinction between * the user requesting collation and the driver supporting it. * Since for now we only need to know whether we need to render the * copies. However it allows the logic to be clearer. * These fields are changed by native code which detects the driver's * capabilities and the user's choices. */ private boolean driverDoesMultipleCopies = true; private boolean driverDoesCollation = true; private boolean userRequestedCollation = false; private boolean noDefaultPrinter = false; /** * The Windows device context we will print into. * This variable is set after the Print dialog * is okayed by the user. If the user cancels * the print dialog, then this variable is 0. * Much of the configuration information for a printer is * obtained through printer device specific handles. * We need to associate these with, and free with, the mPrintDC. */ private final HandleRecord handleRecord = new HandleRecord(); private int mPrintPaperSize; private int mPrintXRes; // pixels per inch in x direction private int mPrintYRes; // pixels per inch in y direction private int mPrintPhysX; // x offset in pixels of printable area private int mPrintPhysY; // y offset in pixels of printable area private int mPrintWidth; // width in pixels of printable area private int mPrintHeight; // height in pixels of printable area private int mPageWidth; // width in pixels of entire page private int mPageHeight; // height in pixels of entire page private int mAttSides; private int mAttChromaticity; private int mAttXRes; private int mAttYRes; private int mAttQuality; private int mAttCollate; private int mAttCopies; private int mAttOrientation; private int mAttMediaSizeName; private int mAttMediaTray; private String mDestination = null; /** * The last color set into the print device context or * <code>null</code> if no color has been set. */ private Color mLastColor; /** * The last text color set into the print device context or * <code>null</code> if no color has been set. */ private Color mLastTextColor; /** * The last java font set as a GDI font in the printer * device context. Can be NULL if no GDI font has been * set. */ private Font mLastFont; private int mLastRotation; private float mLastAwScale; private ComponentPeer dialogOwnerPeer; private final Object disposerReferent = new Object(); /* Static Initializations */ static { // AWT has to be initialized for the native code to function correctly. Toolkit.getDefaultToolkit(); initIDs(); forcePDL = false; forceRaster = false; shapeTextProp = false; /* The system property FORCE_PIPE_PROP * can be used to force the printing code to * use a particular pipeline. Either the raster * pipeline or the pdl pipeline can be forced. */ String forceStr = (String)java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction(FORCE_PIPE_PROP)); if (forceStr != null) { if (forceStr.equalsIgnoreCase(FORCE_PDL)) { forcePDL = true; } else if (forceStr.equalsIgnoreCase(FORCE_RASTER)) { forceRaster = true; } } String shapeTextStr = (String)java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction(SHAPE_TEXT_PROP)); if (shapeTextStr != null) { shapeTextProp = true; } } /* Constructors */ public WPrinterJob() { Disposer.addRecord(disposerReferent, handleRecord); initAttributeMembers(); } /* Instance Methods */ /** * Display a dialog to the user allowing the modification of a * PageFormat instance. * The <code>page</code> argument is used to initialize controls * in the page setup dialog. * If the user cancels the dialog, then the method returns the * original <code>page</code> object unmodified. * If the user okays the dialog then the method returns a new * PageFormat object with the indicated changes. * In either case the original <code>page</code> object will * not be modified. * @param page the default PageFormat presented to the user * for modification * @return the original <code>page</code> object if the dialog * is cancelled, or a new PageFormat object containing * the format indicated by the user if the dialog is * acknowledged * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since JDK1.2 */ public PageFormat pageDialog(PageFormat page) throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } PrintService printservice = getPrintService(); PageFormat pageClone = (PageFormat) page.clone(); Frame frame = getEmbeddedFrame(); if (frame != null) { dialogOwnerPeer = frame.getPeer(); } boolean doIt = pageSetup(pageClone, null); if (doIt && printservice != null) { updatePageAttributes(printservice, pageClone); return pageClone; } return page; } /** * Presents the user a dialog for changing properties of the * print job interactively. * @returns false if the user cancels the dialog and * true otherwise. * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ public boolean printDialog() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } if (noDefaultPrinter == true) { return false; } Pageable pageable = getPageable(); Frame frame = getEmbeddedFrame(); if (frame != null) dialogOwnerPeer = frame.getPeer(); boolean flag = jobSetup(pageable, checkAllowedToPrintToFile()); if (flag && isOpenBook(pageable)) { float f = (float)mPrintXRes / 72; float f1 = (float)mPrintYRes / 72; float f2 = (float)mPageWidth / f; float f3 = (float)mPageHeight / f1; PageFormat pageformat = pageable.getPageFormat(0); Paper paper = pageformat.getPaper(); switch (mAttOrientation) { case 2: pageformat.setOrientation(0); paper.setSize(f3, f2); break; default: pageformat.setOrientation(1); paper.setSize(f2, f3); break; } pageformat.setPaper(paper); pageformat = validatePage(pageformat); setPrintable(pageable.getPrintable(0), pageformat); pageable = getPageable(); pageformat = pageable.getPageFormat(0); paper = pageformat.getPaper(); } return flag; } public final int[] getWin32MediaAttrib() { int ai[] = new int[2]; if (attributes != null) { Media media = (Media)attributes.get( javax.print.attribute.standard.Media.class); if (media instanceof MediaSizeName) { MediaSizeName mediasizename = (MediaSizeName)media; MediaSize mediasize = MediaSize.getMediaSizeForName(mediasizename); if (mediasize != null) { ai[0] = (int)(mediasize.getX(25400) * 72.0); ai[1] = (int)(mediasize.getY(25400) * 72.0); } } } return ai; } /** * Associate this PrinterJob with a new PrintService. * * Throws <code>PrinterException</code> if the specified service * cannot support the <code>Pageable</code> and * </code>Printable</code> interfaces necessary to support 2D printing. * @param a print service which supports 2D printing. * * @throws PrinterException if the specified service does not support * 2D printing. */ public void setPrintService(PrintService service) throws PrinterException { super.setPrintService(service); setNativePrintService(service.getName()); } /* associates this job with the specified native service */ private native void setNativePrintService(String name); public PrintService getPrintService() { String printerName = getNativePrintService(); if (printerName != null) { PrintService defSvc = super.lookupDefaultPrintService(); if ((defSvc != null) && (defSvc.getName().equals(printerName))) { return defSvc; } else { PrintService[] svcs = super.lookupPrintServices(); for (int i=0; i<svcs.length; i++) { if (svcs[i].getName().equals(printerName)) { return svcs[i]; } } } } return super.getPrintService(); } private native String getNativePrintService(); public final String getPrinterAttrib() { PrintService printservice = getPrintService(); return printservice == null ? null : printservice.getName(); } private int getStyle(String s) { String s1 = s.toLowerCase(); for (int i = 0; i < boldItalicNames.length; i++) if (s1.indexOf(boldItalicNames[i]) != -1) return 3; for (int j = 0; j < italicNames.length; j++) if (s1.indexOf(italicNames[j]) != -1) return 2; for (int k = 0; k < boldNames.length; k++) if (s1.indexOf(boldNames[k]) != -1) return 1; return 0; } private void initAttributeMembers() { mAttSides = 0; mAttChromaticity = 0; mAttXRes = 0; mAttYRes = 0; mAttQuality = 0; mAttCollate = -1; mAttCopies = 0; mAttOrientation = 0; mAttMediaTray = 0; mAttMediaSizeName = 0; mDestination = null; } /** * copy the attributes to the native print job */ protected void setAttributes(PrintRequestAttributeSet attributes) throws PrinterException { // initialize attribute values initAttributeMembers(); super.setAttributes(attributes); mAttCopies = getCopiesInt(); mDestination = destinationAttr; if (attributes == null) { return; } Attribute attr; Attribute[] attrs = attributes.toArray(); for (int i=0; i<attrs.length; i++) { try { attr = attrs[i]; if (attr.getCategory()==Sides.class) { if (attr.equals(Sides.TWO_SIDED_LONG_EDGE)) { mAttSides = 2; // DMDUP_VERTICAL } else if (attr.equals(Sides.TWO_SIDED_SHORT_EDGE)) { mAttSides = 3; // DMDUP_HORIZONTAL } else { // Sides.ONE_SIDED mAttSides = 1; } } else if (attr.getCategory()==Chromaticity.class) { if (attr.equals(Chromaticity.COLOR)) { mAttChromaticity = 2; // DMCOLOR_COLOR } else { mAttChromaticity = 1; // DMCOLOR_MONOCHROME } } else if (attr.getCategory()==PrinterResolution.class) { PrinterResolution pr = (PrinterResolution)attr; mAttXRes = pr.getCrossFeedResolution(PrinterResolution.DPI); mAttYRes = pr.getFeedResolution(PrinterResolution.DPI); } else if (attr.getCategory()==PrintQuality.class) { if (attr.equals(PrintQuality.HIGH)) { mAttQuality = -4; // DMRES_HIGH } else if (attr.equals(PrintQuality.NORMAL)) { mAttQuality = -3; // DMRES_MEDIUM } else { mAttQuality = -2; // DMRES_LOW } } else if (attr.getCategory()==SheetCollate.class) { if (attr.equals(SheetCollate.COLLATED)) { mAttCollate = 1; // DMCOLLATE_TRUE } else { mAttCollate = 0; // DMCOLLATE_FALSE } } else if (attr.getCategory() == Media.class || attr.getCategory() ==SunAlternateMedia.class) { /* SunAlternateMedia is used if its a tray, and * any Media that is specified is not a tray. */ if (attr.getCategory() == SunAlternateMedia.class) { Media media = (Media)attributes.get(Media.class); if (media == null || !(media instanceof MediaTray)) { attr = ((SunAlternateMedia)attr).getMedia(); } } if (attr instanceof MediaSizeName) { // Note: Nothing to do here. } if (attr instanceof MediaTray) { if (attr.equals(MediaTray.BOTTOM)) { mAttMediaTray = 2; // DMBIN_LOWER } else if (attr.equals(MediaTray.ENVELOPE)) { mAttMediaTray = 5; // DMBIN_ENVELOPE } else if (attr.equals(MediaTray.LARGE_CAPACITY)) { mAttMediaTray = 11; // DMBIN_LARGECAPACITY } else if (attr.equals(MediaTray.MAIN)) { mAttMediaTray =1; // DMBIN_UPPER } else if (attr.equals(MediaTray.MANUAL)) { mAttMediaTray = 4; // DMBIN_MANUAL } else if (attr.equals(MediaTray.MIDDLE)) { mAttMediaTray = 3; // DMBIN_MIDDLE } else if (attr.equals(MediaTray.SIDE)) { // no equivalent predefined value mAttMediaTray = 7; // DMBIN_AUTO } else if (attr.equals(MediaTray.TOP)) { mAttMediaTray =1; // DMBIN_UPPER } else { if (attr instanceof Win32MediaTray) { mAttMediaTray = ((Win32MediaTray)attr).winID; } else { mAttMediaTray =1; // default } } } } } catch (ClassCastException e) { } } } /** * Alters the orientation and Paper to match defaults obtained * from a printer. */ private native void getDefaultPage(PageFormat page); /** * The passed in PageFormat will be copied and altered to describe * the default page size and orientation of the PrinterJob's * current printer. * Note: PageFormat.getPaper() returns a clone and getDefaultPage() * gets that clone so it won't overwrite the original paper. */ public PageFormat defaultPage(PageFormat page) { PageFormat newPage = (PageFormat)page.clone(); getDefaultPage(newPage); return newPage; } /** * validate the paper size against the current printer. */ protected native void validatePaper(Paper origPaper, Paper newPaper ); /** * Examine the metrics captured by the * <code>PeekGraphics</code> instance and * if capable of directly converting this * print job to the printer's control language * or the native OS's graphics primitives, then * return a <code>PathGraphics</code> to perform * that conversion. If there is not an object * capable of the conversion then return * <code>null</code>. Returning <code>null</code> * causes the print job to be rasterized. */ protected Graphics2D createPathGraphics(PeekGraphics peekGraphics, PrinterJob printerJob, Printable painter, PageFormat pageFormat, int pageIndex) { WPathGraphics pathGraphics; PeekMetrics metrics = peekGraphics.getMetrics(); /* If the application has drawn anything that * out PathGraphics class can not handle then * return a null PathGraphics. If the property * to force the raster pipeline has been set then * we also want to avoid the path (pdl) pipeline * and return null. */ if (forcePDL == false && (forceRaster == true || metrics.hasNonSolidColors() || metrics.hasCompositing() )) { pathGraphics = null; } else { BufferedImage bufferedImage = new BufferedImage(8, 8, BufferedImage.TYPE_INT_RGB); Graphics2D bufferedGraphics = bufferedImage.createGraphics(); boolean canRedraw = peekGraphics.getAWTDrawingOnly() == false; pathGraphics = new WPathGraphics(bufferedGraphics, printerJob, painter, pageFormat, pageIndex, canRedraw); } return pathGraphics; } protected double getXRes() { if (mAttXRes != 0) { return mAttXRes; } else { return mPrintXRes; } } protected double getYRes() { if (mAttYRes != 0) { return mAttYRes; } else { return mPrintYRes; } } protected double getPhysicalPrintableX(Paper p) { return mPrintPhysX; } protected double getPhysicalPrintableY(Paper p) { return mPrintPhysY; } protected double getPhysicalPrintableWidth(Paper p) { return mPrintWidth; } protected double getPhysicalPrintableHeight(Paper p) { return mPrintHeight; } protected double getPhysicalPageWidth(Paper p) { return mPageWidth; } protected double getPhysicalPageHeight(Paper p) { return mPageHeight; } /** * We don't (yet) provide API to support collation, and * when we do the logic here will require adjustment, but * this method is currently necessary to honour user-originated * collation requests - which can only originate from the print dialog. */ protected boolean isCollated() { return userRequestedCollation; } /** * Returns how many times the entire book should * be printed by the PrintJob. If the printer * itself supports collation then this method * should return 1 indicating that the entire * book need only be printed once and the copies * will be collated and made in the printer. */ protected int getCollatedCopies() { if (!driverDoesCollation) { // if collation request is from attribute set if (super.isCollated()) { // we will do our own collation so we need to // tell the printer to not collate and copies=1 mAttCollate = 0; mAttCopies = 1; return getCopiesInt(); // else if collation request is from native print dialog // and collation attribue is not set } else if (isCollated() && !collateAttReq) { // we will do our own collation so we need to // tell the printer to not collate and copies=1 mAttCollate = 0; mAttCopies = 1; return getCopies(); } } return 1; } /** * Returns how many times each page in the book * should be consecutively printed by PrinterJob. * If the underlying Window's driver will * generate the copies, rather than having RasterPrinterJob * iterate over the number of copies, this method always returns * 1. */ protected int getNoncollatedCopies() { if (driverDoesMultipleCopies || isCollated()) { return 1; } else { return getCopies(); } } public final int getOrientAttrib() { OrientationRequested orientationrequested = attributes != null ? (OrientationRequested)attributes.get( javax.print.attribute.standard.OrientationRequested.class) : null; if (orientationrequested != null) { if (orientationrequested.equals( OrientationRequested.REVERSE_LANDSCAPE)) return 2; if (orientationrequested.equals(OrientationRequested.LANDSCAPE)) return 0; } return 1; } private long getDevMode() { return handleRecord.mPrintHDevMode; } private long getDevNames() { return handleRecord.mPrintHDevNames; } /** * Return the Window's device context that we are printing * into. */ private long getPrintDC() { return handleRecord.mPrintDC; } protected void beginPath() { beginPath(getPrintDC()); } protected void endPath() { endPath(getPrintDC()); } protected void closeFigure() { closeFigure(getPrintDC()); } protected void fillPath() { fillPath(getPrintDC()); } protected void moveTo(float x, float y) { moveTo(getPrintDC(), x, y); } protected void lineTo(float x, float y) { lineTo(getPrintDC(), x, y); } protected void polyBezierTo(float control1x, float control1y, float control2x, float control2y, float endX, float endY) { polyBezierTo(getPrintDC(), control1x, control1y, control2x, control2y, endX, endY); } /** * Set the current polgon fill rule into the printer device context. * The <code>fillRule</code> should * be one of the following Windows constants: * <code>ALTERNATE</code> or <code>WINDING</code>. */ protected void setPolyFillMode(int fillRule) { setPolyFillMode(getPrintDC(), fillRule); } private void setDevMode(long l) { handleRecord.mPrintHDevMode = l; } private void setDevNames(long l) { handleRecord.mPrintHDevNames = l; } private void setPrintDC(long l) { handleRecord.mPrintDC = l; } /* * Create a Window's solid brush for the color specified * by <code>(red, green, blue)</code>. Once the brush * is created, select it in the current printing device * context and free the old brush. */ protected void selectSolidBrush(Color color) { /* We only need to select a brush if the color has changed. */ if (color.equals(mLastColor) == false) { mLastColor = color; float[] rgb = color.getColorComponents(null); selectSolidBrush(getPrintDC(), (int) (rgb[0] * MAX_WCOLOR), (int) (rgb[1] * MAX_WCOLOR), (int) (rgb[2] * MAX_WCOLOR)); } } /** * Return the x coordinate of the current pen * position in the print device context. */ protected int getPenX() { return getPenX(getPrintDC()); } /** * Return the y coordinate of the current pen * position in the print device context. */ protected int getPenY() { return getPenY(getPrintDC()); } /** * Set the current path in the printer device's * context to be clipping path. */ protected void selectClipPath() { selectClipPath(getPrintDC()); } protected void frameRect(float x, float y, float width, float height) { frameRect(getPrintDC(), x, y, width, height); } protected void fillRect(float x, float y, float width, float height, Color color) { float[] rgb = color.getColorComponents(null); fillRect(getPrintDC(), x, y, width, height, (int) (rgb[0] * MAX_WCOLOR), (int) (rgb[1] * MAX_WCOLOR), (int) (rgb[2] * MAX_WCOLOR)); } protected void selectPen(float width, Color color) { float[] rgb = color.getColorComponents(null); selectPen(getPrintDC(), width, (int) (rgb[0] * MAX_WCOLOR), (int) (rgb[1] * MAX_WCOLOR), (int) (rgb[2] * MAX_WCOLOR)); } protected boolean selectStylePen(int cap, int join, float width, Color color) { long endCap; long lineJoin; float[] rgb = color.getColorComponents(null); switch(cap) { case BasicStroke.CAP_BUTT: endCap = PS_ENDCAP_FLAT; break; case BasicStroke.CAP_ROUND: endCap = PS_ENDCAP_ROUND; break; default: case BasicStroke.CAP_SQUARE: endCap = PS_ENDCAP_SQUARE; break; } switch(join) { case BasicStroke.JOIN_BEVEL:lineJoin = PS_JOIN_BEVEL; break; default: case BasicStroke.JOIN_MITER:lineJoin = PS_JOIN_MITER; break; case BasicStroke.JOIN_ROUND:lineJoin = PS_JOIN_ROUND; break; } return (selectStylePen(getPrintDC(), endCap, lineJoin, width, (int) (rgb[0] * MAX_WCOLOR), (int) (rgb[1] * MAX_WCOLOR), (int) (rgb[2] * MAX_WCOLOR))); } /** * Set a GDI font capable of drawing the java Font * passed in. */ protected boolean setFont(Font font, int rotation, float awScale) { boolean didSetFont = true; if (font.equals(mLastFont) == false || (rotation != mLastRotation) || (awScale != mLastAwScale)) { int fontStyle = font.getStyle() | getStyle(font.getFontName()); didSetFont = setFont(getPrintDC(), font.getFamily(), font.getSize2D(), (fontStyle & Font.BOLD) != 0, (fontStyle & Font.ITALIC) != 0, rotation, awScale); if (didSetFont) { mLastFont = font; mLastRotation = rotation; mLastAwScale = awScale; } } return didSetFont; } /** * Set the GDI color for text drawing. */ protected void setTextColor(Color color) { /* We only need to select a brush if the color has changed. */ if (color.equals(mLastTextColor) == false) { mLastTextColor = color; float[] rgb = color.getColorComponents(null); setTextColor(getPrintDC(), (int) (rgb[0] * MAX_WCOLOR), (int) (rgb[1] * MAX_WCOLOR), (int) (rgb[2] * MAX_WCOLOR)); } } /** * Draw the string <code>text</code> to the printer's * device context at the specified position. */ protected void textOut(String text, float x, float y, Font font) { textOut(getPrintDC(), text, x, y, font); } /** * Draw the 24 bit BGR image buffer represented by * <code>image</code> to the GDI device context * <code>printDC</code>. The image is drawn at * <code>(destX, destY)</code> in device coordinates. * The image is scaled into a square of size * specified by <code>destWidth</code> and * <code>destHeight</code>. The portion of the * source image copied into that square is specified * by <code>srcX</code>, <code>srcY</code>, * <code>srcWidth</code>, and srcHeight. */ protected void drawImage3ByteBGR(byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, float srcWidth, float srcHeight) { drawImage3ByteBGR(getPrintDC(), image, destX, destY, destWidth, destHeight, srcX, srcY, srcWidth, srcHeight); } /** * Begin a new page. */ protected void startPage(PageFormat format, Printable painter, int index) { /* Invalidate any device state caches we are * maintaining. Win95/98 resets the device * context attributes to default values at * the start of each page. */ invalidateCachedState(); deviceStartPage(format, painter, index); } /** * End a page. */ protected void endPage(PageFormat format, Printable painter, int index) { deviceEndPage(format, painter, index); } /** * Forget any device state we may have cached. */ private void invalidateCachedState() { mLastColor = null; mLastTextColor = null; mLastFont = null; } /** * Set the number of copies to be printed. */ public void setCopies(int copies) { super.setCopies(copies); setNativeCopies(copies); } /* Native Methods */ /** * Set copies in device. */ public native void setNativeCopies(int copies); /** * Displays the page setup dialog placing the user's * settings into 'page'. */ public native boolean pageSetup(PageFormat page, Printable painter); /** * Displays the print dialog and records the user's settings * into this object. Return false if the user cancels the * dialog. * If the dialog is to use a set of attributes, useAttributes is true. */ private native boolean jobSetup(Pageable doc, boolean allowPrintToFile); private static native void initIDs(); /* Make sure printer DC is intialised and that info about the printer * is reflected back up to Java code */ protected native void initPrinter(); /** * Call Window's StartDoc routine to begin a * print job. The DC from the print dialog is * used. If the print dialog was not displayed * then a DC for the default printer is created. */ private native void _startDoc(String dest); protected void startDoc() { _startDoc(mDestination); } /** * Call Window's EndDoc routine to end a * print job. */ protected native void endDoc(); /** * Call Window's AbortDoc routine to abort a * print job. */ protected native void abortDoc(); /** * Call Window's deleteDC routine to end a * print job. */ private static native void deleteDC(long l, long l1, long l2); /** * Begin a new page. This call's Window's * StartPage routine. */ protected native void deviceStartPage(PageFormat format, Printable painter, int index); /** * End a page. This call's Window's EndPage * routine. */ protected native void deviceEndPage(PageFormat format, Printable painter, int index); /** * Prints the contents of the array of ints, 'data' * to the current page. The band is placed at the * location (x, y) in device coordinates on the * page. The width and height of the band is * specified by the caller. */ protected native void printBand(byte[] data, int x, int y, int width, int height); /** * Begin a Window's rendering path in the device * context <code>printDC</code>. */ protected native void beginPath(long printDC); /** * End a Window's rendering path in the device * context <code>printDC</code>. */ protected native void endPath(long printDC); /** * Close a subpath in a Window's rendering path in the device * context <code>printDC</code>. */ protected native void closeFigure(long printDC); /** * Fill a defined Window's rendering path in the device * context <code>printDC</code>. */ protected native void fillPath(long printDC); /** * Move the Window's pen position to <code>(x,y)</code> * in the device context <code>printDC</code>. */ protected native void moveTo(long printDC, float x, float y); /** * Draw a line from the current pen position to * <code>(x,y)</code> in the device context <code>printDC</code>. */ protected native void lineTo(long printDC, float x, float y); protected native void polyBezierTo(long printDC, float control1x, float control1y, float control2x, float control2y, float endX, float endY); /** * Set the current polgon fill rule into the device context * <code>printDC</code>. The <code>fillRule</code> should * be one of the following Windows constants: * <code>ALTERNATE</code> or <code>WINDING</code>. */ protected native void setPolyFillMode(long printDC, int fillRule); /** * Create a Window's solid brush for the color specified * by <code>(red, green, blue)</code>. Once the brush * is created, select it in the device * context <code>printDC</code> and free the old brush. */ protected native void selectSolidBrush(long printDC, int red, int green, int blue); /** * Return the x coordinate of the current pen * position in the device context * <code>printDC</code>. */ protected native int getPenX(long printDC); /** * Return the y coordinate of the current pen * position in the device context * <code>printDC</code>. */ protected native int getPenY(long printDC); /** * Select the device context's current path * to be the clipping path. */ protected native void selectClipPath(long printDC); /** * Draw a rectangle using specified brush. */ protected native void frameRect(long printDC, float x, float y, float width, float height); /** * Fill a rectangle specified by the coordinates using * specified brush. */ protected native void fillRect(long printDC, float x, float y, float width, float height, int red, int green, int blue); /** * Create a solid brush using the RG & B colors and width. * Select this brush and delete the old one. */ protected native void selectPen(long printDC, float width, int red, int green, int blue); /** * Create a solid brush using the RG & B colors and specified * pen styles. Select this created brush and delete the old one. */ protected native boolean selectStylePen(long printDC, long cap, long join, float width, int red, int green, int blue); /** * Set a GDI font capable of drawing the java logical Font * passed in. */ protected native boolean setLogicalFont(Font font, int rotation, float awScale); public Frame getEmbeddedFrame() { java.awt.Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); if (window != null && (window instanceof EmbeddedFrame)) return (Frame)window; Frame aframe[] = Frame.getFrames(); for (int i = 0; i < aframe.length; i++) if (aframe[i] instanceof EmbeddedFrame) return aframe[i]; return null; } /** * Set a GDI font capable of drawing the java Font * passed in. */ protected native boolean setFont(long printDC, String familyName, float fontSize, boolean bold, boolean italic, int rotation, float awScale); /** * Set the GDI color for text drawing. */ protected native void setTextColor(long printDC, int red, int green, int blue); /** * Draw the string <code>text</code> into the device * context <code>printDC</code> at the specified * position. */ protected native void textOut(long printDC, String text, float x, float y, Font font); /** * Draw the 24 bit BGR image buffer represented by * <code>image</code> to the GDI device context * <code>printDC</code>. The image is drawn at * <code>(destX, destY)</code> in device coordinates. * The image is scaled into a square of size * specified by <code>destWidth</code> and * <code>destHeight</code>. The portion of the * source image copied into that square is specified * by <code>srcX</code>, <code>srcY</code>, * <code>srcWidth</code>, and srcHeight. */ protected native void drawImage3ByteBGR(long printDC, byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, float srcWidth, float srcHeight); }