OSDN Git Service

* gnu/java/awt/peer/gtk/GdkGraphics2D.java:
[pf3gnuchains/gcc-fork.git] / libjava / gnu / java / awt / peer / gtk / GdkGraphics2D.java
1 /* GdkGraphics2D.java
2    Copyright (C) 2003 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.java.awt.peer.gtk;
40
41 import java.awt.*;
42 import java.awt.geom.*;
43 import java.awt.font.*;
44 import java.awt.color.*;
45 import java.awt.image.*;
46 import java.awt.image.renderable.*;
47 import java.util.HashMap;
48 import java.util.Map;
49
50 import java.text.AttributedCharacterIterator;
51 import java.util.Map;
52 import java.util.Stack;
53 import java.lang.Integer;
54 import gnu.java.awt.ClasspathToolkit;
55 import gnu.java.awt.peer.ClasspathFontPeer;
56 import gnu.classpath.Configuration;
57
58 public class GdkGraphics2D extends Graphics2D
59 {
60
61   //////////////////////////////////////
62   ////// State Management Methods //////
63   //////////////////////////////////////
64
65   static 
66   {
67     if (Configuration.INIT_LOAD_LIBRARY)
68       {
69         System.loadLibrary("gtkpeer");
70       }
71
72     if (GtkToolkit.useGraphics2D ())
73       initStaticState ();
74   }
75   native static void initStaticState ();
76   private final int native_state = GtkGenericPeer.getUniqueInteger();  
77
78   private Paint paint;
79   private Stroke stroke;
80   private Color fg;
81   private Color bg;
82   private Shape clip;
83   private AffineTransform transform;
84   private GtkComponentPeer component;
85   private Font font;  
86   private RenderingHints hints;
87
88   private Stack stateStack;
89   
90   native private int[] initState (GtkComponentPeer component);
91   native private void initState (int width, int height);
92   native private void copyState (GdkGraphics2D g);
93   native public void dispose ();
94
95   public void finalize ()
96   {
97     dispose();
98   }
99
100   public Graphics create ()
101   {
102     return new GdkGraphics2D (this);
103   }
104
105   public Graphics create (int x, int y, int width, int height)
106   {
107     return new GdkGraphics2D (width, height);
108   }
109
110   GdkGraphics2D (GdkGraphics2D g)
111   {
112     paint = g.paint;
113     stroke = g.stroke;
114     hints = g.hints;
115
116     if (g.fg.getAlpha() != -1)
117       fg = new Color (g.fg.getRed (), g.fg.getGreen (), 
118                       g.fg.getBlue (), g.fg.getAlpha ());
119     else 
120       fg = new Color (g.fg.getRGB ());
121
122     if (g.bg.getAlpha() != -1)
123       bg = new Color(g.bg.getRed (), g.bg.getGreen (), 
124                      g.bg.getBlue (), g.bg.getAlpha ());
125     else
126       bg = new Color (g.bg.getRGB ());
127
128     if (g.clip == null)
129       clip = null;
130     else
131       clip = new Rectangle (g.getClipBounds ());
132
133     if (g.transform == null)
134       transform = new AffineTransform ();
135     else
136       transform = new AffineTransform (g.transform);
137
138     font = g.font;
139     component = g.component;
140     copyState (g);
141
142     setColor (fg);
143     setBackground (bg);
144     setPaint (paint);
145     setStroke (stroke);
146     setClip (clip);
147     setTransform (transform);
148     stateStack = new Stack();
149   }
150
151   GdkGraphics2D (int width, int height)
152   {
153     initState (width, height);
154
155     setColor(Color.black);
156     setBackground (Color.black);
157     setPaint (getColor());
158     setFont (new Font("SansSerif", Font.PLAIN, 12));
159     setTransform (new AffineTransform ());
160     setStroke (new BasicStroke ());
161     setRenderingHints (new HashMap ());
162
163     stateStack = new Stack();
164   }
165
166   GdkGraphics2D (GtkComponentPeer component)
167   {
168     this.component = component;
169     int rgb[] = initState (component);
170
171     setColor (new Color (rgb[0], rgb[1], rgb[2]));
172     setBackground (new Color (rgb[3], rgb[4], rgb[5]));
173     setPaint (getColor());
174     setFont (new Font("SansSerif", Font.PLAIN, 12));
175     setTransform (new AffineTransform ());
176     setStroke (new BasicStroke ());
177     setRenderingHints (new HashMap ());
178
179     stateStack = new Stack ();
180   }
181
182
183   ////////////////////////////////////
184   ////// Native Drawing Methods //////
185   ////////////////////////////////////
186
187   // GDK drawing methods
188   private native void gdkDrawDrawable (GdkGraphics2D other, int x, int y);
189
190   // drawing utility methods
191   private native void drawPixels (int pixels[], int w, int h, int stride, double i2u[]);
192   private native void setTexturePixels (int pixels[], int w, int h, int stride);
193   private native void setGradient (double x1, double y1,
194                                    double x2, double y2,
195                                    int r1, int g1, int b1, int a1,
196                                    int r2, int g2, int b2, int a2,
197                                    boolean cyclic);
198
199   // simple passthroughs to cairo
200   private native void cairoSave ();
201   private native void cairoRestore ();
202   private native void cairoSetMatrix (double m[]);
203   private native void cairoSetFont (GdkClasspathFontPeer peer);
204   private native void cairoShowGlyphs (int codes[],
205                                        float positions[]);
206   private native void cairoSetOperator (int cairoOperator);
207   private native void cairoSetRGBColor (double red, double green, double blue);
208   private native void cairoSetAlpha (double alpha);
209   private native void cairoSetFillRule (int cairoFillRule);
210   private native void cairoSetLineWidth (double width);
211   private native void cairoSetLineCap (int cairoLineCap);
212   private native void cairoSetLineJoin (int cairoLineJoin);
213   private native void cairoSetDash (double dashes[], int ndash, double offset);
214   private native void cairoSetMiterLimit (double limit);
215   private native void cairoNewPath ();
216   private native void cairoMoveTo (double x, double y);
217   private native void cairoLineTo (double x, double y);
218   private native void cairoCurveTo (double x1, double y1,
219                                     double x2, double y2,
220                                     double x3, double y3);  
221   private native void cairoRelMoveTo (double dx, double dy);
222   private native void cairoRelLineTo (double dx, double dy);
223   private native void cairoRelCurveTo (double dx1, double dy1,
224                                        double dx2, double dy2,
225                                        double dx3, double dy3);
226   private native void cairoRectangle (double x, double y, 
227                                    double width, double height);
228   private native void cairoClosePath ();
229   private native void cairoStroke ();
230   private native void cairoFill ();
231   private native void cairoClip ();
232
233
234   /////////////////////////////////////////////
235   ////// General Drawing Support Methods //////
236   /////////////////////////////////////////////
237
238     private class DrawState
239     {
240         private Paint paint;
241         private Stroke stroke;
242         private Color fg;
243         private Color bg;
244         private Shape clip;
245         private AffineTransform transform;
246         private Font font;  
247         DrawState (GdkGraphics2D g)
248         {
249             this.paint = g.paint;
250             this.stroke = g.stroke;
251             this.fg = g.fg;
252             this.bg = g.bg;
253             this.clip = g.clip;
254             if (g.transform != null)
255                 this.transform = (AffineTransform) g.transform.clone();
256             this.font = g.font;
257         }
258         public void restore(GdkGraphics2D g)
259         {
260             g.paint = this.paint;
261             g.stroke = this.stroke;
262             g.fg = this.fg;
263             g.bg = this.bg;
264             g.clip = this.clip;
265             g.transform = this.transform;
266             g.font = this.font;
267         }
268     }
269     
270     private void stateSave ()
271     {
272         stateStack.push (new DrawState (this));
273         cairoSave ();
274     }
275
276     private void stateRestore ()
277     {
278         ((DrawState)(stateStack.pop ())).restore (this);
279         cairoRestore ();
280     }
281
282
283   double x;
284   double y;
285   private void setPos (double nx, double ny)
286   {
287     x = nx;
288     y = ny;
289   }
290
291   private void walkPath(PathIterator p)
292   {
293     double coords[] = new double[6];
294
295     cairoSetFillRule (p.getWindingRule ());
296     for ( ; ! p.isDone (); p.next())
297       {
298         int seg = p.currentSegment (coords);
299         switch(seg)
300           {
301
302           case PathIterator.SEG_MOVETO:
303             setPos(coords[0], coords[1]);
304             cairoMoveTo (coords[0], coords[1]);
305             break;
306
307           case PathIterator.SEG_LINETO:
308             setPos(coords[0], coords[1]);
309             cairoLineTo (coords[0], coords[1]);
310             break;
311
312           case PathIterator.SEG_QUADTO:
313
314             // splitting a quadratic bezier into a cubic:
315             // see: http://pfaedit.sourceforge.net/bezier.html
316
317             double x1 = x + (2.0/3.0) * (coords[0] - x);
318             double y1 = y + (2.0/3.0) * (coords[1] - y);
319             
320             double x2 = x1 + (1.0/3.0) * (coords[2] - x);
321             double y2 = y1 + (1.0/3.0) * (coords[3] - y);
322
323             setPos(coords[2], coords[3]);
324             cairoCurveTo (x1, y1,
325                           x2, y2,
326                           coords[2], coords[3]);
327             break;
328
329           case PathIterator.SEG_CUBICTO:
330             setPos(coords[4], coords[5]);
331             cairoCurveTo (coords[0], coords[1],
332                           coords[2], coords[3],
333                           coords[4], coords[5]);
334             break;
335
336           case PathIterator.SEG_CLOSE:
337             cairoClosePath ();
338             break;
339           }
340       }    
341   }
342
343
344   private Map getDefaultHints()
345   {
346     HashMap defaultHints = new HashMap ();
347     
348     defaultHints.put (RenderingHints.KEY_TEXT_ANTIALIASING, 
349                       RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
350                       
351     defaultHints.put (RenderingHints.KEY_STROKE_CONTROL, 
352                       RenderingHints.VALUE_STROKE_DEFAULT);    
353                       
354     defaultHints.put (RenderingHints.KEY_FRACTIONALMETRICS, 
355                       RenderingHints.VALUE_FRACTIONALMETRICS_OFF);    
356                       
357     defaultHints.put (RenderingHints.KEY_ANTIALIASING, 
358                       RenderingHints.VALUE_ANTIALIAS_OFF);    
359                       
360     defaultHints.put (RenderingHints.KEY_RENDERING,  
361                       RenderingHints.VALUE_RENDER_DEFAULT);
362     
363     return defaultHints;
364     
365   }
366
367   //////////////////////////////////////////////////
368   ////// Implementation of Graphics2D Methods //////
369   //////////////////////////////////////////////////
370
371   public void draw (Shape s)
372   {
373
374     if (stroke != null &&
375         !(stroke instanceof BasicStroke))
376       {
377         fill (stroke.createStrokedShape (s));
378         return;
379       }
380
381     stateSave ();
382     cairoNewPath ();
383
384     boolean normalize;
385     normalize = hints.containsValue (RenderingHints.VALUE_STROKE_NORMALIZE)
386                 || hints.containsValue (RenderingHints.VALUE_STROKE_DEFAULT);
387
388     if (normalize)
389       translate (0.5,0.5);      
390     
391     if (s instanceof Rectangle2D)
392       {
393         Rectangle2D r = (Rectangle2D)s;
394         cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
395       }
396     else      
397       walkPath (s.getPathIterator (null));
398     cairoStroke ();
399     
400     if (normalize)
401       translate (-0.5,-0.5);
402       
403     stateRestore ();
404   }
405
406   public void fill (Shape s)
407   {
408     stateSave();
409     cairoNewPath ();
410     if (s instanceof Rectangle2D)
411       {
412         Rectangle2D r = (Rectangle2D)s;
413         cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
414       }
415     else      
416       walkPath (s.getPathIterator (null));
417     cairoFill ();
418     stateRestore ();
419   }
420
421   public void clip (Shape s)
422   {
423       // update it
424
425       if (clip == null || s == null)
426           clip = s;
427       else if (s instanceof Rectangle2D
428                && clip instanceof Rectangle2D)
429           {
430               Rectangle2D r = (Rectangle2D)s;
431               Rectangle2D curr = (Rectangle2D)clip;
432               clip = curr.createIntersection (r);
433           }
434       else
435           throw new UnsupportedOperationException ();
436
437       // draw it
438       if (clip != null)
439           {
440               cairoNewPath ();
441               if (clip instanceof Rectangle2D)
442                   {
443                       Rectangle2D r = (Rectangle2D)clip;
444                       cairoRectangle (r.getX (), r.getY (), 
445                                       r.getWidth (), r.getHeight ());
446                   }
447               else
448                   walkPath (clip.getPathIterator (null));
449               cairoClosePath ();
450               cairoClip ();
451           }
452   }
453
454   public Paint getPaint ()
455   {
456     return paint;
457   }
458
459   public AffineTransform getTransform ()
460   {
461       return (AffineTransform) transform.clone ();
462   }
463
464   public void setPaint (Paint p)
465   {
466     if (paint == null)
467         return;
468       
469     paint = p;
470     if (paint instanceof Color)
471       {
472         setColor ((Color) paint);
473       }
474     else if (paint instanceof TexturePaint)
475       {
476         TexturePaint tp = (TexturePaint) paint;
477         BufferedImage img = tp.getImage ();
478         int pixels[] = img.getRGB(0, 0, img.getWidth (), 
479                                   img.getHeight (), null, 
480                                   0, img.getWidth ());
481         setTexturePixels (pixels, img.getWidth (), 
482                           img.getHeight (), img.getWidth ());
483       }
484     else if (paint instanceof GradientPaint)
485       {
486         GradientPaint gp = (GradientPaint) paint;
487         Point2D p1 = gp.getPoint1 ();
488         Point2D p2 = gp.getPoint2 ();
489         Color c1 = gp.getColor1 ();
490         Color c2 = gp.getColor2 ();        
491         setGradient (p1.getX (), p1.getY (),
492                      p2.getX (), p2.getY (),
493                      c1.getRed (), c1.getGreen (), 
494                      c1.getBlue (), c1.getAlpha (),
495                      c2.getRed (), c2.getGreen (), 
496                      c2.getBlue (), c2.getAlpha (),
497                      gp.isCyclic ());
498       }
499     else
500       throw new java.lang.UnsupportedOperationException ();
501   }
502
503   public void setTransform (AffineTransform tx)
504   {
505     transform = tx;
506     if (transform != null)
507       {
508         double m[] = new double[6];
509         transform.getMatrix (m);
510         cairoSetMatrix (m);
511       }
512   }
513
514   public void transform (AffineTransform tx)
515   {
516     if (transform == null)
517       transform = new AffineTransform (tx);
518     else
519       transform.concatenate (tx);
520     setTransform (transform);
521   }
522
523   public void rotate(double theta)
524   {
525     transform (AffineTransform.getRotateInstance (theta));
526   }
527
528   public void rotate(double theta, double x, double y)
529   {
530     transform (AffineTransform.getRotateInstance (theta, x, y));
531   }
532
533   public void scale(double sx, double sy)
534   {
535     transform (AffineTransform.getScaleInstance (sx, sy));
536   }
537
538   public void translate (double tx, double ty)
539   {
540     transform (AffineTransform.getTranslateInstance (tx, ty));
541   }
542
543   public void translate (int x, int y)
544   {
545     translate ((double) x, (double) y);
546   }
547
548   public void shear(double shearX, double shearY)
549   {
550     transform (AffineTransform.getShearInstance (shearX, shearY));
551   }
552
553   public Stroke getStroke()
554   {
555     return stroke;
556   }
557
558   public void setStroke (Stroke st)
559   {
560     stroke = st;
561     if (stroke instanceof BasicStroke)
562       {
563         BasicStroke bs = (BasicStroke) stroke;
564         cairoSetLineCap (bs.getEndCap());
565         cairoSetLineWidth (bs.getLineWidth() / 2.0);
566         cairoSetLineJoin (bs.getLineJoin());
567         cairoSetMiterLimit (bs.getMiterLimit());
568         float dashes[] = bs.getDashArray();
569         if (dashes != null)
570           {
571             double double_dashes[] = new double[dashes.length];
572             for (int i = 0; i < dashes.length; i++)
573               double_dashes[i] = dashes[i];
574             cairoSetDash (double_dashes, double_dashes.length, 
575                           (double) bs.getDashPhase ());        
576           }
577       }
578   }
579
580
581   ////////////////////////////////////////////////
582   ////// Implementation of Graphics Methods //////
583   ////////////////////////////////////////////////
584
585   public void setPaintMode () 
586   { 
587     setComposite (java.awt.AlphaComposite.SrcOver); 
588   }
589
590   public void setXORMode (Color c) 
591   { 
592     setComposite (new gnu.java.awt.BitwiseXORComposite(c)); 
593   }
594
595   public void setColor (Color c)
596   {
597     fg = c;
598     paint = c;
599     cairoSetRGBColor (fg.getRed() / 255.0, 
600                       fg.getGreen() / 255.0, 
601                       fg.getBlue() / 255.0);
602     cairoSetAlpha ((fg.getAlpha() & 255) / 255.0);
603   }
604
605   public Color getColor ()
606   {
607     return fg;
608   }
609
610   public void clipRect (int x, int y, int width, int height)
611   {
612       clip (new Rectangle (x, y, width, height));
613   }
614
615   public Shape getClip ()
616   {
617     return getClipInDevSpace ();
618   }
619
620   public Rectangle getClipBounds ()
621   {
622     if (clip == null)
623       return null;
624     else
625       return clip.getBounds ();
626   }
627
628     protected Rectangle2D getClipInDevSpace ()
629     {
630         Rectangle2D uclip = clip.getBounds2D ();
631         if (transform == null)
632             return uclip;
633         else
634             {
635                 Point2D pos = transform.transform (new Point2D.Double(uclip.getX (), 
636                                                                       uclip.getY ()), 
637                                                    (Point2D)null);              
638                 Point2D extent = transform.deltaTransform (new Point2D.Double(uclip.getWidth (), 
639                                                                               uclip.getHeight ()), 
640                                                            (Point2D)null);
641                 return new Rectangle2D.Double (pos.getX (), pos.getY (),
642                                                extent.getX (), extent.getY ());       
643             }
644     }
645
646   public void setClip (int x, int y, int width, int height)
647   {
648       cairoNewPath ();
649       cairoRectangle (x, y, width, height);
650       cairoClosePath ();
651       cairoClip ();
652       clip = new Rectangle2D.Double ((double)x, (double)y, 
653                                      (double)width, (double)height);
654   }
655
656   public void setClip (Shape s)
657   {
658     clip (s);
659   }
660
661   public void draw3DRect(int x, int y, int width, 
662                          int height, boolean raised)
663   {
664     Color std = fg;
665     Color light = std.brighter();
666     Color dark = std.darker();
667
668     if (!raised)
669       {
670         Color t = light;
671         light = dark;
672         dark = t;
673       }
674     
675     double x1 = (double) x;
676     double x2 = (double) x + width;
677
678     double y1 = (double) y;
679     double y2 = (double) y + height;
680
681     stateSave ();
682     
683     cairoNewPath ();
684     
685     boolean normalize;
686     normalize = hints.containsValue (RenderingHints.VALUE_STROKE_NORMALIZE)
687                 || hints.containsValue (RenderingHints.VALUE_STROKE_DEFAULT);
688                 
689     if (normalize) 
690       {
691         x1 += 0.5;
692         y1 += 0.5; 
693         x2 += 0.5;
694         y2 += 0.5; 
695       }
696     
697     setColor (light);
698     cairoMoveTo (x1, y1);
699     cairoLineTo (x2, y1);
700     cairoLineTo (x2, y2);
701     cairoStroke ();
702     
703     cairoNewPath ();
704     setColor (dark);
705     cairoMoveTo (x1, y1);
706     cairoLineTo (x1, y2);
707     cairoLineTo (x2, y2);
708     cairoStroke ();
709     
710     stateRestore ();    
711   }
712
713   public void fill3DRect(int x, int y, int width, 
714                          int height, boolean raised)
715   {
716     double step = 1.0;
717     if (stroke != null && stroke instanceof BasicStroke)
718       {
719         BasicStroke bs = (BasicStroke) stroke;
720         step = bs.getLineWidth();
721       }
722
723     Color bright = fg.brighter ();
724     Color dark = fg.darker ();
725       
726     draw3DRect (x, y, width, height, raised);
727     
728     stateSave ();
729     translate (step/2.0, step/2.0);
730     cairoNewPath ();
731     cairoRectangle ((double) x, (double) y, 
732                     ((double) width) - step, 
733                     ((double) height) - step );
734     cairoClosePath ();
735     cairoFill ();
736     stateRestore ();
737   }
738
739
740   public void drawRect (int x, int y, int width, int height)
741   {
742     draw(new Rectangle (x, y, width, height));
743   }
744
745   public void fillRect (int x, int y, int width, int height)
746   {
747     fill(new Rectangle (x, y, width, height));
748   }
749
750   public void clearRect (int x, int y, int width, int height)
751   {
752     stateSave ();
753     cairoSetRGBColor (bg.getRed() / 255.0, 
754                       bg.getGreen() / 255.0, 
755                       bg.getBlue() / 255.0);
756     cairoSetAlpha (1.0);
757     cairoNewPath ();
758     cairoRectangle (x, y, width, height);
759     cairoClosePath ();
760     cairoFill ();
761     stateRestore ();
762   }
763
764   public void setBackground(Color c)
765   {
766     bg = c;
767   }
768
769   public Color getBackground()
770   {
771     return bg;
772   }
773
774   private void doPolygon(int[] xPoints, int[] yPoints, int nPoints, 
775                          boolean close, boolean fill)
776   {    
777     if (nPoints < 1)
778       return;
779     GeneralPath gp = new GeneralPath (PathIterator.WIND_EVEN_ODD);
780     gp.moveTo ((float)xPoints[0], (float)yPoints[0]);
781     for (int i = 1; i < nPoints; i++)
782       gp.lineTo ((float)xPoints[i], (float)yPoints[i]);
783     
784     if (close)
785       gp.closePath ();
786
787     Shape sh = gp;
788     if (fill == false &&
789         stroke != null &&
790         !(stroke instanceof BasicStroke))
791       {
792         sh = stroke.createStrokedShape (gp);
793         fill = true;
794       }
795     
796     if (fill) 
797       fill (sh);
798     else 
799       draw (sh);
800   }
801
802   public void drawLine (int x1, int y1, int x2, int y2)
803   {
804     int xp[] = new int[2];
805     int yp[] = new int[2];
806
807     xp[0] = x1;
808     xp[1] = x2;
809     yp[0] = y1;
810     yp[1] = y2;
811     
812     doPolygon (xp, yp, 2, false, false);
813   }
814
815   public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
816   {
817     doPolygon (xPoints, yPoints, nPoints, true, true);
818   }
819   
820   public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
821   {    
822     doPolygon (xPoints, yPoints, nPoints, true, false);
823   }
824
825   public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
826   {
827     doPolygon (xPoints, yPoints, nPoints, false, false);
828   }
829
830   private boolean drawRaster (ColorModel cm, Raster r, 
831                               AffineTransform imageToUser)
832   {
833     if (r == null)
834       return false;
835
836     SampleModel sm = r.getSampleModel ();
837     DataBuffer db = r.getDataBuffer ();
838
839     if (db == null || sm == null)
840       return false;
841
842     if (cm == null)
843       cm = ColorModel.getRGBdefault ();
844
845     double[] i2u = new double[6];
846     if (imageToUser != null)
847       imageToUser.getMatrix(i2u);
848     else
849       {
850         i2u[0] = 1; i2u[1] = 0;
851         i2u[2] = 0; i2u[3] = 1;
852         i2u[2] = 0; i2u[3] = 0;
853       }
854
855     int pixels[] = null;
856
857     if (sm.getDataType () == DataBuffer.TYPE_INT &&
858         db instanceof DataBufferInt &&
859         db.getNumBanks () == 1)
860       {
861         // single bank, ARGB-ints buffer in sRGB space
862         DataBufferInt dbi = (DataBufferInt)db;
863         pixels = dbi.getData ();
864       }
865     else
866       pixels = r.getPixels (0, 0, r.getWidth (), r.getHeight (), pixels);
867     
868     ColorSpace cs = cm.getColorSpace ();
869     if (cs != null && 
870         cs.getType () != ColorSpace.CS_sRGB)
871       {
872         int pixels2[] = new int[pixels.length];        
873         for (int i = 0; i < pixels2.length; i++)
874           pixels2[i] = cm.getRGB (pixels[i]);        
875         pixels = pixels2;
876       }
877     
878     stateSave ();
879     translate (x, y);
880     drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth (), i2u);
881     stateRestore ();    
882     return true;
883   }
884
885   public void drawRenderedImage(RenderedImage image,
886                                 AffineTransform xform)
887   {
888     drawRaster (image.getColorModel(), image.getData(), xform);
889   }
890   
891   public void drawRenderableImage(RenderableImage image,
892                                   AffineTransform xform)
893   {
894     drawRenderedImage (image.createRendering (new RenderContext (xform)), xform);
895   }
896   
897   public boolean drawImage(Image img, 
898                            AffineTransform xform,
899                            ImageObserver obs)
900   {
901     if (img instanceof GtkOffScreenImage &&
902         img.getGraphics () instanceof GdkGraphics2D &&            
903         (xform == null 
904          || xform.getType () == AffineTransform.TYPE_IDENTITY 
905          || xform.getType () == AffineTransform.TYPE_TRANSLATION)
906         ) 
907       {
908         // we are being asked to flush a double buffer from Gdk
909         GdkGraphics2D g2 = (GdkGraphics2D) img.getGraphics ();
910         gdkDrawDrawable (g2, (int)xform.getTranslateX(), (int)xform.getTranslateY());
911         return true;
912       }
913     else
914       {
915         if (img instanceof BufferedImage)
916           {
917             // draw an image which has actually been loaded into memory fully
918             BufferedImage b = (BufferedImage) img;
919             return drawRaster (b.getColorModel (), b.getData (), xform);
920           }        
921         else
922           {
923             // begin progressive loading in a separate thread
924             new PainterThread (this, img, xform);
925             return false;
926           }
927       }
928   }
929
930   public void drawImage(BufferedImage image,
931                         BufferedImageOp op,
932                         int x,
933                         int y)
934   {
935     Image filtered = op.filter(image, null);
936     drawImage(filtered, new AffineTransform(1f,0f,0f,1f,x,y), null);
937   }
938
939   public boolean drawImage (Image img, int x, int y, 
940                             ImageObserver observer)
941   {
942     return drawImage(img, new AffineTransform(1f,0f,0f,1f,x,y), observer);    
943   }
944
945
946   ////////////////////////////////////////
947   ////// Supporting Private Classes //////
948   ////////////////////////////////////////
949   
950   private class PainterThread implements Runnable, ImageConsumer
951   {
952
953     // this is a helper which is spun off when someone tries to do
954     // Graphics2D.drawImage on an image we cannot determine to be either
955     // one of our own offscreen images or a BufferedImage; that is, when
956     // someone wants to draw an image which is possibly still loading over
957     // a network or something. you run it in a separate thread and it
958     // writes through to the underlying Graphics2D as pixels becomg
959     // available.
960
961     GdkGraphics2D gr;
962     Image image;
963     ColorModel defaultModel;
964     AffineTransform xform;
965
966     public PainterThread (GdkGraphics2D g, Image im, AffineTransform xf)
967     {
968       image = im;
969       xform = xf;
970       this.gr = (GdkGraphics2D) g.create ();
971       new Thread (this).start ();
972     }
973     
974     public void imageComplete (int status)
975     {
976     }
977     
978     public void setColorModel (ColorModel model) 
979     {
980       defaultModel = model;
981     }
982     
983     public void setDimensions (int width, int height)
984     {
985     }
986     
987     public void setHints (int hintflags)
988     {
989     }
990     
991     public void setPixels (int x, int y, int w, int h, ColorModel model, 
992                            byte[] pixels, int off, int scansize)
993     {
994     }
995     
996     public void setPixels (int x, int y, int w, int h, ColorModel model, 
997                            int[] pixels, int off, int scansize)
998       {
999         gr.stateSave ();
1000         gr.translate (x, y);
1001
1002         if (model == null)
1003           model = defaultModel;
1004
1005         int pixels2[];
1006         if (model != null)
1007           {
1008             pixels2 = new int[pixels.length];
1009             for (int yy = 0; yy < h; yy++)
1010               for (int xx = 0; xx < w; xx++)
1011                 {
1012                   int i = yy * scansize + xx;
1013                   pixels2[i] = model.getRGB (pixels[i]);
1014                 }
1015           }
1016         else
1017           pixels2 = pixels;
1018
1019         double[] xf = new double[6];
1020         xform.getMatrix(xf);        
1021         gr.drawPixels (pixels2, w, h, scansize, xf);
1022         gr.stateRestore ();
1023       }
1024
1025     public void setProperties (java.util.Hashtable props)
1026     {
1027     }
1028     
1029     public void run ()
1030     {
1031       image.getSource ().startProduction (this);
1032       gr.dispose ();
1033     }
1034   }
1035
1036
1037
1038   ///////////////////////////////////////////////
1039   ////// Unimplemented Stubs and Overloads //////
1040   ///////////////////////////////////////////////
1041
1042   
1043     
1044   public boolean hit(Rectangle rect, Shape text,
1045                      boolean onStroke)
1046   {
1047     throw new java.lang.UnsupportedOperationException ();
1048   }
1049
1050   public GraphicsConfiguration getDeviceConfiguration()
1051   {
1052     throw new java.lang.UnsupportedOperationException ();
1053   }
1054
1055   public void setComposite(Composite comp)
1056   {
1057     throw new java.lang.UnsupportedOperationException ();
1058   }
1059
1060   public void setRenderingHint(RenderingHints.Key hintKey,
1061                                Object hintValue)
1062   {
1063     hints.put (hintKey, hintValue);    
1064   }
1065
1066   public Object getRenderingHint(RenderingHints.Key hintKey)
1067   {
1068     return hints.get (hintKey);
1069   }
1070   
1071   public void setRenderingHints(Map hints)
1072   {
1073     this.hints = new RenderingHints (getDefaultHints ());
1074     this.hints.add (new RenderingHints (hints));
1075   }
1076
1077   public void addRenderingHints(Map hints)
1078   {
1079     this.hints.add (new RenderingHints (hints));
1080   }
1081
1082   public RenderingHints getRenderingHints()
1083   {
1084     return hints;
1085   }
1086
1087   public Composite getComposite()
1088   {
1089     throw new java.lang.UnsupportedOperationException ();
1090   }
1091
1092   public FontRenderContext getFontRenderContext ()
1093   {
1094     return new FontRenderContext (transform, true, true);
1095   }
1096
1097   public void drawGlyphVector (GlyphVector g, float x, float y)
1098   {    
1099     stateSave ();
1100     setFont (g.getFont ());
1101     translate ((double)x, (double)y);
1102     cairoMoveTo (0, 0);
1103     int nglyphs = g.getNumGlyphs ();
1104     int codes[] = g.getGlyphCodes (0, nglyphs, (int []) null);
1105     float posns[] = g.getGlyphPositions (0, nglyphs, (float []) null);
1106     cairoShowGlyphs (codes, posns);
1107     stateRestore ();
1108   }
1109
1110   public void copyArea (int x, int y, int width, int height, int dx, int dy)
1111   {
1112     throw new java.lang.UnsupportedOperationException ();
1113   }
1114
1115   public void drawArc (int x, int y, int width, int height,
1116                        int startAngle, int arcAngle)
1117   {
1118     draw (new Arc2D.Double((double)x, (double)y, 
1119                            (double)width, (double)height,
1120                            (double)startAngle, (double)arcAngle,
1121                            Arc2D.OPEN));
1122   }
1123
1124   public boolean drawImage (Image img, int x, int y, Color bgcolor, 
1125                             ImageObserver observer)
1126   {
1127     throw new java.lang.UnsupportedOperationException ();
1128   }
1129
1130   public boolean drawImage (Image img, int x, int y, int width, int height, 
1131                             Color bgcolor, ImageObserver observer)
1132   {
1133     throw new java.lang.UnsupportedOperationException ();
1134   }
1135
1136   public boolean drawImage (Image img, int x, int y, int width, int height, 
1137                             ImageObserver observer)
1138   {
1139     throw new java.lang.UnsupportedOperationException ();
1140   }
1141
1142   public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, 
1143                             int sx1, int sy1, int sx2, int sy2, 
1144                             Color bgcolor, ImageObserver observer)
1145   {
1146     throw new java.lang.UnsupportedOperationException ();
1147   }
1148
1149   public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, 
1150                             int sx1, int sy1, int sx2, int sy2, 
1151                             ImageObserver observer) 
1152   {
1153     throw new java.lang.UnsupportedOperationException ();
1154   }
1155
1156   public void drawOval(int x, int y, int width, int height)
1157   {
1158     drawArc (x, y, width, height, 0, 360);
1159   }
1160
1161   public void drawRoundRect(int x, int y, int width, int height, 
1162                             int arcWidth, int arcHeight)
1163   {
1164     int x1 = x + arcWidth, x2 = x + width - arcWidth;
1165     int y1 = y + arcHeight, y2 = y + height - arcHeight;
1166     fillRect (x1, y, x2 - x1, height);
1167     fillRect (x, y1, width, y2 - y1);
1168     fillArc (x, y, arcWidth, arcHeight, 90, 90);
1169     fillArc (x1, y, arcWidth, arcHeight, 0, 90);
1170     fillArc (x2, y2, arcWidth, arcHeight, 270, 90);
1171     fillArc (x, y2, arcWidth, arcHeight, 180, 90);
1172   }
1173
1174   public void drawString (String str, int x, int y)
1175   {
1176     drawString (str, (float)x, (float)y);
1177   }
1178
1179   public void drawString (String str, float x, float y)
1180   {
1181     GlyphVector gv = font.createGlyphVector (getFontRenderContext(), str);
1182     drawGlyphVector (gv, x, y);
1183   }
1184
1185   public void drawString (AttributedCharacterIterator ci, int x, int y)
1186   {
1187     drawString (ci, (float)x, (float)y);
1188   }
1189
1190   public void drawString (AttributedCharacterIterator ci, float x, float y)
1191   {
1192     GlyphVector gv = font.createGlyphVector (getFontRenderContext(), ci);
1193     drawGlyphVector (gv, x, y);
1194   }
1195
1196   public void fillArc (int x, int y, int width, int height, 
1197                        int startAngle, int arcAngle)
1198   {
1199     fill (new Arc2D.Double((double)x, (double)y, 
1200                            (double)width, (double)height,
1201                            (double)startAngle, (double)arcAngle,
1202                            Arc2D.OPEN));
1203   }
1204
1205   public void fillOval(int x, int y, int width, int height)
1206   {
1207     fillArc (x, y, width, height, 0, 360);
1208   }
1209
1210   public void fillRoundRect (int x, int y, int width, int height, 
1211                              int arcWidth, int arcHeight)
1212   {
1213     int x1 = x + arcWidth, x2 = x + width - arcWidth;
1214     int y1 = y + arcHeight, y2 = y + height - arcHeight;
1215     fillRect (x1, y, x2 - x1, height);
1216     fillRect (x, y1, width, y2 - y1);
1217     fillArc (x, y, arcWidth, arcHeight, 90, 90);
1218     fillArc (x1, y, arcWidth, arcHeight, 0, 90);
1219     fillArc (x2, y2, arcWidth, arcHeight, 270, 90);
1220     fillArc (x, y2, arcWidth, arcHeight, 180, 90);
1221   }
1222
1223   public Font getFont ()
1224   {
1225     return font;
1226   }
1227
1228   public FontMetrics getFontMetrics ()
1229   {
1230     return Toolkit.getDefaultToolkit ().getFontMetrics (font);
1231   }
1232
1233   public FontMetrics getFontMetrics (Font f)
1234   {
1235     return Toolkit.getDefaultToolkit ().getFontMetrics (f);
1236   }
1237
1238   public void setFont (Font f)
1239   {
1240     if (f.getPeer() instanceof GdkClasspathFontPeer)
1241       font = f;
1242     else
1243       font = 
1244         ((ClasspathToolkit)(Toolkit.getDefaultToolkit ()))
1245         .getFont (f.getName(), f.getAttributes ());
1246
1247     if (f != null && 
1248         f.getPeer() instanceof GdkClasspathFontPeer)
1249       cairoSetFont ((GdkClasspathFontPeer) f.getPeer());
1250   }
1251
1252   public String toString()
1253   {
1254     throw new java.lang.UnsupportedOperationException ();
1255   }
1256
1257 }