OSDN Git Service

11c0371bd08a7606dd4faa3654104d15b255178f
[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
48 import java.text.AttributedCharacterIterator;
49 import java.util.Map;
50 import java.lang.Integer;
51 import gnu.classpath.Configuration;
52
53 public class GdkGraphics2D extends Graphics2D
54 {
55
56   //////////////////////////////////////
57   ////// State Management Methods //////
58   //////////////////////////////////////
59
60   static 
61   {
62     if (Configuration.INIT_LOAD_LIBRARY)
63       {
64         System.loadLibrary("gtkpeer");
65       }
66     initStaticState ();
67   }
68   native static void initStaticState ();
69   private final int native_state = GtkGenericPeer.getUniqueInteger();  
70
71   private Paint paint;
72   private Stroke stroke;
73   private Color fg;
74   private Color bg;
75   private Shape clip;
76   private AffineTransform transform;
77   private GtkComponentPeer component;
78   private GdkFont font;  
79
80   native private int[] initState (GtkComponentPeer component);
81   native private void initState (int width, int height);
82   native private void copyState (GdkGraphics2D g);
83   native public void dispose ();
84
85   public void finalize ()
86   {
87     dispose();
88   }
89
90   public Graphics create ()
91   {
92     return new GdkGraphics2D (this);
93   }
94
95   public Graphics create (int x, int y, int width, int height)
96   {
97     return new GdkGraphics2D (width, height);
98   }
99
100   GdkGraphics2D (GdkGraphics2D g)
101   {
102     paint = g.paint;
103     stroke = g.stroke;
104
105     if (g.fg.getAlpha() != -1)
106       fg = new Color (g.fg.getRed (), g.fg.getGreen (), 
107                       g.fg.getBlue (), g.fg.getAlpha ());
108     else 
109       fg = new Color (g.fg.getRGB ());
110
111     if (g.bg.getAlpha() != -1)
112       bg = new Color(g.bg.getRed (), g.bg.getGreen (), 
113                      g.bg.getBlue (), g.bg.getAlpha ());
114     else
115       bg = new Color (g.bg.getRGB ());
116
117     if (g.clip == null)
118       clip = null;
119     else
120       clip = new Rectangle (g.getClipBounds ());
121
122     if (g.transform == null)
123       transform = null;
124     else
125       transform = new AffineTransform (g.transform);
126
127     component = g.component;
128     copyState (g);
129
130     setColor (fg);
131     setClip (clip);
132     setTransform (transform);
133   }
134
135   GdkGraphics2D (int width, int height)
136   {
137     initState (width, height);
138     bg = Color.black;
139     fg = Color.black;
140     transform = new AffineTransform ();
141   }
142
143   GdkGraphics2D (GtkComponentPeer component)
144   {
145     this.component = component;
146     int rgb[] = initState (component);
147     fg = new Color (rgb[0], rgb[1], rgb[2]);
148     bg = new Color (rgb[3], rgb[4], rgb[5]);
149     transform = new AffineTransform ();
150   }
151
152
153   ////////////////////////////////////
154   ////// Native Drawing Methods //////
155   ////////////////////////////////////
156
157   // GDK drawing methods
158   private native void gdkDrawDrawable (GdkGraphics2D other, int x, int y);
159
160   // drawing utility methods
161   private native void drawPixels (int pixels[], int w, int h, int stride);
162   private native void setTexturePixels (int pixels[], int w, int h, int stride);
163   private native void setGradient (double x1, double y1,
164                                    double x2, double y2,
165                                    int r1, int g1, int b1, int a1,
166                                    int r2, int g2, int b2, int a2,
167                                    boolean cyclic);
168
169   // simple passthroughs to cairo
170   private native void cairoSave ();
171   private native void cairoRestore ();
172   private native void cairoSetMatrix (double m00, double m10, 
173                                       double m01, double m11,
174                                       double m02, double m12);
175   private native void cairoSetOperator (int cairoOperator);
176   private native void cairoSetRGBColor (double red, double green, double blue);
177   private native void cairoSetAlpha (double alpha);
178   private native void cairoSetFillRule (int cairoFillRule);
179   private native void cairoSetLineWidth (double width);
180   private native void cairoSetLineCap (int cairoLineCap);
181   private native void cairoSetLineJoin (int cairoLineJoin);
182   private native void cairoSetDash (double dashes[], int ndash, double offset);
183   private native void cairoSetMiterLimit (double limit);
184   private native void cairoTranslate (double tx, double ty);
185   private native void cairoScale (double sx, double sy);
186   private native void cairoRotate (double angle);
187   private native void cairoNewPath ();
188   private native void cairoMoveTo (double x, double y);
189   private native void cairoLineTo (double x, double y);
190   private native void cairoCurveTo (double x1, double y1,
191                                  double x2, double y2,
192                                  double x3, double y3);  
193   private native void cairoRelMoveTo (double dx, double dy);
194   private native void cairoRelLineTo (double dx, double dy);
195   private native void cairoRelCurveTo (double dx1, double dy1,
196                                     double dx2, double dy2,
197                                     double dx3, double dy3);
198   private native void cairoRectangle (double x, double y, 
199                                    double width, double height);
200   private native void cairoClosePath ();
201   private native void cairoStroke ();
202   private native void cairoFill ();
203   private native void cairoClip ();
204
205
206   /////////////////////////////////////////////
207   ////// General Drawing Support Methods //////
208   /////////////////////////////////////////////
209
210   double x;
211   double y;
212   private void setPos (double nx, double ny)
213   {
214     x = nx;
215     y = ny;
216   }
217
218   private void walkPath(PathIterator p)
219   {
220     double coords[] = new double[6];
221
222     cairoSetFillRule (p.getWindingRule ());
223     for ( ; ! p.isDone (); p.next())
224       {
225         int seg = p.currentSegment (coords);
226         switch(seg)
227           {
228
229           case PathIterator.SEG_MOVETO:
230             setPos(coords[0], coords[1]);
231             cairoMoveTo (coords[0], coords[1]);
232             break;
233
234           case PathIterator.SEG_LINETO:
235             setPos(coords[0], coords[1]);
236             cairoLineTo (coords[0], coords[1]);
237             break;
238
239           case PathIterator.SEG_QUADTO:
240
241             // splitting a quadratic bezier into a cubic:
242             // see: http://pfaedit.sourceforge.net/bezier.html
243
244             double x1 = x + (2.0/3.0) * (coords[0] - x);
245             double y1 = y + (2.0/3.0) * (coords[1] - y);
246             
247             double x2 = x1 + (1.0/3.0) * (coords[2] - x);
248             double y2 = y1 + (1.0/3.0) * (coords[3] - y);
249
250             setPos(coords[2], coords[3]);
251             cairoCurveTo (x1, y1,
252                           x2, y2,
253                           coords[2], coords[3]);
254             break;
255
256           case PathIterator.SEG_CUBICTO:
257             setPos(coords[4], coords[5]);
258             cairoCurveTo (coords[0], coords[1],
259                           coords[2], coords[3],
260                           coords[4], coords[5]);
261             break;
262
263           case PathIterator.SEG_CLOSE:
264             cairoClosePath ();
265             break;
266           }
267       }    
268   }
269
270
271   //////////////////////////////////////////////////
272   ////// Implementation of Graphics2D Methods //////
273   //////////////////////////////////////////////////
274
275   public void draw (Shape s)
276   {
277
278     if (stroke != null &&
279         !(stroke instanceof BasicStroke))
280       {
281         fill (stroke.createStrokedShape (s));
282         return;
283       }
284
285     cairoSave ();
286     cairoNewPath ();
287     if (s instanceof Rectangle2D)
288       {
289         Rectangle2D r = (Rectangle2D)s;
290         cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
291       }
292     else      
293       walkPath (s.getPathIterator (null));
294     cairoStroke ();
295     cairoRestore ();
296   }
297
298   public void fill(Shape s)
299   {
300     cairoSave();
301     cairoNewPath ();
302     if (s instanceof Rectangle2D)
303       {
304         Rectangle2D r = (Rectangle2D)s;
305         cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ());
306       }
307     else      
308       walkPath (s.getPathIterator (null));
309     cairoFill ();
310     cairoRestore ();
311   }
312
313   public void clip (Shape s)
314   {
315     clip = s;
316     cairoNewPath ();
317     if (s instanceof Rectangle2D)
318       {
319         Rectangle2D r = (Rectangle2D)s;
320         cairoRectangle (r.getX (), r.getY (), 
321                         r.getWidth (), r.getHeight ());
322       }
323     else      
324       walkPath (s.getPathIterator (null));
325     cairoClosePath ();
326     cairoClip ();
327   }
328
329   public Paint getPaint ()
330   {
331     return paint;
332   }
333
334   public AffineTransform getTransform ()
335   {
336     return transform;
337   }
338
339   public void setPaint (Paint p)
340   {
341     paint = p;
342     if (paint instanceof Color)
343       {
344         setColor ((Color) paint);
345       }
346     else if (paint instanceof TexturePaint)
347       {
348         TexturePaint tp = (TexturePaint) paint;
349         BufferedImage img = tp.getImage ();
350         int pixels[] = img.getRGB(0, 0, img.getWidth (), 
351                                   img.getHeight (), null, 
352                                   0, img.getWidth ());
353         setTexturePixels (pixels, img.getWidth (), 
354                           img.getHeight (), img.getWidth ());
355       }
356     else if (paint instanceof GradientPaint)
357       {
358         GradientPaint gp = (GradientPaint) paint;
359         Point2D p1 = gp.getPoint1 ();
360         Point2D p2 = gp.getPoint2 ();
361         Color c1 = gp.getColor1 ();
362         Color c2 = gp.getColor2 ();        
363         setGradient (p1.getX (), p1.getY (),
364                      p2.getX (), p2.getY (),
365                      c1.getRed (), c1.getGreen (), 
366                      c1.getBlue (), c1.getAlpha (),
367                      c2.getRed (), c2.getGreen (), 
368                      c2.getBlue (), c2.getAlpha (),
369                      gp.isCyclic ());
370       }
371     else
372       throw new java.lang.UnsupportedOperationException ();
373   }
374
375   public void setTransform (AffineTransform tx)
376   {
377     transform = tx;
378     if (transform != null)
379       {
380         double m[] = new double[6];
381         transform.getMatrix (m);
382         cairoSetMatrix (m[0], m[1], m[2], m[3], m[4], m[5]);
383       }
384   }
385
386   public void transform (AffineTransform tx)
387   {
388     if (transform == null)
389       transform = new AffineTransform (tx);
390     else
391       transform.concatenate (tx);
392     setTransform (transform);
393   }
394
395   public void rotate(double theta)
396   {
397     if (transform != null)
398       transform.rotate (theta);
399     cairoRotate (theta);
400   }
401
402   public void rotate(double theta, double x, double y)
403   {
404     if (transform != null)
405       transform.rotate (theta, x, y);
406     cairoTranslate (x, y);
407     cairoRotate (theta);
408     cairoTranslate (-x, -y);
409   }
410
411   public void scale(double sx, double sy)
412   {
413     if (transform != null)
414       transform.scale (sx, sy);
415     cairoScale (sx, sy);
416   }
417
418   public void translate (double tx, double ty)
419   {
420     if (transform != null)
421       transform.translate (tx, ty);
422     cairoTranslate (tx, ty);
423   }
424
425   public void translate (int x, int y)
426   {
427     translate ((double) x, (double) y);
428   }
429
430   public Stroke getStroke()
431   {
432     return stroke;
433   }
434
435   public void setStroke (Stroke st)
436   {
437     stroke = st;
438     if (stroke instanceof BasicStroke)
439       {
440         BasicStroke bs = (BasicStroke) stroke;
441         cairoSetLineCap (bs.getEndCap());
442         cairoSetLineWidth (bs.getLineWidth());
443         cairoSetLineJoin (bs.getLineJoin());
444         cairoSetMiterLimit (bs.getMiterLimit());
445         float dashes[] = bs.getDashArray();
446         if (dashes != null)
447           {
448             double double_dashes[] = new double[dashes.length];
449             for (int i = 0; i < dashes.length; i++)
450               double_dashes[i] = dashes[i];
451             cairoSetDash (double_dashes, double_dashes.length, 
452                           (double) bs.getDashPhase ());        
453           }
454       }
455   }
456
457
458   ////////////////////////////////////////////////
459   ////// Implementation of Graphics Methods //////
460   ////////////////////////////////////////////////
461
462   public void setPaintMode () 
463   { 
464     setComposite (java.awt.AlphaComposite.Xor); 
465   }
466
467   public void setXORMode (Color c) 
468   { 
469     setComposite (new BitwiseXorComposite (c)); 
470   }
471
472   public void setColor (Color c)
473   {
474     fg = c;
475     cairoSetRGBColor (fg.getRed() / 255.0, 
476                       fg.getGreen() / 255.0, 
477                       fg.getBlue() / 255.0);
478     cairoSetAlpha ((fg.getAlpha() & 255) / 255.0);
479   }
480
481   public Color getColor ()
482   {
483     return fg;
484   }
485
486   public void clipRect (int x, int y, int width, int height)
487   {
488     // this is *slightly* different than all the other clip functions: it
489     // intersects the clip area with the new clip rectangle. obviously.  of
490     // course, since Shape doesn't *have* any way of intersecting with a
491     // rectangle, we will promote the current clipping region to its
492     // bounding rectangle and then intersect with that.
493     if (clip == null)
494       {
495         cairoNewPath ();
496         cairoRectangle (x, y, width, height);
497         cairoClosePath ();
498         cairoClip ();
499         clip = new Rectangle (x, y, width, height);
500       }
501     else
502       {
503         clip (clip.getBounds ().intersection 
504               (new Rectangle (x, y, width, height)));
505       }
506   }
507
508   public Shape getClip ()
509   {
510     return clip;
511   }
512
513   public Rectangle getClipBounds ()
514   {
515     if (clip == null)
516       return null;
517     else
518       return clip.getBounds ();
519   }
520
521   public void setClip (int x, int y, int width, int height)
522   {
523     cairoNewPath ();
524     cairoRectangle (x, y, width, height);
525     cairoClosePath ();
526     cairoClip ();
527     clip = new Rectangle (x, y, width, height);
528   }
529
530   public void setClip (Shape s)
531   {
532     clip (s);
533   }
534
535   public void draw3DRect(int x, int y, int width, 
536                          int height, boolean raised)
537   {
538     Color std = fg;
539     Color light = std.brighter();
540     Color dark = std.darker();
541
542     if (!raised)
543       {
544         Color t = light;
545         light = dark;
546         dark = t;
547       }
548     
549     double x1 = (double) x;
550     double x2 = (double) x + width;
551
552     double y1 = (double) y;
553     double y2 = (double) y + height;
554
555     cairoSave ();
556     
557     cairoNewPath ();
558     setColor (light);
559     cairoMoveTo (x1, y1);
560     cairoLineTo (x2, y1);
561     cairoLineTo (x2, y2);
562     cairoStroke ();
563     
564     cairoNewPath ();
565     setColor (dark);
566     cairoMoveTo (x1, y1);
567     cairoLineTo (x1, y2);
568     cairoLineTo (x2, y2);
569     cairoStroke ();
570     
571     cairoRestore ();    
572     setColor (std);
573
574   }
575
576   public void fill3DRect(int x, int y, int width, 
577                          int height, boolean raised)
578   {
579     double step = 1.0;
580     if (stroke != null && stroke instanceof BasicStroke)
581       {
582         BasicStroke bs = (BasicStroke) stroke;
583         step = bs.getLineWidth();
584       }
585
586     Color bright = fg.brighter ();
587     Color dark = fg.darker ();
588       
589     draw3DRect (x, y, width, height, raised);
590     
591     cairoSave ();
592     cairoTranslate (step/2.0, step/2.0);
593     cairoNewPath ();
594     cairoRectangle ((double) x, (double) y, 
595                     ((double) width) - step, 
596                     ((double) height) - step );
597     cairoClosePath ();
598     cairoFill ();
599     cairoRestore ();
600   }
601
602
603   public void drawRect (int x, int y, int width, int height)
604   {
605     draw(new Rectangle (x, y, width, height));
606   }
607
608   public void fillRect (int x, int y, int width, int height)
609   {
610     fill(new Rectangle (x, y, width, height));
611   }
612
613   public void clearRect (int x, int y, int width, int height)
614   {
615     cairoSave ();
616     cairoSetRGBColor (bg.getRed() / 255.0, 
617                       bg.getGreen() / 255.0, 
618                       bg.getBlue() / 255.0);
619     cairoSetAlpha (1.0);
620     cairoNewPath ();
621     cairoRectangle (x, y, width, height);
622     cairoClosePath ();
623     cairoFill ();
624     cairoRestore ();
625   }
626
627   public void setBackground(Color c)
628   {
629     bg = c;
630   }
631
632
633   public Color getBackground()
634   {
635     return bg;
636   }
637
638
639   private void doPolygon(int[] xPoints, int[] yPoints, int nPoints, 
640                          boolean close, boolean fill)
641   {    
642     if (nPoints < 1)
643       return;
644     GeneralPath gp = new GeneralPath ();
645     gp.moveTo ((float)xPoints[0], (float)yPoints[0]);
646     for (int i = 1; i < nPoints; i++)
647       gp.lineTo ((float)xPoints[i], (float)yPoints[i]);
648     
649     if (close)
650       gp.closePath ();
651
652     Shape sh = gp;
653     if (fill == false &&
654         stroke != null &&
655         !(stroke instanceof BasicStroke))
656       {
657         sh = stroke.createStrokedShape (gp);
658         fill = true;
659       }
660     
661     if (fill) 
662       fill (sh);
663     else 
664       draw (sh);
665   }
666
667   public void drawLine (int x1, int y1, int x2, int y2)
668   {
669     int xp[] = new int[2];
670     int yp[] = new int[2];
671
672     xp[0] = x1;
673     xp[1] = x2;
674     yp[0] = y1;
675     yp[1] = y2;
676     
677     doPolygon (xp, yp, 2, false, false);
678   }
679
680   public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
681   {
682     doPolygon (xPoints, yPoints, nPoints, true, true);
683   }
684   
685   public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
686   {    
687     doPolygon (xPoints, yPoints, nPoints, true, false);
688   }
689
690   public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
691   {
692     doPolygon (xPoints, yPoints, nPoints, false, false);
693   }
694
695   private boolean drawRaster (ColorModel cm, Raster r)
696   {
697     if (r == null)
698       return false;
699
700     SampleModel sm = r.getSampleModel ();
701     DataBuffer db = r.getDataBuffer ();
702
703     if (db == null || sm == null)
704       return false;
705
706     if (cm == null)
707       cm = ColorModel.getRGBdefault ();
708
709     int pixels[] = null;
710
711     if (sm.getDataType () == DataBuffer.TYPE_INT &&
712         db instanceof DataBufferInt &&
713         db.getNumBanks () == 1)
714       {
715         // single bank, ARGB-ints buffer in sRGB space
716         DataBufferInt dbi = (DataBufferInt)db;
717         pixels = dbi.getData ();
718       }
719     else
720       pixels = r.getPixels (0, 0, r.getWidth (), r.getHeight (), pixels);
721     
722     ColorSpace cs = cm.getColorSpace ();
723     if (cs != null && 
724         cs.getType () != ColorSpace.CS_sRGB)
725       {
726         int pixels2[] = new int[pixels.length];        
727         for (int i = 0; i < pixels2.length; i++)
728           pixels2[i] = cm.getRGB (pixels[i]);        
729         pixels = pixels2;
730       }
731     
732     cairoSave ();
733     cairoTranslate (x, y);
734     drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth ());
735     cairoRestore ();    
736     return true;
737   }
738
739   public boolean drawImage (Image img, int x, int y, 
740                             ImageObserver observer)
741   {
742     if (img instanceof GtkOffScreenImage &&
743         img.getGraphics () instanceof GdkGraphics2D &&            
744         (transform == null || transform.isIdentity ())) 
745       {
746         // we are being asked to flush a double buffer from Gdk
747         GdkGraphics2D g2 = (GdkGraphics2D) img.getGraphics ();
748         gdkDrawDrawable (g2, x, y);
749         return true;
750       }
751     else
752       {
753         if (img instanceof BufferedImage)
754           {
755             // draw an image which has actually been loaded into memory fully
756             BufferedImage b = (BufferedImage) img;
757             return drawRaster (b.getColorModel (), b.getData ());
758           }        
759         else
760           {
761             // begin progressive loading in a separate thread
762             new PainterThread (this, img);
763             return false;
764           }
765       }
766   }
767
768
769   ////////////////////////////////////////
770   ////// Supporting Private Classes //////
771   ////////////////////////////////////////
772   
773   private class PainterThread implements Runnable, ImageConsumer
774   {
775
776     // this is a helper which is spun off when someone tries to do
777     // Graphics2D.drawImage on an image we cannot determine to be either
778     // one of our own offscreen images or a BufferedImage; that is, when
779     // someone wants to draw an image which is possibly still loading over
780     // a network or something. you run it in a separate thread and it
781     // writes through to the underlying Graphics2D as pixels becomg
782     // available.
783
784     GdkGraphics2D gr;
785     Image image;
786     ColorModel defaultModel;
787
788     public PainterThread (GdkGraphics2D g, Image im)
789     {
790       image = im;
791       this.gr = (GdkGraphics2D) g.create ();
792       new Thread (this).start ();
793     }
794     
795     public void imageComplete (int status)
796     {
797     }
798     
799     public void setColorModel (ColorModel model) 
800     {
801       defaultModel = model;
802     }
803     
804     public void setDimensions (int width, int height)
805     {
806     }
807     
808     public void setHints (int hintflags)
809     {
810     }
811     
812     public void setPixels (int x, int y, int w, int h, ColorModel model, 
813                            byte[] pixels, int off, int scansize)
814     {
815     }
816     
817     public void setPixels (int x, int y, int w, int h, ColorModel model, 
818                            int[] pixels, int off, int scansize)
819       {
820         gr.cairoSave ();
821         gr.cairoTranslate (x, y);
822
823         if (model == null)
824           model = defaultModel;
825
826         int pixels2[];
827         if (model != null)
828           {
829             pixels2 = new int[pixels.length];
830             for (int yy = 0; yy < h; yy++)
831               for (int xx = 0; xx < w; xx++)
832                 {
833                   int i = yy * scansize + xx;
834                   pixels2[i] = model.getRGB (pixels[i]);
835                 }
836           }
837         else
838           pixels2 = pixels;
839
840         gr.drawPixels (pixels2, w, h, scansize);
841         gr.cairoRestore ();
842       }
843
844     public void setProperties (java.util.Hashtable props)
845     {
846     }
847     
848     public void run ()
849     {
850       image.getSource ().startProduction (this);
851       gr.dispose ();
852     }
853   }
854
855
856   private class BitwiseXorComposite implements Composite
857   {
858     // this is a special class which does a bitwise XOR composite, for
859     // backwards compatibility sake. it does *not* implement the
860     // porter-duff XOR operator.  the porter-duff XOR is unrelated to
861     // bitwise XOR; it just happens to have a similar name but it
862     // represents a desire to composite the exclusive or of overlapping
863     // subpixel regions. bitwise XOR is for drawing "highlights" such as
864     // cursors (in a cheap oldskool bitblit fashion) by inverting colors
865     // temporarily and then inverting them back.
866
867     Color xorColor;
868     
869     class BitwiseXorCompositeContext implements CompositeContext
870     {
871       ColorModel srcColorModel;
872       ColorModel dstColorModel;
873       
874       public BitwiseXorCompositeContext (ColorModel s,
875                                          ColorModel d)
876       {
877         srcColorModel = s;
878         dstColorModel = d;
879       }
880
881       public void dispose () 
882       {
883       }
884
885       public void compose (Raster src,
886                            Raster dstIn,
887                            WritableRaster dstOut)
888       {
889         Rectangle srcRect = src.getBounds ();
890         Rectangle dstInRect = dstIn.getBounds ();
891         Rectangle dstOutRect = dstOut.getBounds ();
892         
893         int xp = xorColor.getRGB ();
894         int x = 0, y = 0;
895         int w = Math.min (Math.min (srcRect.width, dstOutRect.width), dstInRect.width);
896         int h = Math.min (Math.min (srcRect.height, dstOutRect.height), dstInRect.height);
897         Object srcPix = null, dstPix = null;
898
899         for (y = 0; y < h; y++)
900           for (x = 0; x < w; x++)
901             {
902               srcPix = src.getDataElements (x + srcRect.x, y + srcRect.y, srcPix);
903               dstPix = dstIn.getDataElements (x + dstInRect.x, y + dstInRect.y, dstPix);
904               int sp = srcColorModel.getRGB (srcPix);
905               int dp = dstColorModel.getRGB (dstPix);
906               int rp = sp ^ xp ^ dp;
907               dstOut.setDataElements (x + dstOutRect.x, y + dstOutRect.y, 
908                                       dstColorModel.getDataElements (rp, null));
909             }
910       }
911     }
912     
913     public BitwiseXorComposite (Color c)
914     {
915       xorColor = c;
916     }
917     
918     public CompositeContext createContext (ColorModel srcColorModel, 
919                                            ColorModel dstColorModel, 
920                                            RenderingHints hints) 
921     {
922       return new BitwiseXorCompositeContext (srcColorModel, dstColorModel);
923     }
924   }  
925
926
927   ///////////////////////////////////////////////
928   ////// Unimplemented Stubs and Overloads //////
929   ///////////////////////////////////////////////
930
931   public boolean drawImage(Image image, 
932                            AffineTransform xform,
933                            ImageObserver obs)
934   {
935     throw new java.lang.UnsupportedOperationException ();
936   }
937   
938   public void drawImage(BufferedImage image,
939                         BufferedImageOp op,
940                         int x,
941                         int y)
942   {
943     throw new java.lang.UnsupportedOperationException ();
944   }
945   
946   public void drawRenderedImage(RenderedImage image,
947                                 AffineTransform xform)
948   {
949     throw new java.lang.UnsupportedOperationException ();
950   }
951   
952   public void drawRenderableImage(RenderableImage image,
953                                   AffineTransform xform)
954   {
955     throw new java.lang.UnsupportedOperationException ();
956   }
957
958   public void drawString(String text, float x, float y)
959   {
960     throw new java.lang.UnsupportedOperationException ();
961   }
962   
963   public void drawString(AttributedCharacterIterator iterator,
964                          float x, float y)
965   {
966     throw new java.lang.UnsupportedOperationException ();
967   }
968     
969   public boolean hit(Rectangle rect, Shape text,
970                      boolean onStroke)
971   {
972     throw new java.lang.UnsupportedOperationException ();
973   }
974
975   public GraphicsConfiguration getDeviceConfiguration()
976   {
977     throw new java.lang.UnsupportedOperationException ();
978   }
979
980   public void setComposite(Composite comp)
981   {
982     throw new java.lang.UnsupportedOperationException ();
983   }
984
985   public void setRenderingHint(RenderingHints.Key hintKey,
986                                Object hintValue)
987   {
988     throw new java.lang.UnsupportedOperationException ();
989   }
990
991   public Object getRenderingHint(RenderingHints.Key hintKey)
992   {
993     throw new java.lang.UnsupportedOperationException ();
994   }
995   
996   public void setRenderingHints(Map hints)
997   {
998     throw new java.lang.UnsupportedOperationException ();
999   }
1000
1001   public void addRenderingHints(Map hints)
1002   {
1003     throw new java.lang.UnsupportedOperationException ();
1004   }
1005
1006   public RenderingHints getRenderingHints()
1007   {
1008     throw new java.lang.UnsupportedOperationException ();
1009   }
1010
1011   public void shear(double shearX, double shearY)
1012   {
1013     throw new java.lang.UnsupportedOperationException ();
1014   }
1015
1016   public Composite getComposite()
1017   {
1018     throw new java.lang.UnsupportedOperationException ();
1019   }
1020
1021   public FontRenderContext getFontRenderContext ()
1022   {
1023     throw new java.lang.UnsupportedOperationException ();
1024   }
1025
1026   public void drawGlyphVector (GlyphVector g, float x, float y)
1027   {
1028     throw new java.lang.UnsupportedOperationException ();
1029   }
1030
1031   public void copyArea (int x, int y, int width, int height, int dx, int dy)
1032   {
1033     throw new java.lang.UnsupportedOperationException ();
1034   }
1035
1036   public void drawArc (int x, int y, int width, int height,
1037                        int startAngle, int arcAngle)
1038   {
1039     throw new java.lang.UnsupportedOperationException ();
1040   }
1041
1042   public boolean drawImage (Image img, int x, int y, Color bgcolor, 
1043                             ImageObserver observer)
1044   {
1045     throw new java.lang.UnsupportedOperationException ();
1046   }
1047
1048   public boolean drawImage (Image img, int x, int y, int width, int height, 
1049                             Color bgcolor, ImageObserver observer)
1050   {
1051     throw new java.lang.UnsupportedOperationException ();
1052   }
1053
1054   public boolean drawImage (Image img, int x, int y, int width, int height, 
1055                             ImageObserver observer)
1056   {
1057     throw new java.lang.UnsupportedOperationException ();
1058   }
1059
1060   public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, 
1061                             int sx1, int sy1, int sx2, int sy2, 
1062                             Color bgcolor, ImageObserver observer)
1063   {
1064     throw new java.lang.UnsupportedOperationException ();
1065   }
1066
1067   public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, 
1068                             int sx1, int sy1, int sx2, int sy2, 
1069                             ImageObserver observer) 
1070   {
1071     throw new java.lang.UnsupportedOperationException ();
1072   }
1073
1074   public void drawOval(int x, int y, int width, int height)
1075   {
1076     throw new java.lang.UnsupportedOperationException ();
1077   }
1078
1079   public void drawRoundRect(int x, int y, int width, int height, 
1080                             int arcWidth, int arcHeight)
1081   {
1082     throw new java.lang.UnsupportedOperationException ();
1083   }
1084
1085   public void drawString (String str, int x, int y)
1086   {
1087     throw new java.lang.UnsupportedOperationException ();
1088   }
1089
1090   public void drawString (AttributedCharacterIterator ci, int x, int y)
1091   {
1092     throw new java.lang.UnsupportedOperationException ();
1093   }
1094
1095   public void fillArc (int x, int y, int width, int height, 
1096                        int startAngle, int arcAngle)
1097   {
1098     cairoNewPath ();
1099     walkPath (new Arc2D.Double((double)x, (double)y, 
1100                                (double)width, (double)height,
1101                                (double)startAngle, (double)arcAngle,
1102                                Arc2D.PIE).getPathIterator (null));
1103     cairoClosePath ();
1104     cairoFill ();
1105   }
1106
1107   public void fillOval(int x, int y, int width, int height)
1108   {
1109     throw new java.lang.UnsupportedOperationException ();
1110   }
1111
1112   public void fillRoundRect (int x, int y, int width, int height, 
1113                              int arcWidth, int arcHeight)
1114   {
1115     throw new java.lang.UnsupportedOperationException ();
1116   }
1117
1118   public Font getFont ()
1119   {
1120     throw new java.lang.UnsupportedOperationException ();
1121   }
1122
1123   public FontMetrics getFontMetrics ()
1124   {
1125     throw new java.lang.UnsupportedOperationException ();
1126   }
1127
1128   public FontMetrics getFontMetrics (Font f)
1129   {
1130     throw new java.lang.UnsupportedOperationException ();
1131   }
1132
1133   public void setFont (Font f)
1134   {
1135     if (f instanceof GdkFont)
1136       font = (GdkFont) f;
1137     else
1138       font = new GdkFont (f.getAttributes ());
1139   }
1140
1141   public String toString()
1142   {
1143     throw new java.lang.UnsupportedOperationException ();
1144   }
1145
1146 }