OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@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, 2004 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 "gtkcairopeer.h"
39 #include "gdkfont.h"
40 #include "gnu_java_awt_peer_gtk_GdkGraphics2D.h"
41 #include <gdk/gdktypes.h>
42 #include <gdk/gdkprivate.h>
43 #include <gdk/gdkx.h>
44
45 #include <gdk-pixbuf/gdk-pixbuf.h>
46 #include <gdk-pixbuf/gdk-pixdata.h>
47
48 #include <cairo.h>
49
50 #include <stdio.h>
51 #include <stdlib.h>
52
53 struct state_table *native_graphics2d_state_table;
54
55 #define NSA_G2D_INIT(env, clazz) \
56   native_graphics2d_state_table = init_state_table (env, clazz)
57
58 #define NSA_GET_G2D_PTR(env, obj) \
59   get_state (env, obj, native_graphics2d_state_table)
60
61 #define NSA_SET_G2D_PTR(env, obj, ptr) \
62   set_state (env, obj, native_graphics2d_state_table, (void *)ptr)
63
64 #define NSA_DEL_G2D_PTR(env, obj) \
65   remove_state_slot (env, obj, native_graphics2d_state_table)
66
67 JNIEXPORT void JNICALL
68 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initStaticState 
69   (JNIEnv *env, jclass clazz)
70 {
71    gdk_threads_enter();
72    NSA_G2D_INIT (env, clazz);
73    gdk_threads_leave();
74 }
75
76 /* these public final constants are part of the java2d public API, so we
77    write them explicitly here to save fetching them from the constant pool
78    all the time. */
79
80 #ifndef min
81 #define min(x,y) ((x) < (y) ? (x) : (y))
82 #endif
83
84 enum java_awt_alpha_composite_rule
85   {
86     java_awt_alpha_composite_CLEAR = 1,
87     java_awt_alpha_composite_SRC = 2,
88     java_awt_alpha_composite_SRC_OVER = 3,
89     java_awt_alpha_composite_DST_OVER = 4,
90     java_awt_alpha_composite_SRC_IN = 5,
91     java_awt_alpha_composite_DST_IN = 6,
92     java_awt_alpha_composite_SRC_OUT = 7,
93     java_awt_alpha_composite_DST_OUT = 8,
94     java_awt_alpha_composite_DST = 9,
95     java_awt_alpha_composite_SRC_ATOP = 10,
96     java_awt_alpha_composite_DST_ATOP = 11,
97     java_awt_alpha_composite_XOR = 12
98   };
99
100 enum java_awt_basic_stroke_join_rule
101   {
102     java_awt_basic_stroke_JOIN_MITER = 0,
103     java_awt_basic_stroke_JOIN_ROUND = 1,
104     java_awt_basic_stroke_JOIN_BEVEL = 2
105   };
106
107 enum java_awt_basic_stroke_cap_rule
108   {
109     java_awt_basic_stroke_CAP_BUTT = 0,
110     java_awt_basic_stroke_CAP_ROUND = 1,
111     java_awt_basic_stroke_CAP_SQUARE = 2
112   };
113
114 enum java_awt_geom_path_iterator_winding_rule
115   {
116     java_awt_geom_path_iterator_WIND_EVEN_ODD = 0,
117     java_awt_geom_path_iterator_WIND_NON_ZERO = 1
118   };
119
120 enum java_awt_rendering_hints_filter
121   {
122     java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR = 0,    
123     java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR = 1,
124     java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED = 2,
125     java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY = 3,
126     java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT = 4
127  
128   };
129
130 static int
131 peer_is_disposed(JNIEnv *env, jobject obj)
132 {
133   static jfieldID fid = NULL;
134   jclass cls;
135   jobject peer;
136
137   return 0;
138
139   if (fid == NULL)
140     {
141       cls = (*env)->GetObjectClass(env, obj);
142       fid = (*env)->GetFieldID(env, cls, "component",
143                                "Lgnu/java/awt/peer/gtk/GtkComponentPeer;");
144     }
145   g_assert(fid != NULL);
146   peer = (*env)->GetObjectField(env, obj, fid);
147   if (peer == NULL || NSA_GET_PTR (env, peer) != NULL)
148     return 0;
149   else
150     {
151       return 1;
152     }
153 }
154
155
156 static void 
157 grab_current_drawable (GtkWidget *widget, GdkDrawable **draw, GdkWindow **win)
158 {  
159   g_assert (widget != NULL);
160   g_assert (draw != NULL);
161   g_assert (win != NULL);
162
163   *win = widget->window;
164
165   *draw = *win;
166   gdk_window_get_internal_paint_info (*win, draw, 0, 0); 
167   g_object_ref (*draw);
168 }
169
170
171 static int
172 x_server_has_render_extension (void)
173 {
174   int ev = 0, err = 0; 
175   return (int) XRenderQueryExtension (GDK_DISPLAY (), &ev, &err);
176 }
177
178
179 static void
180 init_graphics2d_as_pixbuf (struct graphics2d *gr)
181 {
182   gint width, height;
183   gint bits_per_sample = 8;
184   gint total_channels = 4;
185   gboolean has_alpha = TRUE;
186   
187   g_assert (gr != NULL);
188   g_assert (gr->drawable != NULL);
189
190   if (gr->debug) printf ("initializing graphics2d as pixbuf\n");
191   gdk_drawable_get_size (gr->drawable, &width, &height);
192   gr->drawbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 
193                                 has_alpha, bits_per_sample,
194                                 width, height);
195   g_assert (gr->drawbuf != NULL);
196   g_assert (gdk_pixbuf_get_bits_per_sample (gr->drawbuf) == bits_per_sample);
197   g_assert (gdk_pixbuf_get_n_channels (gr->drawbuf) == total_channels);
198   
199   gr->surface = cairo_surface_create_for_image (gdk_pixbuf_get_pixels (gr->drawbuf), 
200                                                 CAIRO_FORMAT_ARGB32, 
201                                                 gdk_pixbuf_get_width (gr->drawbuf), 
202                                                 gdk_pixbuf_get_height (gr->drawbuf), 
203                                                 gdk_pixbuf_get_rowstride (gr->drawbuf));      
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 init_graphics2d_as_renderable (struct graphics2d *gr)
211 {
212   Drawable draw;
213   Display * dpy;
214   Visual * vis;
215   
216   g_assert (gr != NULL);
217   g_assert (gr->drawable != NULL);
218
219   gr->drawbuf = NULL;
220   
221   if (gr->debug) printf ("initializing graphics2d as renderable\n");
222   draw = gdk_x11_drawable_get_xid (gr->drawable);
223   
224   dpy = gdk_x11_drawable_get_xdisplay (gr->drawable);
225   g_assert (dpy != NULL);
226   
227   vis = gdk_x11_visual_get_xvisual (gdk_drawable_get_visual (gr->drawable));
228   g_assert (vis != NULL);
229   
230   gr->surface = cairo_xlib_surface_create (dpy, draw, vis, 
231                                            CAIRO_FORMAT_ARGB32,
232                                            DefaultColormap (dpy, DefaultScreen (dpy)));
233   g_assert (gr->surface != NULL);
234   g_assert (gr->cr != NULL);
235   cairo_set_target_surface (gr->cr, gr->surface);
236 }
237
238 static void
239 begin_drawing_operation (struct graphics2d * gr)
240 {  
241   g_assert(cairo_status (gr->cr) == CAIRO_STATUS_SUCCESS);
242   if (gr->drawbuf)
243     {
244
245       gint drawable_width, drawable_height;
246       gint pixbuf_width, pixbuf_height;
247       gint width, height;
248       
249       gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
250       pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
251       pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
252       width = min (drawable_width, pixbuf_width);
253       height = min (drawable_height, pixbuf_height);
254
255       gdk_pixbuf_get_from_drawable (gr->drawbuf, /* destination pixbuf */
256                                     gr->drawable, 
257                                     NULL, /* colormap */
258                                     0, 0, 0, 0,
259                                     width, height); 
260       
261       if (gr->debug) printf ("copied (%d, %d) pixels from GDK drawable to pixbuf\n",
262                              width, height);      
263     }
264 }
265
266 static void
267 end_drawing_operation (struct graphics2d * gr)
268 {
269   g_assert(cairo_status (gr->cr) == CAIRO_STATUS_SUCCESS);
270   if (gr->drawbuf)
271     { 
272       gint drawable_width, drawable_height;
273       gint pixbuf_width, pixbuf_height;
274       gint width, height;
275       
276       gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
277       pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
278       pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
279       width = min (drawable_width, pixbuf_width);
280       height = min (drawable_height, pixbuf_height);
281
282       gdk_draw_pixbuf (gr->drawable, NULL, gr->drawbuf,
283                        0, 0, 0, 0, 
284                        width, height, 
285                        GDK_RGB_DITHER_NORMAL, 0, 0);
286
287       if (gr->debug) printf ("copied (%d, %d) pixels from pixbuf to GDK drawable\n",
288                              width, height);
289     }
290 }
291
292
293 static void 
294 update_pattern_transform (struct graphics2d *gr)
295 {
296   double a, b, c, d, tx, ty;
297   cairo_matrix_t *mat = NULL;
298
299   g_assert (gr != NULL);
300   if (gr->pattern == NULL)
301     return;
302
303   return;
304   /* temporarily disabled: ambiguous behavior */
305   /*   cairo_get_matrix (gr->cr, &a, &b, &c, &d, &tx, &ty); */
306   mat = cairo_matrix_create ();
307   g_assert (mat != NULL);
308   cairo_matrix_set_affine (mat, a, b, c, d, tx, ty);
309   cairo_pattern_set_matrix (gr->pattern, mat);
310   cairo_matrix_destroy (mat);
311 }
312
313 static void
314 check_for_debug (struct graphics2d *gr)
315 {
316   gr->debug = (gboolean)(getenv("DEBUGJ2D") != NULL);
317 }
318
319 static void
320 realize_cb (GtkWidget *widget, jobject peer)
321 {
322   gdk_threads_leave ();
323
324   (*gdk_env)->CallVoidMethod (gdk_env, peer, initComponentGraphics2DID);
325
326   gdk_threads_enter ();
327 }
328
329 JNIEXPORT void JNICALL
330 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState
331   (JNIEnv *env, jobject obj, jobject old)
332 {
333   struct graphics2d *g = NULL, *g_old = NULL;
334
335   gdk_threads_enter();
336   g = (struct graphics2d *) malloc (sizeof (struct graphics2d));
337   g_assert (g != NULL);
338   memset (g, 0, sizeof(struct graphics2d));
339
340   g_old = (struct graphics2d *) NSA_GET_G2D_PTR (env, old);
341   g_assert (g_old != NULL);
342
343   if (g_old->debug) printf ("copying state from existing graphics2d\n");
344
345   g->drawable = g_old->drawable;
346   g->debug = g_old->debug; 
347
348   g_object_ref (g->drawable);
349   
350   g->cr = cairo_create();
351   g_assert (g->cr != NULL);
352
353   if (x_server_has_render_extension ())
354     init_graphics2d_as_renderable (g);
355   else
356     init_graphics2d_as_pixbuf (g);
357
358   cairo_surface_set_filter (g->surface, CAIRO_FILTER_FAST);
359
360   NSA_SET_G2D_PTR (env, obj, g);
361   gdk_threads_leave();
362 }
363
364
365 JNIEXPORT void JNICALL
366 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__II
367   (JNIEnv *env, jobject obj, jint width, jint height)
368 {
369   struct graphics2d *gr;
370   
371   gdk_threads_enter();
372   gr = (struct graphics2d *) malloc (sizeof (struct graphics2d));
373   g_assert (gr != NULL);
374   memset (gr, 0, sizeof(struct graphics2d));
375
376   check_for_debug (gr);  
377
378   if (gr->debug) printf ("constructing offscreen drawable of size (%d,%d)\n",
379                          width, height);
380
381   gr->drawable = (GdkDrawable *) gdk_pixmap_new (NULL, width, height, 
382                                                  gdk_rgb_get_visual ()->depth);
383   g_assert (gr->drawable != NULL);
384
385   gr->cr = cairo_create();
386   g_assert (gr->cr != NULL);
387
388   if (x_server_has_render_extension ())
389     init_graphics2d_as_renderable (gr);
390   else
391     init_graphics2d_as_pixbuf (gr);
392
393   if (gr->debug) printf ("constructed offscreen drawable of size (%d,%d)\n",
394                          width, height);
395   NSA_SET_G2D_PTR (env, obj, gr);
396   gdk_threads_leave();
397 }
398
399 JNIEXPORT void JNICALL
400 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable
401   (JNIEnv *env, jobject self, jobject other, jint x, jint y)
402 {
403   struct graphics2d *src = NULL, *dst = NULL;
404   gint s_height, s_width, d_height, d_width, height, width;
405   cairo_matrix_t *matrix;
406   cairo_operator_t tmp_op;
407
408   gdk_threads_enter();
409   if (peer_is_disposed(env, self)) { gdk_threads_leave(); return; }
410   src = (struct graphics2d *)NSA_GET_G2D_PTR (env, other);
411   dst = (struct graphics2d *)NSA_GET_G2D_PTR (env, self);
412   g_assert (src != NULL);
413   g_assert (dst != NULL);  
414
415   if (src->debug) printf ("copying from offscreen drawable\n");
416
417   begin_drawing_operation(dst); 
418
419   /* gdk_flush(); */
420
421   gdk_drawable_get_size (src->drawable, &s_width, &s_height);
422   gdk_drawable_get_size (dst->drawable, &d_width, &d_height);
423   width = min (s_width, d_width);
424   height = min (s_height, d_height);
425
426   matrix = cairo_matrix_create ();
427   cairo_surface_get_matrix (src->surface, matrix);
428   cairo_matrix_translate (matrix, (double)-x, (double)-y);
429   cairo_surface_set_matrix (src->surface, matrix);
430
431   tmp_op = cairo_current_operator (dst->cr); 
432   cairo_set_operator(dst->cr, CAIRO_OPERATOR_SRC); 
433   cairo_show_surface (dst->cr, src->surface, width, height);
434   cairo_set_operator(dst->cr, tmp_op);
435
436   cairo_matrix_translate (matrix, (double)x, (double)y);
437   cairo_surface_set_matrix (src->surface, matrix);
438   cairo_matrix_destroy (matrix);
439
440   gdk_flush();
441
442   end_drawing_operation(dst);
443
444   if (src->debug) printf ("copied %d x %d pixels from offscreen drawable\n", width, height);
445   gdk_threads_leave();
446 }
447
448 JNIEXPORT void JNICALL
449 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2
450   (JNIEnv *env, jobject obj, jobject peer)
451 {
452   struct graphics2d *gr = NULL;
453   GtkWidget *widget = NULL;
454   void *ptr = NULL;
455
456   gdk_threads_enter();
457   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
458   ptr = NSA_GET_PTR (env, peer);
459   g_assert (ptr != NULL);
460
461   gr = (struct graphics2d *) malloc (sizeof (struct graphics2d));
462   g_assert (gr != NULL);
463   memset (gr, 0, sizeof(struct graphics2d));
464
465   check_for_debug (gr);
466
467   gr->cr = cairo_create();
468   g_assert (gr->cr != NULL);
469
470   widget = GTK_WIDGET (ptr);
471   g_assert (widget != NULL);
472
473   grab_current_drawable (widget, &(gr->drawable), &(gr->win));
474   g_assert (gr->drawable != NULL);
475
476   if (x_server_has_render_extension ())
477     init_graphics2d_as_renderable (gr);
478   else
479     init_graphics2d_as_pixbuf (gr);
480
481   NSA_SET_G2D_PTR (env, obj, gr);
482   gdk_threads_leave();
483 }
484
485 JNIEXPORT void JNICALL
486 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_connectSignals
487   (JNIEnv *env, jobject obj, jobject peer)
488 {
489   void *ptr;
490
491   ptr = NSA_GET_PTR (env, peer);
492
493   gdk_threads_enter ();
494
495   g_signal_connect_after (G_OBJECT (ptr), "realize",
496                           G_CALLBACK (realize_cb), obj);
497
498   gdk_threads_leave ();
499 }
500
501 JNIEXPORT void JNICALL
502 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_dispose
503   (JNIEnv *env, jobject obj)
504 {
505   struct graphics2d *gr = NULL;
506
507   gdk_threads_enter();
508   gr = (struct graphics2d *) NSA_DEL_G2D_PTR (env, obj);
509   if (gr == NULL) 
510     {
511       gdk_threads_leave();
512       return; /* dispose has been called more than once */
513     }
514
515   if (gr->surface)
516     cairo_surface_destroy (gr->surface);
517
518   cairo_destroy (gr->cr);
519
520   if (gr->drawbuf)
521     g_object_unref (gr->drawbuf); 
522
523   g_object_unref (gr->drawable);
524
525   if (gr->pattern)
526     cairo_pattern_destroy (gr->pattern);
527
528   if (gr->pattern_surface)
529     cairo_surface_destroy (gr->pattern_surface);
530
531   if (gr->pattern_pixels)
532     free (gr->pattern_pixels);
533
534   if (gr->debug) printf ("disposed of graphics2d\n");
535
536   free (gr);
537   gdk_threads_leave();
538 }
539
540
541 JNIEXPORT void JNICALL
542 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setGradient 
543   (JNIEnv *env, jobject obj, 
544    jdouble x1, jdouble y1, 
545    jdouble x2, jdouble y2,
546    jint r1, jint g1, jint b1, jint a1,
547    jint r2, jint g2, jint b2, jint a2,
548    jboolean cyclic)
549 {
550   struct graphics2d *gr = NULL;
551   cairo_surface_t *surf = NULL;
552   cairo_matrix_t *mat = NULL;
553   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
554   g_assert (gr != NULL);
555
556   gdk_threads_enter();
557   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
558   if (gr->debug) printf ("setGradient (%f,%f) -> (%f,%f); (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",
559                          x1, y1, 
560                          x2, y2, 
561                          r1, g1, b1, a1, 
562                          r2, g2, b2, a2);
563   
564   cairo_save (gr->cr);
565   
566   if (cyclic)
567     surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 3, 2);
568   else
569     surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 2, 2);      
570   g_assert (surf != NULL);
571
572   cairo_set_target_surface (gr->cr, surf);
573   
574   cairo_identity_matrix (gr->cr);
575
576   cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0);
577   cairo_set_alpha (gr->cr, a1 / 255.0);
578   cairo_rectangle (gr->cr, 0, 0, 1, 2);
579   cairo_fill (gr->cr);
580     
581   cairo_set_rgb_color (gr->cr, r2 / 255.0, g2 / 255.0, b2 / 255.0);
582   cairo_set_alpha (gr->cr, a2 / 255.0);
583   cairo_rectangle (gr->cr, 1, 0, 1, 2);
584   cairo_fill (gr->cr);
585
586   if (cyclic)
587     {
588       cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0);
589       cairo_set_alpha (gr->cr, a1 / 255.0);
590       cairo_rectangle (gr->cr, 2, 0, 1, 2);
591       cairo_fill (gr->cr);
592     }
593
594   mat = cairo_matrix_create ();
595   g_assert (mat != NULL);
596
597   /* 
598      consider the vector [x2 - x1, y2 - y1] = [p,q]
599
600      this is a line in space starting at an 'origin' x1, y1.
601
602      it can also be thought of as a "transformed" unit vector in either the
603      x or y directions. we have just *drawn* our gradient as a unit vector
604      (well, a 2-3x unit vector) in the x dimension. so what we want to know
605      is which transformation turns our existing unit vector into [p,q].
606
607      which means solving for M in 
608  
609      [p,q] = M[1,0]
610
611      [p,q] = |a b| [1,0]
612              |c d|      
613
614      [p,q] = [a,c], with b = d = 0.
615
616      what does this mean? it means that our gradient is 1-dimensional; as
617      you move through the x axis of our 2 or 3 pixel gradient from logical
618      x positions 0 to 1, the transformation of your x coordinate under the
619      matrix M causes you to accumulate both x and y values in fill
620      space. the y value of a gradient coordinate is ignored, since the
621      gradient is one dimensional. which is correct.
622
623      unfortunately we want the opposite transformation, it seems, because of
624      the way cairo is going to use this transformation. I'm a bit confused by
625      that, but it seems to work right, so we take reciprocals of values and
626      negate offsets. oh well.
627      
628    */
629   {
630     double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1));
631     double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1));
632     double dx = (x1 == 0.) ? 0. : 1. / x1;
633     double dy = (y1 == 0.) ? 0. : 1. / y1;
634     
635     cairo_matrix_set_affine (mat,
636                              a, 0.,
637                              c, 0.,
638                              dx, dy);
639     
640     cairo_surface_set_matrix (surf, mat);
641     cairo_matrix_destroy (mat);
642     cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR);
643   }
644
645   /* FIXME: repeating gradients (not to mention hold gradients) don't seem to work. */
646   /*   cairo_surface_set_repeat (surf, cyclic ? 1 : 0); */
647
648   if (gr->pattern)
649     cairo_pattern_destroy (gr->pattern);
650   
651   if (gr->pattern_surface)
652     cairo_surface_destroy (gr->pattern_surface);
653
654   if (gr->pattern_pixels)
655     free (gr->pattern_pixels);
656   
657   gr->pattern_pixels = NULL;  
658   gr->pattern_surface = surf;  
659   gr->pattern = cairo_pattern_create_for_surface(surf);
660
661   cairo_restore (gr->cr);    
662   cairo_set_pattern (gr->cr, gr->pattern);
663   gdk_threads_leave();
664 }
665
666 JNIEXPORT void JNICALL
667 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setTexturePixels 
668   (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride)
669 {
670   struct graphics2d *gr = NULL;
671   jint *jpixels = NULL;
672
673   gdk_threads_enter();
674   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
675   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
676   g_assert (gr != NULL);
677
678   if (gr->debug) printf ("setTexturePixels (%d pixels, %dx%d, stride: %d)\n",
679                          (*env)->GetArrayLength (env, jarr), w, h, stride);
680
681   if (gr->pattern)
682     cairo_pattern_destroy (gr->pattern);
683
684   if (gr->pattern_surface)
685     cairo_surface_destroy (gr->pattern_surface);
686
687   if (gr->pattern_pixels)
688     free (gr->pattern_pixels);
689
690   gr->pattern = NULL;
691   gr->pattern_surface = NULL;
692   gr->pattern_pixels = NULL;
693
694   gr->pattern_pixels = (char *) malloc (h * stride * 4);
695   g_assert (gr->pattern_pixels != NULL);
696
697   jpixels = (*env)->GetIntArrayElements (env, jarr, NULL);
698   g_assert (jpixels != NULL);
699   memcpy (gr->pattern_pixels, jpixels, h * stride * 4);
700   (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0);
701
702   gr->pattern_surface = cairo_surface_create_for_image (gr->pattern_pixels, 
703                                                         CAIRO_FORMAT_ARGB32, 
704                                                         w, h, stride * 4);
705   g_assert (gr->pattern_surface != NULL);
706   cairo_surface_set_repeat (gr->pattern_surface, 1);
707   gr->pattern = cairo_pattern_create_for_surface (gr->pattern_surface);
708   g_assert (gr->pattern != NULL);
709   cairo_set_pattern (gr->cr, gr->pattern);
710   gdk_threads_leave();
711 }
712
713 JNIEXPORT void JNICALL
714 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels 
715   (JNIEnv *env, jobject obj, jintArray java_pixels, 
716    jint w, jint h, jint stride, jdoubleArray java_matrix)
717 {
718   struct graphics2d *gr = NULL;
719   jint *native_pixels = NULL;
720   jdouble *native_matrix = NULL;
721
722   gdk_threads_enter();
723   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
724
725   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
726   g_assert (gr != NULL);
727
728   if (gr->debug) printf ("drawPixels (%d pixels, %dx%d, stride: %d)\n",
729                          (*env)->GetArrayLength (env, java_pixels), w, h, stride);
730
731   native_pixels = (*env)->GetIntArrayElements (env, java_pixels, NULL);
732   native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL);
733   g_assert (native_pixels != NULL);
734   g_assert (native_matrix != NULL);
735   g_assert ((*env)->GetArrayLength (env, java_matrix) == 6);
736
737   begin_drawing_operation (gr);
738   
739  {
740    cairo_matrix_t *mat = NULL;
741    cairo_surface_t *surf = cairo_surface_create_for_image ((char *)native_pixels, 
742                                                            CAIRO_FORMAT_ARGB32, 
743                                                            w, h, stride * 4);   
744    mat = cairo_matrix_create ();
745    cairo_matrix_set_affine (mat, 
746                             native_matrix[0], native_matrix[1],
747                             native_matrix[2], native_matrix[3],
748                             native_matrix[4], native_matrix[5]);
749    cairo_surface_set_matrix (surf, mat);
750    cairo_surface_set_filter (surf, cairo_surface_get_filter(gr->surface));
751
752    cairo_show_surface (gr->cr, surf, w, h);
753    cairo_matrix_destroy (mat);
754    cairo_surface_destroy (surf);
755  }
756   
757  end_drawing_operation (gr);
758  
759  (*env)->ReleaseIntArrayElements (env, java_pixels, native_pixels, 0);
760  (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0);
761  
762   gdk_threads_leave();
763 }
764
765 JNIEXPORT jintArray JNICALL
766 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getImagePixels 
767    (JNIEnv *env, jobject obj)
768 {
769   struct graphics2d *gr = NULL;
770   jintArray java_pixels;
771   jint* native_pixels;
772   GdkPixbuf *buf = NULL;
773   gint width, height;
774   gint bits_per_sample = 8;
775   gboolean has_alpha = TRUE;
776   gint total_channels = 4;
777   jint i;
778
779   gdk_threads_enter();
780   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return NULL; }
781
782   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
783   g_assert (gr != NULL);
784   
785   if (gr->debug) printf ("getImagePixels\n");
786   
787   gdk_drawable_get_size (gr->drawable, &width, &height);
788     
789   buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 
790                         bits_per_sample,
791                         width, height);
792   g_assert (buf != NULL);
793   g_assert (gdk_pixbuf_get_bits_per_sample (buf) == bits_per_sample);
794   g_assert (gdk_pixbuf_get_n_channels (buf) == total_channels);
795   
796       
797   /* copy pixels from drawable to pixbuf */
798   
799   gdk_pixbuf_get_from_drawable (buf, gr->drawable,
800                                 NULL, 
801                                 0, 0, 0, 0,
802                                 width, height);
803                                                                                                       
804   native_pixels= gdk_pixbuf_get_pixels (buf);
805
806 #ifndef WORDS_BIGENDIAN
807   /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
808   for (i=0; i<width * height; i++)
809     {
810       native_pixels[i] = SWAPU32 ((unsigned)native_pixels[i]);
811     }
812 #endif
813
814    java_pixels = (*env) -> NewIntArray (env, width * height);   
815    
816    (*env)->SetIntArrayRegion(env, java_pixels, 
817                             (jsize)0, (jsize) width*height, 
818                             (jint*) native_pixels);
819    
820    gdk_threads_leave();
821    return java_pixels;
822 }
823
824 /* passthrough methods to cairo */
825
826 JNIEXPORT void JNICALL
827 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSave 
828    (JNIEnv *env, jobject obj)
829 {
830   struct graphics2d *gr = NULL;
831
832   gdk_threads_enter();
833   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
834
835   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
836   g_assert (gr != NULL);
837   if (gr->debug) printf ("cairo_save\n");
838   cairo_save (gr->cr);
839   gdk_threads_leave();
840 }
841
842 JNIEXPORT void JNICALL
843 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRestore 
844    (JNIEnv *env, jobject obj)
845 {
846   struct graphics2d *gr = NULL;
847
848   gdk_threads_enter();
849   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
850
851   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
852   g_assert (gr != NULL);
853   if (gr->debug) printf ("cairo_restore\n");
854   cairo_restore (gr->cr);
855   update_pattern_transform (gr);
856   gdk_threads_leave();
857 }
858
859 JNIEXPORT void JNICALL
860 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMatrix 
861    (JNIEnv *env, jobject obj, jdoubleArray java_matrix)
862 {
863   struct graphics2d *gr = NULL;
864   jdouble *native_matrix = NULL;
865
866   gdk_threads_enter();
867   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
868
869   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
870   /* cairoSetMatrix was called before this graphics object's component
871      was realized. */
872   if (gr == NULL) { gdk_threads_leave (); return; }
873
874   native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL);  
875   g_assert (native_matrix != NULL);
876   g_assert ((*env)->GetArrayLength (env, java_matrix) == 6);
877
878   if (gr->debug) printf ("cairo_set_matrix [ %f, %f, %f, %f, %f, %f ]\n",
879                          native_matrix[0], native_matrix[1],
880                          native_matrix[2], native_matrix[3],
881                          native_matrix[4], native_matrix[5]);
882
883   {
884     cairo_matrix_t * mat = cairo_matrix_create ();
885     cairo_matrix_set_affine (mat, 
886                              native_matrix[0], native_matrix[1],
887                              native_matrix[2], native_matrix[3],
888                              native_matrix[4], native_matrix[5]);
889     cairo_set_matrix (gr->cr, mat);
890     cairo_matrix_destroy (mat);
891   }
892
893   (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0);
894   update_pattern_transform (gr);
895   gdk_threads_leave();
896 }
897
898 static void
899 install_font_peer(cairo_t *cr,
900                   struct peerfont *pfont,
901                   int debug)
902 {
903   cairo_font_t *ft;
904   FT_Face face = NULL;
905
906   g_assert(cr != NULL);
907   g_assert(pfont != NULL);
908   
909   if (pfont->graphics_resource == NULL)
910     {
911       face = pango_ft2_font_get_face (pfont->font);
912       g_assert (face != NULL);
913       
914       ft = cairo_ft_font_create_for_ft_face (face);
915       g_assert (ft != NULL);
916       
917       if (debug) printf ("install_font_peer made new cairo font for '%s' at %f\n", 
918                          face->family_name,
919                          (pango_font_description_get_size (pfont->desc) / 
920                           (double)PANGO_SCALE) * (96.0 / 72.0));
921     
922       cairo_set_font (cr, ft); 
923       cairo_font_destroy (ft);
924       cairo_scale_font (cr, 
925                         (pango_font_description_get_size (pfont->desc) / 
926                          (double)PANGO_SCALE) * (96.0 / 72.0));
927       ft = cairo_current_font (cr);
928       pfont->graphics_resource = ft;
929     }
930   else
931     {
932       if (debug) printf ("install_font_peer reused existing font resource\n");
933       ft = (cairo_font_t *) pfont->graphics_resource;
934       cairo_set_font (cr, ft);       
935     }
936 }
937
938 static cairo_t *metrics_cairo = NULL;
939 static cairo_surface_t *metrics_surface = NULL;
940
941 static void
942 ensure_metrics_cairo()
943 {
944   if (metrics_cairo == NULL)
945     {
946       metrics_cairo = cairo_create ();
947       metrics_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, 1, 1);
948       cairo_set_target_surface (metrics_cairo, metrics_surface);
949     }
950 }
951
952
953 JNIEXPORT void JNICALL
954 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_releasePeerGraphicsResource
955    (JNIEnv *env, jclass clazz, jobject java_font)
956 {
957   struct peerfont *pfont = NULL;
958
959   g_assert(java_font != NULL);
960
961   gdk_threads_enter();
962   pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, java_font);
963   g_assert (pfont != NULL);
964   if (pfont->graphics_resource != NULL)
965     {
966       cairo_font_destroy ((cairo_font_t *) pfont->graphics_resource);
967       pfont->graphics_resource = NULL;
968     }
969   gdk_threads_leave();
970 }
971
972 JNIEXPORT void JNICALL
973 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getPeerTextMetrics
974    (JNIEnv *env, jclass clazz, jobject java_font, jstring str, jdoubleArray java_metrics)
975 {
976   struct peerfont *pfont = NULL;
977   const char *cstr = NULL;
978   jdouble *native_metrics = NULL;
979   cairo_text_extents_t extents;
980
981   g_assert(java_font != NULL);
982   gdk_threads_enter();
983
984   pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, java_font);
985   g_assert (pfont != NULL);
986
987   ensure_metrics_cairo();
988   install_font_peer (metrics_cairo, pfont, 0);
989
990   cstr = (*env)->GetStringUTFChars (env, str, NULL);
991   g_assert(cstr != NULL);
992   cairo_text_extents (metrics_cairo, cstr, &extents);
993
994   native_metrics = (*env)->GetDoubleArrayElements (env, java_metrics, NULL);
995   g_assert (native_metrics != NULL);
996
997   native_metrics[TEXT_METRICS_X_BEARING] = extents.x_bearing;
998   native_metrics[TEXT_METRICS_Y_BEARING] = extents.y_bearing;
999   native_metrics[TEXT_METRICS_WIDTH] = extents.width;
1000   native_metrics[TEXT_METRICS_HEIGHT] = extents.height;
1001   native_metrics[TEXT_METRICS_X_ADVANCE] = extents.x_advance;
1002   native_metrics[TEXT_METRICS_Y_ADVANCE] = extents.y_advance;
1003          
1004   (*env)->ReleaseStringUTFChars (env, str, cstr);  
1005   (*env)->ReleaseDoubleArrayElements (env, java_metrics, native_metrics, 0);
1006   gdk_threads_leave();
1007 }
1008
1009 JNIEXPORT void JNICALL
1010 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getPeerFontMetrics
1011    (JNIEnv *env, jclass clazz, jobject java_font, jdoubleArray java_metrics)
1012 {
1013   struct peerfont *pfont = NULL;
1014   jdouble *native_metrics = NULL;
1015   cairo_font_extents_t extents;
1016
1017   g_assert(java_font != NULL);
1018
1019   gdk_threads_enter();
1020
1021   pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, java_font);
1022   g_assert (pfont != NULL);
1023
1024   ensure_metrics_cairo();
1025   install_font_peer (metrics_cairo, pfont, 0);
1026
1027   cairo_current_font_extents (metrics_cairo, &extents); 
1028
1029   native_metrics = (*env)->GetDoubleArrayElements (env, java_metrics, NULL);
1030   g_assert (native_metrics != NULL);
1031
1032   native_metrics[FONT_METRICS_ASCENT] = extents.ascent;
1033   native_metrics[FONT_METRICS_MAX_ASCENT] = extents.ascent;
1034   native_metrics[FONT_METRICS_DESCENT] = extents.descent;
1035   if (native_metrics[FONT_METRICS_DESCENT] < 0)
1036     native_metrics[FONT_METRICS_DESCENT] = - native_metrics[FONT_METRICS_DESCENT];
1037   native_metrics[FONT_METRICS_MAX_DESCENT] = native_metrics[FONT_METRICS_DESCENT];
1038   native_metrics[FONT_METRICS_MAX_ADVANCE] = extents.max_x_advance;
1039
1040   (*env)->ReleaseDoubleArrayElements (env, java_metrics, native_metrics, 0);
1041   gdk_threads_leave();
1042 }
1043
1044 static void
1045 paint_glyph_run(struct graphics2d *gr,
1046                 cairo_glyph_t **glyphs,
1047                 gint *n_glyphs,
1048                 PangoLayoutRun *run)
1049 {
1050   gint i = 0;
1051   gint x = 0, y = 0;
1052
1053   g_assert (gr != NULL);
1054   g_assert (glyphs != NULL);
1055   g_assert (n_glyphs != NULL);
1056   g_assert (run != NULL);
1057
1058   if (run->glyphs != NULL && run->glyphs->num_glyphs > 0)
1059     {
1060       if (*n_glyphs < run->glyphs->num_glyphs)
1061         {
1062           *glyphs = g_realloc(*glyphs, 
1063                               (sizeof(cairo_glyph_t) 
1064                                * run->glyphs->num_glyphs));
1065           *n_glyphs = run->glyphs->num_glyphs;
1066         }
1067       
1068       g_assert (*glyphs != NULL);
1069
1070       if (gr->debug) printf ("painting %d glyphs: ", run->glyphs->num_glyphs);
1071
1072       for (i = 0; i < run->glyphs->num_glyphs; ++i)
1073         {         
1074           (*glyphs)[i].index = run->glyphs->glyphs[i].glyph;
1075
1076           (*glyphs)[i].x =
1077             ((double) (x + run->glyphs->glyphs[i].geometry.x_offset)) 
1078             / ((double) PANGO_SCALE);
1079
1080           (*glyphs)[i].y =
1081             ((double) (y + run->glyphs->glyphs[i].geometry.y_offset)) 
1082             / ((double) PANGO_SCALE);
1083           
1084           if (gr->debug) printf(" (%ld @ %f,%f)",  
1085                                 (*glyphs)[i].index,  
1086                                 (*glyphs)[i].x, 
1087                                 (*glyphs)[i].y);
1088             
1089           x += run->glyphs->glyphs[i].geometry.width;
1090         }
1091
1092       if (gr->debug) printf("\n");
1093       begin_drawing_operation (gr);
1094       cairo_show_glyphs (gr->cr, *glyphs, run->glyphs->num_glyphs);
1095       end_drawing_operation (gr);      
1096     }
1097 }
1098
1099 JNIEXPORT void JNICALL
1100 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawString
1101   (JNIEnv *env, jobject obj, jobject font, jstring str, float x, float y)
1102 {
1103   struct graphics2d *gr = NULL;
1104   const char *cstr = NULL;
1105   struct peerfont *pfont = NULL;
1106
1107   /*
1108   cairo_glyph_t *glyphs = NULL;
1109   gint n_glyphs = 0;
1110   PangoLayoutRun *run = NULL;
1111   PangoLayoutIter *iter = NULL;
1112   */
1113
1114   g_assert(obj != NULL);
1115   g_assert(font != NULL);
1116   g_assert(str != NULL);
1117
1118   gdk_threads_enter ();
1119   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1120
1121   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1122   g_assert(gr != NULL);
1123
1124   pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, font);
1125   g_assert (pfont != NULL);
1126
1127   cstr = (*env)->GetStringUTFChars (env, str, NULL);
1128   g_assert(cstr != NULL);
1129
1130   if (gr->debug) printf ("painting string '%s' at (%f,%f)\n", cstr, x, y);
1131
1132   /* For now we let cairo do the glyph conversion; eventually this
1133    * ought to be unified with pango, but it is impossible to get
1134    * pango and cairo to agree on metrics at the moment, so we either
1135    * have to use "all cairo" metrics (the string-based APIs) or 
1136    * "all pango" metrics (the glyph-vector based APIs). 
1137    */
1138
1139   install_font_peer (gr->cr, pfont, gr->debug);
1140   cairo_move_to (gr->cr, x, y);
1141   cairo_show_text (gr->cr, cstr);
1142   
1143   /*
1144     
1145   pango_layout_set_text (gr->pango_layout, cstr, -1);
1146
1147   iter = pango_layout_get_iter (gr->pango_layout);
1148   g_assert(iter != NULL);
1149
1150   cairo_translate (gr->cr, x, y);
1151
1152   do 
1153     {
1154       run = pango_layout_iter_get_run (iter);
1155       if (run != NULL)
1156         paint_glyph_run (gr, &glyphs, &n_glyphs, run);
1157     } 
1158   while (pango_layout_iter_next_run (iter));
1159   
1160   if (glyphs != NULL)
1161     g_free (glyphs);
1162
1163   cairo_translate (gr->cr, -x, -y);
1164   
1165   pango_layout_iter_free (iter);
1166
1167   */
1168
1169   gdk_threads_leave ();
1170
1171   (*env)->ReleaseStringUTFChars (env, str, cstr);
1172 }
1173
1174
1175 JNIEXPORT void JNICALL
1176 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkGlyphVector
1177    (JNIEnv *env, jobject self, jobject font, jobject java_vec, jfloat x, jfloat y)
1178 {
1179   
1180   struct graphics2d *gr = NULL;
1181   struct peerfont *pfont = NULL;
1182   struct glyphvec *gv = NULL;
1183   PangoLayoutRun *run = NULL;
1184   cairo_glyph_t *glyphs = NULL;
1185   gint n_glyphs = 0;
1186
1187   g_assert (self != NULL);
1188   g_assert (java_vec != NULL);
1189
1190   gdk_threads_enter ();
1191   if (peer_is_disposed(env, self)) { gdk_threads_leave(); return; }
1192
1193   gr = (struct graphics2d *)NSA_GET_G2D_PTR (env, self);
1194   gv = (struct glyphvec *)NSA_GET_GV_PTR (env, java_vec);
1195   pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, font);
1196
1197   g_assert (gr != NULL);
1198   g_assert (gv != NULL);
1199   g_assert (pfont != NULL);
1200
1201   if (gr->debug) printf ("painting pango glyph vector\n");
1202
1203   install_font_peer (gr->cr, pfont, gr->debug);
1204   cairo_translate (gr->cr, x, y);
1205
1206   /* nb. PangoLayoutRun is a typedef for PangoGlyphItem. */
1207   run = (PangoLayoutRun *) gv->glyphitems;
1208   if (run != NULL)
1209     paint_glyph_run (gr, &glyphs, &n_glyphs, run);
1210
1211   if (glyphs != NULL)
1212     g_free (glyphs);
1213
1214   cairo_translate (gr->cr, -x, -y);
1215   gdk_threads_leave ();  
1216 }
1217
1218 JNIEXPORT void JNICALL
1219 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkTextLayout
1220    (JNIEnv *env, jobject self, jobject font, jobject java_layout, jfloat x, jfloat y)
1221 {
1222   /* 
1223    * FIXME: Some day we expect either cairo or pango will know how to make
1224    * a pango layout paint to a cairo surface. that day is not yet here.
1225    */
1226
1227   struct graphics2d *gr = NULL;
1228   struct peerfont *pfont = NULL;
1229   struct textlayout *tl = NULL;
1230   PangoLayoutIter *i = NULL;
1231   PangoLayoutRun *run = NULL;
1232   cairo_glyph_t *glyphs = NULL;
1233   gint n_glyphs = 0;
1234
1235   g_assert (self != NULL);
1236   g_assert (java_layout != NULL);
1237
1238   gr = (struct graphics2d *)NSA_GET_G2D_PTR (env, self);
1239   tl = (struct textlayout *)NSA_GET_TEXT_LAYOUT_PTR (env, java_layout);
1240   pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, font);
1241
1242   g_assert (gr != NULL);
1243   g_assert (tl != NULL);
1244   g_assert (tl->pango_layout != NULL);
1245   g_assert (pfont != NULL);
1246
1247   if (gr->debug) printf ("painting pango layout\n");
1248
1249   gdk_threads_enter ();
1250   if (peer_is_disposed(env, self)) { gdk_threads_leave(); return; }
1251
1252   i = pango_layout_get_iter (tl->pango_layout);
1253   g_assert (i != NULL);
1254
1255   install_font_peer (gr->cr, pfont, gr->debug);
1256   cairo_translate (gr->cr, x, y);
1257
1258   do 
1259     {
1260       run = pango_layout_iter_get_run (i);
1261       if (run != NULL)
1262         paint_glyph_run (gr, &glyphs, &n_glyphs, run);
1263     } 
1264   while (pango_layout_iter_next_run (i));
1265   
1266   if (glyphs != NULL)
1267     g_free (glyphs);
1268
1269   cairo_translate (gr->cr, -x, -y);
1270   
1271   pango_layout_iter_free (i);
1272   gdk_threads_leave ();
1273 }
1274
1275 JNIEXPORT void JNICALL
1276 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetOperator 
1277    (JNIEnv *env, jobject obj, jint op)
1278 {
1279   struct graphics2d *gr = NULL;
1280
1281   gdk_threads_enter();
1282   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1283
1284   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1285   g_assert (gr != NULL);
1286   if (gr->debug) printf ("cairo_set_operator %d\n", op);
1287   switch ((enum java_awt_alpha_composite_rule) op)
1288     {
1289     case java_awt_alpha_composite_CLEAR: 
1290       cairo_set_operator (gr->cr, CAIRO_OPERATOR_CLEAR);
1291       break;
1292       
1293     case java_awt_alpha_composite_SRC: 
1294       cairo_set_operator (gr->cr, CAIRO_OPERATOR_SRC);
1295       break;
1296       
1297     case java_awt_alpha_composite_SRC_OVER: 
1298       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER);
1299       break;
1300
1301     case java_awt_alpha_composite_DST_OVER: 
1302       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER_REVERSE);
1303       break;
1304
1305     case java_awt_alpha_composite_SRC_IN: 
1306       cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN);
1307       break;
1308
1309     case java_awt_alpha_composite_DST_IN: 
1310       cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN_REVERSE);
1311       break;
1312
1313     case java_awt_alpha_composite_SRC_OUT: 
1314       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT);
1315       break;
1316
1317     case java_awt_alpha_composite_DST_OUT: 
1318       cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT_REVERSE);
1319       break;
1320
1321     case java_awt_alpha_composite_DST: 
1322       cairo_set_operator (gr->cr, CAIRO_OPERATOR_DST);
1323       break;
1324
1325     case java_awt_alpha_composite_SRC_ATOP: 
1326       cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP);
1327       break;
1328
1329     case java_awt_alpha_composite_DST_ATOP: 
1330       cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP_REVERSE);
1331       break;
1332
1333     case java_awt_alpha_composite_XOR: 
1334       cairo_set_operator (gr->cr, CAIRO_OPERATOR_XOR);
1335       break;
1336     }
1337   gdk_threads_leave();
1338 }
1339
1340 JNIEXPORT void JNICALL
1341 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetRGBColor 
1342    (JNIEnv *env, jobject obj, jdouble r, jdouble g, jdouble b)
1343 {
1344   struct graphics2d *gr = NULL;
1345
1346   gdk_threads_enter();
1347   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1348
1349   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1350   g_assert (gr != NULL);
1351
1352   /* this is a very weird fact: GDK Pixbufs and RENDER drawables consider
1353      colors in opposite pixel order. I have no idea why.  thus when you
1354      draw to a PixBuf, you must exchange the R and B components of your
1355      color. */
1356
1357   if (gr->debug) printf ("cairo_set_rgb_color (%f, %f, %f)\n", r, g, b);
1358
1359   if (gr->drawbuf)
1360     cairo_set_rgb_color (gr->cr, b, g, r);
1361   else
1362     cairo_set_rgb_color (gr->cr, r, g, b);
1363
1364   gdk_threads_leave();
1365 }
1366
1367 JNIEXPORT void JNICALL
1368 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetAlpha 
1369    (JNIEnv *env, jobject obj, jdouble a)
1370 {
1371   struct graphics2d *gr = NULL;
1372
1373   gdk_threads_enter();
1374   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1375
1376   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1377   g_assert (gr != NULL);
1378   if (gr->debug) printf ("cairo_set_alpha %f\n", a);  
1379   cairo_set_alpha (gr->cr, a);
1380   gdk_threads_leave();
1381 }
1382
1383 JNIEXPORT void JNICALL
1384 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetFillRule 
1385    (JNIEnv *env, jobject obj, jint rule)
1386 {
1387   struct graphics2d *gr = NULL;
1388
1389   gdk_threads_enter();
1390   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1391
1392   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1393   if (gr->debug) printf ("cairo_set_fill_rule %d\n", rule);
1394   g_assert (gr != NULL);
1395   switch ((enum java_awt_geom_path_iterator_winding_rule) rule)
1396     {
1397     case java_awt_geom_path_iterator_WIND_NON_ZERO:
1398       cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_WINDING);
1399       break;
1400     case java_awt_geom_path_iterator_WIND_EVEN_ODD:
1401       cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_EVEN_ODD);
1402       break;
1403     }  
1404   gdk_threads_leave();
1405 }
1406
1407 JNIEXPORT void JNICALL
1408 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineWidth 
1409    (JNIEnv *env, jobject obj, jdouble width)
1410 {
1411   struct graphics2d *gr = NULL;
1412
1413   gdk_threads_enter();
1414   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1415
1416   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1417   g_assert (gr != NULL);
1418   if (gr->debug) printf ("cairo_set_line_width %f\n", width);
1419   cairo_set_line_width (gr->cr, width);
1420   gdk_threads_leave();
1421 }
1422
1423 JNIEXPORT void JNICALL
1424 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineCap 
1425    (JNIEnv *env, jobject obj, jint cap)
1426 {
1427   struct graphics2d *gr = NULL;
1428
1429   gdk_threads_enter();
1430   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1431
1432   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1433   g_assert (gr != NULL);
1434   if (gr->debug) printf ("cairo_set_line_cap %d\n", cap);
1435   switch ((enum java_awt_basic_stroke_cap_rule) cap)
1436     {
1437     case java_awt_basic_stroke_CAP_BUTT: 
1438       cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_BUTT);
1439       break;
1440
1441     case java_awt_basic_stroke_CAP_ROUND: 
1442       cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_ROUND);
1443       break;
1444
1445     case java_awt_basic_stroke_CAP_SQUARE: 
1446       cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_SQUARE);
1447       break;
1448     }
1449   gdk_threads_leave();
1450 }
1451
1452 JNIEXPORT void JNICALL
1453 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineJoin 
1454    (JNIEnv *env, jobject obj, jint join)
1455 {
1456   struct graphics2d *gr = NULL;
1457
1458   gdk_threads_enter();
1459   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1460
1461   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1462   g_assert (gr != NULL);
1463   if (gr->debug) printf ("cairo_set_line_join %d\n", join);
1464   switch ((enum java_awt_basic_stroke_join_rule) join)
1465     {
1466     case java_awt_basic_stroke_JOIN_MITER:
1467       cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_MITER);
1468       break;
1469
1470     case java_awt_basic_stroke_JOIN_ROUND:
1471       cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_ROUND);
1472       break;
1473
1474     case java_awt_basic_stroke_JOIN_BEVEL:
1475       cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_BEVEL);
1476       break;
1477     }
1478   gdk_threads_leave();
1479 }
1480
1481 JNIEXPORT void JNICALL
1482 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetDash 
1483    (JNIEnv *env, jobject obj, jdoubleArray dashes, jint ndash, jdouble offset)
1484 {
1485   struct graphics2d *gr = NULL;
1486   jdouble *dasharr = NULL;
1487
1488   gdk_threads_enter();
1489   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1490
1491   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1492   g_assert (gr != NULL);
1493   if (gr->debug) printf ("cairo_set_dash\n");
1494   dasharr = (*env)->GetDoubleArrayElements (env, dashes, NULL);  
1495   g_assert (dasharr != NULL);
1496   cairo_set_dash (gr->cr, dasharr, ndash, offset);
1497   (*env)->ReleaseDoubleArrayElements (env, dashes, dasharr, 0);
1498   gdk_threads_leave();
1499 }
1500
1501 JNIEXPORT void JNICALL
1502 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMiterLimit 
1503    (JNIEnv *env, jobject obj, jdouble miter)
1504 {
1505   struct graphics2d *gr = NULL;
1506
1507   gdk_threads_enter();
1508   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1509
1510   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1511   g_assert (gr != NULL);
1512   if (gr->debug) printf ("cairo_set_miter_limit %f\n", miter);
1513   cairo_set_miter_limit (gr->cr, miter);
1514   gdk_threads_leave();
1515 }
1516
1517
1518 JNIEXPORT void JNICALL
1519 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoNewPath 
1520    (JNIEnv *env, jobject obj)
1521 {
1522   struct graphics2d *gr = NULL;
1523
1524   gdk_threads_enter();
1525   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1526
1527   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1528   if (gr == NULL) { gdk_threads_leave (); return; }
1529   if (gr->debug) printf ("cairo_new_path\n");
1530   cairo_new_path (gr->cr);
1531   gdk_threads_leave();
1532 }
1533
1534 JNIEXPORT void JNICALL
1535 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoMoveTo 
1536    (JNIEnv *env, jobject obj, jdouble x, jdouble y)
1537 {
1538   struct graphics2d *gr = NULL;
1539
1540   gdk_threads_enter();
1541   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1542
1543   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1544   g_assert (gr != NULL);
1545   if (gr->debug) printf ("cairo_move_to (%f, %f)\n", x, y);
1546   cairo_move_to (gr->cr, x, y);
1547   gdk_threads_leave();
1548 }
1549
1550 JNIEXPORT void JNICALL
1551 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoLineTo 
1552    (JNIEnv *env, jobject obj, jdouble x, jdouble y)
1553 {
1554   struct graphics2d *gr = NULL;
1555
1556   gdk_threads_enter();
1557   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1558
1559   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1560   g_assert (gr != NULL);
1561   if (gr->debug) printf ("cairo_line_to (%f, %f)\n", x, y);
1562   cairo_line_to (gr->cr, x, y);
1563   gdk_threads_leave();
1564 }
1565
1566 JNIEXPORT void JNICALL
1567 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoCurveTo 
1568    (JNIEnv *env, jobject obj, jdouble x1, jdouble y1, jdouble x2, jdouble y2, jdouble x3, jdouble y3)
1569 {
1570   struct graphics2d *gr = NULL;
1571
1572   gdk_threads_enter();
1573   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1574
1575   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1576   g_assert (gr != NULL);
1577   if (gr->debug) printf ("cairo_curve_to (%f, %f), (%f, %f), (%f, %f)\n", x1, y1, x2, y2, x3, y3);
1578   cairo_curve_to (gr->cr, x1, y1, x2, y2, x3, y3);
1579   gdk_threads_leave();
1580 }
1581
1582 JNIEXPORT void JNICALL
1583 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelMoveTo 
1584    (JNIEnv *env, jobject obj, jdouble dx, jdouble dy)
1585 {
1586   struct graphics2d *gr = NULL;
1587
1588   gdk_threads_enter();
1589   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1590
1591   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1592   g_assert (gr != NULL);
1593   if (gr->debug) printf ("cairo_rel_move_to (%f, %f)\n", dx, dy);
1594   cairo_rel_move_to (gr->cr, dx, dy);
1595   gdk_threads_leave();
1596 }
1597
1598 JNIEXPORT void JNICALL
1599 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelLineTo 
1600    (JNIEnv *env, jobject obj, jdouble dx, jdouble dy)
1601 {
1602   struct graphics2d *gr = NULL;
1603
1604   gdk_threads_enter();
1605   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1606
1607   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1608   g_assert (gr != NULL);
1609   if (gr->debug) printf ("cairo_rel_line_to (%f, %f)\n", dx, dy);
1610   cairo_rel_line_to (gr->cr, dx, dy);
1611   gdk_threads_leave();
1612 }
1613
1614 JNIEXPORT void JNICALL
1615 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelCurveTo 
1616    (JNIEnv *env, jobject obj, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2, jdouble dx3, jdouble dy3)
1617 {
1618   struct graphics2d *gr = NULL;
1619
1620   gdk_threads_enter();
1621   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1622
1623   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1624   g_assert (gr != NULL);
1625   if (gr->debug) printf ("cairo_rel_curve_to (%f, %f), (%f, %f), (%f, %f)\n", dx1, dy1, dx2, dy2, dx3, dy3);
1626   cairo_rel_curve_to (gr->cr, dx1, dy1, dx2, dy2, dx3, dy3);
1627   gdk_threads_leave();
1628 }
1629
1630 JNIEXPORT void JNICALL
1631 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRectangle 
1632    (JNIEnv *env, jobject obj, jdouble x, jdouble y, jdouble width, jdouble height)
1633 {
1634   struct graphics2d *gr = NULL;
1635
1636   gdk_threads_enter();
1637   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1638
1639   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1640   if (gr == NULL) { gdk_threads_leave (); return; }
1641   if (gr->debug) printf ("cairo_rectangle (%f, %f) (%f, %f)\n", x, y, width, height);
1642   cairo_rectangle (gr->cr, x, y, width, height);
1643   gdk_threads_leave();
1644 }
1645
1646 JNIEXPORT void JNICALL
1647 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClosePath 
1648    (JNIEnv *env, jobject obj)
1649 {
1650   struct graphics2d *gr = NULL;
1651
1652   gdk_threads_enter();
1653   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1654
1655   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1656   g_assert (gr != NULL);
1657   if (gr->debug) printf ("cairo_close_path\n");
1658   cairo_close_path (gr->cr);
1659   gdk_threads_leave();
1660 }
1661
1662 JNIEXPORT void JNICALL
1663 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoStroke 
1664    (JNIEnv *env, jobject obj)
1665 {
1666   struct graphics2d *gr = NULL;
1667
1668   gdk_threads_enter();
1669   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1670
1671   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1672   g_assert (gr != NULL);
1673   if (gr->debug) printf ("cairo_stroke\n");
1674   begin_drawing_operation (gr);
1675   cairo_stroke (gr->cr);
1676   end_drawing_operation (gr);
1677   gdk_threads_leave();
1678 }
1679
1680 JNIEXPORT void JNICALL
1681 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoFill 
1682    (JNIEnv *env, jobject obj)
1683 {
1684   struct graphics2d *gr = NULL;
1685
1686   gdk_threads_enter();
1687   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1688
1689   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1690   g_assert (gr != NULL);
1691   if (gr->debug) printf ("cairo_fill\n");
1692   begin_drawing_operation (gr);
1693   cairo_fill (gr->cr);
1694   end_drawing_operation (gr);
1695   gdk_threads_leave();
1696 }
1697
1698 JNIEXPORT void JNICALL
1699 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClip 
1700    (JNIEnv *env, jobject obj)
1701 {
1702   struct graphics2d *gr = NULL;
1703
1704   gdk_threads_enter();
1705   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1706
1707   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1708   if (gr == NULL) { gdk_threads_leave (); return; }
1709   if (gr->debug) printf ("cairo_clip\n");
1710   begin_drawing_operation (gr);
1711   cairo_init_clip (gr->cr);
1712   cairo_clip (gr->cr);
1713   end_drawing_operation (gr);
1714   gdk_threads_leave();
1715 }
1716
1717 JNIEXPORT void JNICALL
1718 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSurfaceSetFilter
1719    (JNIEnv *env, jobject obj, jint filter)
1720 {
1721    struct graphics2d *gr = NULL;   
1722
1723    gdk_threads_enter();
1724   if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
1725
1726    gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
1727    g_assert (gr != NULL);
1728    if (gr->debug) printf ("cairo_surface_set_filter %d\n", filter);   
1729    switch ((enum java_awt_rendering_hints_filter) filter)
1730      {
1731      case java_awt_rendering_hints_VALUE_INTERPOLATION_NEAREST_NEIGHBOR:
1732        cairo_surface_set_filter (gr->surface, CAIRO_FILTER_NEAREST);
1733        break;
1734      case java_awt_rendering_hints_VALUE_INTERPOLATION_BILINEAR:
1735        cairo_surface_set_filter (gr->surface, CAIRO_FILTER_BILINEAR);
1736        break; 
1737      case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_SPEED:
1738        cairo_surface_set_filter (gr->surface, CAIRO_FILTER_FAST);
1739        break;
1740      case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_DEFAULT:
1741        cairo_surface_set_filter (gr->surface, CAIRO_FILTER_NEAREST);
1742        break;
1743      case java_awt_rendering_hints_VALUE_ALPHA_INTERPOLATION_QUALITY:
1744        cairo_surface_set_filter (gr->surface, CAIRO_FILTER_BEST);
1745        break;
1746      }
1747    gdk_threads_leave();
1748 }