View Javadoc
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.lang.ref.SoftReference;
29  import java.util.Hashtable;
30  import sun.font.CharToGlyphMapper;
31  import sun.font.CompositeFont;
32  import sun.font.Font2D;
33  import sun.font.Font2DHandle;
34  import sun.font.FontManager;
35  import sun.font.FontManagerFactory;
36  import sun.font.FontUtilities;
37  
38  import java.awt.Color;
39  import java.awt.Font;
40  import java.awt.Graphics2D;
41  import java.awt.Image;
42  import java.awt.Paint;
43  import java.awt.Polygon;
44  import java.awt.Shape;
45  
46  import java.text.AttributedCharacterIterator;
47  
48  import java.awt.font.FontRenderContext;
49  import java.awt.font.GlyphVector;
50  import java.awt.font.TextAttribute;
51  import java.awt.font.TextLayout;
52  
53  import java.awt.geom.AffineTransform;
54  import java.awt.geom.Arc2D;
55  import java.awt.geom.Ellipse2D;
56  import java.awt.geom.Line2D;
57  import java.awt.geom.Point2D;
58  import java.awt.geom.Rectangle2D;
59  import java.awt.geom.RoundRectangle2D;
60  import java.awt.geom.PathIterator;
61  
62  import java.awt.image.BufferedImage;
63  import java.awt.image.BufferedImageOp;
64  import java.awt.image.ColorModel;
65  import java.awt.image.DataBuffer;
66  import java.awt.image.DataBufferInt;
67  import java.awt.image.ImageObserver;
68  import java.awt.image.IndexColorModel;
69  import java.awt.image.Raster;
70  import java.awt.image.RenderedImage;
71  import java.awt.image.SampleModel;
72  import java.awt.image.SinglePixelPackedSampleModel;
73  import java.awt.image.VolatileImage;
74  import sun.awt.image.ByteComponentRaster;
75  import sun.awt.image.ToolkitImage;
76  import sun.awt.image.SunWritableRaster;
77  
78  import java.awt.print.PageFormat;
79  import java.awt.print.Printable;
80  import java.awt.print.PrinterException;
81  import java.awt.print.PrinterGraphics;
82  import java.awt.print.PrinterJob;
83  
84  import java.util.Map;
85  
86  public abstract class PathGraphics extends ProxyGraphics2D {
87  
88      private Printable mPainter;
89      private PageFormat mPageFormat;
90      private int mPageIndex;
91      private boolean mCanRedraw;
92      protected boolean printingGlyphVector;
93  
94      protected PathGraphics(Graphics2D graphics, PrinterJob printerJob,
95                             Printable painter, PageFormat pageFormat,
96                             int pageIndex, boolean canRedraw) {
97          super(graphics, printerJob);
98  
99          mPainter = painter;
100         mPageFormat = pageFormat;
101         mPageIndex = pageIndex;
102         mCanRedraw = canRedraw;
103     }
104 
105     /**
106      * Return the Printable instance responsible for drawing
107      * into this Graphics.
108      */
109     protected Printable getPrintable() {
110         return mPainter;
111     }
112 
113     /**
114      * Return the PageFormat associated with this page of
115      * Graphics.
116      */
117     protected PageFormat getPageFormat() {
118         return mPageFormat;
119     }
120 
121     /**
122      * Return the page index associated with this Graphics.
123      */
124     protected int getPageIndex() {
125         return mPageIndex;
126     }
127 
128     /**
129      * Return true if we are allowed to ask the application
130      * to redraw portions of the page. In general, with the
131      * PrinterJob API, the application can be asked to do a
132      * redraw. When PrinterJob is emulating PrintJob then we
133      * can not.
134      */
135     public boolean canDoRedraws() {
136         return mCanRedraw;
137     }
138 
139      /**
140       * Redraw a rectanglular area using a proxy graphics
141       */
142     public abstract void redrawRegion(Rectangle2D region,
143                                       double scaleX, double scaleY,
144                                       Shape clip,
145                                       AffineTransform devTransform)
146 
147                     throws PrinterException ;
148 
149     /**
150      * Draws a line, using the current color, between the points
151      * <code>(x1,&nbsp;y1)</code> and <code>(x2,&nbsp;y2)</code>
152      * in this graphics context's coordinate system.
153      * @param   x1  the first point's <i>x</i> coordinate.
154      * @param   y1  the first point's <i>y</i> coordinate.
155      * @param   x2  the second point's <i>x</i> coordinate.
156      * @param   y2  the second point's <i>y</i> coordinate.
157      */
158     public void drawLine(int x1, int y1, int x2, int y2) {
159 
160         Paint paint = getPaint();
161 
162         try {
163             AffineTransform deviceTransform = getTransform();
164             if (getClip() != null) {
165                 deviceClip(getClip().getPathIterator(deviceTransform));
166             }
167 
168             deviceDrawLine(x1, y1, x2, y2, (Color) paint);
169 
170         } catch (ClassCastException e) {
171             throw new IllegalArgumentException("Expected a Color instance");
172         }
173     }
174 
175 
176     /**
177      * Draws the outline of the specified rectangle.
178      * The left and right edges of the rectangle are at
179      * <code>x</code> and <code>x&nbsp;+&nbsp;width</code>.
180      * The top and bottom edges are at
181      * <code>y</code> and <code>y&nbsp;+&nbsp;height</code>.
182      * The rectangle is drawn using the graphics context's current color.
183      * @param         x   the <i>x</i> coordinate
184      *                         of the rectangle to be drawn.
185      * @param         y   the <i>y</i> coordinate
186      *                         of the rectangle to be drawn.
187      * @param         width   the width of the rectangle to be drawn.
188      * @param         height   the height of the rectangle to be drawn.
189      * @see          java.awt.Graphics#fillRect
190      * @see          java.awt.Graphics#clearRect
191      */
192     public void drawRect(int x, int y, int width, int height) {
193 
194         Paint paint = getPaint();
195 
196         try {
197             AffineTransform deviceTransform = getTransform();
198             if (getClip() != null) {
199                 deviceClip(getClip().getPathIterator(deviceTransform));
200             }
201 
202             deviceFrameRect(x, y, width, height, (Color) paint);
203 
204         } catch (ClassCastException e) {
205             throw new IllegalArgumentException("Expected a Color instance");
206         }
207 
208     }
209 
210     /**
211      * Fills the specified rectangle.
212      * The left and right edges of the rectangle are at
213      * <code>x</code> and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>.
214      * The top and bottom edges are at
215      * <code>y</code> and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.
216      * The resulting rectangle covers an area
217      * <code>width</code> pixels wide by
218      * <code>height</code> pixels tall.
219      * The rectangle is filled using the graphics context's current color.
220      * @param         x   the <i>x</i> coordinate
221      *                         of the rectangle to be filled.
222      * @param         y   the <i>y</i> coordinate
223      *                         of the rectangle to be filled.
224      * @param         width   the width of the rectangle to be filled.
225      * @param         height   the height of the rectangle to be filled.
226      * @see           java.awt.Graphics#clearRect
227      * @see           java.awt.Graphics#drawRect
228      */
229     public void fillRect(int x, int y, int width, int height){
230 
231         Paint paint = getPaint();
232 
233         try {
234             AffineTransform deviceTransform = getTransform();
235             if (getClip() != null) {
236                 deviceClip(getClip().getPathIterator(deviceTransform));
237             }
238 
239             deviceFillRect(x, y, width, height, (Color) paint);
240 
241         } catch (ClassCastException e) {
242             throw new IllegalArgumentException("Expected a Color instance");
243         }
244     }
245 
246        /**
247      * Clears the specified rectangle by filling it with the background
248      * color of the current drawing surface. This operation does not
249      * use the current paint mode.
250      * <p>
251      * Beginning with Java&nbsp;1.1, the background color
252      * of offscreen images may be system dependent. Applications should
253      * use <code>setColor</code> followed by <code>fillRect</code> to
254      * ensure that an offscreen image is cleared to a specific color.
255      * @param       x the <i>x</i> coordinate of the rectangle to clear.
256      * @param       y the <i>y</i> coordinate of the rectangle to clear.
257      * @param       width the width of the rectangle to clear.
258      * @param       height the height of the rectangle to clear.
259      * @see         java.awt.Graphics#fillRect(int, int, int, int)
260      * @see         java.awt.Graphics#drawRect
261      * @see         java.awt.Graphics#setColor(java.awt.Color)
262      * @see         java.awt.Graphics#setPaintMode
263      * @see         java.awt.Graphics#setXORMode(java.awt.Color)
264      */
265     public void clearRect(int x, int y, int width, int height) {
266 
267         fill(new Rectangle2D.Float(x, y, width, height), getBackground());
268     }
269 
270         /**
271      * Draws an outlined round-cornered rectangle using this graphics
272      * context's current color. The left and right edges of the rectangle
273      * are at <code>x</code> and <code>x&nbsp;+&nbsp;width</code>,
274      * respectively. The top and bottom edges of the rectangle are at
275      * <code>y</code> and <code>y&nbsp;+&nbsp;height</code>.
276      * @param      x the <i>x</i> coordinate of the rectangle to be drawn.
277      * @param      y the <i>y</i> coordinate of the rectangle to be drawn.
278      * @param      width the width of the rectangle to be drawn.
279      * @param      height the height of the rectangle to be drawn.
280      * @param      arcWidth the horizontal diameter of the arc
281      *                    at the four corners.
282      * @param      arcHeight the vertical diameter of the arc
283      *                    at the four corners.
284      * @see        java.awt.Graphics#fillRoundRect
285      */
286     public void drawRoundRect(int x, int y, int width, int height,
287                               int arcWidth, int arcHeight) {
288 
289         draw(new RoundRectangle2D.Float(x, y,
290                                         width, height,
291                                         arcWidth, arcHeight));
292     }
293 
294 
295     /**
296      * Fills the specified rounded corner rectangle with the current color.
297      * The left and right edges of the rectangle
298      * are at <code>x</code> and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>,
299      * respectively. The top and bottom edges of the rectangle are at
300      * <code>y</code> and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.
301      * @param       x the <i>x</i> coordinate of the rectangle to be filled.
302      * @param       y the <i>y</i> coordinate of the rectangle to be filled.
303      * @param       width the width of the rectangle to be filled.
304      * @param       height the height of the rectangle to be filled.
305      * @param       arcWidth the horizontal diameter
306      *                     of the arc at the four corners.
307      * @param       arcHeight the vertical diameter
308      *                     of the arc at the four corners.
309      * @see         java.awt.Graphics#drawRoundRect
310      */
311     public void fillRoundRect(int x, int y, int width, int height,
312                               int arcWidth, int arcHeight) {
313 
314         fill(new RoundRectangle2D.Float(x, y,
315                                         width, height,
316                                         arcWidth, arcHeight));
317     }
318 
319     /**
320      * Draws the outline of an oval.
321      * The result is a circle or ellipse that fits within the
322      * rectangle specified by the <code>x</code>, <code>y</code>,
323      * <code>width</code>, and <code>height</code> arguments.
324      * <p>
325      * The oval covers an area that is
326      * <code>width&nbsp;+&nbsp;1</code> pixels wide
327      * and <code>height&nbsp;+&nbsp;1</code> pixels tall.
328      * @param       x the <i>x</i> coordinate of the upper left
329      *                     corner of the oval to be drawn.
330      * @param       y the <i>y</i> coordinate of the upper left
331      *                     corner of the oval to be drawn.
332      * @param       width the width of the oval to be drawn.
333      * @param       height the height of the oval to be drawn.
334      * @see         java.awt.Graphics#fillOval
335      * @since       JDK1.0
336      */
337     public void drawOval(int x, int y, int width, int height) {
338         draw(new Ellipse2D.Float(x, y, width, height));
339     }
340 
341         /**
342      * Fills an oval bounded by the specified rectangle with the
343      * current color.
344      * @param       x the <i>x</i> coordinate of the upper left corner
345      *                     of the oval to be filled.
346      * @param       y the <i>y</i> coordinate of the upper left corner
347      *                     of the oval to be filled.
348      * @param       width the width of the oval to be filled.
349      * @param       height the height of the oval to be filled.
350      * @see         java.awt.Graphics#drawOval
351      */
352     public void fillOval(int x, int y, int width, int height){
353 
354         fill(new Ellipse2D.Float(x, y, width, height));
355     }
356 
357     /**
358      * Draws the outline of a circular or elliptical arc
359      * covering the specified rectangle.
360      * <p>
361      * The resulting arc begins at <code>startAngle</code> and extends
362      * for <code>arcAngle</code> degrees, using the current color.
363      * Angles are interpreted such that 0&nbsp;degrees
364      * is at the 3&nbsp;o'clock position.
365      * A positive value indicates a counter-clockwise rotation
366      * while a negative value indicates a clockwise rotation.
367      * <p>
368      * The center of the arc is the center of the rectangle whose origin
369      * is (<i>x</i>,&nbsp;<i>y</i>) and whose size is specified by the
370      * <code>width</code> and <code>height</code> arguments.
371      * <p>
372      * The resulting arc covers an area
373      * <code>width&nbsp;+&nbsp;1</code> pixels wide
374      * by <code>height&nbsp;+&nbsp;1</code> pixels tall.
375      * <p>
376      * The angles are specified relative to the non-square extents of
377      * the bounding rectangle such that 45 degrees always falls on the
378      * line from the center of the ellipse to the upper right corner of
379      * the bounding rectangle. As a result, if the bounding rectangle is
380      * noticeably longer in one axis than the other, the angles to the
381      * start and end of the arc segment will be skewed farther along the
382      * longer axis of the bounds.
383      * @param        x the <i>x</i> coordinate of the
384      *                    upper-left corner of the arc to be drawn.
385      * @param        y the <i>y</i>  coordinate of the
386      *                    upper-left corner of the arc to be drawn.
387      * @param        width the width of the arc to be drawn.
388      * @param        height the height of the arc to be drawn.
389      * @param        startAngle the beginning angle.
390      * @param        arcAngle the angular extent of the arc,
391      *                    relative to the start angle.
392      * @see         java.awt.Graphics#fillArc
393      */
394     public void drawArc(int x, int y, int width, int height,
395                                  int startAngle, int arcAngle) {
396         draw(new Arc2D.Float(x, y, width, height,
397                              startAngle, arcAngle,
398                              Arc2D.OPEN));
399     }
400 
401 
402     /**
403      * Fills a circular or elliptical arc covering the specified rectangle.
404      * <p>
405      * The resulting arc begins at <code>startAngle</code> and extends
406      * for <code>arcAngle</code> degrees.
407      * Angles are interpreted such that 0&nbsp;degrees
408      * is at the 3&nbsp;o'clock position.
409      * A positive value indicates a counter-clockwise rotation
410      * while a negative value indicates a clockwise rotation.
411      * <p>
412      * The center of the arc is the center of the rectangle whose origin
413      * is (<i>x</i>,&nbsp;<i>y</i>) and whose size is specified by the
414      * <code>width</code> and <code>height</code> arguments.
415      * <p>
416      * The resulting arc covers an area
417      * <code>width&nbsp;+&nbsp;1</code> pixels wide
418      * by <code>height&nbsp;+&nbsp;1</code> pixels tall.
419      * <p>
420      * The angles are specified relative to the non-square extents of
421      * the bounding rectangle such that 45 degrees always falls on the
422      * line from the center of the ellipse to the upper right corner of
423      * the bounding rectangle. As a result, if the bounding rectangle is
424      * noticeably longer in one axis than the other, the angles to the
425      * start and end of the arc segment will be skewed farther along the
426      * longer axis of the bounds.
427      * @param        x the <i>x</i> coordinate of the
428      *                    upper-left corner of the arc to be filled.
429      * @param        y the <i>y</i>  coordinate of the
430      *                    upper-left corner of the arc to be filled.
431      * @param        width the width of the arc to be filled.
432      * @param        height the height of the arc to be filled.
433      * @param        startAngle the beginning angle.
434      * @param        arcAngle the angular extent of the arc,
435      *                    relative to the start angle.
436      * @see         java.awt.Graphics#drawArc
437      */
438     public void fillArc(int x, int y, int width, int height,
439                                  int startAngle, int arcAngle) {
440 
441         fill(new Arc2D.Float(x, y, width, height,
442                              startAngle, arcAngle,
443                              Arc2D.PIE));
444     }
445 
446     /**
447      * Draws a sequence of connected lines defined by
448      * arrays of <i>x</i> and <i>y</i> coordinates.
449      * Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates defines a point.
450      * The figure is not closed if the first point
451      * differs from the last point.
452      * @param       xPoints an array of <i>x</i> points
453      * @param       yPoints an array of <i>y</i> points
454      * @param       nPoints the total number of points
455      * @see         java.awt.Graphics#drawPolygon(int[], int[], int)
456      * @since       JDK1.1
457      */
458     public void drawPolyline(int xPoints[], int yPoints[],
459                              int nPoints) {
460         float fromX;
461         float fromY;
462         float toX;
463         float toY;
464 
465         if (nPoints > 0) {
466             fromX = xPoints[0];
467             fromY = yPoints[0];
468             for(int i = 1; i < nPoints; i++) {
469                 toX = xPoints[i];
470                 toY = yPoints[i];
471                 draw(new Line2D.Float(fromX, fromY, toX, toY));
472                 fromX = toX;
473                 fromY = toY;
474             }
475         }
476 
477     }
478 
479 
480     /**
481      * Draws a closed polygon defined by
482      * arrays of <i>x</i> and <i>y</i> coordinates.
483      * Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates defines a point.
484      * <p>
485      * This method draws the polygon defined by <code>nPoint</code> line
486      * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>
487      * line segments are line segments from
488      * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
489      * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for
490      * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.
491      * The figure is automatically closed by drawing a line connecting
492      * the final point to the first point, if those points are different.
493      * @param        xPoints   a an array of <code>x</code> coordinates.
494      * @param        yPoints   a an array of <code>y</code> coordinates.
495      * @param        nPoints   a the total number of points.
496      * @see          java.awt.Graphics#fillPolygon
497      * @see          java.awt.Graphics#drawPolyline
498      */
499     public void drawPolygon(int xPoints[], int yPoints[],
500                                      int nPoints) {
501 
502         draw(new Polygon(xPoints, yPoints, nPoints));
503     }
504 
505     /**
506      * Draws the outline of a polygon defined by the specified
507      * <code>Polygon</code> object.
508      * @param        p the polygon to draw.
509      * @see          java.awt.Graphics#fillPolygon
510      * @see          java.awt.Graphics#drawPolyline
511      */
512     public void drawPolygon(Polygon p) {
513         draw(p);
514     }
515 
516      /**
517      * Fills a closed polygon defined by
518      * arrays of <i>x</i> and <i>y</i> coordinates.
519      * <p>
520      * This method draws the polygon defined by <code>nPoint</code> line
521      * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>
522      * line segments are line segments from
523      * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
524      * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for
525      * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.
526      * The figure is automatically closed by drawing a line connecting
527      * the final point to the first point, if those points are different.
528      * <p>
529      * The area inside the polygon is defined using an
530      * even-odd fill rule, also known as the alternating rule.
531      * @param        xPoints   a an array of <code>x</code> coordinates.
532      * @param        yPoints   a an array of <code>y</code> coordinates.
533      * @param        nPoints   a the total number of points.
534      * @see          java.awt.Graphics#drawPolygon(int[], int[], int)
535      */
536     public void fillPolygon(int xPoints[], int yPoints[],
537                             int nPoints) {
538 
539         fill(new Polygon(xPoints, yPoints, nPoints));
540     }
541 
542 
543     /**
544      * Fills the polygon defined by the specified Polygon object with
545      * the graphics context's current color.
546      * <p>
547      * The area inside the polygon is defined using an
548      * even-odd fill rule, also known as the alternating rule.
549      * @param        p the polygon to fill.
550      * @see          java.awt.Graphics#drawPolygon(int[], int[], int)
551      */
552     public void fillPolygon(Polygon p) {
553 
554         fill(p);
555     }
556 
557     /**
558      * Draws the text given by the specified string, using this
559      * graphics context's current font and color. The baseline of the
560      * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this
561      * graphics context's coordinate system.
562      * @param       str      the string to be drawn.
563      * @param       x        the <i>x</i> coordinate.
564      * @param       y        the <i>y</i> coordinate.
565      * @see         java.awt.Graphics#drawBytes
566      * @see         java.awt.Graphics#drawChars
567      * @since       JDK1.0
568      */
569     public void drawString(String str, int x, int y) {
570         drawString(str, (float) x, (float) y);
571     }
572 
573     public void drawString(String str, float x, float y) {
574         if (str.length() == 0) {
575             return;
576         }
577         TextLayout layout =
578             new TextLayout(str, getFont(), getFontRenderContext());
579         layout.draw(this, x, y);
580     }
581 
582     protected void drawString(String str, float x, float y,
583                               Font font, FontRenderContext frc, float w) {
584         TextLayout layout =
585             new TextLayout(str, font, frc);
586         Shape textShape =
587             layout.getOutline(AffineTransform.getTranslateInstance(x, y));
588         fill(textShape);
589     }
590 
591     /**
592      * Draws the text given by the specified iterator, using this
593      * graphics context's current color. The iterator has to specify a font
594      * for each character. The baseline of the
595      * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this
596      * graphics context's coordinate system.
597      * @param       iterator the iterator whose text is to be drawn
598      * @param       x        the <i>x</i> coordinate.
599      * @param       y        the <i>y</i> coordinate.
600      * @see         java.awt.Graphics#drawBytes
601      * @see         java.awt.Graphics#drawChars
602      */
603     public void drawString(AttributedCharacterIterator iterator,
604                            int x, int y) {
605         drawString(iterator, (float) x, (float) y);
606     }
607     public void drawString(AttributedCharacterIterator iterator,
608                            float x, float y) {
609         if (iterator == null) {
610             throw
611                 new NullPointerException("attributedcharacteriterator is null");
612         }
613         TextLayout layout =
614             new TextLayout(iterator, getFontRenderContext());
615         layout.draw(this, x, y);
616     }
617 
618     /**
619      * Draws a GlyphVector.
620      * The rendering attributes applied include the clip, transform,
621      * paint or color, and composite attributes.  The GlyphVector specifies
622      * individual glyphs from a Font.
623      * @param g The GlyphVector to be drawn.
624      * @param x,y The coordinates where the glyphs should be drawn.
625      * @see #setPaint
626      * @see java.awt.Graphics#setColor
627      * @see #transform
628      * @see #setTransform
629      * @see #setComposite
630      * @see #clip
631      * @see #setClip
632      */
633     public void drawGlyphVector(GlyphVector g,
634                                 float x,
635                                 float y) {
636 
637         /* We should not reach here if printingGlyphVector is already true.
638          * Add an assert so this can be tested if need be.
639          * But also ensure that we do at least render properly by filling
640          * the outline.
641          */
642         if (printingGlyphVector) {
643             assert !printingGlyphVector; // ie false.
644             fill(g.getOutline(x, y));
645             return;
646         }
647 
648         try {
649             printingGlyphVector = true;
650             if (RasterPrinterJob.shapeTextProp ||
651                 !printedSimpleGlyphVector(g, x, y)) {
652                 fill(g.getOutline(x, y));
653             }
654         } finally {
655             printingGlyphVector = false;
656         }
657     }
658 
659     protected static SoftReference<Hashtable<Font2DHandle,Object>>
660         fontMapRef = new SoftReference<Hashtable<Font2DHandle,Object>>(null);
661 
662     protected int platformFontCount(Font font, String str) {
663         return 0;
664     }
665 
666     /**
667      * Default implementation returns false.
668      * Callers of this method must always be prepared for this,
669      * and delegate to outlines or some other solution.
670      */
671     protected boolean printGlyphVector(GlyphVector gv, float x, float y) {
672         return false;
673     }
674 
675     /* GlyphVectors are usually encountered because TextLayout is in use.
676      * Some times TextLayout is needed to handle complex text or some
677      * rendering attributes trigger it.
678      * We try to print GlyphVectors by reconstituting into a String,
679      * as that is most recoverable for applications that export to formats
680      * such as Postscript or PDF. In some cases (eg where its not complex
681      * text and its just that positions aren't what we'd expect) we print
682      * one character at a time. positioning individually.
683      * Failing that, if we can directly send glyph codes to the printer
684      * then we do that (printGlyphVector).
685      * As a last resort we return false and let the caller print as filled
686      * shapes.
687      */
688     boolean printedSimpleGlyphVector(GlyphVector g, float x, float y) {
689 
690         int flags = g.getLayoutFlags();
691 
692         /* We can't handle RTL, re-ordering, complex glyphs etc by
693          * reconstituting glyphs into a String. So if any flags besides
694          * position adjustments are set, see if we can directly
695          * print the GlyphVector as glyph codes, using the positions
696          * layout has assigned. If that fails return false;
697          */
698         if (flags != 0 && flags != GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) {
699             return printGlyphVector(g, x, y);
700         }
701 
702         Font font = g.getFont();
703         Font2D font2D = FontUtilities.getFont2D(font);
704         if (font2D.handle.font2D != font2D) {
705             /* suspicious, may be a bad font. lets bail */
706             return false;
707         }
708         Hashtable<Font2DHandle,Object> fontMap;
709         synchronized (PathGraphics.class) {
710             fontMap = fontMapRef.get();
711             if (fontMap == null) {
712                 fontMap = new Hashtable<Font2DHandle,Object>();
713                 fontMapRef =
714                     new SoftReference<Hashtable<Font2DHandle,Object>>(fontMap);
715             }
716         }
717 
718         int numGlyphs = g.getNumGlyphs();
719         int[] glyphCodes = g.getGlyphCodes(0, numGlyphs, null);
720 
721         char[] glyphToCharMap = null;
722         char[][] mapArray = null;
723         CompositeFont cf = null;
724 
725         /* Build the needed maps for this font in a synchronized block */
726         synchronized (fontMap) {
727             if (font2D instanceof CompositeFont) {
728                 cf = (CompositeFont)font2D;
729                 int numSlots = cf.getNumSlots();
730                 mapArray = (char[][])fontMap.get(font2D.handle);
731                 if (mapArray == null) {
732                     mapArray = new char[numSlots][];
733                     fontMap.put(font2D.handle, mapArray);
734                 }
735                 for (int i=0; i<numGlyphs;i++) {
736                     int slot = glyphCodes[i] >>> 24;
737                     if (slot >= numSlots) { /* shouldn't happen */
738                         return false;
739                     }
740                     if (mapArray[slot] == null) {
741                         Font2D slotFont = cf.getSlotFont(slot);
742                         char[] map = (char[])fontMap.get(slotFont.handle);
743                         if (map == null) {
744                             map = getGlyphToCharMapForFont(slotFont);
745                         }
746                         mapArray[slot] = map;
747                     }
748                 }
749             } else {
750                 glyphToCharMap = (char[])fontMap.get(font2D.handle);
751                 if (glyphToCharMap == null) {
752                     glyphToCharMap = getGlyphToCharMapForFont(font2D);
753                     fontMap.put(font2D.handle, glyphToCharMap);
754                 }
755             }
756         }
757 
758         char[] chars = new char[numGlyphs];
759         if (cf != null) {
760             for (int i=0; i<numGlyphs; i++) {
761                 int gc = glyphCodes[i];
762                 char[] map = mapArray[gc >>> 24];
763                 gc = gc & 0xffffff;
764                 if (map == null) {
765                     return false;
766                 }
767                 /* X11 symbol & dingbats fonts used only for global metrics,
768                  * so the glyph codes we have really refer to Lucida Sans
769                  * Regular.
770                  * So its possible the glyph code may appear out of range.
771                  * Note that later on we double-check the glyph codes that
772                  * we get from re-creating the GV from the string are the
773                  * same as those we started with.
774                  *
775                  * If the glyphcode is INVISIBLE_GLYPH_ID then this may
776                  * be \t, \n or \r which are mapped to that by layout.
777                  * This is a case we can handle. It doesn't matter what
778                  * character we use (we use \n) so long as layout maps it
779                  * back to this in the verification, since the invisible
780                  * glyph isn't visible :)
781                  */
782                 char ch;
783                 if (gc == CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
784                     ch = '\n';
785                 } else if (gc < 0 || gc >= map.length) {
786                     return false;
787                 } else {
788                     ch = map[gc];
789                 }
790                 if (ch != CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
791                     chars[i] = ch;
792                 } else {
793                     return false;
794                 }
795             }
796         } else {
797             for (int i=0; i<numGlyphs; i++) {
798                 int gc = glyphCodes[i];
799                 char ch;
800                 if (gc == CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
801                     ch = '\n';
802                 } else if (gc < 0 || gc >= glyphToCharMap.length) {
803                     return false;
804                 } else {
805                     ch = glyphToCharMap[gc];
806                 }
807                 if (ch != CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
808                     chars[i] = ch;
809                 } else {
810                     return false;
811                 }
812             }
813         }
814 
815         FontRenderContext gvFrc = g.getFontRenderContext();
816         GlyphVector gv2 = font.createGlyphVector(gvFrc, chars);
817         if (gv2.getNumGlyphs() != numGlyphs) {
818             return printGlyphVector(g, x, y);
819         }
820         int[] glyphCodes2 = gv2.getGlyphCodes(0, numGlyphs, null);
821         /*
822          * Needed to double-check remapping of X11 symbol & dingbats.
823          */
824         for (int i=0; i<numGlyphs; i++) {
825             if (glyphCodes[i] != glyphCodes2[i]) {
826                 return printGlyphVector(g, x, y);
827             }
828         }
829 
830         FontRenderContext g2dFrc = getFontRenderContext();
831         boolean compatibleFRC = gvFrc.equals(g2dFrc);
832         /* If differ only in specifying A-A or a translation, these are
833          * also compatible FRC's, and we can do one drawString call.
834          */
835         if (!compatibleFRC &&
836             gvFrc.usesFractionalMetrics() == g2dFrc.usesFractionalMetrics()) {
837             AffineTransform gvAT = gvFrc.getTransform();
838             AffineTransform g2dAT = getTransform();
839             double[] gvMatrix = new double[4];
840             double[] g2dMatrix = new double[4];
841             gvAT.getMatrix(gvMatrix);
842             g2dAT.getMatrix(g2dMatrix);
843             compatibleFRC = true;
844             for (int i=0;i<4;i++) {
845                 if (gvMatrix[i] != g2dMatrix[i]) {
846                     compatibleFRC = false;
847                     break;
848                 }
849             }
850         }
851 
852         String str = new String(chars, 0, numGlyphs);
853         int numFonts = platformFontCount(font, str);
854         if (numFonts == 0) {
855             return false;
856         }
857 
858         float[] positions = g.getGlyphPositions(0, numGlyphs, null);
859         boolean noPositionAdjustments =
860             ((flags & GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS) == 0) ||
861             samePositions(gv2, glyphCodes2, glyphCodes, positions);
862 
863         /* We have to consider that the application may be directly
864          * creating a GlyphVector, rather than one being created by
865          * TextLayout or indirectly from drawString. In such a case, if the
866          * font has layout attributes, the text may measure differently
867          * when we reconstitute it into a String and ask for the length that
868          * drawString would use. For example, KERNING will be applied in such
869          * a case but that Font attribute is not applied when the application
870          * directly created a GlyphVector. So in this case we need to verify
871          * that the text measures the same in both cases - ie that the
872          * layout attribute has no effect. If it does we can't always
873          * use the drawString call unless we can coerce the drawString call
874          * into measuring and displaying the string to the same length.
875          * That is the case where there is only one font used and we can
876          * specify the overall advance of the string. (See below).
877          */
878 
879         Point2D gvAdvancePt = g.getGlyphPosition(numGlyphs);
880         float gvAdvanceX = (float)gvAdvancePt.getX();
881         boolean layoutAffectsAdvance = false;
882         if (font.hasLayoutAttributes() && printingGlyphVector &&
883             noPositionAdjustments) {
884 
885             /* If TRACKING is in use then the glyph vector will report
886              * position adjustments, then that ought to be sufficient to
887              * tell us we can't just ask native to do "drawString". But layout
888              * always sets the position adjustment flag, so we don't believe
889              * it and verify the positions are really different than
890              * createGlyphVector() (with no layout) would create. However
891              * inconsistently, TRACKING is applied when creating a GlyphVector,
892              * since it doesn't actually require "layout" (even though its
893              * considered a layout attribute), it just requires a fractional
894              * tweak to the[default]advances. So we need to specifically
895              * check for tracking until such time as as we can trust
896              * the GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS bit.
897              */
898             Map<TextAttribute, ?> map = font.getAttributes();
899             Object o = map.get(TextAttribute.TRACKING);
900             boolean tracking = o != null && (o instanceof Number) &&
901                 (((Number)o).floatValue() != 0f);
902 
903             if (tracking) {
904                 noPositionAdjustments = false;
905             } else {
906                 Rectangle2D bounds = font.getStringBounds(str, gvFrc);
907                 float strAdvanceX = (float)bounds.getWidth();
908                 if (Math.abs(strAdvanceX - gvAdvanceX) > 0.00001) {
909                     layoutAffectsAdvance = true;
910                 }
911             }
912         }
913 
914         if (compatibleFRC && noPositionAdjustments && !layoutAffectsAdvance) {
915             drawString(str, x, y, font, gvFrc, 0f);
916             return true;
917         }
918 
919         /* If positions have not been explicitly assigned, we can
920          * ask the string to be drawn adjusted to this width.
921          * This call is supported only in the PS generator.
922          * GDI has API to specify the advance for each glyph in a
923          * string which could be used here too, but that is not yet
924          * implemented, and we'd need to update the signature of the
925          * drawString method to take the advances (ie relative positions)
926          * and use that instead of the width.
927          */
928         if (numFonts == 1 && canDrawStringToWidth() && noPositionAdjustments) {
929             drawString(str, x, y, font, gvFrc, gvAdvanceX);
930             return true;
931         }
932 
933         /* In some scripts chars drawn individually do not have the
934          * same representation (glyphs) as when combined with other chars.
935          * The logic here is erring on the side of caution, in particular
936          * in including supplementary characters.
937          */
938         if (FontUtilities.isComplexText(chars, 0, chars.length)) {
939             return printGlyphVector(g, x, y);
940         }
941 
942         /* If we reach here we have mapped all the glyphs back
943          * one-to-one to simple unicode chars that we know are in the font.
944          * We can call "drawChars" on each one of them in turn, setting
945          * the position based on the glyph positions.
946          * There's typically overhead in this. If numGlyphs is 'large',
947          * it may even be better to try printGlyphVector() in this case.
948          * This may be less recoverable for apps, but sophisticated apps
949          * should be able to recover the text from simple glyph vectors
950          * and we can avoid penalising the more common case - although
951          * this is already a minority case.
952          */
953         if (numGlyphs > 10 && printGlyphVector(g, x, y)) {
954             return true;
955         }
956 
957         for (int i=0; i<numGlyphs; i++) {
958             String s = new String(chars, i, 1);
959             drawString(s, x+positions[i*2], y+positions[i*2+1],
960                        font, gvFrc, 0f);
961         }
962         return true;
963     }
964 
965     /* The same codes must be in the same positions for this to return true.
966      * This would look cleaner if it took the original GV as a parameter but
967      * we already have the codes and will need to get the positions array
968      * too in most cases anyway. So its cheaper to pass them in.
969      * This call wouldn't be necessary if layout didn't always set the
970      * FLAG_HAS_POSITION_ADJUSTMENTS even if the default advances are used
971      * and there was no re-ordering (this should be fixed some day).
972      */
973     private boolean samePositions(GlyphVector gv, int[] gvcodes,
974                                   int[] origCodes, float[] origPositions) {
975 
976         int numGlyphs = gv.getNumGlyphs();
977         float[] gvpos = gv.getGlyphPositions(0, numGlyphs, null);
978 
979         /* this shouldn't happen here, but just in case */
980         if (numGlyphs != gvcodes.length ||  /* real paranoia here */
981             origCodes.length != gvcodes.length ||
982             origPositions.length != gvpos.length) {
983             return false;
984         }
985 
986         for (int i=0; i<numGlyphs; i++) {
987             if (gvcodes[i] != origCodes[i] || gvpos[i] != origPositions[i]) {
988                 return false;
989             }
990         }
991         return true;
992     }
993 
994     protected boolean canDrawStringToWidth() {
995         return false;
996     }
997 
998     /* return an array which can map glyphs back to char codes.
999      * Glyphs which aren't mapped from a simple unicode code point
1000      * will have no mapping in this array, and will be assumed to be
1001      * because of some substitution that we can't handle.
1002      */
1003     private static char[] getGlyphToCharMapForFont(Font2D font2D) {
1004         /* NB Composites report the number of glyphs in slot 0.
1005          * So if a string uses a char from a later slot, or a fallback slot,
1006          * it will not be able to use this faster path.
1007          */
1008         int numGlyphs = font2D.getNumGlyphs();
1009         int missingGlyph = font2D.getMissingGlyphCode();
1010         char[] glyphToCharMap = new char[numGlyphs];
1011         int glyph;
1012 
1013         for (int i=0;i<numGlyphs; i++) {
1014             glyphToCharMap[i] = CharToGlyphMapper.INVISIBLE_GLYPH_ID;
1015         }
1016 
1017         /* Consider refining the ranges to try to map by asking the font
1018          * what ranges it supports.
1019          * Since a glyph may be mapped by multiple code points, and this
1020          * code can't handle that, we always prefer the earlier code point.
1021          */
1022         for (char c=0; c<0xFFFF; c++) {
1023            if (c >= CharToGlyphMapper.HI_SURROGATE_START &&
1024                c <= CharToGlyphMapper.LO_SURROGATE_END) {
1025                 continue;
1026             }
1027             glyph = font2D.charToGlyph(c);
1028             if (glyph != missingGlyph &&
1029                 glyph >= 0 && glyph < numGlyphs &&
1030                 (glyphToCharMap[glyph] ==
1031                  CharToGlyphMapper.INVISIBLE_GLYPH_ID)) {
1032                 glyphToCharMap[glyph] = c;
1033             }
1034         }
1035         return glyphToCharMap;
1036     }
1037 
1038     /**
1039      * Strokes the outline of a Shape using the settings of the current
1040      * graphics state.  The rendering attributes applied include the
1041      * clip, transform, paint or color, composite and stroke attributes.
1042      * @param s The shape to be drawn.
1043      * @see #setStroke
1044      * @see #setPaint
1045      * @see java.awt.Graphics#setColor
1046      * @see #transform
1047      * @see #setTransform
1048      * @see #clip
1049      * @see #setClip
1050      * @see #setComposite
1051      */
1052     public void draw(Shape s) {
1053 
1054         fill(getStroke().createStrokedShape(s));
1055     }
1056 
1057     /**
1058      * Fills the interior of a Shape using the settings of the current
1059      * graphics state. The rendering attributes applied include the
1060      * clip, transform, paint or color, and composite.
1061      * @see #setPaint
1062      * @see java.awt.Graphics#setColor
1063      * @see #transform
1064      * @see #setTransform
1065      * @see #setComposite
1066      * @see #clip
1067      * @see #setClip
1068      */
1069     public void fill(Shape s) {
1070         Paint paint = getPaint();
1071 
1072         try {
1073             fill(s, (Color) paint);
1074 
1075         /* The PathGraphics class only supports filling with
1076          * solid colors and so we do not expect the cast of Paint
1077          * to Color to fail. If it does fail then something went
1078          * wrong, like the app draw a page with a solid color but
1079          * then redrew it with a Gradient.
1080          */
1081         } catch (ClassCastException e) {
1082             throw new IllegalArgumentException("Expected a Color instance");
1083         }
1084     }
1085 
1086     public void fill(Shape s, Color color) {
1087         AffineTransform deviceTransform = getTransform();
1088 
1089         if (getClip() != null) {
1090             deviceClip(getClip().getPathIterator(deviceTransform));
1091         }
1092         deviceFill(s.getPathIterator(deviceTransform), color);
1093     }
1094 
1095     /**
1096      * Fill the path defined by <code>pathIter</code>
1097      * with the specified color.
1098      * The path is provided in device coordinates.
1099      */
1100     protected abstract void deviceFill(PathIterator pathIter, Color color);
1101 
1102     /*
1103      * Set the clipping path to that defined by
1104      * the passed in <code>PathIterator</code>.
1105      */
1106     protected abstract void deviceClip(PathIterator pathIter);
1107 
1108     /*
1109      * Draw the outline of the rectangle without using path
1110      * if supported by platform.
1111      */
1112     protected abstract void deviceFrameRect(int x, int y,
1113                                             int width, int height,
1114                                             Color color);
1115 
1116     /*
1117      * Draw a line without using path if supported by platform.
1118      */
1119     protected abstract void deviceDrawLine(int xBegin, int yBegin,
1120                                            int xEnd, int yEnd, Color color);
1121 
1122     /*
1123      * Fill a rectangle using specified color.
1124      */
1125     protected abstract void deviceFillRect(int x, int y,
1126                                            int width, int height, Color color);
1127 
1128     /* Obtain a BI from known implementations of java.awt.Image
1129      */
1130     protected BufferedImage getBufferedImage(Image img) {
1131         if (img instanceof BufferedImage) {
1132             // Otherwise we expect a BufferedImage to behave as a standard BI
1133             return (BufferedImage)img;
1134         } else if (img instanceof ToolkitImage) {
1135             // This can be null if the image isn't loaded yet.
1136             // This is fine as in that case our caller will return
1137             // as it will only draw a fully loaded image
1138             return ((ToolkitImage)img).getBufferedImage();
1139         } else if (img instanceof VolatileImage) {
1140             // VI needs to make a new BI: this is unavoidable but
1141             // I don't expect VI's to be "huge" in any case.
1142             return ((VolatileImage)img).getSnapshot();
1143         } else {
1144             // may be null or may be some non-standard Image which
1145             // shouldn't happen as Image is implemented by the platform
1146             // not by applications
1147             // If you add a new Image implementation to the platform you
1148             // will need to support it here similarly to VI.
1149             return null;
1150         }
1151     }
1152 
1153     /**
1154      * Return true if the BufferedImage argument has non-opaque
1155      * bits in it and therefore can not be directly rendered by
1156      * GDI. Return false if the image is opaque. If this function
1157      * can not tell for sure whether the image has transparent
1158      * pixels then it assumes that it does.
1159      */
1160     protected boolean hasTransparentPixels(BufferedImage bufferedImage) {
1161         ColorModel colorModel = bufferedImage.getColorModel();
1162         boolean hasTransparency = colorModel == null
1163             ? true
1164             : colorModel.getTransparency() != ColorModel.OPAQUE;
1165 
1166         /*
1167          * For the default INT ARGB check the image to see if any pixels are
1168          * really transparent. If there are no transparent pixels then the
1169          * transparency of the color model can be ignored.
1170          * We assume that IndexColorModel images have already been
1171          * checked for transparency and will be OPAQUE unless they actually
1172          * have transparent pixels present.
1173          */
1174         if (hasTransparency && bufferedImage != null) {
1175             if (bufferedImage.getType()==BufferedImage.TYPE_INT_ARGB ||
1176                 bufferedImage.getType()==BufferedImage.TYPE_INT_ARGB_PRE) {
1177                 DataBuffer db =  bufferedImage.getRaster().getDataBuffer();
1178                 SampleModel sm = bufferedImage.getRaster().getSampleModel();
1179                 if (db instanceof DataBufferInt &&
1180                     sm instanceof SinglePixelPackedSampleModel) {
1181                     SinglePixelPackedSampleModel psm =
1182                         (SinglePixelPackedSampleModel)sm;
1183                     // Stealing the data array for reading only...
1184                     int[] int_data =
1185                         SunWritableRaster.stealData((DataBufferInt) db, 0);
1186                     int x = bufferedImage.getMinX();
1187                     int y = bufferedImage.getMinY();
1188                     int w = bufferedImage.getWidth();
1189                     int h = bufferedImage.getHeight();
1190                     int stride = psm.getScanlineStride();
1191                     boolean hastranspixel = false;
1192                     for (int j = y; j < y+h; j++) {
1193                         int yoff = j * stride;
1194                         for (int i = x; i < x+w; i++) {
1195                             if ((int_data[yoff+i] & 0xff000000)!=0xff000000 ) {
1196                                 hastranspixel = true;
1197                                 break;
1198                             }
1199                         }
1200                         if (hastranspixel) {
1201                             break;
1202                         }
1203                     }
1204                     if (hastranspixel == false) {
1205                         hasTransparency = false;
1206                     }
1207                 }
1208             }
1209         }
1210 
1211         return hasTransparency;
1212     }
1213 
1214     protected boolean isBitmaskTransparency(BufferedImage bufferedImage) {
1215         ColorModel colorModel = bufferedImage.getColorModel();
1216         return (colorModel != null &&
1217                 colorModel.getTransparency() == ColorModel.BITMASK);
1218     }
1219 
1220 
1221     /* An optimisation for the special case of ICM images which have
1222      * bitmask transparency.
1223      */
1224     protected boolean drawBitmaskImage(BufferedImage bufferedImage,
1225                                        AffineTransform xform,
1226                                        Color bgcolor,
1227                                        int srcX, int srcY,
1228                                        int srcWidth, int srcHeight) {
1229 
1230         ColorModel colorModel = bufferedImage.getColorModel();
1231         IndexColorModel icm;
1232         int [] pixels;
1233 
1234         if (!(colorModel instanceof IndexColorModel)) {
1235             return false;
1236         } else {
1237             icm = (IndexColorModel)colorModel;
1238         }
1239 
1240         if (colorModel.getTransparency() != ColorModel.BITMASK) {
1241             return false;
1242         }
1243 
1244         // to be compatible with 1.1 printing which treated b/g colors
1245         // with alpha 128 as opaque
1246         if (bgcolor != null && bgcolor.getAlpha() < 128) {
1247             return false;
1248         }
1249 
1250         if ((xform.getType()
1251              & ~( AffineTransform.TYPE_UNIFORM_SCALE
1252                   | AffineTransform.TYPE_TRANSLATION
1253                   | AffineTransform.TYPE_QUADRANT_ROTATION
1254                   )) != 0) {
1255             return false;
1256         }
1257 
1258         if ((getTransform().getType()
1259              & ~( AffineTransform.TYPE_UNIFORM_SCALE
1260                   | AffineTransform.TYPE_TRANSLATION
1261                   | AffineTransform.TYPE_QUADRANT_ROTATION
1262                   )) != 0) {
1263             return false;
1264         }
1265 
1266         BufferedImage subImage = null;
1267         Raster raster = bufferedImage.getRaster();
1268         int transpixel = icm.getTransparentPixel();
1269         byte[] alphas = new byte[icm.getMapSize()];
1270         icm.getAlphas(alphas);
1271         if (transpixel >= 0) {
1272             alphas[transpixel] = 0;
1273         }
1274 
1275         /* don't just use srcWidth & srcHeight from application - they
1276          * may exceed the extent of the image - may need to clip.
1277          * The image xform will ensure that points are still mapped properly.
1278          */
1279         int rw = raster.getWidth();
1280         int rh = raster.getHeight();
1281         if (srcX > rw || srcY > rh) {
1282             return false;
1283         }
1284         int right, bottom, wid, hgt;
1285         if (srcX+srcWidth > rw) {
1286             right = rw;
1287             wid = right - srcX;
1288         } else {
1289             right = srcX+srcWidth;
1290             wid = srcWidth;
1291         }
1292         if (srcY+srcHeight > rh) {
1293             bottom = rh;
1294             hgt = bottom - srcY;
1295         } else {
1296             bottom = srcY+srcHeight;
1297             hgt = srcHeight;
1298         }
1299         pixels = new int[wid];
1300         for (int j=srcY; j<bottom; j++) {
1301             int startx = -1;
1302             raster.getPixels(srcX, j, wid, 1, pixels);
1303             for (int i=srcX; i<right; i++) {
1304                 if (alphas[pixels[i-srcX]] == 0) {
1305                     if (startx >=0) {
1306                         subImage = bufferedImage.getSubimage(startx, j,
1307                                                              i-startx, 1);
1308                         xform.translate(startx, j);
1309                         drawImageToPlatform(subImage, xform, bgcolor,
1310                                       0, 0, i-startx, 1, true);
1311                         xform.translate(-startx, -j);
1312                         startx = -1;
1313                     }
1314                 } else if (startx < 0) {
1315                     startx = i;
1316                 }
1317             }
1318             if (startx >= 0) {
1319                 subImage = bufferedImage.getSubimage(startx, j,
1320                                                      right - startx, 1);
1321                 xform.translate(startx, j);
1322                 drawImageToPlatform(subImage, xform, bgcolor,
1323                               0, 0, right - startx, 1, true);
1324                 xform.translate(-startx, -j);
1325             }
1326         }
1327         return true;
1328     }
1329 
1330 
1331 
1332     /**
1333      * The various <code>drawImage()</code> methods for
1334      * <code>PathGraphics</code> are all decomposed
1335      * into an invocation of <code>drawImageToPlatform</code>.
1336      * The portion of the passed in image defined by
1337      * <code>srcX, srcY, srcWidth, and srcHeight</code>
1338      * is transformed by the supplied AffineTransform and
1339      * drawn using PS to the printer context.
1340      *
1341      * @param   img     The image to be drawn.
1342      *                  This method does nothing if <code>img</code> is null.
1343      * @param   xform   Used to transform the image before drawing.
1344      *                  This can be null.
1345      * @param   bgcolor This color is drawn where the image has transparent
1346      *                  pixels. If this parameter is null then the
1347      *                  pixels already in the destination should show
1348      *                  through.
1349      * @param   srcX    With srcY this defines the upper-left corner
1350      *                  of the portion of the image to be drawn.
1351      *
1352      * @param   srcY    With srcX this defines the upper-left corner
1353      *                  of the portion of the image to be drawn.
1354      * @param   srcWidth    The width of the portion of the image to
1355      *                      be drawn.
1356      * @param   srcHeight   The height of the portion of the image to
1357      *                      be drawn.
1358      * @param   handlingTransparency if being recursively called to
1359      *                    print opaque region of transparent image
1360      */
1361     protected abstract boolean
1362         drawImageToPlatform(Image img, AffineTransform xform,
1363                             Color bgcolor,
1364                             int srcX, int srcY,
1365                             int srcWidth, int srcHeight,
1366                             boolean handlingTransparency);
1367 
1368     /**
1369      * Draws as much of the specified image as is currently available.
1370      * The image is drawn with its top-left corner at
1371      * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
1372      * space. Transparent pixels in the image do not affect whatever
1373      * pixels are already there.
1374      * <p>
1375      * This method returns immediately in all cases, even if the
1376      * complete image has not yet been loaded, and it has not been dithered
1377      * and converted for the current output device.
1378      * <p>
1379      * If the image has not yet been completely loaded, then
1380      * <code>drawImage</code> returns <code>false</code>. As more of
1381      * the image becomes available, the process that draws the image notifies
1382      * the specified image observer.
1383      * @param    img the specified image to be drawn.
1384      * @param    x   the <i>x</i> coordinate.
1385      * @param    y   the <i>y</i> coordinate.
1386      * @param    observer    object to be notified as more of
1387      *                          the image is converted.
1388      * @see      java.awt.Image
1389      * @see      java.awt.image.ImageObserver
1390      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1391      * @since    JDK1.0
1392      */
1393     public boolean drawImage(Image img, int x, int y,
1394                              ImageObserver observer) {
1395 
1396         return drawImage(img, x, y, null, observer);
1397     }
1398 
1399     /**
1400      * Draws as much of the specified image as has already been scaled
1401      * to fit inside the specified rectangle.
1402      * <p>
1403      * The image is drawn inside the specified rectangle of this
1404      * graphics context's coordinate space, and is scaled if
1405      * necessary. Transparent pixels do not affect whatever pixels
1406      * are already there.
1407      * <p>
1408      * This method returns immediately in all cases, even if the
1409      * entire image has not yet been scaled, dithered, and converted
1410      * for the current output device.
1411      * If the current output representation is not yet complete, then
1412      * <code>drawImage</code> returns <code>false</code>. As more of
1413      * the image becomes available, the process that draws the image notifies
1414      * the image observer by calling its <code>imageUpdate</code> method.
1415      * <p>
1416      * A scaled version of an image will not necessarily be
1417      * available immediately just because an unscaled version of the
1418      * image has been constructed for this output device.  Each size of
1419      * the image may be cached separately and generated from the original
1420      * data in a separate image production sequence.
1421      * @param    img    the specified image to be drawn.
1422      * @param    x      the <i>x</i> coordinate.
1423      * @param    y      the <i>y</i> coordinate.
1424      * @param    width  the width of the rectangle.
1425      * @param    height the height of the rectangle.
1426      * @param    observer    object to be notified as more of
1427      *                          the image is converted.
1428      * @see      java.awt.Image
1429      * @see      java.awt.image.ImageObserver
1430      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1431      * @since    JDK1.0
1432      */
1433     public boolean drawImage(Image img, int x, int y,
1434                              int width, int height,
1435                              ImageObserver observer) {
1436 
1437         return drawImage(img, x, y, width, height, null, observer);
1438 
1439     }
1440 
1441     /*
1442      * Draws as much of the specified image as is currently available.
1443      * The image is drawn with its top-left corner at
1444      * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
1445      * space.  Transparent pixels are drawn in the specified
1446      * background color.
1447      * <p>
1448      * This operation is equivalent to filling a rectangle of the
1449      * width and height of the specified image with the given color and then
1450      * drawing the image on top of it, but possibly more efficient.
1451      * <p>
1452      * This method returns immediately in all cases, even if the
1453      * complete image has not yet been loaded, and it has not been dithered
1454      * and converted for the current output device.
1455      * <p>
1456      * If the image has not yet been completely loaded, then
1457      * <code>drawImage</code> returns <code>false</code>. As more of
1458      * the image becomes available, the process that draws the image notifies
1459      * the specified image observer.
1460      * @param    img    the specified image to be drawn.
1461      *                  This method does nothing if <code>img</code> is null.
1462      * @param    x      the <i>x</i> coordinate.
1463      * @param    y      the <i>y</i> coordinate.
1464      * @param    bgcolor the background color to paint under the
1465      *                   non-opaque portions of the image.
1466      *                   In this WPathGraphics implementation,
1467      *                   this parameter can be null in which
1468      *                   case that background is made a transparent
1469      *                   white.
1470      * @param    observer    object to be notified as more of
1471      *                          the image is converted.
1472      * @see      java.awt.Image
1473      * @see      java.awt.image.ImageObserver
1474      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1475      * @since    JDK1.0
1476      */
1477     public boolean drawImage(Image img, int x, int y,
1478                              Color bgcolor,
1479                              ImageObserver observer) {
1480 
1481         if (img == null) {
1482             return true;
1483         }
1484 
1485         boolean result;
1486         int srcWidth = img.getWidth(null);
1487         int srcHeight = img.getHeight(null);
1488 
1489         if (srcWidth < 0 || srcHeight < 0) {
1490             result = false;
1491         } else {
1492             result = drawImage(img, x, y, srcWidth, srcHeight, bgcolor, observer);
1493         }
1494 
1495         return result;
1496     }
1497 
1498     /**
1499      * Draws as much of the specified image as has already been scaled
1500      * to fit inside the specified rectangle.
1501      * <p>
1502      * The image is drawn inside the specified rectangle of this
1503      * graphics context's coordinate space, and is scaled if
1504      * necessary. Transparent pixels are drawn in the specified
1505      * background color.
1506      * This operation is equivalent to filling a rectangle of the
1507      * width and height of the specified image with the given color and then
1508      * drawing the image on top of it, but possibly more efficient.
1509      * <p>
1510      * This method returns immediately in all cases, even if the
1511      * entire image has not yet been scaled, dithered, and converted
1512      * for the current output device.
1513      * If the current output representation is not yet complete then
1514      * <code>drawImage</code> returns <code>false</code>. As more of
1515      * the image becomes available, the process that draws the image notifies
1516      * the specified image observer.
1517      * <p>
1518      * A scaled version of an image will not necessarily be
1519      * available immediately just because an unscaled version of the
1520      * image has been constructed for this output device.  Each size of
1521      * the image may be cached separately and generated from the original
1522      * data in a separate image production sequence.
1523      * @param    img       the specified image to be drawn.
1524      *                     This method does nothing if <code>img</code> is null.
1525      * @param    x         the <i>x</i> coordinate.
1526      * @param    y         the <i>y</i> coordinate.
1527      * @param    width     the width of the rectangle.
1528      * @param    height    the height of the rectangle.
1529      * @param    bgcolor   the background color to paint under the
1530      *                         non-opaque portions of the image.
1531      * @param    observer    object to be notified as more of
1532      *                          the image is converted.
1533      * @see      java.awt.Image
1534      * @see      java.awt.image.ImageObserver
1535      * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1536      * @since    JDK1.0
1537      */
1538     public boolean drawImage(Image img, int x, int y,
1539                              int width, int height,
1540                              Color bgcolor,
1541                              ImageObserver observer) {
1542 
1543         if (img == null) {
1544             return true;
1545         }
1546 
1547         boolean result;
1548         int srcWidth = img.getWidth(null);
1549         int srcHeight = img.getHeight(null);
1550 
1551         if (srcWidth < 0 || srcHeight < 0) {
1552             result = false;
1553         } else {
1554             result = drawImage(img,
1555                          x, y, x + width, y + height,
1556                          0, 0, srcWidth, srcHeight,
1557                          observer);
1558         }
1559 
1560         return result;
1561     }
1562 
1563     /**
1564      * Draws as much of the specified area of the specified image as is
1565      * currently available, scaling it on the fly to fit inside the
1566      * specified area of the destination drawable surface. Transparent pixels
1567      * do not affect whatever pixels are already there.
1568      * <p>
1569      * This method returns immediately in all cases, even if the
1570      * image area to be drawn has not yet been scaled, dithered, and converted
1571      * for the current output device.
1572      * If the current output representation is not yet complete then
1573      * <code>drawImage</code> returns <code>false</code>. As more of
1574      * the image becomes available, the process that draws the image notifies
1575      * the specified image observer.
1576      * <p>
1577      * This method always uses the unscaled version of the image
1578      * to render the scaled rectangle and performs the required
1579      * scaling on the fly. It does not use a cached, scaled version
1580      * of the image for this operation. Scaling of the image from source
1581      * to destination is performed such that the first coordinate
1582      * of the source rectangle is mapped to the first coordinate of
1583      * the destination rectangle, and the second source coordinate is
1584      * mapped to the second destination coordinate. The subimage is
1585      * scaled and flipped as needed to preserve those mappings.
1586      * @param       img the specified image to be drawn
1587      * @param       dx1 the <i>x</i> coordinate of the first corner of the
1588      *                    destination rectangle.
1589      * @param       dy1 the <i>y</i> coordinate of the first corner of the
1590      *                    destination rectangle.
1591      * @param       dx2 the <i>x</i> coordinate of the second corner of the
1592      *                    destination rectangle.
1593      * @param       dy2 the <i>y</i> coordinate of the second corner of the
1594      *                    destination rectangle.
1595      * @param       sx1 the <i>x</i> coordinate of the first corner of the
1596      *                    source rectangle.
1597      * @param       sy1 the <i>y</i> coordinate of the first corner of the
1598      *                    source rectangle.
1599      * @param       sx2 the <i>x</i> coordinate of the second corner of the
1600      *                    source rectangle.
1601      * @param       sy2 the <i>y</i> coordinate of the second corner of the
1602      *                    source rectangle.
1603      * @param       observer object to be notified as more of the image is
1604      *                    scaled and converted.
1605      * @see         java.awt.Image
1606      * @see         java.awt.image.ImageObserver
1607      * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1608      * @since       JDK1.1
1609      */
1610     public boolean drawImage(Image img,
1611                              int dx1, int dy1, int dx2, int dy2,
1612                              int sx1, int sy1, int sx2, int sy2,
1613                              ImageObserver observer) {
1614 
1615         return drawImage(img,
1616                          dx1, dy1, dx2, dy2,
1617                          sx1, sy1, sx2, sy2,
1618                          null, observer);
1619     }
1620 
1621     /**
1622      * Draws as much of the specified area of the specified image as is
1623      * currently available, scaling it on the fly to fit inside the
1624      * specified area of the destination drawable surface.
1625      * <p>
1626      * Transparent pixels are drawn in the specified background color.
1627      * This operation is equivalent to filling a rectangle of the
1628      * width and height of the specified image with the given color and then
1629      * drawing the image on top of it, but possibly more efficient.
1630      * <p>
1631      * This method returns immediately in all cases, even if the
1632      * image area to be drawn has not yet been scaled, dithered, and converted
1633      * for the current output device.
1634      * If the current output representation is not yet complete then
1635      * <code>drawImage</code> returns <code>false</code>. As more of
1636      * the image becomes available, the process that draws the image notifies
1637      * the specified image observer.
1638      * <p>
1639      * This method always uses the unscaled version of the image
1640      * to render the scaled rectangle and performs the required
1641      * scaling on the fly. It does not use a cached, scaled version
1642      * of the image for this operation. Scaling of the image from source
1643      * to destination is performed such that the first coordinate
1644      * of the source rectangle is mapped to the first coordinate of
1645      * the destination rectangle, and the second source coordinate is
1646      * mapped to the second destination coordinate. The subimage is
1647      * scaled and flipped as needed to preserve those mappings.
1648      * @param       img the specified image to be drawn
1649      *                  This method does nothing if <code>img</code> is null.
1650      * @param       dx1 the <i>x</i> coordinate of the first corner of the
1651      *                    destination rectangle.
1652      * @param       dy1 the <i>y</i> coordinate of the first corner of the
1653      *                    destination rectangle.
1654      * @param       dx2 the <i>x</i> coordinate of the second corner of the
1655      *                    destination rectangle.
1656      * @param       dy2 the <i>y</i> coordinate of the second corner of the
1657      *                    destination rectangle.
1658      * @param       sx1 the <i>x</i> coordinate of the first corner of the
1659      *                    source rectangle.
1660      * @param       sy1 the <i>y</i> coordinate of the first corner of the
1661      *                    source rectangle.
1662      * @param       sx2 the <i>x</i> coordinate of the second corner of the
1663      *                    source rectangle.
1664      * @param       sy2 the <i>y</i> coordinate of the second corner of the
1665      *                    source rectangle.
1666      * @param       bgcolor the background color to paint under the
1667      *                    non-opaque portions of the image.
1668      * @param       observer object to be notified as more of the image is
1669      *                    scaled and converted.
1670      * @see         java.awt.Image
1671      * @see         java.awt.image.ImageObserver
1672      * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
1673      * @since       JDK1.1
1674      */
1675     public boolean drawImage(Image img,
1676                              int dx1, int dy1, int dx2, int dy2,
1677                              int sx1, int sy1, int sx2, int sy2,
1678                              Color bgcolor,
1679                              ImageObserver observer) {
1680 
1681         if (img == null) {
1682             return true;
1683         }
1684         int imgWidth = img.getWidth(null);
1685         int imgHeight = img.getHeight(null);
1686 
1687         if (imgWidth < 0 || imgHeight < 0) {
1688             return true;
1689         }
1690 
1691         int srcWidth = sx2 - sx1;
1692         int srcHeight = sy2 - sy1;
1693 
1694         /* Create a transform which describes the changes
1695          * from the source coordinates to the destination
1696          * coordinates. The scaling is determined by the
1697          * ratio of the two rectangles, while the translation
1698          * comes from the difference of their origins.
1699          */
1700         float scalex = (float) (dx2 - dx1) / srcWidth;
1701         float scaley = (float) (dy2 - dy1) / srcHeight;
1702         AffineTransform xForm
1703             = new AffineTransform(scalex,
1704                                   0,
1705                                   0,
1706                                   scaley,
1707                                   dx1 - (sx1 * scalex),
1708                                   dy1 - (sy1 * scaley));
1709 
1710         /* drawImageToPlatform needs the top-left of the source area and
1711          * a positive width and height. The xform describes how to map
1712          * src->dest, so that information is not lost.
1713          */
1714         int tmp=0;
1715         if (sx2 < sx1) {
1716             tmp = sx1;
1717             sx1 = sx2;
1718             sx2 = tmp;
1719         }
1720         if (sy2 < sy1) {
1721             tmp = sy1;
1722             sy1 = sy2;
1723             sy2 = tmp;
1724         }
1725 
1726         /* if src area is beyond the bounds of the image, we must clip it.
1727          * The transform is based on the specified area, not the clipped one.
1728          */
1729         if (sx1 < 0) {
1730             sx1 = 0;
1731         } else if (sx1 > imgWidth) { // empty srcArea, nothing to draw
1732             sx1 = imgWidth;
1733         }
1734         if (sx2 < 0) { // empty srcArea, nothing to draw
1735             sx2 = 0;
1736         } else if (sx2 > imgWidth) {
1737             sx2 = imgWidth;
1738         }
1739         if (sy1 < 0) {
1740             sy1 = 0;
1741         } else if (sy1 > imgHeight) { // empty srcArea
1742             sy1 = imgHeight;
1743         }
1744         if (sy2 < 0) {  // empty srcArea
1745             sy2 = 0;
1746         } else if (sy2 > imgHeight) {
1747             sy2 = imgHeight;
1748         }
1749 
1750         srcWidth =  sx2 - sx1;
1751         srcHeight = sy2 - sy1;
1752 
1753         if (srcWidth <= 0 || srcHeight <= 0) {
1754             return true;
1755         }
1756 
1757         return drawImageToPlatform(img, xForm, bgcolor,
1758                                    sx1, sy1, srcWidth, srcHeight, false);
1759 
1760 
1761     }
1762 
1763     /**
1764      * Draws an image, applying a transform from image space into user space
1765      * before drawing.
1766      * The transformation from user space into device space is done with
1767      * the current transform in the Graphics2D.
1768      * The given transformation is applied to the image before the
1769      * transform attribute in the Graphics2D state is applied.
1770      * The rendering attributes applied include the clip, transform,
1771      * and composite attributes. Note that the result is
1772      * undefined, if the given transform is noninvertible.
1773      * @param img The image to be drawn.
1774      *            This method does nothing if <code>img</code> is null.
1775      * @param xform The transformation from image space into user space.
1776      * @param obs The image observer to be notified as more of the image
1777      * is converted.
1778      * @see #transform
1779      * @see #setTransform
1780      * @see #setComposite
1781      * @see #clip
1782      * @see #setClip
1783      */
1784     public boolean drawImage(Image img,
1785                              AffineTransform xform,
1786                              ImageObserver obs) {
1787 
1788         if (img == null) {
1789             return true;
1790         }
1791 
1792         boolean result;
1793         int srcWidth = img.getWidth(null);
1794         int srcHeight = img.getHeight(null);
1795 
1796         if (srcWidth < 0 || srcHeight < 0) {
1797             result = false;
1798         } else {
1799             result = drawImageToPlatform(img, xform, null,
1800                                          0, 0, srcWidth, srcHeight, false);
1801         }
1802 
1803         return result;
1804     }
1805 
1806     /**
1807      * Draws a BufferedImage that is filtered with a BufferedImageOp.
1808      * The rendering attributes applied include the clip, transform
1809      * and composite attributes.  This is equivalent to:
1810      * <pre>
1811      * img1 = op.filter(img, null);
1812      * drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null);
1813      * </pre>
1814      * @param op The filter to be applied to the image before drawing.
1815      * @param img The BufferedImage to be drawn.
1816      *            This method does nothing if <code>img</code> is null.
1817      * @param x,y The location in user space where the image should be drawn.
1818      * @see #transform
1819      * @see #setTransform
1820      * @see #setComposite
1821      * @see #clip
1822      * @see #setClip
1823      */
1824     public void drawImage(BufferedImage img,
1825                           BufferedImageOp op,
1826                           int x,
1827                           int y) {
1828 
1829         if (img == null) {
1830             return;
1831         }
1832 
1833         int srcWidth = img.getWidth(null);
1834         int srcHeight = img.getHeight(null);
1835 
1836         if (op != null) {
1837             img = op.filter(img, null);
1838         }
1839         if (srcWidth <= 0 || srcHeight <= 0) {
1840             return;
1841         } else {
1842             AffineTransform xform = new AffineTransform(1f,0f,0f,1f,x,y);
1843             drawImageToPlatform(img, xform, null,
1844                                 0, 0, srcWidth, srcHeight, false);
1845         }
1846 
1847     }
1848 
1849     /**
1850      * Draws an image, applying a transform from image space into user space
1851      * before drawing.
1852      * The transformation from user space into device space is done with
1853      * the current transform in the Graphics2D.
1854      * The given transformation is applied to the image before the
1855      * transform attribute in the Graphics2D state is applied.
1856      * The rendering attributes applied include the clip, transform,
1857      * and composite attributes. Note that the result is
1858      * undefined, if the given transform is noninvertible.
1859      * @param img The image to be drawn.
1860      *            This method does nothing if <code>img</code> is null.
1861      * @param xform The transformation from image space into user space.
1862      * @see #transform
1863      * @see #setTransform
1864      * @see #setComposite
1865      * @see #clip
1866      * @see #setClip
1867      */
1868     public void drawRenderedImage(RenderedImage img,
1869                                   AffineTransform xform) {
1870 
1871         if (img == null) {
1872             return;
1873         }
1874 
1875         BufferedImage bufferedImage = null;
1876         int srcWidth = img.getWidth();
1877         int srcHeight = img.getHeight();
1878 
1879         if (srcWidth <= 0 || srcHeight <= 0) {
1880             return;
1881         }
1882 
1883         if (img instanceof BufferedImage) {
1884             bufferedImage = (BufferedImage) img;
1885         } else {
1886             bufferedImage = new BufferedImage(srcWidth, srcHeight,
1887                                               BufferedImage.TYPE_INT_ARGB);
1888             Graphics2D imageGraphics = bufferedImage.createGraphics();
1889             imageGraphics.drawRenderedImage(img, xform);
1890         }
1891 
1892         drawImageToPlatform(bufferedImage, xform, null,
1893                             0, 0, srcWidth, srcHeight, false);
1894 
1895     }
1896 
1897 }