/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* A class which rasterizes a printer job.
*
* @author Richard Blanchard
*/
/* Class Constants */
/* Printer destination type. */
/* File destination type. */
/* Stream destination type. */
/**
* Maximum amount of memory in bytes to use for the
* buffered image "band". 4Mb is a compromise between
* limiting the number of bands on hi-res printers and
* not using too much of the Java heap or causing paging
* on systems with little RAM.
*/
/* Dots Per Inch */
/**
* 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.
*/
/**
* When the system property FORCE_PIPE_PROP has this value
* then each page of a print job will be rendered through
* the raster pipeline.
*/
/**
* When the system property FORCE_PIPE_PROP has this value
* then each page of a print job will be rendered through
* the PDL pipeline.
*/
/**
* 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
*/
/**
* values obtained from System properties in static initialiser block
*/
public static boolean forcePDL = false;
public static boolean forceRaster = false;
public static boolean shapeTextProp = false;
static {
/* 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.
*/
forcePDL = true;
forceRaster = true;
}
}
if (shapeTextStr != null) {
shapeTextProp = true;
}
}
/* Instance Variables */
/**
* Used to minimise GC & reallocation of band when printing
*/
/**
* The number of book copies to be printed.
*/
/**
* Collation effects the order of the pages printed
* when multiple copies are requested. For two copies
* of a three page document the page order is:
* mCollate true: 1, 2, 3, 1, 2, 3
* mCollate false: 1, 1, 2, 2, 3, 3
*/
private boolean mCollate = false;
/**
* The zero based indices of the first and last
* pages to be printed. If 'mFirstPage' is
* UNDEFINED_PAGE_NUM then the first page to
* be printed is page 0. If 'mLastPage' is
* UNDEFINED_PAGE_NUM then the last page to
* be printed is the last one in the book.
*/
/**
* The previous print stream Paper
* Used to check if the paper size has changed such that the
* implementation needs to emit the new paper size information
* into the print stream.
* Since we do our own rotation, and the margins aren't relevant,
* Its strictly the dimensions of the paper that we will check.
*/
/**
* The document to be printed. It is initialized to an
* empty (zero pages) book.
*/
// MacOSX - made protected so subclasses can reference it.
/**
* The name of the job being printed.
*/
/**
* Printing cancellation flags
*/
// MacOSX - made protected so subclasses can reference it.
protected boolean performingPrinting = false;
// MacOSX - made protected so subclasses can reference it.
protected boolean userCancelled = false;
/**
* Print to file permission variables.
*/
/**
* List of areas & the graphics state for redrawing
*/
/* variables representing values extracted from an attribute set.
* These take precedence over values set on a printer job
*/
private int copiesAttr;
protected boolean noJobSheet = false;
protected boolean collateAttReq = false;
/**
* Device rotation flag, if it support 270, this is set to true;
*/
protected boolean landscapeRotates270 = false;
/**
* attributes used by no-args page and print dialog and print method to
* communicate state
*/
/**
* Class to keep state information for redrawing areas
* "region" is an area at as a high a resolution as possible.
* The redrawing code needs to look at sx, sy to calculate the scale
* to device resolution.
*/
private class GraphicsState {
}
/**
* Service for this job
*/
/* Constructors */
public RasterPrinterJob()
{
}
/* Abstract Methods */
/**
* Returns the resolution in dots per inch across the width
* of the page.
*/
abstract protected double getXRes();
/**
* Returns the resolution in dots per inch down the height
* of the page.
*/
abstract protected double getYRes();
/**
* Must be obtained from the current printer.
* Value is in device pixels.
* Not adjusted for orientation of the paper.
*/
/**
* Must be obtained from the current printer.
* Value is in device pixels.
* Not adjusted for orientation of the paper.
*/
/**
* Must be obtained from the current printer.
* Value is in device pixels.
* Not adjusted for orientation of the paper.
*/
/**
* Must be obtained from the current printer.
* Value is in device pixels.
* Not adjusted for orientation of the paper.
*/
/**
* Must be obtained from the current printer.
* Value is in device pixels.
* Not adjusted for orientation of the paper.
*/
/**
* Must be obtained from the current printer.
* Value is in device pixels.
* Not adjusted for orientation of the paper.
*/
/**
* Begin a new page.
*/
int index, boolean paperChanged)
throws PrinterException;
/**
* End a page.
*/
int index)
throws PrinterException;
/**
* 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.
*/
throws PrinterException;
/* Instance Methods */
/**
* save graphics state of a PathGraphics for later redrawing
* of part of page represented by the region in that state
*/
}
/*
* A convenience method which returns the default service
* for 2D <code>PrinterJob</code>s.
* May return null if there is no suitable default (although there
* may still be 2D services available).
* @return default 2D print service, or null.
* @since 1.4
*/
/* Pageable implies Printable so checking both isn't strictly needed */
return service;
} else {
PrintService []services =
return services[0];
}
}
return null;
}
/**
* Returns the service (printer) for this printer job.
* Implementations of this class which do not support print services
* may return null;
* @return the service for this printer job.
*
*/
try {
} catch (PrinterException e) {
}
}
try {
} catch (PrinterException e) {
}
}
}
}
return myService;
}
/**
* 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 or no longer available.
*/
throws PrinterException {
throw new PrinterException("Service cannot be null");
} else if (!(service instanceof StreamPrintService) &&
throw new PrinterException("Null PrintService name.");
} else {
// Check the list of services. This service may have been
// deleted already
PrinterState.class);
PrinterStateReasons.class);
if ((prnStateReasons != null) &&
{
throw new PrinterException("PrintService is no longer available.");
}
}
} else {
}
}
}
PageFormat page) {
return;
}
// We should limit the list where we search the matching
// media, this will prevent mapping to wrong media ex. Ledger
// can be mapped to B. Especially useful when creating
// custom MediaSize.
try {
} catch (IllegalArgumentException iae) {
}
}
switch (page.getOrientation()) {
case PageFormat.LANDSCAPE :
break;
case PageFormat.REVERSE_LANDSCAPE:
break;
default:
}
if (attributes == null) {
attributes = new HashPrintRequestAttributeSet();
}
}
try {
} catch (IllegalArgumentException iae) {
}
}
/**
* 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 1.2
*/
throws HeadlessException {
if (GraphicsEnvironment.isHeadless()) {
throw new HeadlessException();
}
final GraphicsConfiguration gc =
return null;
}
return service;
}
});
return page;
}
return page;
} else {
return newPage;
}
}
/**
* return a PageFormat corresponding to the updated attributes,
* or null if the user cancelled the dialog.
*/
throws HeadlessException {
if (GraphicsEnvironment.isHeadless()) {
throw new HeadlessException();
}
final GraphicsConfiguration gc =
return null;
}
return service;
}
});
return null;
}
pageDialog.show();
}
}
}
media =
}
if (!(media instanceof MediaSizeName)) {
}
}
// Should pass in same unit as updatePageAttributes
// to avoid rounding off errors.
}
else {
if (w >= 72.0 * 6.0) {
ix = 72.0;
} else {
ix = w / 6.0;
iw = w * 0.75;
}
if (h >= 72.0 * 6.0) {
iy = 72.0;
} else {
iy = h / 6.0;
ih = h * 0.75;
}
}
return page;
} else {
return null;
}
}
/**
* Presents the user a dialog for changing properties of the
* print job interactively.
* The services browsable here are determined by the type of
* service currently installed.
* If the application installed a StreamPrintService on this
* PrinterJob, only the available StreamPrintService (factories) are
* browsable.
*
* @param attributes to store changed properties.
* @return false if the user cancels the dialog and true otherwise.
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
*/
throws HeadlessException {
if (GraphicsEnvironment.isHeadless()) {
throw new HeadlessException();
}
// Check for native, note that default dialog is COMMON.
this.attributes = attributes;
try {
debug_println("calling setAttributes in printDialog");
} catch (PrinterException e) {
}
boolean ret = printDialog();
this.attributes = attributes;
return ret;
}
/* A security check has already been performed in the
* java.awt.print.printerJob.getPrinterJob method.
* So by the time we get here, it is OK for the current thread
* to print either to a file (from a Dialog we control!) or
* to a chosen printer.
*
* We raise privilege when we put up the dialog, to avoid
* the "warning applet window" banner.
*/
final GraphicsConfiguration gc =
return null;
}
return service;
}
});
return false;
}
if (service instanceof StreamPrintService) {
}
} else {
services =
return services;
}
});
/*
* No services but default PrintService exists?
* Create services using defaultService.
*/
}
}
try {
} catch (IllegalArgumentException iae) {
}
if (newService == null) {
return false;
}
try {
} catch (PrinterException e) {
/*
* The only time it would throw an exception is when
* newService is no longer available but we should still
* select this printer.
*/
}
}
return true;
}
/**
* 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
*/
if (GraphicsEnvironment.isHeadless()) {
throw new HeadlessException();
}
new HashPrintRequestAttributeSet();
if (doPrint) {
}
}
try {
} catch (Exception e) {
mDestination = "out.prn";
getDefaultAttributeValue(Destination.class);
if (defaultDest != null) {
}
}
}
} else {
}
}
}
return doPrint;
}
/**
* The pages in the document to be printed by this PrinterJob
* are drawn by the Printable object 'painter'. The PageFormat
* for each page is the default page format.
* @param Printable Called to render each page of the document.
*/
}
/**
* The pages in the document to be printed by this PrinterJob
* are drawn by the Printable object 'painter'. The PageFormat
* of each page is 'format'.
* @param Printable Called to render each page of the document.
* @param PageFormat The size and orientation of each page to
* be printed.
*/
}
/**
* The pages in the document to be printed are held by the
* Pageable instance 'document'. 'document' will be queried
* for the number of pages as well as the PageFormat and
* Printable for each page.
* @param Pageable The document to be printed. It may not be null.
* @exception NullPointerException the Pageable passed in was null.
* @see PageFormat
* @see Printable
*/
} else {
throw new NullPointerException();
}
}
protected void initPrinter() {
return;
}
return
attrset));
}
/* subclasses may need to pull extra information out of the attribute set
* They can override this method & call super.setAttributes()
*/
throws PrinterException {
/* reset all values to defaults */
setCollated(false);
copiesAttr = 0;
jobNameAttr = null;
userNameAttr = null;
collateAttReq = false;
return;
}
boolean fidelity = false;
fidelity = true;
}
if (fidelity == true) {
if (unsupported != null) {
throw new PrinterException("Fidelity cannot be satisfied");
}
}
/*
* Since we have verified supported values if fidelity is true,
* we can either ignore unsupported values, or substitute a
* reasonable alternative
*/
}
}
} else {
== SunPageSelection.RANGE) {
// get to, from, min, max page ranges
// setPageRanges uses 0-based indexing so we subtract 1
} else {
}
}
} else {
copiesAttr = getCopies();
}
try {
// Old code (new File(destination.getURI())).getPath()
// would generate a "URI is not hierarchical" IAE
// for "file:out.prn" so we use getSchemeSpecificPart instead
} catch (Exception e) { // paranoid exception
getDefaultAttributeValue(Destination.class);
if (defaultDest != null) {
}
}
}
}
} else {
jobNameAttr = getJobName();
}
} else {
try {
userNameAttr = getUserName();
} catch (SecurityException e) {
userNameAttr = "";
}
}
/* OpenBook is used internally only when app uses Printable.
* This is the case when we use the values from the attribute set.
*/
getPageable() instanceof OpenBook) {
/* We could almost(!) use PrinterJob.getPageFormat() except
* here we need to start with the PageFormat from the OpenBook :
*/
/* If there's a media but no media printable area, we can try
* to retrieve the default value for mpa and use that.
*/
null, attributes);
if (mpaVals instanceof MediaPrintableArea[] &&
}
}
int orient;
} else {
}
}
if (media instanceof MediaSizeName) {
paperWid-144.0,
paperHgt-144.0);
}
}
}
}
float [] printableArea =
}
}
} else {
// for AWT where pageable is not an instance of OpenBook,
// we need to save paper info
this.attributes = attributes;
}
}
/*
* Services we don't recognize as built-in services can't be
* implemented as subclasses of PrinterJob, therefore we create
* a DocPrintJob from their service and pass a Doc representing
* the application's printjob
*/
// MacOSX - made protected so subclasses can reference it.
throws PrinterException {
throw new PrinterException("No print service found.");
}
if (attributes == null) {
attributes = new HashPrintRequestAttributeSet();
}
try {
} catch (PrintException e) {
throw new PrinterException(e.toString());
}
}
/**
* Prints a set of pages.
* @exception java.awt.print.PrinterException an error in the print system
* caused the job to be aborted
* @see java.awt.print.Book
* @see java.awt.print.Pageable
* @see java.awt.print.Printable
*/
}
public static boolean debugPrint = false;
if (debugPrint) {
}
}
throws PrinterException {
/*
* In the future PrinterJob will probably always dispatch
* the print job to the PrintService.
* This is how third party 2D Print Services will be invoked
* when applications use the PrinterJob API.
* However the JRE's concrete PrinterJob implementations have
* not yet been re-worked to be implemented as standalone
* services, and are implemented only as subclasses of PrinterJob.
* So here we dispatch only those services we do not recognize
* as implemented through platform subclasses of PrinterJob
* (and this class).
*/
throw new PrinterException("No print service found.");
}
// Check the list of services. This service may have been
// deleted already
PrinterState.class);
PrinterStateReasons.class);
if ((prnStateReasons != null) &&
{
throw new PrinterException("PrintService is no longer available.");
}
}
PrinterIsAcceptingJobs.class)) ==
throw new PrinterException("Printer is not accepting job.");
}
if ((psvc instanceof SunPrinterJobService) &&
// throw exception for invalid destination
if (destinationAttr != null) {
// destinationAttr is null for Destination(new URI(""))
// because isAttributeValueSupported returns false in setAttributes
// Destination(new URI(" ")) throws URISyntaxException
try {
// check if this is a new file and if filename chars are valid
if (f.createNewFile()) {
f.delete();
}
} catch (IOException ioe) {
throw new PrinterException("Cannot write to file:"+
} catch (SecurityException se) {
// only delete access is denied. Just ignore it because in
// most cases the file created in createNewFile gets overwritten
// anyway.
}
if ((f.exists() &&
throw new PrinterException("Cannot write to file:"+
}
}
} else {
return;
}
/* We need to make sure that the collation and copies
* settings are initialised */
initPrinter();
int numCollatedCopies = getCollatedCopies();
int numNonCollatedCopies = getNoncollatedCopies();
+ " getNoncollatedCopies() "+ numNonCollatedCopies);
/* Get the range of pages we are to print. If the
* last page to print is unknown, then we print to
* the end of the document. Note that firstPage
* and lastPage are 0 based page indices.
*/
if (numPages == 0) {
return;
}
int firstPage = getFirstPage();
int lastPage = getLastPage();
}
}
try {
synchronized (this) {
performingPrinting = true;
userCancelled = false;
}
startDoc();
if (isCancelled()) {
cancelDoc();
}
// PageRanges can be set even if RANGE is not selected
// so we need to check if it is selected.
boolean rangeIsSelected = true;
if (attributes != null) {
rangeIsSelected = false;
}
}
+ " numNonCollatedCopies "+ numNonCollatedCopies);
/* Three nested loops iterate over the document. The outer loop
* counts the number of collated copies while the inner loop
* counts the number of nonCollated copies. Normally, one of
* these two loops will only execute once; that is we will
* either print collated copies or noncollated copies. The
* middle loop iterates over the pages.
* If a PageRanges attribute is used, it constrains the pages
* that are imaged. If a platform subclass (though a user dialog)
* requests a page range via setPageRange(). it too can
* constrain the page ranges that are imaged.
* It is expected that only one of these will be used in a
* job but both should be able to co-exist.
*/
(i <= lastPage ||
i++)
{
if (nexti == -1) {
break;
} else if (nexti != i+1) {
continue;
}
}
for(int nonCollated = 0;
nonCollated++)
{
if (isCancelled()) {
cancelDoc();
}
debug_println("printPage "+i);
}
}
}
if (isCancelled()) {
cancelDoc();
}
} finally {
// reset previousPaper in case this job is invoked again.
synchronized (this) {
if (performingPrinting) {
endDoc();
}
performingPrinting = false;
notify();
}
}
}
/**
* updates a Paper object to reflect the current printer's selected
* paper size and imageable area for that paper size.
* Default implementation copies settings from the original, applies
* applies some validity checks, changes them only if they are
* clearly unreasonable, then sets them into the new Paper.
* Subclasses are expected to override this method to make more
* informed decisons.
*/
return;
} else {
/* Assume any +ve values are legal. Overall paper dimensions
* take precedence. Make sure imageable area fits on the paper.
*/
* don't know the limits we have to allow it
*/
}
}
}
}
}
}
/**
* The passed in PageFormat will be copied and altered to describe
* the default page size and orientation of the PrinterJob's
* current printer.
* Platform subclasses which can access the actual default paper size
* for a printer may override this method.
*/
double ptsPerInch = 72.0;
double w, h;
media =
if (media instanceof MediaSizeName &&
null)) {
w - 2.0*ptsPerInch,
h - 2.0*ptsPerInch);
return newPage;
}
}
/* Default to A4 paper outside North America.
*/
defaultCountry != null &&
double mmPerInch = 25.4;
w - 2.0*ptsPerInch,
h - 2.0*ptsPerInch);
}
return newPage;
}
/**
* The passed in PageFormat is cloned and altered to be usable on
* the PrinterJob's current printer.
*/
return newPage;
}
/**
* Set the number of copies to be printed.
*/
mNumCopies = copies;
}
/**
* Get the number of copies to be printed.
*/
public int getCopies() {
return mNumCopies;
}
/* Used when executing a print job where an attribute set may
* over ride API values.
*/
protected int getCopiesInt() {
}
/**
* Get the name of the printing user.
* The caller must have security permission to read system properties.
*/
}
/* Used when executing a print job where an attribute set may
* over ride API values.
*/
if (userNameAttr != null) {
return userNameAttr;
} else {
try {
return getUserName();
} catch (SecurityException e) {
return "";
}
}
}
/**
* Set the name of the document to be printed.
* The document name can not be null.
*/
} else {
throw new NullPointerException();
}
}
/**
* Get the name of the document to be printed.
*/
return mDocName;
}
/* Used when executing a print job where an attribute set may
* over ride API values.
*/
}
/**
* Set the range of pages from a Book to be printed.
* Both 'firstPage' and 'lastPage' are zero based
* page indices. If either parameter is less than
* zero then the page range is set to be from the
* first page to the last.
*/
} else {
}
}
/**
* Return the zero based index of the first page to
* be printed in this job.
*/
protected int getFirstPage() {
}
/**
* Return the zero based index of the last page to
* be printed in this job.
*/
protected int getLastPage() {
return mLastPage;
}
/**
* Set whether copies should be collated or not.
* Two collated copies of a three page document
* print in this order: 1, 2, 3, 1, 2, 3 while
* uncollated copies print in this order:
* 1, 1, 2, 2, 3, 3.
* This is set when request is using an attribute set.
*/
collateAttReq = true;
}
/**
* Return true if collated copies will be printed as determined
* in an attribute set.
*/
protected boolean isCollated() {
return mCollate;
}
/**
* Called by the print() method at the start of
* a print job.
*/
/**
* Called by the print() method at the end of
* a print job.
*/
/* Called by cancelDoc */
protected abstract void abortDoc();
// MacOSX - made protected so subclasses can reference it.
abortDoc();
synchronized (this) {
userCancelled = false;
performingPrinting = false;
notify();
}
throw new PrinterAbortException();
}
/**
* 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() {
}
/**
* Returns how many times each page in the book
* should be consecutively printed by PrintJob.
* If the printer makes copies itself then this
* method should return 1.
*/
protected int getNoncollatedCopies() {
}
/* The printer graphics config is cached on the job, so that it can
* be created once, and updated only as needed (for now only to change
* the bounds if when using a Pageable the page sizes changes).
*/
defaultDeviceTransform == null ||
}
}
return pgConfig;
}
}
return pgConfig;
}
/**
* Print a page from the provided document.
* @return int Printable.PAGE_EXISTS if the page existed and was drawn and
* Printable.NO_SUCH_PAGE if the page did not exist.
* @see java.awt.print.Printable
*/
throws PrinterException
{
try {
} catch (Exception e) {
new PrinterException("Error getting page or printable.[ " +
e +" ]");
throw pe;
}
/* Get the imageable area from Paper instead of PageFormat
* because we do not want it adjusted by the page orientation.
*/
// if non-portrait and 270 degree landscape rotation
} else {
}
}
/* The deviceArea is the imageable area in the printer's
* resolution.
*/
/* Build and hold on to a uniform transform so that
* we can get back to device space at the beginning
* of each band.
*/
/* The scale transform is used to switch from the
* device space to the user's 72 dpi space.
*/
/* bandwidth is multiple of 4 as the data is used in a win32 DIB and
* some drivers behave badly if scanlines aren't multiples of 4 bytes.
*/
}
if (bandWidth <= 0) {
throw new PrinterException("Paper's imageable width is too small.");
}
if (deviceAreaHeight <= 0) {
throw new PrinterException("Paper's imageable height is too small.");
}
/* Figure out the number of lines that will fit into
* our maximum band size. The hard coded 3 reflects the
* fact that we can only create 24 bit per pixel 3 byte BGR
* BufferedImages. FIX.
*/
/* The device transform is used to move the band down
* the page using translates. Normally this is all it
* would do, but since, when printing, the Window's
* DIB format wants the last line to be first (lowest) in
* memory, the deviceTransform moves the origin to the
* bottom of the band and flips the origin. This way the
* app prints upside down into the band which is the DIB
* format.
*/
/* Create a BufferedImage to hold the band. We set the clip
* of the band to be tight around the bits so that the
* application can use it to figure what part of the
* page needs to be drawn. The clip is never altered in
* this method, but we do translate the band's coordinate
* system so that the app will see the clip moving down the
* page though it s always around the same set of pixels.
*/
/* Have the app draw into a PeekGraphics object so we can
* learn something about the needs of the print job.
*/
this);
/* Update the information used to return a GraphicsConfiguration
* for this printer device. It needs to be updated per page as
* not all pages in a job may be the same size (different bounds)
* The transform is the scaling transform as this corresponds to
* the default transform for the device. The width and height are
* those of the paper, not the page format, as we want to describe
* the bounds of the device in its natural coordinate system of
* device coordinate whereas a page format may be in a rotated context.
*/
/* We need to check if the paper size is changed.
* Note that it is not sufficient to ask for the pageformat
* of "pageIndex-1", since PageRanges mean that pages can be
* skipped. So we have to look at the actual last paper size used.
*/
boolean paperChanged =
previousPaper == null ||
/* If we can convert the page directly to the
* underlying graphics system then we do not
* need to rasterize. We also may not need to
* create the 'band' if all the pages can take
* this path.
*/
if (pathGraphics != null) {
// user (0,0) should be origin of page, not imageable area
redrawList.clear();
}
/* This is the banded-raster printing loop.
* It should be moved into its own method.
*/
} else {
if (cachedBand == null ||
bandWidth != cachedBandWidth ||
bandHeight != cachedBandHeight) {
cachedBand = band;
}
new ProxyGraphics2D(bandGraphics, this);
/* We need the actual bits of the BufferedImage to send to
* the native Window's code. 'data' points to the actual
* pixels. Right now these are in ARGB format with 8 bits
* per component. We need to use a monochrome BufferedImage
* for monochrome printers when this is supported by
* BufferedImage. FIX
*/
/* Loop over the page moving our band down the page,
* calling the app to render the band, and then send the band
* to the printer.
*/
/* device's printable x,y is really addressable origin
* we address relative to media origin so when we print a
* band we need to adjust for the different methods of
* addressing it.
*/
bandTop += bandHeight)
{
/* Put the band back into device space and
* erase the contents of the band.
*/
/* Put the band into the correct location on the
* page. Once the band is moved we translate the
* device transform so that the band will move down
* the page on the next iteration of the loop.
*/
/* Switch the band from device space to user,
* 72 dpi, space.
*/
/* if the client has specified an imageable X or Y
* which is off than the physically addressable
* area of the page, then we need to adjust for that
* here so that we pass only non -ve band coordinates
* We also need to translate by the adjusted amount
* so that printing appears in the correct place.
*/
if (bandX < 0) {
bandX = 0;
}
if (bandY < 0) {
bandY = 0;
}
/* Have the app's painter image into the band
* and then send the band to the printer.
*/
}
}
}
}
return pageResult;
}
/**
* If a print job is in progress, print() has been
* called but has not returned, then this signals
* that the job should be cancelled and the next
* chance. If there is no print job in progress then
* this call does nothing.
*/
public void cancel() {
synchronized (this) {
if (performingPrinting) {
userCancelled = true;
}
notify();
}
}
/**
* Returns true is a print job is ongoing but will
* be cancelled and the next opportunity. false is
* returned otherwise.
*/
public boolean isCancelled() {
boolean cancelled = false;
synchronized (this) {
notify();
}
return cancelled;
}
/**
* Return the Pageable describing the pages to be printed.
*/
return mDocument;
}
/**
* 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.
*/
int pageIndex) {
return null;
}
/**
* Create and return an object that will
* gather and hold metrics about the print
* job. This method is passed a <code>Graphics2D</code>
* object that can be used as a proxy for the
* object gathering the print job matrics. The
* method is also supplied with the instance
* controlling the print job, <code>printerJob</code>.
*/
}
/**
* Configure the passed in Graphics2D so that
* is contains the defined initial settings
* for a print job. These settings are:
* color: black.
* clip: <as passed in>
*/
// MacOSX - made protected so subclasses can reference it.
}
/**
* User dialogs should disable "File" buttons if this returns false.
*
*/
public boolean checkAllowedToPrintToFile() {
try {
return true;
} catch (SecurityException e) {
return false;
}
}
/**
* Break this out as it may be useful when we allow API to
* specify printing to a file. In that case its probably right
* to throw a SecurityException if the permission is not granted
*/
private void throwPrintToFile() {
if (printToFilePermission == null) {
}
}
}
/* On-screen drawString renders most control chars as the missing glyph
* and have the non-zero advance of that glyph.
* Exceptions are \t, \n and \r which are considered zero-width.
* This is a utility method used by subclasses to remove them so we
* don't have to worry about platform or font specific handling of them.
*/
char[] in_chars = s.toCharArray();
int pos = 0;
for (int i = 0; i < len; i++) {
char c = in_chars[i];
if (c > '\r' || c < '\t' || c == '\u000b' || c == '\u000c') {
}
}
return s; // no need to make a new String.
} else {
}
}
}