OSDN Git Service

2005-02-15 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GdkGraphics2D.c
index 90b6aa1..e6535b4 100644 (file)
@@ -1,5 +1,5 @@
 /* gnu_java_awt_peer_gtk_GdkGraphics2d.c
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2003, 200 Free Software Foundation, Inc.
 
    This file is part of GNU Classpath.
    
@@ -45,7 +45,8 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gdk-pixbuf/gdk-pixdata.h>
 
-#include <cairo.h>
+#include <cairo-ft.h>
+#include <cairo-xlib.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -175,7 +176,6 @@ x_server_has_render_extension (void)
   return (int) XRenderQueryExtension (GDK_DISPLAY (), &ev, &err);
 }
 
-
 static void
 init_graphics2d_as_pixbuf (struct graphics2d *gr)
 {
@@ -196,13 +196,14 @@ init_graphics2d_as_pixbuf (struct graphics2d *gr)
   g_assert (gdk_pixbuf_get_bits_per_sample (gr->drawbuf) == bits_per_sample);
   g_assert (gdk_pixbuf_get_n_channels (gr->drawbuf) == total_channels);
   
-  gr->surface = cairo_surface_create_for_image (gdk_pixbuf_get_pixels (gr->drawbuf), 
+  gr->surface = cairo_surface_create_for_image ((char *) gdk_pixbuf_get_pixels (gr->drawbuf), 
                                                CAIRO_FORMAT_ARGB32, 
                                                gdk_pixbuf_get_width (gr->drawbuf), 
                                                gdk_pixbuf_get_height (gr->drawbuf), 
                                                gdk_pixbuf_get_rowstride (gr->drawbuf));      
   g_assert (gr->surface != NULL);
   g_assert (gr->cr != NULL);
+  gr->mode = MODE_DRAWABLE_NO_RENDER;
   cairo_set_target_surface (gr->cr, gr->surface);
 }
 
@@ -232,60 +233,99 @@ init_graphics2d_as_renderable (struct graphics2d *gr)
                                           DefaultColormap (dpy, DefaultScreen (dpy)));
   g_assert (gr->surface != NULL);
   g_assert (gr->cr != NULL);
+  gr->mode = MODE_DRAWABLE_WITH_RENDER;
   cairo_set_target_surface (gr->cr, gr->surface);
 }
 
 static void
-begin_drawing_operation (struct graphics2d * gr)
+begin_drawing_operation (JNIEnv *env, struct graphics2d * gr)
 {  
   g_assert(cairo_status (gr->cr) == CAIRO_STATUS_SUCCESS);
-  if (gr->drawbuf)
+
+  switch (gr->mode)
     {
+    case MODE_DRAWABLE_WITH_RENDER:
+      break;
 
-      gint drawable_width, drawable_height;
-      gint pixbuf_width, pixbuf_height;
-      gint width, height;
-      
-      gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
-      pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
-      pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
-      width = min (drawable_width, pixbuf_width);
-      height = min (drawable_height, pixbuf_height);
-
-      gdk_pixbuf_get_from_drawable (gr->drawbuf, /* destination pixbuf */
-                                   gr->drawable, 
-                                   NULL, /* colormap */
-                                   0, 0, 0, 0,
-                                   width, height); 
-      
-      if (gr->debug) printf ("copied (%d, %d) pixels from GDK drawable to pixbuf\n",
-                            width, height);      
+    case MODE_DRAWABLE_NO_RENDER:
+      {
+       
+       gint drawable_width, drawable_height;
+       gint pixbuf_width, pixbuf_height;
+       gint width, height;
+       
+       gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
+       pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
+       pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
+       width = min (drawable_width, pixbuf_width);
+       height = min (drawable_height, pixbuf_height);
+       
+       gdk_pixbuf_get_from_drawable (gr->drawbuf, /* destination pixbuf */
+                                     gr->drawable, 
+                                     NULL, /* colormap */
+                                     0, 0, 0, 0,
+                                     width, height); 
+       
+       if (gr->debug) printf ("copied (%d, %d) pixels from GDK drawable to pixbuf\n",
+                              width, height);      
+      }
+      break;
+
+    case MODE_JAVA_ARRAY:
+      gr->javabuf = (*env)->GetIntArrayElements (env, gr->jarray, &gr->isCopy);
+      gr->surface = cairo_surface_create_for_image ((char *) gr->javabuf, 
+                                                   CAIRO_FORMAT_ARGB32, 
+                                                   gr->width, 
+                                                   gr->height, 
+                                                   gr->width * 4);
+      g_assert(gr->surface != NULL);
+      g_assert(gr->cr != NULL);
+      cairo_set_target_surface (gr->cr, gr->surface);
+      break;
     }
 }
 
 static void
-end_drawing_operation (struct graphics2d * gr)
+end_drawing_operation (JNIEnv *env, struct graphics2d * gr)
 {
   g_assert(cairo_status (gr->cr) == CAIRO_STATUS_SUCCESS);
-  if (gr->drawbuf)
-    { 
-      gint drawable_width, drawable_height;
-      gint pixbuf_width, pixbuf_height;
-      gint width, height;
+
+  switch (gr->mode)
+    {
+    case MODE_DRAWABLE_WITH_RENDER:
+      break;
+
+    case MODE_DRAWABLE_NO_RENDER:
+      {
+
+       gint drawable_width, drawable_height;
+       gint pixbuf_width, pixbuf_height;
+       gint width, height;
+       
+       gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
+       pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
+       pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
+       width = min (drawable_width, pixbuf_width);
+       height = min (drawable_height, pixbuf_height);
+       
+       gdk_draw_pixbuf (gr->drawable, NULL, gr->drawbuf,
+                        0, 0, 0, 0, 
+                        width, height, 
+                        GDK_RGB_DITHER_NORMAL, 0, 0);
+       
+       if (gr->debug) printf ("copied (%d, %d) pixels from pixbuf to GDK drawable\n",
+                              width, height);
+      }
+      break;
       
-      gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height);
-      pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf);
-      pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf);
-      width = min (drawable_width, pixbuf_width);
-      height = min (drawable_height, pixbuf_height);
-
-      gdk_draw_pixbuf (gr->drawable, NULL, gr->drawbuf,
-                      0, 0, 0, 0, 
-                      width, height, 
-                      GDK_RGB_DITHER_NORMAL, 0, 0);
-
-      if (gr->debug) printf ("copied (%d, %d) pixels from pixbuf to GDK drawable\n",
-                            width, height);
+    case MODE_JAVA_ARRAY:
+      /* 
+       * FIXME: Perhaps this should use the isCopy flag to try to avoid
+       * tearing down the cairo surface.
+       */
+      cairo_surface_destroy (gr->surface);
+      gr->surface = NULL;
+      (*env)->ReleaseIntArrayElements (env, gr->jarray, gr->javabuf, JNI_COMMIT);
     }
 }
 
@@ -317,11 +357,11 @@ check_for_debug (struct graphics2d *gr)
 }
 
 static void
-realize_cb (GtkWidget *widget, jobject peer)
+realize_cb (GtkWidget *widget __attribute__ ((unused)), jobject peer)
 {
   gdk_threads_leave ();
 
-  (*gdk_env)->CallVoidMethod (gdk_env, peer, initComponentGraphics2DID);
+  (*gdk_env())->CallVoidMethod (gdk_env(), peer, initComponentGraphics2DID);
 
   gdk_threads_enter ();
 }
@@ -342,18 +382,29 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState
 
   if (g_old->debug) printf ("copying state from existing graphics2d\n");
 
-  g->drawable = g_old->drawable;
   g->debug = g_old->debug; 
+  g->mode = g_old->mode;
 
-  g_object_ref (g->drawable);
+  if (g_old->mode == MODE_JAVA_ARRAY)
+    {
+      g->width = g_old->width;
+      g->height = g_old->height;
+      g->jarray = (*env)->NewGlobalRef(env, g_old->jarray);
+    }
+  else
+    {
+      g->drawable = g_old->drawable;
+
+      g_object_ref (g->drawable);
   
-  g->cr = cairo_create();
-  g_assert (g->cr != NULL);
+      g->cr = cairo_create();
+      g_assert (g->cr != NULL);
 
-  if (x_server_has_render_extension ())
-    init_graphics2d_as_renderable (g);
-  else
-    init_graphics2d_as_pixbuf (g);
+      if (x_server_has_render_extension ())
+       init_graphics2d_as_renderable (g);
+      else
+       init_graphics2d_as_pixbuf (g);
+    }
 
   cairo_surface_set_filter (g->surface, CAIRO_FILTER_FAST);
 
@@ -363,6 +414,37 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState
 
 
 JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState___3III
+(JNIEnv *env, jobject obj, jintArray jarr, jint width, jint height)
+{
+  struct graphics2d *gr;
+
+  gdk_threads_enter();
+  gr = (struct graphics2d *) malloc (sizeof (struct graphics2d));
+  g_assert (gr != NULL);
+  memset (gr, 0, sizeof(struct graphics2d));
+
+  check_for_debug (gr);  
+
+  if (gr->debug) printf ("constructing java-backed image of size (%d,%d)\n",
+                        width, height);
+  
+  gr->cr = cairo_create();
+  g_assert (gr->cr != NULL);
+
+  gr->width = width;
+  gr->height = height;
+  gr->jarray = (*env)->NewGlobalRef(env, jarr);
+  gr->mode = MODE_JAVA_ARRAY;
+
+  if (gr->debug) printf ("constructed java-backed image of size (%d,%d)\n",
+                        width, height);
+
+  NSA_SET_G2D_PTR (env, obj, gr);
+  gdk_threads_leave();  
+}
+
+JNIEXPORT void JNICALL
 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__II
   (JNIEnv *env, jobject obj, jint width, jint height)
 {
@@ -414,7 +496,7 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable
 
   if (src->debug) printf ("copying from offscreen drawable\n");
 
-  begin_drawing_operation(dst); 
+  begin_drawing_operation(env, dst); 
 
   /* gdk_flush(); */
 
@@ -439,7 +521,7 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable
 
   gdk_flush();
 
-  end_drawing_operation(dst);
+  end_drawing_operation(env, dst);
 
   if (src->debug) printf ("copied %d x %d pixels from offscreen drawable\n", width, height);
   gdk_threads_leave();
@@ -531,6 +613,9 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_dispose
   if (gr->pattern_pixels)
     free (gr->pattern_pixels);
 
+  if (gr->mode == MODE_JAVA_ARRAY)
+    (*env)->DeleteGlobalRef(env, gr->jarray);
+
   if (gr->debug) printf ("disposed of graphics2d\n");
 
   free (gr);
@@ -734,7 +819,7 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels
   g_assert (native_matrix != NULL);
   g_assert ((*env)->GetArrayLength (env, java_matrix) == 6);
 
-  begin_drawing_operation (gr);
+  begin_drawing_operation (env, gr);
   
  {
    cairo_matrix_t *mat = NULL;
@@ -748,13 +833,12 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels
                            native_matrix[4], native_matrix[5]);
    cairo_surface_set_matrix (surf, mat);
    cairo_surface_set_filter (surf, cairo_surface_get_filter(gr->surface));
-
    cairo_show_surface (gr->cr, surf, w, h);
    cairo_matrix_destroy (mat);
    cairo_surface_destroy (surf);
  }
   
- end_drawing_operation (gr);
+ end_drawing_operation (env, gr);
  
  (*env)->ReleaseIntArrayElements (env, java_pixels, native_pixels, 0);
  (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0);
@@ -762,65 +846,6 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels
   gdk_threads_leave();
 }
 
-JNIEXPORT jintArray JNICALL
-Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getImagePixels 
-   (JNIEnv *env, jobject obj)
-{
-  struct graphics2d *gr = NULL;
-  jintArray java_pixels;
-  jint* native_pixels;
-  GdkPixbuf *buf = NULL;
-  gint width, height;
-  gint bits_per_sample = 8;
-  gboolean has_alpha = TRUE;
-  gint total_channels = 4;
-  jint i;
-
-  gdk_threads_enter();
-  if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return NULL; }
-
-  gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
-  g_assert (gr != NULL);
-  
-  if (gr->debug) printf ("getImagePixels\n");
-  
-  gdk_drawable_get_size (gr->drawable, &width, &height);
-    
-  buf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 
-                        bits_per_sample,
-                        width, height);
-  g_assert (buf != NULL);
-  g_assert (gdk_pixbuf_get_bits_per_sample (buf) == bits_per_sample);
-  g_assert (gdk_pixbuf_get_n_channels (buf) == total_channels);
-  
-      
-  /* copy pixels from drawable to pixbuf */
-  
-  gdk_pixbuf_get_from_drawable (buf, gr->drawable,
-                                NULL, 
-                                0, 0, 0, 0,
-                                width, height);
-                                                                                                     
-  native_pixels= gdk_pixbuf_get_pixels (buf);
-
-#ifndef WORDS_BIGENDIAN
-  /* convert pixels from 0xBBGGRRAA to 0xAARRGGBB */
-  for (i=0; i<width * height; i++)
-    {
-      native_pixels[i] = SWAPU32 ((unsigned)native_pixels[i]);
-    }
-#endif
-
-   java_pixels = (*env) -> NewIntArray (env, width * height);   
-   
-   (*env)->SetIntArrayRegion(env, java_pixels, 
-                            (jsize)0, (jsize) width*height, 
-                            (jint*) native_pixels);
-   
-   gdk_threads_leave();
-   return java_pixels;
-}
-
 /* passthrough methods to cairo */
 
 JNIEXPORT void JNICALL
@@ -917,13 +942,13 @@ install_font_peer(cairo_t *cr,
       if (debug) printf ("install_font_peer made new cairo font for '%s' at %f\n", 
                         face->family_name,
                         (pango_font_description_get_size (pfont->desc) / 
-                         (double)PANGO_SCALE) * (96.0 / 72.0));
+                         (double)PANGO_SCALE));
     
       cairo_set_font (cr, ft); 
       cairo_font_destroy (ft);
       cairo_scale_font (cr, 
                        (pango_font_description_get_size (pfont->desc) / 
-                        (double)PANGO_SCALE) * (96.0 / 72.0));
+                        (double)PANGO_SCALE));
       ft = cairo_current_font (cr);
       pfont->graphics_resource = ft;
     }
@@ -935,24 +960,10 @@ install_font_peer(cairo_t *cr,
     }
 }
 
-static cairo_t *metrics_cairo = NULL;
-static cairo_surface_t *metrics_surface = NULL;
-
-static void
-ensure_metrics_cairo()
-{
-  if (metrics_cairo == NULL)
-    {
-      metrics_cairo = cairo_create ();
-      metrics_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, 1, 1);
-      cairo_set_target_surface (metrics_cairo, metrics_surface);
-    }
-}
-
 
 JNIEXPORT void JNICALL
 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_releasePeerGraphicsResource
-   (JNIEnv *env, jclass clazz, jobject java_font)
+   (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject java_font)
 {
   struct peerfont *pfont = NULL;
 
@@ -969,80 +980,9 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_releasePeerGraphicsResource
   gdk_threads_leave();
 }
 
-JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getPeerTextMetrics
-   (JNIEnv *env, jclass clazz, jobject java_font, jstring str, jdoubleArray java_metrics)
-{
-  struct peerfont *pfont = NULL;
-  const char *cstr = NULL;
-  jdouble *native_metrics = NULL;
-  cairo_text_extents_t extents;
-
-  g_assert(java_font != NULL);
-  gdk_threads_enter();
-
-  pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, java_font);
-  g_assert (pfont != NULL);
-
-  ensure_metrics_cairo();
-  install_font_peer (metrics_cairo, pfont, 0);
-
-  cstr = (*env)->GetStringUTFChars (env, str, NULL);
-  g_assert(cstr != NULL);
-  cairo_text_extents (metrics_cairo, cstr, &extents);
-
-  native_metrics = (*env)->GetDoubleArrayElements (env, java_metrics, NULL);
-  g_assert (native_metrics != NULL);
-
-  native_metrics[TEXT_METRICS_X_BEARING] = extents.x_bearing;
-  native_metrics[TEXT_METRICS_Y_BEARING] = extents.y_bearing;
-  native_metrics[TEXT_METRICS_WIDTH] = extents.width;
-  native_metrics[TEXT_METRICS_HEIGHT] = extents.height;
-  native_metrics[TEXT_METRICS_X_ADVANCE] = extents.x_advance;
-  native_metrics[TEXT_METRICS_Y_ADVANCE] = extents.y_advance;
-        
-  (*env)->ReleaseStringUTFChars (env, str, cstr);  
-  (*env)->ReleaseDoubleArrayElements (env, java_metrics, native_metrics, 0);
-  gdk_threads_leave();
-}
-
-JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GdkGraphics2D_getPeerFontMetrics
-   (JNIEnv *env, jclass clazz, jobject java_font, jdoubleArray java_metrics)
-{
-  struct peerfont *pfont = NULL;
-  jdouble *native_metrics = NULL;
-  cairo_font_extents_t extents;
-
-  g_assert(java_font != NULL);
-
-  gdk_threads_enter();
-
-  pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, java_font);
-  g_assert (pfont != NULL);
-
-  ensure_metrics_cairo();
-  install_font_peer (metrics_cairo, pfont, 0);
-
-  cairo_current_font_extents (metrics_cairo, &extents); 
-
-  native_metrics = (*env)->GetDoubleArrayElements (env, java_metrics, NULL);
-  g_assert (native_metrics != NULL);
-
-  native_metrics[FONT_METRICS_ASCENT] = extents.ascent;
-  native_metrics[FONT_METRICS_MAX_ASCENT] = extents.ascent;
-  native_metrics[FONT_METRICS_DESCENT] = extents.descent;
-  if (native_metrics[FONT_METRICS_DESCENT] < 0)
-    native_metrics[FONT_METRICS_DESCENT] = - native_metrics[FONT_METRICS_DESCENT];
-  native_metrics[FONT_METRICS_MAX_DESCENT] = native_metrics[FONT_METRICS_DESCENT];
-  native_metrics[FONT_METRICS_MAX_ADVANCE] = extents.max_x_advance;
-
-  (*env)->ReleaseDoubleArrayElements (env, java_metrics, native_metrics, 0);
-  gdk_threads_leave();
-}
-
 static void
-paint_glyph_run(struct graphics2d *gr,
+paint_glyph_run(JNIEnv *env,
+               struct graphics2d *gr,
                cairo_glyph_t **glyphs,
                gint *n_glyphs,
                PangoLayoutRun *run)
@@ -1090,134 +1030,71 @@ paint_glyph_run(struct graphics2d *gr,
        }
 
       if (gr->debug) printf("\n");
-      begin_drawing_operation (gr);
+      begin_drawing_operation (env, gr);
       cairo_show_glyphs (gr->cr, *glyphs, run->glyphs->num_glyphs);
-      end_drawing_operation (gr);      
+      end_drawing_operation (env, gr);      
     }
 }
 
-JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawString
-  (JNIEnv *env, jobject obj, jobject font, jstring str, float x, float y)
-{
-  struct graphics2d *gr = NULL;
-  const char *cstr = NULL;
-  struct peerfont *pfont = NULL;
-
-  /*
-  cairo_glyph_t *glyphs = NULL;
-  gint n_glyphs = 0;
-  PangoLayoutRun *run = NULL;
-  PangoLayoutIter *iter = NULL;
-  */
-
-  g_assert(obj != NULL);
-  g_assert(font != NULL);
-  g_assert(str != NULL);
-
-  gdk_threads_enter ();
-  if (peer_is_disposed(env, obj)) { gdk_threads_leave(); return; }
-
-  gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
-  g_assert(gr != NULL);
-
-  pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, font);
-  g_assert (pfont != NULL);
-
-  cstr = (*env)->GetStringUTFChars (env, str, NULL);
-  g_assert(cstr != NULL);
-
-  if (gr->debug) printf ("painting string '%s' at (%f,%f)\n", cstr, x, y);
-
-  /* For now we let cairo do the glyph conversion; eventually this
-   * ought to be unified with pango, but it is impossible to get
-   * pango and cairo to agree on metrics at the moment, so we either
-   * have to use "all cairo" metrics (the string-based APIs) or 
-   * "all pango" metrics (the glyph-vector based APIs). 
-   */
-
-  install_font_peer (gr->cr, pfont, gr->debug);
-  cairo_move_to (gr->cr, x, y);
-  cairo_show_text (gr->cr, cstr);
-  
-  /*
-    
-  pango_layout_set_text (gr->pango_layout, cstr, -1);
-
-  iter = pango_layout_get_iter (gr->pango_layout);
-  g_assert(iter != NULL);
-
-  cairo_translate (gr->cr, x, y);
-
-  do 
-    {
-      run = pango_layout_iter_get_run (iter);
-      if (run != NULL)
-       paint_glyph_run (gr, &glyphs, &n_glyphs, run);
-    } 
-  while (pango_layout_iter_next_run (iter));
-  
-  if (glyphs != NULL)
-    g_free (glyphs);
-
-  cairo_translate (gr->cr, -x, -y);
-  
-  pango_layout_iter_free (iter);
-
-  */
-
-  gdk_threads_leave ();
-
-  (*env)->ReleaseStringUTFChars (env, str, cstr);
-}
-
 
 JNIEXPORT void JNICALL
-Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkGlyphVector
-   (JNIEnv *env, jobject self, jobject font, jobject java_vec, jfloat x, jfloat y)
+Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGlyphVector
+   (JNIEnv *env, jobject self, 
+    jobject font,
+    jfloat x, jfloat y, jint n,
+    jintArray java_codes,
+    jfloatArray java_positions)
 {
   
   struct graphics2d *gr = NULL;
   struct peerfont *pfont = NULL;
-  struct glyphvec *gv = NULL;
-  PangoLayoutRun *run = NULL;
   cairo_glyph_t *glyphs = NULL;
-  gint n_glyphs = 0;
+  int *native_codes;
+  float *native_positions;
+  jint i = 0;
 
   g_assert (self != NULL);
-  g_assert (java_vec != NULL);
+  g_assert (java_codes != NULL);
+  g_assert (java_positions != NULL);
 
   gdk_threads_enter ();
   if (peer_is_disposed(env, self)) { gdk_threads_leave(); return; }
 
   gr = (struct graphics2d *)NSA_GET_G2D_PTR (env, self);
-  gv = (struct glyphvec *)NSA_GET_GV_PTR (env, java_vec);
-  pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, font);
-
   g_assert (gr != NULL);
-  g_assert (gv != NULL);
+
+  pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, font);
   g_assert (pfont != NULL);
 
-  if (gr->debug) printf ("painting pango glyph vector\n");
+  install_font_peer(gr->cr, pfont, gr->debug);
 
-  install_font_peer (gr->cr, pfont, gr->debug);
-  cairo_translate (gr->cr, x, y);
+  glyphs = malloc( sizeof(cairo_glyph_t) * n);
+  g_assert (glyphs != NULL);
 
-  /* nb. PangoLayoutRun is a typedef for PangoGlyphItem. */
-  run = (PangoLayoutRun *) gv->glyphitems;
-  if (run != NULL)
-    paint_glyph_run (gr, &glyphs, &n_glyphs, run);
+  native_codes = (*env)->GetIntArrayElements (env, java_codes, NULL);
+  native_positions = (*env)->GetFloatArrayElements (env, java_positions, NULL);
+  
+  for (i = 0; i < n; ++i)
+    {
+      glyphs[i].index = native_codes[i];
+      glyphs[i].x = x + native_positions[ 2*i ];
+      glyphs[i].y = y + native_positions[ 2*i + 1];
+    }
 
-  if (glyphs != NULL)
-    g_free (glyphs);
+  (*env)->ReleaseFloatArrayElements (env, java_positions, native_positions, 0);
+  (*env)->ReleaseIntArrayElements (env, java_codes, native_codes, 0);
+
+  begin_drawing_operation (env, gr);  
+  cairo_show_glyphs (gr->cr, glyphs, n);
+  end_drawing_operation (env, gr);
 
-  cairo_translate (gr->cr, -x, -y);
   gdk_threads_leave ();  
+  free(glyphs);
 }
 
 JNIEXPORT void JNICALL
 Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkTextLayout
-   (JNIEnv *env, jobject self, jobject font, jobject java_layout, jfloat x, jfloat y)
+   (JNIEnv *env, jobject self, jobject java_layout, jfloat x, jfloat y)
 {
   /* 
    * FIXME: Some day we expect either cairo or pango will know how to make
@@ -1225,7 +1102,6 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkTextLayout
    */
 
   struct graphics2d *gr = NULL;
-  struct peerfont *pfont = NULL;
   struct textlayout *tl = NULL;
   PangoLayoutIter *i = NULL;
   PangoLayoutRun *run = NULL;
@@ -1237,12 +1113,10 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkTextLayout
 
   gr = (struct graphics2d *)NSA_GET_G2D_PTR (env, self);
   tl = (struct textlayout *)NSA_GET_TEXT_LAYOUT_PTR (env, java_layout);
-  pfont = (struct peerfont *) NSA_GET_FONT_PTR (env, font);
 
   g_assert (gr != NULL);
   g_assert (tl != NULL);
   g_assert (tl->pango_layout != NULL);
-  g_assert (pfont != NULL);
 
   if (gr->debug) printf ("painting pango layout\n");
 
@@ -1252,14 +1126,13 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoDrawGdkTextLayout
   i = pango_layout_get_iter (tl->pango_layout);
   g_assert (i != NULL);
 
-  install_font_peer (gr->cr, pfont, gr->debug);
   cairo_translate (gr->cr, x, y);
 
   do 
     {
       run = pango_layout_iter_get_run (i);
       if (run != NULL)
-       paint_glyph_run (gr, &glyphs, &n_glyphs, run);
+       paint_glyph_run (env, gr, &glyphs, &n_glyphs, run);
     } 
   while (pango_layout_iter_next_run (i));
   
@@ -1671,9 +1544,9 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoStroke
   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
   g_assert (gr != NULL);
   if (gr->debug) printf ("cairo_stroke\n");
-  begin_drawing_operation (gr);
+  begin_drawing_operation (env, gr);
   cairo_stroke (gr->cr);
-  end_drawing_operation (gr);
+  end_drawing_operation (env, gr);
   gdk_threads_leave();
 }
 
@@ -1689,9 +1562,9 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoFill
   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
   g_assert (gr != NULL);
   if (gr->debug) printf ("cairo_fill\n");
-  begin_drawing_operation (gr);
+  begin_drawing_operation (env, gr);
   cairo_fill (gr->cr);
-  end_drawing_operation (gr);
+  end_drawing_operation (env, gr);
   gdk_threads_leave();
 }
 
@@ -1707,10 +1580,10 @@ Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClip
   gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj);
   if (gr == NULL) { gdk_threads_leave (); return; }
   if (gr->debug) printf ("cairo_clip\n");
-  begin_drawing_operation (gr);
+  begin_drawing_operation (env, gr);
   cairo_init_clip (gr->cr);
   cairo_clip (gr->cr);
-  end_drawing_operation (gr);
+  end_drawing_operation (env, gr);
   gdk_threads_leave();
 }