classpath
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Problem with Cairo upgrade and re-targeting


From: Ziga Mahkovec
Subject: Problem with Cairo upgrade and re-targeting
Date: Sun, 19 Jun 2005 17:15:57 +0200

Hi,

I was having problems with the recent Cairo upgrade to 0.5.0.  It was
failing to draw anything on a simple test case such as:

  BufferedImage img = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB);
  Graphics2D g2d = img.createGraphics();
  g2d.setColor(Color.red);
  g2d.fillRect(0, 0, 10, 10);

Note that when using a buffered image, the MODE_JAVA_ARRAY mode is used.
This means that the pixel buffer is stored in javaland and gets passed
to Cairo via JNI (see the GdkGraphics2D peer).

The first problem was an incorrect initialization with a NULL
gr->drawable, but that was easy to fix.  A bigger problem however is the
fact that the recent Cairo API shakeup got rid of the
cairo_set_target_surface call.  Looking at the API docs and this
post[1], it seems that Cairo is no longer re-targetable.

GdkGraphics2D however relies on this.  For each drawing operation, a
handle to the Java array is acquired and passed to Cairo as the new
target.  This diff shows how the API change was reflected:

===================================================================
--- native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c   12 Feb 2005 
09:37:31 -0000      1.22
+++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c   8 Jun 2005 
21:19:25 -0000       1.23
@@ -273,14 +276,15 @@ begin_drawing_operation (JNIEnv *env, st
 
     case MODE_JAVA_ARRAY:
       gr->javabuf = (*env)->GetIntArrayElements (env, gr->jarray, &gr->isCopy);
-      gr->surface = cairo_surface_create_for_image ((char *) gr->javabuf, 
+      gr->surface = cairo_image_surface_create_for_data ((unsigned 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);
+      cairo_destroy (gr->cr);
+      gr->cr = cairo_create (gr->surface);
       break;
     }
 }
===================================================================

This change results in the Cairo context being destroyed before each
drawing operation -- meaning that all graphics state is lost.  For
example, in the above test case, by the time cairo_fill gets called, the
cairo_new_path/cairo_rectangle calls are already lost.

I'm attaching a patch that ought to fix this, but wanted to check a
couple of things first.  The patch only initializes the Cairo surface
and context in initState.  It also uses the GetPrimitiveArrayCritical
JNI call instead of GetIntArrayElements, to make sure that direct access
to the Java pixel buffer is acquired.  Should this fail, it maintains a
separate native pixel buffer and performs some additional copying.  I
tried this with jamvm any some Java2D tests and it worked fine -- the
array was never copied.  Will this work with other runtimes as well?

I'm also not sure about whether it's possible for a runtime to return a
copy of the array with GetPrimitiveArrayCritical (i.e. fail to pin it
down), but *not* during the first attempt.  This case will fail
currently, since we mustn't reinitialize the Cairo context during a
drawing session.  So this patch relies on the runtime either always
providing direct access to the array, or never.

Note that this issue becomes moot once Sven's ideas[2] come to life, so
this should only be a temporary fix.


Comments appreciated,
-- 
Ziga

[1] http://lists.freedesktop.org/archives/cairo/2005-February/003054.html
[2] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20630

Attachment: cairo-target.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]