OSDN Git Service

2003-09-17 Graydon Hoare <graydon@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkGraphics2D.c
1 /* gnu_java_awt_peer_gtk_GdkGraphics2d.c
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 #include "gtkpeer.h"
39 #include "gnu_java_awt_peer_gtk_GdkGraphics2D.h"
40 #include <gdk/gdktypes.h>
41 #include <gdk/gdkprivate.h>
42 #include <gdk/gdkx.h>
43
44 #include <gdk-pixbuf/gdk-pixbuf.h>
45 #include <gdk-pixbuf/gdk-pixdata.h>
46
47 #include <cairo.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50
51 struct state_table *native_graphics2d_state_table;
52
53 #define NSA_G2D_INIT(env, clazz) \
54   native_graphics2d_state_table = init_state_table (env, clazz)
55
56 #define NSA_GET_G2D_PTR(env, obj) \
57   get_state (env, obj, native_graphics2d_state_table)
58
59 #define NSA_SET_G2D_PTR(env, obj, ptr) \
60   set_state (env, obj, native_graphics2d_state_table, (void *)ptr)
61
62 #define NSA_DEL_G2D_PTR(env, obj) \
63   remove_state_slot (env, obj, native_graphics2d_state_table)
64
65 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initStaticState 
66   (JNIEnv *env, jclass clazz)
67 {
68     NSA_G2D_INIT (env, clazz);
69 }
70
71 /* these public final constants are part of the java2d public API, so we
72    write them explicitly here to save fetching them from the constant pool
73    all the time. */
74
75 #ifndef min
76 #define min(x,y) ((x) < (y) ? (x) : (y))
77 #endif
78
79 enum java_awt_alpha_composite_rule
80   {
81     java_awt_alpha_composite_CLEAR = 1,
82     java_awt_alpha_composite_SRC = 2,
83     java_awt_alpha_composite_SRC_OVER = 3,
84     java_awt_alpha_composite_DST_OVER = 4,
85     java_awt_alpha_composite_SRC_IN = 5,
86     java_awt_alpha_composite_DST_IN = 6,
87     java_awt_alpha_composite_SRC_OUT = 7,
88     java_awt_alpha_composite_DST_OUT = 8,
89     java_awt_alpha_composite_DST = 9,
90     java_awt_alpha_composite_SRC_ATOP = 10,
91     java_awt_alpha_composite_DST_ATOP = 11,
92     java_awt_alpha_composite_XOR = 12
93   };
94
95 enum java_awt_basic_stroke_join_rule
96   {
97     java_awt_basic_stroke_JOIN_MITER = 0,
98     java_awt_basic_stroke_JOIN_ROUND = 1,
99     java_awt_basic_stroke_JOIN_BEVEL = 2
100   };
101
102 enum java_awt_basic_stroke_cap_rule
103   {
104     java_awt_basic_stroke_CAP_BUTT = 0,
105     java_awt_basic_stroke_CAP_ROUND = 1,
106     java_awt_basic_stroke_CAP_SQUARE = 2
107   };
108
109 enum java_awt_geom_path_iterator_winding_rule
110   {
111     java_awt_geom_path_iterator_WIND_EVEN_ODD = 0,
112     java_awt_geom_path_iterator_WIND_NON_ZERO = 1
113   };
114
115
116 static void 
117 grab_current_drawable (GtkWidget *widget, GdkDrawable **draw, GdkWindow **win)
118 {  
119   g_assert (widget != NULL);
120   g_assert (draw != NULL);
121   g_assert (win != NULL);
122
123   if (GTK_IS_WINDOW (widget))
124     {
125       *win = find_gtk_layout (widget)->bin_window;
126     }
127   else if (GTK_IS_LAYOUT (widget))
128     {
129       *win = GTK_LAYOUT (widget)->bin_window;
130     }
131   else
132     {
133       *win = widget->window;
134     }
135
136   *draw = *win;
137   gdk_window_get_internal_paint_info (*win, draw, 0, 0);
138   g_object_ref (*draw);
139 }
140
141
142 static int
143 x_server_has_render_extension (void)
144 {
145   int ev = 0, err = 0; 
146   return (int) XRenderQueryExtension (GDK_DISPLAY (), &ev, &err);
147 }
148
149
150 static void
151 init_graphics2d_as_pixbuf (struct graphics2d *gr)
152 {
153   gint width, height;
154   gint bits_per_sample = 8;
155   gint total_channels = 4;
156   gboolean has_alpha = TRUE;
157   
158   g_assert (gr != NULL);
159   g_assert (gr->drawable != NULL);
160
161   if (gr->debug) printf ("initializing graphics2d as pixbuf\n");
162   gdk_drawable_get_size (gr->drawable, &width, &height);
163   gr->drawbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
164                                 has_alpha, bits_per_sample,
165                                 width, height);
166   g_assert (gr->drawbuf != NULL);
167   g_assert (gdk_pixbuf_get_bits_per_sample (gr->drawbuf) == bits_per_sample);
168   g_assert (gdk_pixbuf_get_n_channels (gr->drawbuf) == total_channels);
169   
170   gr->surface = cairo_surface_create_for_image (gdk_pixbuf_get_pixels (gr->drawbuf), 
171                                                 CAIRO_FORMAT_ARGB32, 
172                                                 gdk_pixbuf_get_width (gr->drawbuf), 
173                                                 gdk_pixbuf_get_height (gr->drawbuf), 
174                                                 gdk_pixbuf_get_rowstride (gr->drawbuf));      
175   g_assert (gr->surface != NULL);
176   g_assert (gr->cr != NULL);
177   cairo_set_target_surface (gr->cr, gr->surface);
178 }
179
180 static void
181 init_graphics2d_as_renderable (struct graphics2d *gr)
182 {
183   Drawable draw;
184   Display * dpy;
185   Visual * vis;
186   
187   g_assert (gr != NULL);
188   g_assert (gr->drawable != NULL);
189
190   gr->drawbuf = NULL;
191   
192   if (gr->debug) printf ("initializing graphics2d as renderable\n");
193   draw = gdk_x11_drawable_get_xid (gr->drawable);
194   
195   dpy = gdk_x11_drawable_get_xdisplay (gr->drawable);
196   g_assert (dpy != NULL);
197   
198   vis = gdk_x11_visual_get_xvisual (gdk_drawable_get_visual (gr->drawable));
199   g_assert (vis != NULL);
200   
201   gr->surface = cairo_surface_create_for_drawable (dpy, draw, vis, 
202                                                    CAIRO_FORMAT_ARGB32,
203                                                    DefaultColormap (dpy, DefaultScreen (dpy)));
204   g_assert (gr->surface != NULL);
205   g_assert (gr->cr != NULL);
206   cairo_set_target_surface (gr->cr, gr->surface);
207 }
208
209 static void
210 begin_drawing_operation (struct graphics2d * gr)
211 {  
212   gdk_threads_enter ();
213   if (gr->drawbuf)
214     {
215
216       gint drawable_width, drawable_height;
217       gint pixbuf_width, pixbuf_height;
218       gint width, height;
219       
220       gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
221       pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
222       pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
223       width = min (drawable_width, pixbuf_width);
224       height = min (drawable_height, pixbuf_height);
225
226       gdk_pixbuf_get_from_drawable (gr->drawbuf, /* destination pixbuf */
227                                     gr->drawable, 
228                                     NULL, /* colormap */
229                                     0, 0, 0, 0,
230                                     width, height); 
231       
232       if (gr->debug) printf ("copied (%d, %d) pixels from GDK drawable to pixbuf\n",
233                              width, height);      
234     }
235 }
236
237 static void
238 end_drawing_operation (struct graphics2d * gr)
239 {
240   if (gr->drawbuf)
241     { 
242       gint drawable_width, drawable_height;
243       gint pixbuf_width, pixbuf_height;
244       gint width, height;
245       
246       gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
247       pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
248       pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
249       width = min (drawable_width, pixbuf_width);
250       height = min (drawable_height, pixbuf_height);
251
252       gdk_draw_pixbuf (gr->drawable, NULL, gr->drawbuf,
253                        0, 0, 0, 0, 
254                        width, height, 
255                        GDK_RGB_DITHER_NORMAL, 0, 0);
256
257       if (gr->debug) printf ("copied (%d, %d) pixels from pixbuf to GDK drawable\n",
258                              width, height);
259     }
260   gdk_threads_leave ();
261 }
262
263
264 static void 
265 update_pattern_transform (struct graphics2d *gr)
266 {
267   double a, b, c, d, tx, ty;
268   cairo_matrix_t *mat = NULL;
269
270   g_assert (gr != NULL);
271   if (gr->pattern == NULL)
272     return;
273
274   return;
275   /* temporarily disabled: ambiguous behavior */
276   /*   cairo_get_matrix (gr->cr, &a, &b, &c, &d, &tx, &ty); */
277   mat = cairo_matrix_create ();
278   g_assert (mat != NULL);
279   cairo_matrix_set_affine (mat, a, b, c, d, tx, ty);
280   cairo_surface_set_matrix (gr->pattern, mat);
281   cairo_matrix_destroy (mat);
282 }
283
284 static void
285 check_for_debug (struct graphics2d *gr)
286 {
287   gr->debug = (gboolean)(getenv("DEBUGJ2D") != NULL);
288 }
289
290 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState
291   (JNIEnv *env, jobject obj, jobject old)
292 {
293   struct graphics2d *g = NULL, *g_old = NULL;
294
295   g = (struct graphics2d *) malloc (sizeof (struct graphics2d));
296   g_assert (g != NULL);
297   memset (g, 0, sizeof(struct graphics2d));
298
299   g_old = (struct graphics2d *) NSA_GET_G2D_PTR (env, old);
300   g_assert (g_old != NULL);
301
302   g->drawable = g_old->drawable;
303   g->debug = g_old->debug; 
304
305   gdk_threads_enter ();
306   g_object_ref (g->drawable);
307   
308   g->cr = cairo_create();
309   g_assert (g->cr != NULL);
310
311   if (x_server_has_render_extension ())
312     init_graphics2d_as_renderable (g);
313   else
314     init_graphics2d_as_pixbuf (g);
315
316   cairo_surface_set_filter (g->surface, CAIRO_FILTER_BILINEAR);
317
318   gdk_threads_leave ();
319
320   NSA_SET_G2D_PTR (env, obj, g);
321 }
322
323
324 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__II
325   (JNIEnv *env, jobject obj, jint width, jint height)
326 {
327   struct graphics2d *gr;
328
329   gdk_threads_enter ();
330   
331   gr = (struct graphics2d *) malloc (sizeof (struct graphics2d));
332   g_assert (gr != NULL);
333   memset (gr, 0, sizeof(struct graphics2d));
334
335   check_for_debug (gr);  
336
337   if (gr->debug) printf ("constructing offscreen drawable of size (%d,%d)\n",
338                          width, height);
339   
340   gr->drawable = (GdkDrawable *) gdk_pixmap_new (NULL, width, height, 
341                                                  gdk_rgb_get_visual ()->depth);
342   g_assert (gr->drawable != NULL);
343
344   gr->cr = cairo_create();
345   g_assert (gr->cr != NULL);
346
347   if (x_server_has_render_extension ())
348     init_graphics2d_as_renderable (gr);
349   else
350     init_graphics2d_as_pixbuf (gr);
351
352   gdk_threads_leave ();
353   if (gr->debug) printf ("constructed offscreen drawable of size (%d,%d)\n",
354                          width, height);
355   NSA_SET_G2D_PTR (env, obj, gr);
356 }
357
358 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable
359   (JNIEnv *env, jobject self, jobject other, jint x, jint y)
360 {
361   struct graphics2d *src = NULL, *dst = NULL;
362   gint s_height, s_width, d_height, d_width, height, width;
363   GdkGC *gc;
364
365   src = (struct graphics2d *)NSA_GET_G2D_PTR (env, other);
366   dst = (struct graphics2d *)NSA_GET_G2D_PTR (env, self);
367   g_assert (src != NULL);
368   g_assert (dst != NULL);  
369
370   if (src->debug) printf ("copying from offscreen drawable\n");
371
372   gdk_threads_enter ();
373   gdk_drawable_get_size (src->drawable, &s_width, &s_height);
374   gdk_drawable_get_size (dst->drawable, &d_width, &d_height);
375   width = min (s_width, d_width);
376   height = min (s_width, d_height);
377
378   gc = gdk_gc_new (dst->drawable);
379   g_assert (gc != NULL);
380
381   gdk_draw_drawable(dst->drawable, gc, src->drawable,
382                     0, 0, x, y, width, height);
383
384   g_object_unref (gc);
385
386   if (src->debug) printf ("copied %d x %d pixels from offscreen drawable\n", width, height);
387   gdk_threads_leave ();  
388 }
389
390 static jintArray
391 current_colors_of_widget (GtkWidget *widget, JNIEnv *env)
392 {
393   GdkColor color;
394   jintArray array;
395   jint *rgb;
396
397   g_assert (widget != NULL);
398   g_assert (env != NULL);
399
400   color = widget->style->fg[GTK_STATE_NORMAL];
401   array = (*env)->NewIntArray (env, 6);
402
403   rgb = (*env)->GetIntArrayElements (env, array, NULL);
404   rgb[0] = color.red >> 8;
405   rgb[1] = color.green >> 8;
406   rgb[2] = color.blue >> 8;
407
408   color = widget->style->bg[GTK_STATE_NORMAL];
409   rgb[3] = color.red >> 8;
410   rgb[4] = color.green >> 8;
411   rgb[5] = color.blue >> 8;
412
413   (*env)->ReleaseIntArrayElements (env, array, rgb, 0);
414   
415   return array;
416 }
417
418 JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2
419   (JNIEnv *env, jobject obj, jobject peer)
420 {
421   struct graphics2d *gr = NULL;
422   GtkWidget *widget = NULL;
423   void *ptr = NULL;
424   jintArray color;
425
426   ptr = NSA_GET_PTR (env, peer);
427   g_assert (ptr != NULL);
428   gdk_threads_enter ();
429
430   gr = (struct graphics2d *) malloc (sizeof (struct graphics2d));
431   g_assert (gr != NULL);
432   memset (gr, 0, sizeof(struct graphics2d));
433
434   check_for_debug (gr);
435
436   gr->cr = cairo_create();
437   g_assert (gr->cr != NULL);
438
439   widget = GTK_WIDGET (ptr);
440   g_assert (widget != NULL);
441
442   grab_current_drawable (widget, &(gr->drawable), &(gr->win));
443   g_assert (gr->drawable != NULL);
444
445   if (x_server_has_render_extension ())
446     init_graphics2d_as_renderable (gr);
447   else
448     init_graphics2d_as_pixbuf (gr);
449
450   color = current_colors_of_widget (widget, env);
451
452   gdk_threads_leave ();
453   NSA_SET_G2D_PTR (env, obj, gr);
454   return color;
455 }
456
457 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_dispose
458   (JNIEnv *env, jobject obj)
459 {
460   struct graphics2d *gr = NULL;
461
462   gr = (struct graphics2d *) NSA_DEL_G2D_PTR (env, obj);
463   if (gr == NULL) 
464     return; /* dispose has been called more than once */
465   
466   gdk_threads_enter ();
467
468   if (gr->surface)
469     cairo_surface_destroy (gr->surface);
470
471   cairo_destroy (gr->cr);
472
473   if (gr->drawbuf)
474     g_object_unref (gr->drawbuf); 
475
476   g_object_unref (gr->drawable);
477   free (gr);
478
479   if (gr->pattern)
480     cairo_surface_destroy (gr->pattern);
481
482   if (gr->pattern_pixels)
483     free (gr->pattern_pixels);
484
485   if (gr->debug) printf ("disposed of graphics2d\n");
486
487   gdk_threads_leave ();
488 }
489
490
491 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setGradient 
492   (JNIEnv *env, jobject obj, 
493    jdouble x1, jdouble y1, 
494    jdouble x2, jdouble y2,
495    jint r1, jint g1, jint b1, jint a1,
496    jint r2, jint g2, jint b2, jint a2,
497    jboolean cyclic)
498 {
499   struct graphics2d *gr = NULL;
500   cairo_surface_t *surf = NULL;
501   cairo_matrix_t *mat = NULL;
502   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
503   g_assert (gr != NULL);
504
505   if (gr->debug) printf ("setGradient (%f,%f) -> (%f,%f); (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",
506                          x1, y1, 
507                          x2, y2, 
508                          r1, g1, b1, a1, 
509                          r2, g2, b2, a2);
510   
511   cairo_save (gr->cr);
512   
513   if (cyclic)
514     surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 3, 2);
515   else
516     surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 2, 2);      
517   g_assert (surf != NULL);
518
519   cairo_set_target_surface (gr->cr, surf);
520   
521   cairo_identity_matrix (gr->cr);
522
523   cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0);
524   cairo_set_alpha (gr->cr, a1 / 255.0);
525   cairo_rectangle (gr->cr, 0, 0, 1, 2);
526   cairo_fill (gr->cr);
527     
528   cairo_set_rgb_color (gr->cr, r2 / 255.0, g2 / 255.0, b2 / 255.0);
529   cairo_set_alpha (gr->cr, a2 / 255.0);
530   cairo_rectangle (gr->cr, 1, 0, 1, 2);
531   cairo_fill (gr->cr);
532
533   if (cyclic)
534     {
535       cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0);
536       cairo_set_alpha (gr->cr, a1 / 255.0);
537       cairo_rectangle (gr->cr, 2, 0, 1, 2);
538       cairo_fill (gr->cr);
539     }
540
541   mat = cairo_matrix_create ();
542   g_assert (mat != NULL);
543
544   /* 
545      consider the vector [x2 - x1, y2 - y1] = [p,q]
546
547      this is a line in space starting at an 'origin' x1, y1.
548
549      it can also be thought of as a "transformed" unit vector in either the
550      x or y directions. we have just *drawn* our gradient as a unit vector
551      (well, a 2-3x unit vector) in the x dimension. so what we want to know
552      is which transformation turns our existing unit vector into [p,q].
553
554      which means solving for M in 
555  
556      [p,q] = M[1,0]
557
558      [p,q] = |a b| [1,0]
559              |c d|      
560
561      [p,q] = [a,c], with b = d = 0.
562
563      what does this mean? it means that our gradient is 1-dimensional; as
564      you move through the x axis of our 2 or 3 pixel gradient from logical
565      x positions 0 to 1, the transformation of your x coordinate under the
566      matrix M causes you to accumulate both x and y values in fill
567      space. the y value of a gradient coordinate is ignored, since the
568      gradient is one dimensional. which is correct.
569
570      unfortunately we want the opposite transformation, it seems, because of
571      the way cairo is going to use this transformation. I'm a bit confused by
572      that, but it seems to work right, so we take reciprocals of values and
573      negate offsets. oh well.
574      
575    */
576
577   double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1));
578   double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1));
579   double dx = (x1 == 0.) ? 0. : 1. / x1;
580   double dy = (y1 == 0.) ? 0. : 1. / y1;
581
582   cairo_matrix_set_affine (mat,
583                            a, 0.,
584                            c, 0.,
585                            dx, dy);
586
587   cairo_surface_set_matrix (surf, mat);
588   cairo_matrix_destroy (mat);
589   cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR);
590
591   /* FIXME: repeating gradients (not to mention hold gradients) don't seem to work. */
592   /*   cairo_surface_set_repeat (surf, cyclic ? 1 : 0); */
593
594   if (gr->pattern)
595     cairo_surface_destroy (gr->pattern);
596
597   if (gr->pattern_pixels)
598     {
599       free (gr->pattern_pixels);
600       gr->pattern_pixels = NULL;
601     }
602
603   gr->pattern = surf;  
604
605   cairo_restore (gr->cr);    
606   cairo_set_pattern (gr->cr, gr->pattern);
607
608 }
609
610 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setTexturePixels 
611   (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride)
612 {
613   struct graphics2d *gr = NULL;
614   jint *jpixels = NULL;
615
616   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
617   g_assert (gr != NULL);
618
619   if (gr->debug) printf ("setTexturePixels (%d pixels, %dx%d, stride: %d)\n",
620                          (*env)->GetArrayLength (env, jarr), w, h, stride);
621
622   if (gr->pattern)
623     cairo_surface_destroy (gr->pattern);
624
625   if (gr->pattern_pixels)
626     free (gr->pattern_pixels);
627
628   gr->pattern = NULL;
629   gr->pattern_pixels = NULL;
630
631   gr->pattern_pixels = (char *) malloc (h * stride * 4);
632   g_assert (gr->pattern_pixels != NULL);
633
634   jpixels = (*env)->GetIntArrayElements (env, jarr, NULL);
635   g_assert (jpixels != NULL);
636   memcpy (gr->pattern_pixels, jpixels, h * stride * 4);
637   (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0);
638
639   gr->pattern = cairo_surface_create_for_image (gr->pattern_pixels, 
640                                                 CAIRO_FORMAT_ARGB32, 
641                                                 w, h, stride * 4);
642   g_assert (gr->pattern != NULL);
643   cairo_surface_set_repeat (gr->pattern, 1);
644   cairo_set_pattern (gr->cr, gr->pattern);
645
646 }
647
648 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels 
649   (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride)
650 {
651   struct graphics2d *gr = NULL;
652   jint *jpixels = NULL;
653
654   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
655   g_assert (gr != NULL);
656
657   if (gr->debug) printf ("drawPixels (%d pixels, %dx%d, stride: %d)\n",
658                          (*env)->GetArrayLength (env, jarr), w, h, stride);
659
660   jpixels = (*env)->GetIntArrayElements (env, jarr, NULL);
661   g_assert (jpixels != NULL);
662
663   begin_drawing_operation (gr);
664
665  {
666    cairo_surface_t *surf = cairo_surface_create_for_image ((char *)jpixels, 
667                                                            CAIRO_FORMAT_ARGB32, 
668                                                            w, h, stride * 4);   
669    cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR);
670    cairo_show_surface (gr->cr, surf, w, h);
671    cairo_surface_destroy (surf);
672  }
673
674   end_drawing_operation (gr);
675
676   (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0);
677
678 }
679
680 /* passthrough methods to cairo */
681
682 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSave 
683    (JNIEnv *env, jobject obj)
684 {
685   struct graphics2d *gr = NULL;
686   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
687   g_assert (gr != NULL);
688   if (gr->debug) printf ("cairo_save\n");
689   cairo_save (gr->cr);
690 }
691
692 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRestore 
693    (JNIEnv *env, jobject obj)
694 {
695   struct graphics2d *gr = NULL;
696   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
697   g_assert (gr != NULL);
698   if (gr->debug) printf ("cairo_restore\n");
699   cairo_restore (gr->cr);
700   update_pattern_transform (gr);
701 }
702
703 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMatrix 
704    (JNIEnv *env, jobject obj,
705     jdouble m00, jdouble m10,
706     jdouble m01, jdouble m11,
707     jdouble m02, jdouble m12)
708 {
709   struct graphics2d *gr = NULL;
710   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
711   g_assert (gr != NULL);
712   if (gr->debug) printf ("cairo_set_matrix\n");
713
714   {
715     cairo_matrix_t * mat = cairo_matrix_create ();
716     cairo_matrix_set_affine (mat,
717                              m00, m10,
718                              m01, m11,
719                              m02, m12);
720     cairo_set_matrix (gr->cr, mat);
721     cairo_matrix_destroy (mat);
722   }
723   update_pattern_transform (gr);
724 }
725
726 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetOperator 
727    (JNIEnv *env, jobject obj, jint op)
728 {
729   struct graphics2d *gr = NULL;
730   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
731   g_assert (gr != NULL);
732   if (gr->debug) printf ("cairo_set_operator %d\n", op);
733   switch ((enum java_awt_alpha_composite_rule) op)
734     {
735     case java_awt_alpha_composite_CLEAR: 
736       cairo_set_operator (gr->cr, CAIRO_OPERATOR_CLEAR);
737       break;
738       
739     case java_awt_alpha_composite_SRC: 
740       cairo_set_operator (gr->cr, CAIRO_OPERATOR_SRC);
741       break;
742       
743     case java_awt_alpha_composite_SRC_OVER: 
744       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER);
745       break;
746
747     case java_awt_alpha_composite_DST_OVER: 
748       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER_REVERSE);
749       break;
750
751     case java_awt_alpha_composite_SRC_IN: 
752       cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN);
753       break;
754
755     case java_awt_alpha_composite_DST_IN: 
756       cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN_REVERSE);
757       break;
758
759     case java_awt_alpha_composite_SRC_OUT: 
760       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT);
761       break;
762
763     case java_awt_alpha_composite_DST_OUT: 
764       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT_REVERSE);
765       break;
766
767     case java_awt_alpha_composite_DST: 
768       cairo_set_operator (gr->cr, CAIRO_OPERATOR_DST);
769       break;
770
771     case java_awt_alpha_composite_SRC_ATOP: 
772       cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP);
773       break;
774
775     case java_awt_alpha_composite_DST_ATOP: 
776       cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP_REVERSE);
777       break;
778
779     case java_awt_alpha_composite_XOR: 
780       cairo_set_operator (gr->cr, CAIRO_OPERATOR_XOR);
781       break;
782     }
783 }
784
785 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetRGBColor 
786    (JNIEnv *env, jobject obj, jdouble r, jdouble g, jdouble b)
787 {
788   struct graphics2d *gr = NULL;
789   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
790   g_assert (gr != NULL);
791
792   /* this is a very weird fact: GDK Pixbufs and RENDER drawables consider
793      colors in opposite pixel order. I have no idea why.  thus when you
794      draw to a PixBuf, you must exchange the R and B components of your
795      color. */
796
797   if (gr->debug) printf ("cairo_set_rgb_color (%f, %f, %f)\n", r, g, b);
798
799   if (gr->drawbuf)
800     cairo_set_rgb_color (gr->cr, b, g, r);
801   else
802     cairo_set_rgb_color (gr->cr, r, g, b);
803 }
804
805 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetAlpha 
806    (JNIEnv *env, jobject obj, jdouble a)
807 {
808   struct graphics2d *gr = NULL;
809   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
810   g_assert (gr != NULL);
811   if (gr->debug) printf ("cairo_set_alpha %f\n", a);
812   cairo_set_alpha (gr->cr, a);
813 }
814
815 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetFillRule 
816    (JNIEnv *env, jobject obj, jint rule)
817 {
818   struct graphics2d *gr = NULL;
819   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
820   if (gr->debug) printf ("cairo_set_fill_rule %d\n", rule);
821   g_assert (gr != NULL);
822   switch ((enum java_awt_geom_path_iterator_winding_rule) rule)
823     {
824     case java_awt_geom_path_iterator_WIND_NON_ZERO:
825       cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_WINDING);
826       break;
827     case java_awt_geom_path_iterator_WIND_EVEN_ODD:
828       cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_EVEN_ODD);
829       break;
830     }  
831 }
832
833 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineWidth 
834    (JNIEnv *env, jobject obj, jdouble width)
835 {
836   struct graphics2d *gr = NULL;
837   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
838   g_assert (gr != NULL);
839   if (gr->debug) printf ("cairo_set_line_width %f\n", width);
840   cairo_set_line_width (gr->cr, width);
841 }
842
843 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineCap 
844    (JNIEnv *env, jobject obj, jint cap)
845 {
846   struct graphics2d *gr = NULL;
847   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
848   g_assert (gr != NULL);
849   if (gr->debug) printf ("cairo_set_line_cap %d\n", cap);
850   switch ((enum java_awt_basic_stroke_cap_rule) cap)
851     {
852     case java_awt_basic_stroke_CAP_BUTT: 
853       cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_BUTT);
854       break;
855
856     case java_awt_basic_stroke_CAP_ROUND: 
857       cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_ROUND);
858       break;
859
860     case java_awt_basic_stroke_CAP_SQUARE: 
861       cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_SQUARE);
862       break;
863     }
864 }
865
866 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineJoin 
867    (JNIEnv *env, jobject obj, jint join)
868 {
869   struct graphics2d *gr = NULL;
870   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
871   g_assert (gr != NULL);
872   if (gr->debug) printf ("cairo_set_line_join %d\n", join);
873   switch ((enum java_awt_basic_stroke_join_rule) join)
874     {
875     case java_awt_basic_stroke_JOIN_MITER:
876       cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_MITER);
877       break;
878
879     case java_awt_basic_stroke_JOIN_ROUND:
880       cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_ROUND);
881       break;
882
883     case java_awt_basic_stroke_JOIN_BEVEL:
884       cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_BEVEL);
885       break;
886     }
887 }
888
889 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetDash 
890    (JNIEnv *env, jobject obj, jdoubleArray dashes, jint ndash, jdouble offset)
891 {
892   struct graphics2d *gr = NULL;
893   jdouble *dasharr = NULL;
894   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
895   g_assert (gr != NULL);
896   if (gr->debug) printf ("cairo_set_dash\n");
897   dasharr = (*env)->GetDoubleArrayElements (env, dashes, NULL);  
898   g_assert (dasharr != NULL);
899   cairo_set_dash (gr->cr, dasharr, ndash, offset);
900   (*env)->ReleaseDoubleArrayElements (env, dashes, dasharr, 0);
901 }
902
903 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMiterLimit 
904    (JNIEnv *env, jobject obj, jdouble miter)
905 {
906   struct graphics2d *gr = NULL;
907   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
908   g_assert (gr != NULL);
909   if (gr->debug) printf ("cairo_set_miter_limit %f\n", miter);
910   cairo_set_miter_limit (gr->cr, miter);
911 }
912
913 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoTranslate 
914    (JNIEnv *env, jobject obj, jdouble dx, jdouble dy)
915 {
916   struct graphics2d *gr = NULL;
917   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
918   g_assert (gr != NULL);
919   if (gr->debug) printf ("cairo_translate (%f, %f)\n", dx, dy);
920   cairo_translate (gr->cr, dx, dy);
921   update_pattern_transform (gr);
922 }
923
924 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoScale 
925    (JNIEnv *env, jobject obj, jdouble sx, jdouble sy)
926 {
927   struct graphics2d *gr = NULL;
928   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
929   g_assert (gr != NULL);
930   if (gr->debug) printf ("cairo_scale (%f, %f)\n", sx, sy);
931   cairo_scale (gr->cr, sx, sy);
932   update_pattern_transform (gr);
933 }
934
935 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRotate 
936    (JNIEnv *env, jobject obj, jdouble angle)
937 {
938   struct graphics2d *gr = NULL;
939   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
940   g_assert (gr != NULL);
941   if (gr->debug) printf ("cairo_rotate %f\n", angle);
942   cairo_rotate (gr->cr, angle);
943   update_pattern_transform (gr);
944 }
945
946 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoNewPath 
947    (JNIEnv *env, jobject obj)
948 {
949   struct graphics2d *gr = NULL;
950   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
951   g_assert (gr != NULL);
952   if (gr->debug) printf ("cairo_new_path\n");
953   cairo_new_path (gr->cr);
954 }
955
956 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoMoveTo 
957    (JNIEnv *env, jobject obj, jdouble x, jdouble y)
958 {
959   struct graphics2d *gr = NULL;
960   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
961   g_assert (gr != NULL);
962   if (gr->debug) printf ("cairo_move_to (%f, %f)\n", x, y);
963   cairo_move_to (gr->cr, x, y);
964 }
965
966 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoLineTo 
967    (JNIEnv *env, jobject obj, jdouble x, jdouble y)
968 {
969   struct graphics2d *gr = NULL;
970   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
971   g_assert (gr != NULL);
972   if (gr->debug) printf ("cairo_line_to (%f, %f)\n", x, y);
973   cairo_line_to (gr->cr, x, y);
974 }
975
976 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoCurveTo 
977    (JNIEnv *env, jobject obj, jdouble x1, jdouble y1, jdouble x2, jdouble y2, jdouble x3, jdouble y3)
978 {
979   struct graphics2d *gr = NULL;
980   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
981   g_assert (gr != NULL);
982   if (gr->debug) printf ("cairo_curve_to (%f, %f), (%f, %f), (%f, %f)\n", x1, y1, x2, y2, x3, y3);
983   cairo_curve_to (gr->cr, x1, y1, x2, y2, x3, y3);
984 }
985
986 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelMoveTo 
987    (JNIEnv *env, jobject obj, jdouble dx, jdouble dy)
988 {
989   struct graphics2d *gr = NULL;
990   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
991   g_assert (gr != NULL);
992   if (gr->debug) printf ("cairo_rel_move_to (%f, %f)\n", dx, dy);
993   cairo_rel_move_to (gr->cr, dx, dy);
994 }
995
996 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelLineTo 
997    (JNIEnv *env, jobject obj, jdouble dx, jdouble dy)
998 {
999   struct graphics2d *gr = NULL;
1000   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1001   g_assert (gr != NULL);
1002   if (gr->debug) printf ("cairo_rel_line_to (%f, %f)\n", dx, dy);
1003   cairo_rel_line_to (gr->cr, dx, dy);
1004 }
1005
1006 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelCurveTo 
1007    (JNIEnv *env, jobject obj, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2, jdouble dx3, jdouble dy3)
1008 {
1009   struct graphics2d *gr = NULL;
1010   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1011   g_assert (gr != NULL);
1012   if (gr->debug) printf ("cairo_rel_curve_to (%f, %f), (%f, %f), (%f, %f)\n", dx1, dy1, dx2, dy2, dx3, dy3);
1013   cairo_rel_curve_to (gr->cr, dx1, dy1, dx2, dy2, dx3, dy3);
1014 }
1015
1016 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRectangle 
1017    (JNIEnv *env, jobject obj, jdouble x, jdouble y, jdouble width, jdouble height)
1018 {
1019   struct graphics2d *gr = NULL;
1020   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1021   g_assert (gr != NULL);
1022   if (gr->debug) printf ("cairo_rectangle (%f, %f) (%f, %f)\n", x, y, width, height);
1023   cairo_rectangle (gr->cr, x, y, width, height);
1024 }
1025
1026 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClosePath 
1027    (JNIEnv *env, jobject obj)
1028 {
1029   struct graphics2d *gr = NULL;
1030   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1031   g_assert (gr != NULL);
1032   if (gr->debug) printf ("cairo_close_path\n");
1033   cairo_close_path (gr->cr);
1034 }
1035
1036 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoStroke 
1037    (JNIEnv *env, jobject obj)
1038 {
1039   struct graphics2d *gr = NULL;
1040   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1041   g_assert (gr != NULL);
1042   if (gr->debug) printf ("cairo_stroke\n");
1043   begin_drawing_operation (gr);
1044   cairo_stroke (gr->cr);
1045   end_drawing_operation (gr);
1046 }
1047
1048 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoFill 
1049    (JNIEnv *env, jobject obj)
1050 {
1051   struct graphics2d *gr = NULL;
1052   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1053   g_assert (gr != NULL);
1054   if (gr->debug) printf ("cairo_fill\n");
1055   begin_drawing_operation (gr);
1056   cairo_fill (gr->cr);
1057   end_drawing_operation (gr);
1058 }
1059
1060 JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClip 
1061    (JNIEnv *env, jobject obj)
1062 {
1063   struct graphics2d *gr = NULL;
1064   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1065   g_assert (gr != NULL);
1066   if (gr->debug) printf ("cairo_clip\n");
1067   cairo_clip (gr->cr);
1068 }
1069