Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/print/RasterPrinterJob.java
38829 views
1
/*
2
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.print;
27
28
import java.io.FilePermission;
29
30
import java.awt.Color;
31
import java.awt.Dialog;
32
import java.awt.Frame;
33
import java.awt.Graphics;
34
import java.awt.Graphics2D;
35
import java.awt.GraphicsConfiguration;
36
import java.awt.GraphicsEnvironment;
37
import java.awt.HeadlessException;
38
import java.awt.KeyboardFocusManager;
39
import java.awt.Rectangle;
40
import java.awt.Shape;
41
import java.awt.geom.AffineTransform;
42
import java.awt.geom.Area;
43
import java.awt.geom.Point2D;
44
import java.awt.geom.Rectangle2D;
45
import java.awt.image.BufferedImage;
46
import java.awt.print.Book;
47
import java.awt.print.Pageable;
48
import java.awt.print.PageFormat;
49
import java.awt.print.Paper;
50
import java.awt.print.Printable;
51
import java.awt.print.PrinterAbortException;
52
import java.awt.print.PrinterException;
53
import java.awt.print.PrinterJob;
54
import java.awt.Window;
55
import java.io.File;
56
import java.io.IOException;
57
import java.util.ArrayList;
58
import java.util.Enumeration;
59
import java.util.Locale;
60
import sun.awt.image.ByteInterleavedRaster;
61
62
import javax.print.Doc;
63
import javax.print.DocFlavor;
64
import javax.print.DocPrintJob;
65
import javax.print.PrintException;
66
import javax.print.PrintService;
67
import javax.print.PrintServiceLookup;
68
import javax.print.ServiceUI;
69
import javax.print.StreamPrintService;
70
import javax.print.StreamPrintServiceFactory;
71
import javax.print.attribute.Attribute;
72
import javax.print.attribute.AttributeSet;
73
import javax.print.attribute.HashPrintRequestAttributeSet;
74
import javax.print.attribute.PrintRequestAttributeSet;
75
import javax.print.attribute.Size2DSyntax;
76
import javax.print.attribute.standard.Chromaticity;
77
import javax.print.attribute.standard.Copies;
78
import javax.print.attribute.standard.Destination;
79
import javax.print.attribute.standard.DialogTypeSelection;
80
import javax.print.attribute.standard.Fidelity;
81
import javax.print.attribute.standard.JobName;
82
import javax.print.attribute.standard.JobSheets;
83
import javax.print.attribute.standard.Media;
84
import javax.print.attribute.standard.MediaPrintableArea;
85
import javax.print.attribute.standard.MediaSize;
86
import javax.print.attribute.standard.MediaSizeName;
87
import javax.print.attribute.standard.OrientationRequested;
88
import javax.print.attribute.standard.PageRanges;
89
import javax.print.attribute.standard.PrinterState;
90
import javax.print.attribute.standard.PrinterStateReason;
91
import javax.print.attribute.standard.PrinterStateReasons;
92
import javax.print.attribute.standard.PrinterIsAcceptingJobs;
93
import javax.print.attribute.standard.RequestingUserName;
94
import javax.print.attribute.standard.SheetCollate;
95
import javax.print.attribute.standard.Sides;
96
97
import sun.print.PageableDoc;
98
import sun.print.ServiceDialog;
99
import sun.print.SunPrinterJobService;
100
import sun.print.SunPageSelection;
101
102
/**
103
* A class which rasterizes a printer job.
104
*
105
* @author Richard Blanchard
106
*/
107
public abstract class RasterPrinterJob extends PrinterJob {
108
109
/* Class Constants */
110
111
/* Printer destination type. */
112
protected static final int PRINTER = 0;
113
114
/* File destination type. */
115
protected static final int FILE = 1;
116
117
/* Stream destination type. */
118
protected static final int STREAM = 2;
119
120
/**
121
* Pageable MAX pages
122
*/
123
protected static final int MAX_UNKNOWN_PAGES = 9999;
124
125
protected static final int PD_ALLPAGES = 0x00000000;
126
protected static final int PD_SELECTION = 0x00000001;
127
protected static final int PD_PAGENUMS = 0x00000002;
128
protected static final int PD_NOSELECTION = 0x00000004;
129
130
/**
131
* Maximum amount of memory in bytes to use for the
132
* buffered image "band". 4Mb is a compromise between
133
* limiting the number of bands on hi-res printers and
134
* not using too much of the Java heap or causing paging
135
* on systems with little RAM.
136
*/
137
private static final int MAX_BAND_SIZE = (1024 * 1024 * 4);
138
139
/* Dots Per Inch */
140
private static final float DPI = 72.0f;
141
142
/**
143
* Useful mainly for debugging, this system property
144
* can be used to force the printing code to print
145
* using a particular pipeline. The two currently
146
* supported values are FORCE_RASTER and FORCE_PDL.
147
*/
148
private static final String FORCE_PIPE_PROP = "sun.java2d.print.pipeline";
149
150
/**
151
* When the system property FORCE_PIPE_PROP has this value
152
* then each page of a print job will be rendered through
153
* the raster pipeline.
154
*/
155
private static final String FORCE_RASTER = "raster";
156
157
/**
158
* When the system property FORCE_PIPE_PROP has this value
159
* then each page of a print job will be rendered through
160
* the PDL pipeline.
161
*/
162
private static final String FORCE_PDL = "pdl";
163
164
/**
165
* When the system property SHAPE_TEXT_PROP has this value
166
* then text is always rendered as a shape, and no attempt is made
167
* to match the font through GDI
168
*/
169
private static final String SHAPE_TEXT_PROP = "sun.java2d.print.shapetext";
170
171
/**
172
* values obtained from System properties in static initialiser block
173
*/
174
public static boolean forcePDL = false;
175
public static boolean forceRaster = false;
176
public static boolean shapeTextProp = false;
177
178
static {
179
/* The system property FORCE_PIPE_PROP
180
* can be used to force the printing code to
181
* use a particular pipeline. Either the raster
182
* pipeline or the pdl pipeline can be forced.
183
*/
184
String forceStr =
185
(String)java.security.AccessController.doPrivileged(
186
new sun.security.action.GetPropertyAction(FORCE_PIPE_PROP));
187
188
if (forceStr != null) {
189
if (forceStr.equalsIgnoreCase(FORCE_PDL)) {
190
forcePDL = true;
191
} else if (forceStr.equalsIgnoreCase(FORCE_RASTER)) {
192
forceRaster = true;
193
}
194
}
195
196
String shapeTextStr =
197
(String)java.security.AccessController.doPrivileged(
198
new sun.security.action.GetPropertyAction(SHAPE_TEXT_PROP));
199
200
if (shapeTextStr != null) {
201
shapeTextProp = true;
202
}
203
}
204
205
/* Instance Variables */
206
207
/**
208
* Used to minimize GC & reallocation of band when printing
209
*/
210
private int cachedBandWidth = 0;
211
private int cachedBandHeight = 0;
212
private BufferedImage cachedBand = null;
213
214
/**
215
* The number of book copies to be printed.
216
*/
217
private int mNumCopies = 1;
218
219
/**
220
* Collation effects the order of the pages printed
221
* when multiple copies are requested. For two copies
222
* of a three page document the page order is:
223
* mCollate true: 1, 2, 3, 1, 2, 3
224
* mCollate false: 1, 1, 2, 2, 3, 3
225
*/
226
private boolean mCollate = false;
227
228
/**
229
* The zero based indices of the first and last
230
* pages to be printed. If 'mFirstPage' is
231
* UNDEFINED_PAGE_NUM then the first page to
232
* be printed is page 0. If 'mLastPage' is
233
* UNDEFINED_PAGE_NUM then the last page to
234
* be printed is the last one in the book.
235
*/
236
private int mFirstPage = Pageable.UNKNOWN_NUMBER_OF_PAGES;
237
private int mLastPage = Pageable.UNKNOWN_NUMBER_OF_PAGES;
238
239
/**
240
* The previous print stream Paper
241
* Used to check if the paper size has changed such that the
242
* implementation needs to emit the new paper size information
243
* into the print stream.
244
* Since we do our own rotation, and the margins aren't relevant,
245
* Its strictly the dimensions of the paper that we will check.
246
*/
247
private Paper previousPaper;
248
249
/**
250
* The document to be printed. It is initialized to an
251
* empty (zero pages) book.
252
*/
253
// MacOSX - made protected so subclasses can reference it.
254
protected Pageable mDocument = new Book();
255
256
/**
257
* The name of the job being printed.
258
*/
259
private String mDocName = "Java Printing";
260
261
262
/**
263
* Printing cancellation flags
264
*/
265
// MacOSX - made protected so subclasses can reference it.
266
protected boolean performingPrinting = false;
267
// MacOSX - made protected so subclasses can reference it.
268
protected boolean userCancelled = false;
269
270
/**
271
* Print to file permission variables.
272
*/
273
private FilePermission printToFilePermission;
274
275
/**
276
* List of areas & the graphics state for redrawing
277
*/
278
private ArrayList redrawList = new ArrayList();
279
280
281
/* variables representing values extracted from an attribute set.
282
* These take precedence over values set on a printer job
283
*/
284
private int copiesAttr;
285
private String jobNameAttr;
286
private String userNameAttr;
287
private PageRanges pageRangesAttr;
288
protected Sides sidesAttr;
289
protected String destinationAttr;
290
protected boolean noJobSheet = false;
291
protected int mDestType = RasterPrinterJob.FILE;
292
protected String mDestination = "";
293
protected boolean collateAttReq = false;
294
295
/**
296
* Device rotation flag, if it support 270, this is set to true;
297
*/
298
protected boolean landscapeRotates270 = false;
299
300
/**
301
* attributes used by no-args page and print dialog and print method to
302
* communicate state
303
*/
304
protected PrintRequestAttributeSet attributes = null;
305
306
/**
307
* Class to keep state information for redrawing areas
308
* "region" is an area at as a high a resolution as possible.
309
* The redrawing code needs to look at sx, sy to calculate the scale
310
* to device resolution.
311
*/
312
private class GraphicsState {
313
Rectangle2D region; // Area of page to repaint
314
Shape theClip; // image drawing clip.
315
AffineTransform theTransform; // to transform clip to dev coords.
316
double sx; // X scale from region to device resolution
317
double sy; // Y scale from region to device resolution
318
}
319
320
/**
321
* Service for this job
322
*/
323
protected PrintService myService;
324
325
/* Constructors */
326
327
public RasterPrinterJob()
328
{
329
}
330
331
/* Abstract Methods */
332
333
/**
334
* Returns the resolution in dots per inch across the width
335
* of the page.
336
*/
337
abstract protected double getXRes();
338
339
/**
340
* Returns the resolution in dots per inch down the height
341
* of the page.
342
*/
343
abstract protected double getYRes();
344
345
/**
346
* Must be obtained from the current printer.
347
* Value is in device pixels.
348
* Not adjusted for orientation of the paper.
349
*/
350
abstract protected double getPhysicalPrintableX(Paper p);
351
352
/**
353
* Must be obtained from the current printer.
354
* Value is in device pixels.
355
* Not adjusted for orientation of the paper.
356
*/
357
abstract protected double getPhysicalPrintableY(Paper p);
358
359
/**
360
* Must be obtained from the current printer.
361
* Value is in device pixels.
362
* Not adjusted for orientation of the paper.
363
*/
364
abstract protected double getPhysicalPrintableWidth(Paper p);
365
366
/**
367
* Must be obtained from the current printer.
368
* Value is in device pixels.
369
* Not adjusted for orientation of the paper.
370
*/
371
abstract protected double getPhysicalPrintableHeight(Paper p);
372
373
/**
374
* Must be obtained from the current printer.
375
* Value is in device pixels.
376
* Not adjusted for orientation of the paper.
377
*/
378
abstract protected double getPhysicalPageWidth(Paper p);
379
380
/**
381
* Must be obtained from the current printer.
382
* Value is in device pixels.
383
* Not adjusted for orientation of the paper.
384
*/
385
abstract protected double getPhysicalPageHeight(Paper p);
386
387
/**
388
* Begin a new page.
389
*/
390
abstract protected void startPage(PageFormat format, Printable painter,
391
int index, boolean paperChanged)
392
throws PrinterException;
393
394
/**
395
* End a page.
396
*/
397
abstract protected void endPage(PageFormat format, Printable painter,
398
int index)
399
throws PrinterException;
400
401
/**
402
* Prints the contents of the array of ints, 'data'
403
* to the current page. The band is placed at the
404
* location (x, y) in device coordinates on the
405
* page. The width and height of the band is
406
* specified by the caller.
407
*/
408
abstract protected void printBand(byte[] data, int x, int y,
409
int width, int height)
410
throws PrinterException;
411
412
/* Instance Methods */
413
414
/**
415
* save graphics state of a PathGraphics for later redrawing
416
* of part of page represented by the region in that state
417
*/
418
419
public void saveState(AffineTransform at, Shape clip,
420
Rectangle2D region, double sx, double sy) {
421
GraphicsState gstate = new GraphicsState();
422
gstate.theTransform = at;
423
gstate.theClip = clip;
424
gstate.region = region;
425
gstate.sx = sx;
426
gstate.sy = sy;
427
redrawList.add(gstate);
428
}
429
430
431
/*
432
* A convenience method which returns the default service
433
* for 2D <code>PrinterJob</code>s.
434
* May return null if there is no suitable default (although there
435
* may still be 2D services available).
436
* @return default 2D print service, or null.
437
* @since 1.4
438
*/
439
protected static PrintService lookupDefaultPrintService() {
440
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
441
442
/* Pageable implies Printable so checking both isn't strictly needed */
443
if (service != null &&
444
service.isDocFlavorSupported(
445
DocFlavor.SERVICE_FORMATTED.PAGEABLE) &&
446
service.isDocFlavorSupported(
447
DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
448
return service;
449
} else {
450
PrintService []services =
451
PrintServiceLookup.lookupPrintServices(
452
DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
453
if (services.length > 0) {
454
return services[0];
455
}
456
}
457
return null;
458
}
459
460
/**
461
* Returns the service (printer) for this printer job.
462
* Implementations of this class which do not support print services
463
* may return null;
464
* @return the service for this printer job.
465
*
466
*/
467
public PrintService getPrintService() {
468
if (myService == null) {
469
PrintService svc = PrintServiceLookup.lookupDefaultPrintService();
470
if (svc != null &&
471
svc.isDocFlavorSupported(
472
DocFlavor.SERVICE_FORMATTED.PAGEABLE)) {
473
try {
474
setPrintService(svc);
475
myService = svc;
476
} catch (PrinterException e) {
477
}
478
}
479
if (myService == null) {
480
PrintService[] svcs = PrintServiceLookup.lookupPrintServices(
481
DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
482
if (svcs.length > 0) {
483
try {
484
setPrintService(svcs[0]);
485
myService = svcs[0];
486
} catch (PrinterException e) {
487
}
488
}
489
}
490
}
491
return myService;
492
}
493
494
/**
495
* Associate this PrinterJob with a new PrintService.
496
*
497
* Throws <code>PrinterException</code> if the specified service
498
* cannot support the <code>Pageable</code> and
499
* <code>Printable</code> interfaces necessary to support 2D printing.
500
* @param a print service which supports 2D printing.
501
*
502
* @throws PrinterException if the specified service does not support
503
* 2D printing or no longer available.
504
*/
505
public void setPrintService(PrintService service)
506
throws PrinterException {
507
if (service == null) {
508
throw new PrinterException("Service cannot be null");
509
} else if (!(service instanceof StreamPrintService) &&
510
service.getName() == null) {
511
throw new PrinterException("Null PrintService name.");
512
} else {
513
// Check the list of services. This service may have been
514
// deleted already
515
PrinterState prnState = (PrinterState)service.getAttribute(
516
PrinterState.class);
517
if (prnState == PrinterState.STOPPED) {
518
PrinterStateReasons prnStateReasons =
519
(PrinterStateReasons)service.getAttribute(
520
PrinterStateReasons.class);
521
if ((prnStateReasons != null) &&
522
(prnStateReasons.containsKey(PrinterStateReason.SHUTDOWN)))
523
{
524
throw new PrinterException("PrintService is no longer available.");
525
}
526
}
527
528
529
if (service.isDocFlavorSupported(
530
DocFlavor.SERVICE_FORMATTED.PAGEABLE) &&
531
service.isDocFlavorSupported(
532
DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
533
myService = service;
534
} else {
535
throw new PrinterException("Not a 2D print service: " + service);
536
}
537
}
538
}
539
540
private PageFormat attributeToPageFormat(PrintService service,
541
PrintRequestAttributeSet attSet) {
542
PageFormat page = defaultPage();
543
544
if (service == null) {
545
return page;
546
}
547
548
OrientationRequested orient = (OrientationRequested)
549
attSet.get(OrientationRequested.class);
550
if (orient == null) {
551
orient = (OrientationRequested)
552
service.getDefaultAttributeValue(OrientationRequested.class);
553
}
554
if (orient == OrientationRequested.REVERSE_LANDSCAPE) {
555
page.setOrientation(PageFormat.REVERSE_LANDSCAPE);
556
} else if (orient == OrientationRequested.LANDSCAPE) {
557
page.setOrientation(PageFormat.LANDSCAPE);
558
} else {
559
page.setOrientation(PageFormat.PORTRAIT);
560
}
561
562
Media media = (Media)attSet.get(Media.class);
563
MediaSize size = getMediaSize(media, service, page);
564
565
Paper paper = new Paper();
566
float dim[] = size.getSize(1); //units == 1 to avoid FP error
567
double w = Math.rint((dim[0]*72.0)/Size2DSyntax.INCH);
568
double h = Math.rint((dim[1]*72.0)/Size2DSyntax.INCH);
569
paper.setSize(w, h);
570
MediaPrintableArea area =
571
(MediaPrintableArea)
572
attSet.get(MediaPrintableArea.class);
573
if (area == null) {
574
area = getDefaultPrintableArea(page, w, h);
575
}
576
577
double ix, iw, iy, ih;
578
// Should pass in same unit as updatePageAttributes
579
// to avoid rounding off errors.
580
ix = Math.rint(
581
area.getX(MediaPrintableArea.INCH) * DPI);
582
iy = Math.rint(
583
area.getY(MediaPrintableArea.INCH) * DPI);
584
iw = Math.rint(
585
area.getWidth(MediaPrintableArea.INCH) * DPI);
586
ih = Math.rint(
587
area.getHeight(MediaPrintableArea.INCH) * DPI);
588
paper.setImageableArea(ix, iy, iw, ih);
589
page.setPaper(paper);
590
return page;
591
}
592
protected MediaSize getMediaSize(Media media, PrintService service,
593
PageFormat page) {
594
if (media == null) {
595
media = (Media)service.getDefaultAttributeValue(Media.class);
596
}
597
if (!(media instanceof MediaSizeName)) {
598
media = MediaSizeName.NA_LETTER;
599
}
600
MediaSize size = MediaSize.getMediaSizeForName((MediaSizeName) media);
601
return size != null ? size : MediaSize.NA.LETTER;
602
}
603
604
protected MediaPrintableArea getDefaultPrintableArea(PageFormat page,
605
double w, double h) {
606
double ix, iw, iy, ih;
607
if (w >= 72.0 * 6.0) {
608
ix = 72.0;
609
iw = w - 2 * 72.0;
610
} else {
611
ix = w / 6.0;
612
iw = w * 0.75;
613
}
614
if (h >= 72.0 * 6.0) {
615
iy = 72.0;
616
ih = h - 2 * 72.0;
617
} else {
618
iy = h / 6.0;
619
ih = h * 0.75;
620
}
621
622
return new MediaPrintableArea((float) (ix / DPI), (float) (iy / DPI),
623
(float) (iw / DPI), (float) (ih / DPI), MediaPrintableArea.INCH);
624
}
625
626
protected void updatePageAttributes(PrintService service,
627
PageFormat page) {
628
if (this.attributes == null) {
629
this.attributes = new HashPrintRequestAttributeSet();
630
}
631
632
updateAttributesWithPageFormat(service, page, this.attributes);
633
}
634
635
protected void updateAttributesWithPageFormat(PrintService service,
636
PageFormat page,
637
PrintRequestAttributeSet pageAttributes) {
638
if (service == null || page == null || pageAttributes == null) {
639
return;
640
}
641
642
float x = (float)Math.rint(
643
(page.getPaper().getWidth()*Size2DSyntax.INCH)/
644
(72.0))/(float)Size2DSyntax.INCH;
645
float y = (float)Math.rint(
646
(page.getPaper().getHeight()*Size2DSyntax.INCH)/
647
(72.0))/(float)Size2DSyntax.INCH;
648
649
// We should limit the list where we search the matching
650
// media, this will prevent mapping to wrong media ex. Ledger
651
// can be mapped to B. Especially useful when creating
652
// custom MediaSize.
653
Media[] mediaList = (Media[])service.getSupportedAttributeValues(
654
Media.class, null, null);
655
Media media = null;
656
try {
657
media = CustomMediaSizeName.findMedia(mediaList, x, y,
658
Size2DSyntax.INCH);
659
} catch (IllegalArgumentException iae) {
660
}
661
if ((media == null) ||
662
!(service.isAttributeValueSupported(media, null, null))) {
663
media = (Media)service.getDefaultAttributeValue(Media.class);
664
}
665
666
OrientationRequested orient;
667
switch (page.getOrientation()) {
668
case PageFormat.LANDSCAPE :
669
orient = OrientationRequested.LANDSCAPE;
670
break;
671
case PageFormat.REVERSE_LANDSCAPE:
672
orient = OrientationRequested.REVERSE_LANDSCAPE;
673
break;
674
default:
675
orient = OrientationRequested.PORTRAIT;
676
}
677
678
if (media != null) {
679
pageAttributes.add(media);
680
}
681
pageAttributes.add(orient);
682
683
float ix = (float)(page.getPaper().getImageableX()/DPI);
684
float iw = (float)(page.getPaper().getImageableWidth()/DPI);
685
float iy = (float)(page.getPaper().getImageableY()/DPI);
686
float ih = (float)(page.getPaper().getImageableHeight()/DPI);
687
if (ix < 0) ix = 0f; if (iy < 0) iy = 0f;
688
try {
689
pageAttributes.add(new MediaPrintableArea(ix, iy, iw, ih,
690
MediaPrintableArea.INCH));
691
} catch (IllegalArgumentException iae) {
692
}
693
}
694
695
/**
696
* Display a dialog to the user allowing the modification of a
697
* PageFormat instance.
698
* The <code>page</code> argument is used to initialize controls
699
* in the page setup dialog.
700
* If the user cancels the dialog, then the method returns the
701
* original <code>page</code> object unmodified.
702
* If the user okays the dialog then the method returns a new
703
* PageFormat object with the indicated changes.
704
* In either case the original <code>page</code> object will
705
* not be modified.
706
* @param page the default PageFormat presented to the user
707
* for modification
708
* @return the original <code>page</code> object if the dialog
709
* is cancelled, or a new PageFormat object containing
710
* the format indicated by the user if the dialog is
711
* acknowledged
712
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
713
* returns true.
714
* @see java.awt.GraphicsEnvironment#isHeadless
715
* @since 1.2
716
*/
717
public PageFormat pageDialog(PageFormat page)
718
throws HeadlessException {
719
if (GraphicsEnvironment.isHeadless()) {
720
throw new HeadlessException();
721
}
722
723
final GraphicsConfiguration gc =
724
GraphicsEnvironment.getLocalGraphicsEnvironment().
725
getDefaultScreenDevice().getDefaultConfiguration();
726
727
PrintService service =
728
(PrintService)java.security.AccessController.doPrivileged(
729
new java.security.PrivilegedAction() {
730
public Object run() {
731
PrintService service = getPrintService();
732
if (service == null) {
733
ServiceDialog.showNoPrintService(gc);
734
return null;
735
}
736
return service;
737
}
738
});
739
740
if (service == null) {
741
return page;
742
}
743
updatePageAttributes(service, page);
744
745
PageFormat newPage = null;
746
DialogTypeSelection dts =
747
(DialogTypeSelection)attributes.get(DialogTypeSelection.class);
748
if (dts == DialogTypeSelection.NATIVE) {
749
// Remove DialogTypeSelection.NATIVE to prevent infinite loop in
750
// RasterPrinterJob.
751
attributes.remove(DialogTypeSelection.class);
752
newPage = pageDialog(attributes);
753
// restore attribute
754
attributes.add(DialogTypeSelection.NATIVE);
755
} else {
756
newPage = pageDialog(attributes);
757
}
758
759
if (newPage == null) {
760
return page;
761
} else {
762
return newPage;
763
}
764
}
765
766
/**
767
* return a PageFormat corresponding to the updated attributes,
768
* or null if the user cancelled the dialog.
769
*/
770
public PageFormat pageDialog(final PrintRequestAttributeSet attributes)
771
throws HeadlessException {
772
if (GraphicsEnvironment.isHeadless()) {
773
throw new HeadlessException();
774
}
775
776
DialogTypeSelection dlg =
777
(DialogTypeSelection)attributes.get(DialogTypeSelection.class);
778
779
// Check for native, note that default dialog is COMMON.
780
if (dlg == DialogTypeSelection.NATIVE) {
781
PrintService pservice = getPrintService();
782
PageFormat pageFrmAttrib = attributeToPageFormat(pservice,
783
attributes);
784
setParentWindowID(attributes);
785
PageFormat page = pageDialog(pageFrmAttrib);
786
clearParentWindowID();
787
788
// If user cancels the dialog, pageDialog() will return the original
789
// page object and as per spec, we should return null in that case.
790
if (page == pageFrmAttrib) {
791
return null;
792
}
793
updateAttributesWithPageFormat(pservice, page, attributes);
794
return page;
795
}
796
797
final GraphicsConfiguration gc =
798
GraphicsEnvironment.getLocalGraphicsEnvironment().
799
getDefaultScreenDevice().getDefaultConfiguration();
800
Rectangle bounds = gc.getBounds();
801
int x = bounds.x+bounds.width/3;
802
int y = bounds.y+bounds.height/3;
803
804
PrintService service =
805
(PrintService)java.security.AccessController.doPrivileged(
806
new java.security.PrivilegedAction() {
807
public Object run() {
808
PrintService service = getPrintService();
809
if (service == null) {
810
ServiceDialog.showNoPrintService(gc);
811
return null;
812
}
813
return service;
814
}
815
});
816
817
if (service == null) {
818
return null;
819
}
820
821
if (onTop != null) {
822
attributes.add(onTop);
823
}
824
825
ServiceDialog pageDialog = new ServiceDialog(gc, x, y, service,
826
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
827
attributes, (Frame)null);
828
pageDialog.show();
829
830
if (pageDialog.getStatus() == ServiceDialog.APPROVE) {
831
PrintRequestAttributeSet newas =
832
pageDialog.getAttributes();
833
Class amCategory = SunAlternateMedia.class;
834
835
if (attributes.containsKey(amCategory) &&
836
!newas.containsKey(amCategory)) {
837
attributes.remove(amCategory);
838
}
839
attributes.addAll(newas);
840
return attributeToPageFormat(service, attributes);
841
} else {
842
return null;
843
}
844
}
845
846
protected PageFormat getPageFormatFromAttributes() {
847
Pageable pageable = null;
848
if (attributes == null || attributes.isEmpty() ||
849
!((pageable = getPageable()) instanceof OpenBook)) {
850
return null;
851
}
852
853
PageFormat newPf = attributeToPageFormat(
854
getPrintService(), attributes);
855
PageFormat oldPf = null;
856
if ((oldPf = pageable.getPageFormat(0)) != null) {
857
// If orientation, media, imageable area attributes are not in
858
// "attributes" set, then use respective values of the existing
859
// page format "oldPf".
860
if (attributes.get(OrientationRequested.class) == null) {
861
newPf.setOrientation(oldPf.getOrientation());
862
}
863
864
Paper newPaper = newPf.getPaper();
865
Paper oldPaper = oldPf.getPaper();
866
boolean oldPaperValWasSet = false;
867
if (attributes.get(MediaSizeName.class) == null) {
868
newPaper.setSize(oldPaper.getWidth(), oldPaper.getHeight());
869
oldPaperValWasSet = true;
870
}
871
if (attributes.get(MediaPrintableArea.class) == null) {
872
newPaper.setImageableArea(
873
oldPaper.getImageableX(), oldPaper.getImageableY(),
874
oldPaper.getImageableWidth(),
875
oldPaper.getImageableHeight());
876
oldPaperValWasSet = true;
877
}
878
if (oldPaperValWasSet) {
879
newPf.setPaper(newPaper);
880
}
881
}
882
return newPf;
883
}
884
885
886
/**
887
* Presents the user a dialog for changing properties of the
888
* print job interactively.
889
* The services browsable here are determined by the type of
890
* service currently installed.
891
* If the application installed a StreamPrintService on this
892
* PrinterJob, only the available StreamPrintService (factories) are
893
* browsable.
894
*
895
* @param attributes to store changed properties.
896
* @return false if the user cancels the dialog and true otherwise.
897
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
898
* returns true.
899
* @see java.awt.GraphicsEnvironment#isHeadless
900
*/
901
public boolean printDialog(final PrintRequestAttributeSet attributes)
902
throws HeadlessException {
903
if (GraphicsEnvironment.isHeadless()) {
904
throw new HeadlessException();
905
}
906
907
DialogTypeSelection dlg =
908
(DialogTypeSelection)attributes.get(DialogTypeSelection.class);
909
910
// Check for native, note that default dialog is COMMON.
911
if (dlg == DialogTypeSelection.NATIVE) {
912
this.attributes = attributes;
913
try {
914
debug_println("calling setAttributes in printDialog");
915
setAttributes(attributes);
916
917
} catch (PrinterException e) {
918
919
}
920
921
setParentWindowID(attributes);
922
boolean ret = printDialog();
923
clearParentWindowID();
924
this.attributes = attributes;
925
return ret;
926
927
}
928
929
/* A security check has already been performed in the
930
* java.awt.print.printerJob.getPrinterJob method.
931
* So by the time we get here, it is OK for the current thread
932
* to print either to a file (from a Dialog we control!) or
933
* to a chosen printer.
934
*
935
* We raise privilege when we put up the dialog, to avoid
936
* the "warning applet window" banner.
937
*/
938
final GraphicsConfiguration gc =
939
GraphicsEnvironment.getLocalGraphicsEnvironment().
940
getDefaultScreenDevice().getDefaultConfiguration();
941
942
PrintService service =
943
(PrintService)java.security.AccessController.doPrivileged(
944
new java.security.PrivilegedAction() {
945
public Object run() {
946
PrintService service = getPrintService();
947
if (service == null) {
948
ServiceDialog.showNoPrintService(gc);
949
return null;
950
}
951
return service;
952
}
953
});
954
955
if (service == null) {
956
return false;
957
}
958
959
PrintService[] services;
960
StreamPrintServiceFactory[] spsFactories = null;
961
if (service instanceof StreamPrintService) {
962
spsFactories = lookupStreamPrintServices(null);
963
services = new StreamPrintService[spsFactories.length];
964
for (int i=0; i<spsFactories.length; i++) {
965
services[i] = spsFactories[i].getPrintService(null);
966
}
967
} else {
968
services =
969
(PrintService[])java.security.AccessController.doPrivileged(
970
new java.security.PrivilegedAction() {
971
public Object run() {
972
PrintService[] services = PrinterJob.lookupPrintServices();
973
return services;
974
}
975
});
976
977
if ((services == null) || (services.length == 0)) {
978
/*
979
* No services but default PrintService exists?
980
* Create services using defaultService.
981
*/
982
services = new PrintService[1];
983
services[0] = service;
984
}
985
}
986
987
Rectangle bounds = gc.getBounds();
988
int x = bounds.x+bounds.width/3;
989
int y = bounds.y+bounds.height/3;
990
PrintService newService;
991
// temporarily add an attribute pointing back to this job.
992
PrinterJobWrapper jobWrapper = new PrinterJobWrapper(this);
993
attributes.add(jobWrapper);
994
try {
995
newService =
996
ServiceUI.printDialog(gc, x, y,
997
services, service,
998
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
999
attributes);
1000
} catch (IllegalArgumentException iae) {
1001
newService = ServiceUI.printDialog(gc, x, y,
1002
services, services[0],
1003
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
1004
attributes);
1005
}
1006
attributes.remove(PrinterJobWrapper.class);
1007
1008
if (newService == null) {
1009
return false;
1010
}
1011
1012
if (!service.equals(newService)) {
1013
try {
1014
setPrintService(newService);
1015
} catch (PrinterException e) {
1016
/*
1017
* The only time it would throw an exception is when
1018
* newService is no longer available but we should still
1019
* select this printer.
1020
*/
1021
myService = newService;
1022
}
1023
}
1024
return true;
1025
}
1026
1027
/**
1028
* Presents the user a dialog for changing properties of the
1029
* print job interactively.
1030
* @returns false if the user cancels the dialog and
1031
* true otherwise.
1032
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
1033
* returns true.
1034
* @see java.awt.GraphicsEnvironment#isHeadless
1035
*/
1036
public boolean printDialog() throws HeadlessException {
1037
1038
if (GraphicsEnvironment.isHeadless()) {
1039
throw new HeadlessException();
1040
}
1041
1042
PrintRequestAttributeSet attributes =
1043
new HashPrintRequestAttributeSet();
1044
attributes.add(new Copies(getCopies()));
1045
attributes.add(new JobName(getJobName(), null));
1046
boolean doPrint = printDialog(attributes);
1047
if (doPrint) {
1048
JobName jobName = (JobName)attributes.get(JobName.class);
1049
if (jobName != null) {
1050
setJobName(jobName.getValue());
1051
}
1052
Copies copies = (Copies)attributes.get(Copies.class);
1053
if (copies != null) {
1054
setCopies(copies.getValue());
1055
}
1056
1057
Destination dest = (Destination)attributes.get(Destination.class);
1058
1059
if (dest != null) {
1060
try {
1061
mDestType = RasterPrinterJob.FILE;
1062
mDestination = (new File(dest.getURI())).getPath();
1063
} catch (Exception e) {
1064
mDestination = "out.prn";
1065
PrintService ps = getPrintService();
1066
if (ps != null) {
1067
Destination defaultDest = (Destination)ps.
1068
getDefaultAttributeValue(Destination.class);
1069
if (defaultDest != null) {
1070
mDestination = (new File(defaultDest.getURI())).getPath();
1071
}
1072
}
1073
}
1074
} else {
1075
mDestType = RasterPrinterJob.PRINTER;
1076
PrintService ps = getPrintService();
1077
if (ps != null) {
1078
mDestination = ps.getName();
1079
}
1080
}
1081
}
1082
1083
return doPrint;
1084
}
1085
1086
/**
1087
* The pages in the document to be printed by this PrinterJob
1088
* are drawn by the Printable object 'painter'. The PageFormat
1089
* for each page is the default page format.
1090
* @param Printable Called to render each page of the document.
1091
*/
1092
public void setPrintable(Printable painter) {
1093
setPageable(new OpenBook(defaultPage(new PageFormat()), painter));
1094
}
1095
1096
/**
1097
* The pages in the document to be printed by this PrinterJob
1098
* are drawn by the Printable object 'painter'. The PageFormat
1099
* of each page is 'format'.
1100
* @param Printable Called to render each page of the document.
1101
* @param PageFormat The size and orientation of each page to
1102
* be printed.
1103
*/
1104
public void setPrintable(Printable painter, PageFormat format) {
1105
setPageable(new OpenBook(format, painter));
1106
updatePageAttributes(getPrintService(), format);
1107
}
1108
1109
/**
1110
* The pages in the document to be printed are held by the
1111
* Pageable instance 'document'. 'document' will be queried
1112
* for the number of pages as well as the PageFormat and
1113
* Printable for each page.
1114
* @param Pageable The document to be printed. It may not be null.
1115
* @exception NullPointerException the Pageable passed in was null.
1116
* @see PageFormat
1117
* @see Printable
1118
*/
1119
public void setPageable(Pageable document) throws NullPointerException {
1120
if (document != null) {
1121
mDocument = document;
1122
1123
} else {
1124
throw new NullPointerException();
1125
}
1126
}
1127
1128
protected void initPrinter() {
1129
return;
1130
}
1131
1132
protected boolean isSupportedValue(Attribute attrval,
1133
PrintRequestAttributeSet attrset) {
1134
PrintService ps = getPrintService();
1135
return
1136
(attrval != null && ps != null &&
1137
ps.isAttributeValueSupported(attrval,
1138
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
1139
attrset));
1140
}
1141
1142
/* subclasses may need to pull extra information out of the attribute set
1143
* They can override this method & call super.setAttributes()
1144
*/
1145
protected void setAttributes(PrintRequestAttributeSet attributes)
1146
throws PrinterException {
1147
/* reset all values to defaults */
1148
setCollated(false);
1149
sidesAttr = null;
1150
pageRangesAttr = null;
1151
copiesAttr = 0;
1152
jobNameAttr = null;
1153
userNameAttr = null;
1154
destinationAttr = null;
1155
collateAttReq = false;
1156
1157
PrintService service = getPrintService();
1158
if (attributes == null || service == null) {
1159
return;
1160
}
1161
1162
boolean fidelity = false;
1163
Fidelity attrFidelity = (Fidelity)attributes.get(Fidelity.class);
1164
if (attrFidelity != null && attrFidelity == Fidelity.FIDELITY_TRUE) {
1165
fidelity = true;
1166
}
1167
1168
if (fidelity == true) {
1169
AttributeSet unsupported =
1170
service.getUnsupportedAttributes(
1171
DocFlavor.SERVICE_FORMATTED.PAGEABLE,
1172
attributes);
1173
if (unsupported != null) {
1174
throw new PrinterException("Fidelity cannot be satisfied");
1175
}
1176
}
1177
1178
/*
1179
* Since we have verified supported values if fidelity is true,
1180
* we can either ignore unsupported values, or substitute a
1181
* reasonable alternative
1182
*/
1183
1184
SheetCollate collateAttr =
1185
(SheetCollate)attributes.get(SheetCollate.class);
1186
if (isSupportedValue(collateAttr, attributes)) {
1187
setCollated(collateAttr == SheetCollate.COLLATED);
1188
}
1189
1190
sidesAttr = (Sides)attributes.get(Sides.class);
1191
if (!isSupportedValue(sidesAttr, attributes)) {
1192
sidesAttr = Sides.ONE_SIDED;
1193
}
1194
1195
pageRangesAttr = (PageRanges)attributes.get(PageRanges.class);
1196
if (!isSupportedValue(pageRangesAttr, attributes)) {
1197
pageRangesAttr = null;
1198
} else {
1199
if ((SunPageSelection)attributes.get(SunPageSelection.class)
1200
== SunPageSelection.RANGE) {
1201
// get to, from, min, max page ranges
1202
int[][] range = pageRangesAttr.getMembers();
1203
// setPageRanges uses 0-based indexing so we subtract 1
1204
setPageRange(range[0][0] - 1, range[0][1] - 1);
1205
} else {
1206
setPageRange(-1, - 1);
1207
}
1208
}
1209
1210
Copies copies = (Copies)attributes.get(Copies.class);
1211
if (isSupportedValue(copies, attributes) ||
1212
(!fidelity && copies != null)) {
1213
copiesAttr = copies.getValue();
1214
setCopies(copiesAttr);
1215
} else {
1216
copiesAttr = getCopies();
1217
}
1218
1219
Destination destination =
1220
(Destination)attributes.get(Destination.class);
1221
1222
if (isSupportedValue(destination, attributes)) {
1223
try {
1224
// Old code (new File(destination.getURI())).getPath()
1225
// would generate a "URI is not hierarchical" IAE
1226
// for "file:out.prn" so we use getSchemeSpecificPart instead
1227
destinationAttr = "" + new File(destination.getURI().
1228
getSchemeSpecificPart());
1229
} catch (Exception e) { // paranoid exception
1230
Destination defaultDest = (Destination)service.
1231
getDefaultAttributeValue(Destination.class);
1232
if (defaultDest != null) {
1233
destinationAttr = "" + new File(defaultDest.getURI().
1234
getSchemeSpecificPart());
1235
}
1236
}
1237
}
1238
1239
JobSheets jobSheets = (JobSheets)attributes.get(JobSheets.class);
1240
if (jobSheets != null) {
1241
noJobSheet = jobSheets == JobSheets.NONE;
1242
}
1243
1244
JobName jobName = (JobName)attributes.get(JobName.class);
1245
if (isSupportedValue(jobName, attributes) ||
1246
(!fidelity && jobName != null)) {
1247
jobNameAttr = jobName.getValue();
1248
setJobName(jobNameAttr);
1249
} else {
1250
jobNameAttr = getJobName();
1251
}
1252
1253
RequestingUserName userName =
1254
(RequestingUserName)attributes.get(RequestingUserName.class);
1255
if (isSupportedValue(userName, attributes) ||
1256
(!fidelity && userName != null)) {
1257
userNameAttr = userName.getValue();
1258
} else {
1259
try {
1260
userNameAttr = getUserName();
1261
} catch (SecurityException e) {
1262
userNameAttr = "";
1263
}
1264
}
1265
1266
/* OpenBook is used internally only when app uses Printable.
1267
* This is the case when we use the values from the attribute set.
1268
*/
1269
Media media = (Media)attributes.get(Media.class);
1270
OrientationRequested orientReq =
1271
(OrientationRequested)attributes.get(OrientationRequested.class);
1272
MediaPrintableArea mpa =
1273
(MediaPrintableArea)attributes.get(MediaPrintableArea.class);
1274
1275
if ((orientReq != null || media != null || mpa != null) &&
1276
getPageable() instanceof OpenBook) {
1277
1278
/* We could almost(!) use PrinterJob.getPageFormat() except
1279
* here we need to start with the PageFormat from the OpenBook :
1280
*/
1281
Pageable pageable = getPageable();
1282
Printable printable = pageable.getPrintable(0);
1283
PageFormat pf = (PageFormat)pageable.getPageFormat(0).clone();
1284
Paper paper = pf.getPaper();
1285
1286
/* If there's a media but no media printable area, we can try
1287
* to retrieve the default value for mpa and use that.
1288
*/
1289
if (mpa == null && media != null &&
1290
service.
1291
isAttributeCategorySupported(MediaPrintableArea.class)) {
1292
Object mpaVals = service.
1293
getSupportedAttributeValues(MediaPrintableArea.class,
1294
null, attributes);
1295
if (mpaVals instanceof MediaPrintableArea[] &&
1296
((MediaPrintableArea[])mpaVals).length > 0) {
1297
mpa = ((MediaPrintableArea[])mpaVals)[0];
1298
}
1299
}
1300
1301
if (isSupportedValue(orientReq, attributes) ||
1302
(!fidelity && orientReq != null)) {
1303
int orient;
1304
if (orientReq.equals(OrientationRequested.REVERSE_LANDSCAPE)) {
1305
orient = PageFormat.REVERSE_LANDSCAPE;
1306
} else if (orientReq.equals(OrientationRequested.LANDSCAPE)) {
1307
orient = PageFormat.LANDSCAPE;
1308
} else {
1309
orient = PageFormat.PORTRAIT;
1310
}
1311
pf.setOrientation(orient);
1312
}
1313
1314
if (isSupportedValue(media, attributes) ||
1315
(!fidelity && media != null)) {
1316
if (media instanceof MediaSizeName) {
1317
MediaSizeName msn = (MediaSizeName)media;
1318
MediaSize msz = MediaSize.getMediaSizeForName(msn);
1319
if (msz != null) {
1320
float paperWid = msz.getX(MediaSize.INCH) * 72.0f;
1321
float paperHgt = msz.getY(MediaSize.INCH) * 72.0f;
1322
paper.setSize(paperWid, paperHgt);
1323
if (mpa == null) {
1324
paper.setImageableArea(72.0, 72.0,
1325
paperWid-144.0,
1326
paperHgt-144.0);
1327
}
1328
}
1329
}
1330
}
1331
1332
if (isSupportedValue(mpa, attributes) ||
1333
(!fidelity && mpa != null)) {
1334
float [] printableArea =
1335
mpa.getPrintableArea(MediaPrintableArea.INCH);
1336
for (int i=0; i < printableArea.length; i++) {
1337
printableArea[i] = printableArea[i]*72.0f;
1338
}
1339
paper.setImageableArea(printableArea[0], printableArea[1],
1340
printableArea[2], printableArea[3]);
1341
}
1342
1343
pf.setPaper(paper);
1344
pf = validatePage(pf);
1345
setPrintable(printable, pf);
1346
} else {
1347
// for AWT where pageable is not an instance of OpenBook,
1348
// we need to save paper info
1349
this.attributes = attributes;
1350
}
1351
1352
}
1353
1354
/*
1355
* Services we don't recognize as built-in services can't be
1356
* implemented as subclasses of PrinterJob, therefore we create
1357
* a DocPrintJob from their service and pass a Doc representing
1358
* the application's printjob
1359
*/
1360
// MacOSX - made protected so subclasses can reference it.
1361
protected void spoolToService(PrintService psvc,
1362
PrintRequestAttributeSet attributes)
1363
throws PrinterException {
1364
1365
if (psvc == null) {
1366
throw new PrinterException("No print service found.");
1367
}
1368
1369
DocPrintJob job = psvc.createPrintJob();
1370
Doc doc = new PageableDoc(getPageable());
1371
if (attributes == null) {
1372
attributes = new HashPrintRequestAttributeSet();
1373
}
1374
try {
1375
job.print(doc, attributes);
1376
} catch (PrintException e) {
1377
throw new PrinterException(e.toString());
1378
}
1379
}
1380
1381
/**
1382
* Prints a set of pages.
1383
* @exception java.awt.print.PrinterException an error in the print system
1384
* caused the job to be aborted
1385
* @see java.awt.print.Book
1386
* @see java.awt.print.Pageable
1387
* @see java.awt.print.Printable
1388
*/
1389
public void print() throws PrinterException {
1390
print(attributes);
1391
}
1392
1393
public static boolean debugPrint = false;
1394
protected void debug_println(String str) {
1395
if (debugPrint) {
1396
System.out.println("RasterPrinterJob "+str+" "+this);
1397
}
1398
}
1399
1400
public void print(PrintRequestAttributeSet attributes)
1401
throws PrinterException {
1402
1403
/*
1404
* In the future PrinterJob will probably always dispatch
1405
* the print job to the PrintService.
1406
* This is how third party 2D Print Services will be invoked
1407
* when applications use the PrinterJob API.
1408
* However the JRE's concrete PrinterJob implementations have
1409
* not yet been re-worked to be implemented as standalone
1410
* services, and are implemented only as subclasses of PrinterJob.
1411
* So here we dispatch only those services we do not recognize
1412
* as implemented through platform subclasses of PrinterJob
1413
* (and this class).
1414
*/
1415
PrintService psvc = getPrintService();
1416
debug_println("psvc = "+psvc);
1417
if (psvc == null) {
1418
throw new PrinterException("No print service found.");
1419
}
1420
1421
// Check the list of services. This service may have been
1422
// deleted already
1423
PrinterState prnState = (PrinterState)psvc.getAttribute(
1424
PrinterState.class);
1425
if (prnState == PrinterState.STOPPED) {
1426
PrinterStateReasons prnStateReasons =
1427
(PrinterStateReasons)psvc.getAttribute(
1428
PrinterStateReasons.class);
1429
if ((prnStateReasons != null) &&
1430
(prnStateReasons.containsKey(PrinterStateReason.SHUTDOWN)))
1431
{
1432
throw new PrinterException("PrintService is no longer available.");
1433
}
1434
}
1435
1436
if ((PrinterIsAcceptingJobs)(psvc.getAttribute(
1437
PrinterIsAcceptingJobs.class)) ==
1438
PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) {
1439
throw new PrinterException("Printer is not accepting job.");
1440
}
1441
1442
if ((psvc instanceof SunPrinterJobService) &&
1443
((SunPrinterJobService)psvc).usesClass(getClass())) {
1444
setAttributes(attributes);
1445
// throw exception for invalid destination
1446
if (destinationAttr != null) {
1447
validateDestination(destinationAttr);
1448
}
1449
} else {
1450
spoolToService(psvc, attributes);
1451
return;
1452
}
1453
/* We need to make sure that the collation and copies
1454
* settings are initialised */
1455
initPrinter();
1456
1457
int numCollatedCopies = getCollatedCopies();
1458
int numNonCollatedCopies = getNoncollatedCopies();
1459
debug_println("getCollatedCopies() "+numCollatedCopies
1460
+ " getNoncollatedCopies() "+ numNonCollatedCopies);
1461
1462
/* Get the range of pages we are to print. If the
1463
* last page to print is unknown, then we print to
1464
* the end of the document. Note that firstPage
1465
* and lastPage are 0 based page indices.
1466
*/
1467
int numPages = mDocument.getNumberOfPages();
1468
if (numPages == 0) {
1469
return;
1470
}
1471
1472
int firstPage = getFirstPage();
1473
int lastPage = getLastPage();
1474
if(lastPage == Pageable.UNKNOWN_NUMBER_OF_PAGES){
1475
int totalPages = mDocument.getNumberOfPages();
1476
if (totalPages != Pageable.UNKNOWN_NUMBER_OF_PAGES) {
1477
lastPage = mDocument.getNumberOfPages() - 1;
1478
}
1479
}
1480
1481
try {
1482
synchronized (this) {
1483
performingPrinting = true;
1484
userCancelled = false;
1485
}
1486
1487
startDoc();
1488
if (isCancelled()) {
1489
cancelDoc();
1490
}
1491
1492
// PageRanges can be set even if RANGE is not selected
1493
// so we need to check if it is selected.
1494
boolean rangeIsSelected = true;
1495
if (attributes != null) {
1496
SunPageSelection pages =
1497
(SunPageSelection)attributes.get(SunPageSelection.class);
1498
if ((pages != null) && (pages != SunPageSelection.RANGE)) {
1499
rangeIsSelected = false;
1500
}
1501
}
1502
1503
1504
debug_println("after startDoc rangeSelected? "+rangeIsSelected
1505
+ " numNonCollatedCopies "+ numNonCollatedCopies);
1506
1507
1508
/* Three nested loops iterate over the document. The outer loop
1509
* counts the number of collated copies while the inner loop
1510
* counts the number of nonCollated copies. Normally, one of
1511
* these two loops will only execute once; that is we will
1512
* either print collated copies or noncollated copies. The
1513
* middle loop iterates over the pages.
1514
* If a PageRanges attribute is used, it constrains the pages
1515
* that are imaged. If a platform subclass (though a user dialog)
1516
* requests a page range via setPageRange(). it too can
1517
* constrain the page ranges that are imaged.
1518
* It is expected that only one of these will be used in a
1519
* job but both should be able to co-exist.
1520
*/
1521
for(int collated = 0; collated < numCollatedCopies; collated++) {
1522
for(int i = firstPage, pageResult = Printable.PAGE_EXISTS;
1523
(i <= lastPage ||
1524
lastPage == Pageable.UNKNOWN_NUMBER_OF_PAGES)
1525
&& pageResult == Printable.PAGE_EXISTS;
1526
i++)
1527
{
1528
1529
if ((pageRangesAttr != null) && rangeIsSelected ){
1530
int nexti = pageRangesAttr.next(i);
1531
if (nexti == -1) {
1532
break;
1533
} else if (nexti != i+1) {
1534
continue;
1535
}
1536
}
1537
1538
for(int nonCollated = 0;
1539
nonCollated < numNonCollatedCopies
1540
&& pageResult == Printable.PAGE_EXISTS;
1541
nonCollated++)
1542
{
1543
if (isCancelled()) {
1544
cancelDoc();
1545
}
1546
debug_println("printPage "+i);
1547
pageResult = printPage(mDocument, i);
1548
1549
}
1550
}
1551
}
1552
1553
if (isCancelled()) {
1554
cancelDoc();
1555
}
1556
1557
} finally {
1558
// reset previousPaper in case this job is invoked again.
1559
previousPaper = null;
1560
synchronized (this) {
1561
if (performingPrinting) {
1562
endDoc();
1563
}
1564
performingPrinting = false;
1565
notify();
1566
}
1567
}
1568
}
1569
1570
protected void validateDestination(String dest) throws PrinterException {
1571
if (dest == null) {
1572
return;
1573
}
1574
// dest is null for Destination(new URI(""))
1575
// because isAttributeValueSupported returns false in setAttributes
1576
1577
// Destination(new URI(" ")) throws URISyntaxException
1578
File f = new File(dest);
1579
try {
1580
// check if this is a new file and if filename chars are valid
1581
if (f.createNewFile()) {
1582
f.delete();
1583
}
1584
} catch (IOException ioe) {
1585
throw new PrinterException("Cannot write to file:"+
1586
dest);
1587
} catch (SecurityException se) {
1588
//There is already file read/write access so at this point
1589
// only delete access is denied. Just ignore it because in
1590
// most cases the file created in createNewFile gets overwritten
1591
// anyway.
1592
}
1593
1594
File pFile = f.getParentFile();
1595
if ((f.exists() &&
1596
(!f.isFile() || !f.canWrite())) ||
1597
((pFile != null) &&
1598
(!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {
1599
throw new PrinterException("Cannot write to file:"+
1600
dest);
1601
}
1602
}
1603
1604
/**
1605
* updates a Paper object to reflect the current printer's selected
1606
* paper size and imageable area for that paper size.
1607
* Default implementation copies settings from the original, applies
1608
* applies some validity checks, changes them only if they are
1609
* clearly unreasonable, then sets them into the new Paper.
1610
* Subclasses are expected to override this method to make more
1611
* informed decisons.
1612
*/
1613
protected void validatePaper(Paper origPaper, Paper newPaper) {
1614
if (origPaper == null || newPaper == null) {
1615
return;
1616
} else {
1617
double wid = origPaper.getWidth();
1618
double hgt = origPaper.getHeight();
1619
double ix = origPaper.getImageableX();
1620
double iy = origPaper.getImageableY();
1621
double iw = origPaper.getImageableWidth();
1622
double ih = origPaper.getImageableHeight();
1623
1624
/* Assume any +ve values are legal. Overall paper dimensions
1625
* take precedence. Make sure imageable area fits on the paper.
1626
*/
1627
Paper defaultPaper = new Paper();
1628
wid = ((wid > 0.0) ? wid : defaultPaper.getWidth());
1629
hgt = ((hgt > 0.0) ? hgt : defaultPaper.getHeight());
1630
ix = ((ix > 0.0) ? ix : defaultPaper.getImageableX());
1631
iy = ((iy > 0.0) ? iy : defaultPaper.getImageableY());
1632
iw = ((iw > 0.0) ? iw : defaultPaper.getImageableWidth());
1633
ih = ((ih > 0.0) ? ih : defaultPaper.getImageableHeight());
1634
/* full width/height is not likely to be imageable, but since we
1635
* don't know the limits we have to allow it
1636
*/
1637
if (iw > wid) {
1638
iw = wid;
1639
}
1640
if (ih > hgt) {
1641
ih = hgt;
1642
}
1643
if ((ix + iw) > wid) {
1644
ix = wid - iw;
1645
}
1646
if ((iy + ih) > hgt) {
1647
iy = hgt - ih;
1648
}
1649
newPaper.setSize(wid, hgt);
1650
newPaper.setImageableArea(ix, iy, iw, ih);
1651
}
1652
}
1653
1654
/**
1655
* The passed in PageFormat will be copied and altered to describe
1656
* the default page size and orientation of the PrinterJob's
1657
* current printer.
1658
* Platform subclasses which can access the actual default paper size
1659
* for a printer may override this method.
1660
*/
1661
public PageFormat defaultPage(PageFormat page) {
1662
PageFormat newPage = (PageFormat)page.clone();
1663
newPage.setOrientation(PageFormat.PORTRAIT);
1664
Paper newPaper = new Paper();
1665
double ptsPerInch = 72.0;
1666
double w, h;
1667
Media media = null;
1668
1669
PrintService service = getPrintService();
1670
if (service != null) {
1671
MediaSize size;
1672
media =
1673
(Media)service.getDefaultAttributeValue(Media.class);
1674
1675
if (media instanceof MediaSizeName &&
1676
((size = MediaSize.getMediaSizeForName((MediaSizeName)media)) !=
1677
null)) {
1678
w = size.getX(MediaSize.INCH) * ptsPerInch;
1679
h = size.getY(MediaSize.INCH) * ptsPerInch;
1680
newPaper.setSize(w, h);
1681
newPaper.setImageableArea(ptsPerInch, ptsPerInch,
1682
w - 2.0*ptsPerInch,
1683
h - 2.0*ptsPerInch);
1684
newPage.setPaper(newPaper);
1685
return newPage;
1686
1687
}
1688
}
1689
1690
/* Default to A4 paper outside North America.
1691
*/
1692
String defaultCountry = Locale.getDefault().getCountry();
1693
if (!Locale.getDefault().equals(Locale.ENGLISH) && // ie "C"
1694
defaultCountry != null &&
1695
!defaultCountry.equals(Locale.US.getCountry()) &&
1696
!defaultCountry.equals(Locale.CANADA.getCountry())) {
1697
1698
double mmPerInch = 25.4;
1699
w = Math.rint((210.0*ptsPerInch)/mmPerInch);
1700
h = Math.rint((297.0*ptsPerInch)/mmPerInch);
1701
newPaper.setSize(w, h);
1702
newPaper.setImageableArea(ptsPerInch, ptsPerInch,
1703
w - 2.0*ptsPerInch,
1704
h - 2.0*ptsPerInch);
1705
}
1706
1707
newPage.setPaper(newPaper);
1708
1709
return newPage;
1710
}
1711
1712
/**
1713
* The passed in PageFormat is cloned and altered to be usable on
1714
* the PrinterJob's current printer.
1715
*/
1716
public PageFormat validatePage(PageFormat page) {
1717
PageFormat newPage = (PageFormat)page.clone();
1718
Paper newPaper = new Paper();
1719
validatePaper(newPage.getPaper(), newPaper);
1720
newPage.setPaper(newPaper);
1721
1722
return newPage;
1723
}
1724
1725
/**
1726
* Set the number of copies to be printed.
1727
*/
1728
public void setCopies(int copies) {
1729
mNumCopies = copies;
1730
}
1731
1732
/**
1733
* Get the number of copies to be printed.
1734
*/
1735
public int getCopies() {
1736
return mNumCopies;
1737
}
1738
1739
/* Used when executing a print job where an attribute set may
1740
* over ride API values.
1741
*/
1742
protected int getCopiesInt() {
1743
return (copiesAttr > 0) ? copiesAttr : getCopies();
1744
}
1745
1746
/**
1747
* Get the name of the printing user.
1748
* The caller must have security permission to read system properties.
1749
*/
1750
public String getUserName() {
1751
return System.getProperty("user.name");
1752
}
1753
1754
/* Used when executing a print job where an attribute set may
1755
* over ride API values.
1756
*/
1757
protected String getUserNameInt() {
1758
if (userNameAttr != null) {
1759
return userNameAttr;
1760
} else {
1761
try {
1762
return getUserName();
1763
} catch (SecurityException e) {
1764
return "";
1765
}
1766
}
1767
}
1768
1769
/**
1770
* Set the name of the document to be printed.
1771
* The document name can not be null.
1772
*/
1773
public void setJobName(String jobName) {
1774
if (jobName != null) {
1775
mDocName = jobName;
1776
} else {
1777
throw new NullPointerException();
1778
}
1779
}
1780
1781
/**
1782
* Get the name of the document to be printed.
1783
*/
1784
public String getJobName() {
1785
return mDocName;
1786
}
1787
1788
/* Used when executing a print job where an attribute set may
1789
* over ride API values.
1790
*/
1791
protected String getJobNameInt() {
1792
return (jobNameAttr != null) ? jobNameAttr : getJobName();
1793
}
1794
1795
/**
1796
* Set the range of pages from a Book to be printed.
1797
* Both 'firstPage' and 'lastPage' are zero based
1798
* page indices. If either parameter is less than
1799
* zero then the page range is set to be from the
1800
* first page to the last.
1801
*/
1802
protected void setPageRange(int firstPage, int lastPage) {
1803
if(firstPage >= 0 && lastPage >= 0) {
1804
mFirstPage = firstPage;
1805
mLastPage = lastPage;
1806
if(mLastPage < mFirstPage) mLastPage = mFirstPage;
1807
} else {
1808
mFirstPage = Pageable.UNKNOWN_NUMBER_OF_PAGES;
1809
mLastPage = Pageable.UNKNOWN_NUMBER_OF_PAGES;
1810
}
1811
}
1812
1813
/**
1814
* Return the zero based index of the first page to
1815
* be printed in this job.
1816
*/
1817
protected int getFirstPage() {
1818
return mFirstPage == Book.UNKNOWN_NUMBER_OF_PAGES ? 0 : mFirstPage;
1819
}
1820
1821
/**
1822
* Return the zero based index of the last page to
1823
* be printed in this job.
1824
*/
1825
protected int getLastPage() {
1826
return mLastPage;
1827
}
1828
1829
/**
1830
* Set whether copies should be collated or not.
1831
* Two collated copies of a three page document
1832
* print in this order: 1, 2, 3, 1, 2, 3 while
1833
* uncollated copies print in this order:
1834
* 1, 1, 2, 2, 3, 3.
1835
* This is set when request is using an attribute set.
1836
*/
1837
protected void setCollated(boolean collate) {
1838
mCollate = collate;
1839
collateAttReq = true;
1840
}
1841
1842
/**
1843
* Return true if collated copies will be printed as determined
1844
* in an attribute set.
1845
*/
1846
protected boolean isCollated() {
1847
return mCollate;
1848
}
1849
1850
protected final int getSelectAttrib() {
1851
if (attributes != null) {
1852
SunPageSelection pages =
1853
(SunPageSelection)attributes.get(SunPageSelection.class);
1854
if (pages == SunPageSelection.RANGE) {
1855
return PD_PAGENUMS;
1856
} else if (pages == SunPageSelection.SELECTION) {
1857
return PD_SELECTION;
1858
} else if (pages == SunPageSelection.ALL) {
1859
return PD_ALLPAGES;
1860
}
1861
}
1862
return PD_NOSELECTION;
1863
}
1864
1865
//returns 1-based index for "From" page
1866
protected final int getFromPageAttrib() {
1867
if (attributes != null) {
1868
PageRanges pageRangesAttr =
1869
(PageRanges)attributes.get(PageRanges.class);
1870
if (pageRangesAttr != null) {
1871
int[][] range = pageRangesAttr.getMembers();
1872
return range[0][0];
1873
}
1874
}
1875
return getMinPageAttrib();
1876
}
1877
1878
//returns 1-based index for "To" page
1879
protected final int getToPageAttrib() {
1880
if (attributes != null) {
1881
PageRanges pageRangesAttr =
1882
(PageRanges)attributes.get(PageRanges.class);
1883
if (pageRangesAttr != null) {
1884
int[][] range = pageRangesAttr.getMembers();
1885
return range[range.length-1][1];
1886
}
1887
}
1888
return getMaxPageAttrib();
1889
}
1890
1891
protected final int getMinPageAttrib() {
1892
if (attributes != null) {
1893
SunMinMaxPage s =
1894
(SunMinMaxPage)attributes.get(SunMinMaxPage.class);
1895
if (s != null) {
1896
return s.getMin();
1897
}
1898
}
1899
return 1;
1900
}
1901
1902
protected final int getMaxPageAttrib() {
1903
if (attributes != null) {
1904
SunMinMaxPage s =
1905
(SunMinMaxPage)attributes.get(SunMinMaxPage.class);
1906
if (s != null) {
1907
return s.getMax();
1908
}
1909
}
1910
1911
Pageable pageable = getPageable();
1912
if (pageable != null) {
1913
int numPages = pageable.getNumberOfPages();
1914
if (numPages <= Pageable.UNKNOWN_NUMBER_OF_PAGES) {
1915
numPages = MAX_UNKNOWN_PAGES;
1916
}
1917
return ((numPages == 0) ? 1 : numPages);
1918
}
1919
1920
return Integer.MAX_VALUE;
1921
}
1922
/**
1923
* Called by the print() method at the start of
1924
* a print job.
1925
*/
1926
protected abstract void startDoc() throws PrinterException;
1927
1928
/**
1929
* Called by the print() method at the end of
1930
* a print job.
1931
*/
1932
protected abstract void endDoc() throws PrinterException;
1933
1934
/* Called by cancelDoc */
1935
protected abstract void abortDoc();
1936
1937
// MacOSX - made protected so subclasses can reference it.
1938
protected void cancelDoc() throws PrinterAbortException {
1939
abortDoc();
1940
synchronized (this) {
1941
userCancelled = false;
1942
performingPrinting = false;
1943
notify();
1944
}
1945
throw new PrinterAbortException();
1946
}
1947
1948
/**
1949
* Returns how many times the entire book should
1950
* be printed by the PrintJob. If the printer
1951
* itself supports collation then this method
1952
* should return 1 indicating that the entire
1953
* book need only be printed once and the copies
1954
* will be collated and made in the printer.
1955
*/
1956
protected int getCollatedCopies() {
1957
return isCollated() ? getCopiesInt() : 1;
1958
}
1959
1960
/**
1961
* Returns how many times each page in the book
1962
* should be consecutively printed by PrintJob.
1963
* If the printer makes copies itself then this
1964
* method should return 1.
1965
*/
1966
protected int getNoncollatedCopies() {
1967
return isCollated() ? 1 : getCopiesInt();
1968
}
1969
1970
1971
/* The printer graphics config is cached on the job, so that it can
1972
* be created once, and updated only as needed (for now only to change
1973
* the bounds if when using a Pageable the page sizes changes).
1974
*/
1975
1976
private int deviceWidth, deviceHeight;
1977
private AffineTransform defaultDeviceTransform;
1978
private PrinterGraphicsConfig pgConfig;
1979
1980
synchronized void setGraphicsConfigInfo(AffineTransform at,
1981
double pw, double ph) {
1982
Point2D.Double pt = new Point2D.Double(pw, ph);
1983
at.transform(pt, pt);
1984
1985
if (pgConfig == null ||
1986
defaultDeviceTransform == null ||
1987
!at.equals(defaultDeviceTransform) ||
1988
deviceWidth != (int)pt.getX() ||
1989
deviceHeight != (int)pt.getY()) {
1990
1991
deviceWidth = (int)pt.getX();
1992
deviceHeight = (int)pt.getY();
1993
defaultDeviceTransform = at;
1994
pgConfig = null;
1995
}
1996
}
1997
1998
synchronized PrinterGraphicsConfig getPrinterGraphicsConfig() {
1999
if (pgConfig != null) {
2000
return pgConfig;
2001
}
2002
String deviceID = "Printer Device";
2003
PrintService service = getPrintService();
2004
if (service != null) {
2005
deviceID = service.toString();
2006
}
2007
pgConfig = new PrinterGraphicsConfig(deviceID,
2008
defaultDeviceTransform,
2009
deviceWidth, deviceHeight);
2010
return pgConfig;
2011
}
2012
2013
/**
2014
* Print a page from the provided document.
2015
* @return int Printable.PAGE_EXISTS if the page existed and was drawn and
2016
* Printable.NO_SUCH_PAGE if the page did not exist.
2017
* @see java.awt.print.Printable
2018
*/
2019
protected int printPage(Pageable document, int pageIndex)
2020
throws PrinterException
2021
{
2022
PageFormat page;
2023
PageFormat origPage;
2024
Printable painter;
2025
try {
2026
origPage = document.getPageFormat(pageIndex);
2027
page = (PageFormat)origPage.clone();
2028
painter = document.getPrintable(pageIndex);
2029
} catch (Exception e) {
2030
PrinterException pe =
2031
new PrinterException("Error getting page or printable.[ " +
2032
e +" ]");
2033
pe.initCause(e);
2034
throw pe;
2035
}
2036
2037
/* Get the imageable area from Paper instead of PageFormat
2038
* because we do not want it adjusted by the page orientation.
2039
*/
2040
Paper paper = page.getPaper();
2041
// if non-portrait and 270 degree landscape rotation
2042
if (page.getOrientation() != PageFormat.PORTRAIT &&
2043
landscapeRotates270) {
2044
2045
double left = paper.getImageableX();
2046
double top = paper.getImageableY();
2047
double width = paper.getImageableWidth();
2048
double height = paper.getImageableHeight();
2049
paper.setImageableArea(paper.getWidth()-left-width,
2050
paper.getHeight()-top-height,
2051
width, height);
2052
page.setPaper(paper);
2053
if (page.getOrientation() == PageFormat.LANDSCAPE) {
2054
page.setOrientation(PageFormat.REVERSE_LANDSCAPE);
2055
} else {
2056
page.setOrientation(PageFormat.LANDSCAPE);
2057
}
2058
}
2059
2060
double xScale = getXRes() / 72.0;
2061
double yScale = getYRes() / 72.0;
2062
2063
/* The deviceArea is the imageable area in the printer's
2064
* resolution.
2065
*/
2066
Rectangle2D deviceArea =
2067
new Rectangle2D.Double(paper.getImageableX() * xScale,
2068
paper.getImageableY() * yScale,
2069
paper.getImageableWidth() * xScale,
2070
paper.getImageableHeight() * yScale);
2071
2072
/* Build and hold on to a uniform transform so that
2073
* we can get back to device space at the beginning
2074
* of each band.
2075
*/
2076
AffineTransform uniformTransform = new AffineTransform();
2077
2078
/* The scale transform is used to switch from the
2079
* device space to the user's 72 dpi space.
2080
*/
2081
AffineTransform scaleTransform = new AffineTransform();
2082
scaleTransform.scale(xScale, yScale);
2083
2084
/* bandwidth is multiple of 4 as the data is used in a win32 DIB and
2085
* some drivers behave badly if scanlines aren't multiples of 4 bytes.
2086
*/
2087
int bandWidth = (int) deviceArea.getWidth();
2088
if (bandWidth % 4 != 0) {
2089
bandWidth += (4 - (bandWidth % 4));
2090
}
2091
if (bandWidth <= 0) {
2092
throw new PrinterException("Paper's imageable width is too small.");
2093
}
2094
2095
int deviceAreaHeight = (int)deviceArea.getHeight();
2096
if (deviceAreaHeight <= 0) {
2097
throw new PrinterException("Paper's imageable height is too small.");
2098
}
2099
2100
/* Figure out the number of lines that will fit into
2101
* our maximum band size. The hard coded 3 reflects the
2102
* fact that we can only create 24 bit per pixel 3 byte BGR
2103
* BufferedImages. FIX.
2104
*/
2105
int bandHeight = (int)(MAX_BAND_SIZE / bandWidth / 3);
2106
2107
int deviceLeft = (int)Math.rint(paper.getImageableX() * xScale);
2108
int deviceTop = (int)Math.rint(paper.getImageableY() * yScale);
2109
2110
/* The device transform is used to move the band down
2111
* the page using translates. Normally this is all it
2112
* would do, but since, when printing, the Window's
2113
* DIB format wants the last line to be first (lowest) in
2114
* memory, the deviceTransform moves the origin to the
2115
* bottom of the band and flips the origin. This way the
2116
* app prints upside down into the band which is the DIB
2117
* format.
2118
*/
2119
AffineTransform deviceTransform = new AffineTransform();
2120
deviceTransform.translate(-deviceLeft, deviceTop);
2121
deviceTransform.translate(0, bandHeight);
2122
deviceTransform.scale(1, -1);
2123
2124
/* Create a BufferedImage to hold the band. We set the clip
2125
* of the band to be tight around the bits so that the
2126
* application can use it to figure what part of the
2127
* page needs to be drawn. The clip is never altered in
2128
* this method, but we do translate the band's coordinate
2129
* system so that the app will see the clip moving down the
2130
* page though it s always around the same set of pixels.
2131
*/
2132
BufferedImage pBand = new BufferedImage(1, 1,
2133
BufferedImage.TYPE_3BYTE_BGR);
2134
2135
/* Have the app draw into a PeekGraphics object so we can
2136
* learn something about the needs of the print job.
2137
*/
2138
2139
PeekGraphics peekGraphics = createPeekGraphics(pBand.createGraphics(),
2140
this);
2141
2142
Rectangle2D.Double pageFormatArea =
2143
new Rectangle2D.Double(page.getImageableX(),
2144
page.getImageableY(),
2145
page.getImageableWidth(),
2146
page.getImageableHeight());
2147
peekGraphics.transform(scaleTransform);
2148
peekGraphics.translate(-getPhysicalPrintableX(paper) / xScale,
2149
-getPhysicalPrintableY(paper) / yScale);
2150
peekGraphics.transform(new AffineTransform(page.getMatrix()));
2151
initPrinterGraphics(peekGraphics, pageFormatArea);
2152
AffineTransform pgAt = peekGraphics.getTransform();
2153
2154
/* Update the information used to return a GraphicsConfiguration
2155
* for this printer device. It needs to be updated per page as
2156
* not all pages in a job may be the same size (different bounds)
2157
* The transform is the scaling transform as this corresponds to
2158
* the default transform for the device. The width and height are
2159
* those of the paper, not the page format, as we want to describe
2160
* the bounds of the device in its natural coordinate system of
2161
* device coordinate whereas a page format may be in a rotated context.
2162
*/
2163
setGraphicsConfigInfo(scaleTransform,
2164
paper.getWidth(), paper.getHeight());
2165
int pageResult = painter.print(peekGraphics, origPage, pageIndex);
2166
debug_println("pageResult "+pageResult);
2167
if (pageResult == Printable.PAGE_EXISTS) {
2168
debug_println("startPage "+pageIndex);
2169
2170
/* We need to check if the paper size is changed.
2171
* Note that it is not sufficient to ask for the pageformat
2172
* of "pageIndex-1", since PageRanges mean that pages can be
2173
* skipped. So we have to look at the actual last paper size used.
2174
*/
2175
Paper thisPaper = page.getPaper();
2176
boolean paperChanged =
2177
previousPaper == null ||
2178
thisPaper.getWidth() != previousPaper.getWidth() ||
2179
thisPaper.getHeight() != previousPaper.getHeight();
2180
previousPaper = thisPaper;
2181
2182
startPage(page, painter, pageIndex, paperChanged);
2183
Graphics2D pathGraphics = createPathGraphics(peekGraphics, this,
2184
painter, page,
2185
pageIndex);
2186
2187
/* If we can convert the page directly to the
2188
* underlying graphics system then we do not
2189
* need to rasterize. We also may not need to
2190
* create the 'band' if all the pages can take
2191
* this path.
2192
*/
2193
if (pathGraphics != null) {
2194
pathGraphics.transform(scaleTransform);
2195
// user (0,0) should be origin of page, not imageable area
2196
pathGraphics.translate(-getPhysicalPrintableX(paper) / xScale,
2197
-getPhysicalPrintableY(paper) / yScale);
2198
pathGraphics.transform(new AffineTransform(page.getMatrix()));
2199
initPrinterGraphics(pathGraphics, pageFormatArea);
2200
2201
redrawList.clear();
2202
2203
AffineTransform initialTx = pathGraphics.getTransform();
2204
2205
painter.print(pathGraphics, origPage, pageIndex);
2206
2207
for (int i=0;i<redrawList.size();i++) {
2208
GraphicsState gstate = (GraphicsState)redrawList.get(i);
2209
pathGraphics.setTransform(initialTx);
2210
((PathGraphics)pathGraphics).redrawRegion(
2211
gstate.region,
2212
gstate.sx,
2213
gstate.sy,
2214
gstate.theClip,
2215
gstate.theTransform);
2216
}
2217
2218
/* This is the banded-raster printing loop.
2219
* It should be moved into its own method.
2220
*/
2221
} else {
2222
BufferedImage band = cachedBand;
2223
if (cachedBand == null ||
2224
bandWidth != cachedBandWidth ||
2225
bandHeight != cachedBandHeight) {
2226
band = new BufferedImage(bandWidth, bandHeight,
2227
BufferedImage.TYPE_3BYTE_BGR);
2228
cachedBand = band;
2229
cachedBandWidth = bandWidth;
2230
cachedBandHeight = bandHeight;
2231
}
2232
Graphics2D bandGraphics = band.createGraphics();
2233
2234
Rectangle2D.Double clipArea =
2235
new Rectangle2D.Double(0, 0, bandWidth, bandHeight);
2236
2237
initPrinterGraphics(bandGraphics, clipArea);
2238
2239
ProxyGraphics2D painterGraphics =
2240
new ProxyGraphics2D(bandGraphics, this);
2241
2242
Graphics2D clearGraphics = band.createGraphics();
2243
clearGraphics.setColor(Color.white);
2244
2245
/* We need the actual bits of the BufferedImage to send to
2246
* the native Window's code. 'data' points to the actual
2247
* pixels. Right now these are in ARGB format with 8 bits
2248
* per component. We need to use a monochrome BufferedImage
2249
* for monochrome printers when this is supported by
2250
* BufferedImage. FIX
2251
*/
2252
ByteInterleavedRaster tile = (ByteInterleavedRaster)band.getRaster();
2253
byte[] data = tile.getDataStorage();
2254
2255
/* Loop over the page moving our band down the page,
2256
* calling the app to render the band, and then send the band
2257
* to the printer.
2258
*/
2259
int deviceBottom = deviceTop + deviceAreaHeight;
2260
2261
/* device's printable x,y is really addressable origin
2262
* we address relative to media origin so when we print a
2263
* band we need to adjust for the different methods of
2264
* addressing it.
2265
*/
2266
int deviceAddressableX = (int)getPhysicalPrintableX(paper);
2267
int deviceAddressableY = (int)getPhysicalPrintableY(paper);
2268
2269
for (int bandTop = 0; bandTop <= deviceAreaHeight;
2270
bandTop += bandHeight)
2271
{
2272
2273
/* Put the band back into device space and
2274
* erase the contents of the band.
2275
*/
2276
clearGraphics.fillRect(0, 0, bandWidth, bandHeight);
2277
2278
/* Put the band into the correct location on the
2279
* page. Once the band is moved we translate the
2280
* device transform so that the band will move down
2281
* the page on the next iteration of the loop.
2282
*/
2283
bandGraphics.setTransform(uniformTransform);
2284
bandGraphics.transform(deviceTransform);
2285
deviceTransform.translate(0, -bandHeight);
2286
2287
/* Switch the band from device space to user,
2288
* 72 dpi, space.
2289
*/
2290
bandGraphics.transform(scaleTransform);
2291
bandGraphics.transform(new AffineTransform(page.getMatrix()));
2292
2293
Rectangle clip = bandGraphics.getClipBounds();
2294
clip = pgAt.createTransformedShape(clip).getBounds();
2295
2296
if ((clip == null) || peekGraphics.hitsDrawingArea(clip) &&
2297
(bandWidth > 0 && bandHeight > 0)) {
2298
2299
/* if the client has specified an imageable X or Y
2300
* which is off than the physically addressable
2301
* area of the page, then we need to adjust for that
2302
* here so that we pass only non -ve band coordinates
2303
* We also need to translate by the adjusted amount
2304
* so that printing appears in the correct place.
2305
*/
2306
int bandX = deviceLeft - deviceAddressableX;
2307
if (bandX < 0) {
2308
bandGraphics.translate(bandX/xScale,0);
2309
bandX = 0;
2310
}
2311
int bandY = deviceTop + bandTop - deviceAddressableY;
2312
if (bandY < 0) {
2313
bandGraphics.translate(0,bandY/yScale);
2314
bandY = 0;
2315
}
2316
/* Have the app's painter image into the band
2317
* and then send the band to the printer.
2318
*/
2319
painterGraphics.setDelegate((Graphics2D) bandGraphics.create());
2320
painter.print(painterGraphics, origPage, pageIndex);
2321
painterGraphics.dispose();
2322
printBand(data, bandX, bandY, bandWidth, bandHeight);
2323
}
2324
}
2325
2326
clearGraphics.dispose();
2327
bandGraphics.dispose();
2328
2329
}
2330
debug_println("calling endPage "+pageIndex);
2331
endPage(page, painter, pageIndex);
2332
}
2333
2334
return pageResult;
2335
}
2336
2337
/**
2338
* If a print job is in progress, print() has been
2339
* called but has not returned, then this signals
2340
* that the job should be cancelled and the next
2341
* chance. If there is no print job in progress then
2342
* this call does nothing.
2343
*/
2344
public void cancel() {
2345
synchronized (this) {
2346
if (performingPrinting) {
2347
userCancelled = true;
2348
}
2349
notify();
2350
}
2351
}
2352
2353
/**
2354
* Returns true is a print job is ongoing but will
2355
* be cancelled and the next opportunity. false is
2356
* returned otherwise.
2357
*/
2358
public boolean isCancelled() {
2359
2360
boolean cancelled = false;
2361
2362
synchronized (this) {
2363
cancelled = (performingPrinting && userCancelled);
2364
notify();
2365
}
2366
2367
return cancelled;
2368
}
2369
2370
/**
2371
* Return the Pageable describing the pages to be printed.
2372
*/
2373
protected Pageable getPageable() {
2374
return mDocument;
2375
}
2376
2377
/**
2378
* Examine the metrics captured by the
2379
* <code>PeekGraphics</code> instance and
2380
* if capable of directly converting this
2381
* print job to the printer's control language
2382
* or the native OS's graphics primitives, then
2383
* return a <code>PathGraphics</code> to perform
2384
* that conversion. If there is not an object
2385
* capable of the conversion then return
2386
* <code>null</code>. Returning <code>null</code>
2387
* causes the print job to be rasterized.
2388
*/
2389
protected Graphics2D createPathGraphics(PeekGraphics graphics,
2390
PrinterJob printerJob,
2391
Printable painter,
2392
PageFormat pageFormat,
2393
int pageIndex) {
2394
2395
return null;
2396
}
2397
2398
/**
2399
* Create and return an object that will
2400
* gather and hold metrics about the print
2401
* job. This method is passed a <code>Graphics2D</code>
2402
* object that can be used as a proxy for the
2403
* object gathering the print job matrics. The
2404
* method is also supplied with the instance
2405
* controlling the print job, <code>printerJob</code>.
2406
*/
2407
protected PeekGraphics createPeekGraphics(Graphics2D graphics,
2408
PrinterJob printerJob) {
2409
2410
return new PeekGraphics(graphics, printerJob);
2411
}
2412
2413
/**
2414
* Configure the passed in Graphics2D so that
2415
* is contains the defined initial settings
2416
* for a print job. These settings are:
2417
* color: black.
2418
* clip: <as passed in>
2419
*/
2420
// MacOSX - made protected so subclasses can reference it.
2421
protected void initPrinterGraphics(Graphics2D g, Rectangle2D clip) {
2422
2423
g.setClip(clip);
2424
g.setPaint(Color.black);
2425
}
2426
2427
2428
/**
2429
* User dialogs should disable "File" buttons if this returns false.
2430
*
2431
*/
2432
public boolean checkAllowedToPrintToFile() {
2433
try {
2434
throwPrintToFile();
2435
return true;
2436
} catch (SecurityException e) {
2437
return false;
2438
}
2439
}
2440
2441
/**
2442
* Break this out as it may be useful when we allow API to
2443
* specify printing to a file. In that case its probably right
2444
* to throw a SecurityException if the permission is not granted
2445
*/
2446
private void throwPrintToFile() {
2447
SecurityManager security = System.getSecurityManager();
2448
if (security != null) {
2449
if (printToFilePermission == null) {
2450
printToFilePermission =
2451
new FilePermission("<<ALL FILES>>", "read,write");
2452
}
2453
security.checkPermission(printToFilePermission);
2454
}
2455
}
2456
2457
/* On-screen drawString renders most control chars as the missing glyph
2458
* and have the non-zero advance of that glyph.
2459
* Exceptions are \t, \n and \r which are considered zero-width.
2460
* This is a utility method used by subclasses to remove them so we
2461
* don't have to worry about platform or font specific handling of them.
2462
*/
2463
protected String removeControlChars(String s) {
2464
char[] in_chars = s.toCharArray();
2465
int len = in_chars.length;
2466
char[] out_chars = new char[len];
2467
int pos = 0;
2468
2469
for (int i = 0; i < len; i++) {
2470
char c = in_chars[i];
2471
if (c > '\r' || c < '\t' || c == '\u000b' || c == '\u000c') {
2472
out_chars[pos++] = c;
2473
}
2474
}
2475
if (pos == len) {
2476
return s; // no need to make a new String.
2477
} else {
2478
return new String(out_chars, 0, pos);
2479
}
2480
}
2481
2482
private DialogOnTop onTop = null;
2483
2484
private long parentWindowID = 0L;
2485
2486
/* Called from native code */
2487
private long getParentWindowID() {
2488
return parentWindowID;
2489
}
2490
2491
private void clearParentWindowID() {
2492
parentWindowID = 0L;
2493
onTop = null;
2494
}
2495
2496
private void setParentWindowID(PrintRequestAttributeSet attrs) {
2497
parentWindowID = 0L;
2498
onTop = (DialogOnTop)attrs.get(DialogOnTop.class);
2499
if (onTop != null) {
2500
parentWindowID = onTop.getID();
2501
}
2502
}
2503
}
2504
2505