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