[cairo-commit] rcairo/src cairo.def, 1.16, 1.17 rb_cairo.h, 1.21, 1.22 rb_cairo_context.c, 1.27, 1.28 rb_cairo_exception.c, 1.3, 1.4 rb_cairo_font_face.c, 1.5, 1.6 rb_cairo_private.c, 1.8, 1.9 rb_cairo_private.h, 1.11, 1.12 rb_cairo_surface.c, 1.40, 1.41

Kouhei Sutou commit at pdx.freedesktop.org
Sat Aug 16 05:52:19 PDT 2008


Committed by: kou

Update of /cvs/cairo/rcairo/src
In directory kemper:/tmp/cvs-serv9707/src

Modified Files:
	cairo.def rb_cairo.h rb_cairo_context.c rb_cairo_exception.c 
	rb_cairo_font_face.c rb_cairo_private.c rb_cairo_private.h 
	rb_cairo_surface.c 
Log Message:
        * src/lib/cairo.rb (Cairo.exit_application): add.

        * src/rb_cairo_surface.c: use rb_cairo__invoke_callback().

        * src/rb_cairo_private.c, src/rb_cairo_private.h
        (rb_cairo__invoke_callback): use rb_protect() and exit if an
        exception is raised in callback.

        * src/rb_cairo_font_face.c: support Cairo::UserFontFace.

        * src/rb_cairo_exception.c, src/rb_cairo_private.h
        (rb_cairo__exception_to_status): add.

        * src/rb_cairo_context.c (cr_show_text_glyphs): initialize variables.

        * src/cairo.def, src/rb_cairo.h: add
        rb_cCairo_UserFontFace_TextToGlyphsData.

        * test/test_font_face.rb: add tests for user font.


Index: cairo.def
===================================================================
RCS file: /cvs/cairo/rcairo/src/cairo.def,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- cairo.def	16 Aug 2008 08:16:37 -0000	1.16
+++ cairo.def	16 Aug 2008 12:52:16 -0000	1.17
@@ -18,6 +18,7 @@
     rb_cCairo_FontFace        DATA
     rb_cCairo_ToyFontFace     DATA
     rb_cCairo_UserFontFace    DATA
+    rb_cCairo_UserFontFace_TextToGlyphsData DATA
     rb_cCairo_FontExtents     DATA
     rb_cCairo_FontOptions     DATA
     rb_cCairo_ScaledFont      DATA

Index: rb_cairo.h
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- rb_cairo.h	16 Aug 2008 08:16:39 -0000	1.21
+++ rb_cairo.h	16 Aug 2008 12:52:16 -0000	1.22
@@ -86,6 +86,7 @@
 RB_CAIRO_VAR VALUE rb_cCairo_FontFace;
 RB_CAIRO_VAR VALUE rb_cCairo_ToyFontFace;
 RB_CAIRO_VAR VALUE rb_cCairo_UserFontFace;
+RB_CAIRO_VAR VALUE rb_cCairo_UserFontFace_TextToGlyphsData;
 RB_CAIRO_VAR VALUE rb_cCairo_FontExtents;
 RB_CAIRO_VAR VALUE rb_cCairo_FontOptions;
 RB_CAIRO_VAR VALUE rb_cCairo_ScaledFont;

Index: rb_cairo_context.c
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo_context.c,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- rb_cairo_context.c	16 Aug 2008 08:34:18 -0000	1.27
+++ rb_cairo_context.c	16 Aug 2008 12:52:16 -0000	1.28
@@ -1185,10 +1185,10 @@
   cairo_t *cr;
   const char *utf8;
   int utf8_len;
-  cairo_glyph_t *glyphs;
-  int num_glyphs;
-  cairo_text_cluster_t *clusters;
-  int num_clusters;
+  cairo_glyph_t *glyphs = NULL;
+  int num_glyphs = 0;
+  cairo_text_cluster_t *clusters = NULL;
+  int num_clusters = 0;
   cairo_bool_t backward;
 
   cr = _SELF;
@@ -1202,8 +1202,10 @@
                           glyphs, num_glyphs,
                           clusters, num_clusters,
                           backward);
-  cairo_glyph_free (glyphs);
-  cairo_text_cluster_free (clusters);
+  if (glyphs)
+    cairo_glyph_free (glyphs);
+  if (clusters)
+    cairo_text_cluster_free (clusters);
 
   return self;
 }

Index: rb_cairo_exception.c
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo_exception.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- rb_cairo_exception.c	13 Aug 2008 08:27:44 -0000	1.3
+++ rb_cairo_exception.c	16 Aug 2008 12:52:16 -0000	1.4
@@ -13,6 +13,7 @@
 */
 
 #include "rb_cairo.h"
+#include "rb_cairo_private.h"
 
 static VALUE rb_eCairo_InvalidRestoreError;
 static VALUE rb_eCairo_InvalidPopGroupError;
@@ -162,6 +163,83 @@
     }
 }
 
+cairo_status_t
+rb_cairo__exception_to_status (VALUE exception)
+{
+  if (NIL_P (exception))
+    return CAIRO_STATUS_SUCCESS;
+  else if (rb_cairo__is_kind_of (exception, rb_eNoMemError))
+    return CAIRO_STATUS_NO_MEMORY;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidRestoreError))
+    return CAIRO_STATUS_INVALID_RESTORE;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidPopGroupError))
+    return CAIRO_STATUS_INVALID_POP_GROUP;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_NoCurrentPointError))
+    return CAIRO_STATUS_NO_CURRENT_POINT;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidMatrixError))
+    return CAIRO_STATUS_INVALID_MATRIX;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidStatusError))
+    return CAIRO_STATUS_INVALID_STATUS;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_NullPointerError))
+    return CAIRO_STATUS_NULL_POINTER;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidStringError))
+    return CAIRO_STATUS_INVALID_STRING;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidPathDataError))
+    return CAIRO_STATUS_INVALID_PATH_DATA;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_ReadError))
+    return CAIRO_STATUS_READ_ERROR;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_WriteError))
+    return CAIRO_STATUS_WRITE_ERROR;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_SurfaceFinishedError))
+    return CAIRO_STATUS_SURFACE_FINISHED;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_SurfaceTypeMismatchError))
+    return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_PatternTypeMismatchError))
+    return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidContentError))
+    return CAIRO_STATUS_INVALID_CONTENT;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidFormatError))
+    return CAIRO_STATUS_INVALID_FORMAT;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidVisualError))
+    return CAIRO_STATUS_INVALID_VISUAL;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_FileNotFoundError))
+    return CAIRO_STATUS_FILE_NOT_FOUND;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidDashError))
+    return CAIRO_STATUS_INVALID_DASH;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidDscCommentError))
+    return CAIRO_STATUS_INVALID_DSC_COMMENT;
+#if CAIRO_CHECK_VERSION(1, 3, 0)
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidIndexError))
+    return CAIRO_STATUS_INVALID_INDEX;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_ClipNotRepresentableError))
+    return CAIRO_STATUS_CLIP_NOT_REPRESENTABLE;
+#endif
+#if CAIRO_CHECK_VERSION(1, 5, 6)
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_TempFileError))
+    return CAIRO_STATUS_TEMP_FILE_ERROR;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidStringError))
+    return CAIRO_STATUS_INVALID_STRIDE;
+#endif
+#if CAIRO_CHECK_VERSION(1, 7, 2)
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_FontTypeMismatch))
+    return CAIRO_STATUS_FONT_TYPE_MISMATCH;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_UserFontImmutable))
+    return CAIRO_STATUS_USER_FONT_IMMUTABLE;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_UserFontError))
+    return CAIRO_STATUS_USER_FONT_ERROR;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_NegativeCount))
+    return CAIRO_STATUS_NEGATIVE_COUNT;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidClusters))
+    return CAIRO_STATUS_INVALID_CLUSTERS;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidSlant))
+    return CAIRO_STATUS_INVALID_SLANT;
+  else if (rb_cairo__is_kind_of (exception, rb_eCairo_InvalidWeight))
+    return CAIRO_STATUS_INVALID_WEIGHT;
+#endif
+
+  return -1;
+}
+
 void
 Init_cairo_exception ()
 {

Index: rb_cairo_font_face.c
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo_font_face.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- rb_cairo_font_face.c	14 Aug 2008 08:11:12 -0000	1.5
+++ rb_cairo_font_face.c	16 Aug 2008 12:52:16 -0000	1.6
@@ -19,6 +19,24 @@
 VALUE rb_cCairo_FontFace;
 VALUE rb_cCairo_ToyFontFace = Qnil;
 VALUE rb_cCairo_UserFontFace = Qnil;
+VALUE rb_cCairo_UserFontFace_TextToGlyphsData = Qnil;
+
+#if CAIRO_CHECK_VERSION(1, 7, 2)
+static cairo_user_data_key_t ruby_object_key;
+static ID cr_id_call;
+static ID cr_id_new;
+
+static ID cr_id_init;
+static ID cr_id_render_glyph;
+static ID cr_id_text_to_glyphs;
+static ID cr_id_unicode_to_glyph;
+
+static ID cr_id_at_glyphs;
+static ID cr_id_at_clusters;
+static ID cr_id_at_backward;
+static ID cr_id_at_need_glyphs;
+static ID cr_id_at_need_clusters;
+#endif
 
 #define _SELF  (RVAL2CRFONTFACE(self))
 
@@ -65,12 +83,14 @@
 
       switch (cairo_font_face_get_type (face))
         {
+#if CAIRO_CHECK_VERSION(1, 7, 2)
         case CAIRO_FONT_TYPE_TOY:
           klass = rb_cCairo_ToyFontFace;
           break;
         case CAIRO_FONT_TYPE_USER:
           klass = rb_cCairo_UserFontFace;
           break;
+#endif
         default:
           klass = rb_cCairo_FontFace;
           break;
@@ -90,6 +110,7 @@
   return Data_Wrap_Struct (klass, NULL, cr_font_face_free, NULL);
 }
 
+#if CAIRO_CHECK_VERSION(1, 7, 2)
 static VALUE
 cr_toy_font_face_initialize (int argc, VALUE *argv, VALUE self)
 {
@@ -151,10 +172,452 @@
   return INT2NUM (cairo_toy_font_face_get_weight (_SELF));
 }
 
+typedef struct cr_user_font_face_invoke_data
+{
+  VALUE receiver;
+  ID method;
+  int argc;
+  VALUE *argv;
+  cairo_status_t *status;
+  VALUE result;
+  cr_callback_func_t after_hook;
+  void *after_hook_data;
+} cr_user_font_face_invoke_data_t;
+
+static VALUE
+cr_user_font_face_invoke_body (VALUE user_data)
+{
+  cr_user_font_face_invoke_data_t *data;
+  VALUE result;
+
+  data = (cr_user_font_face_invoke_data_t *)user_data;
+  result = rb_funcall2 (data->receiver, data->method, data->argc, data->argv);
+  data->result = result;
+  if (data->after_hook)
+    result = data->after_hook(user_data);
+  return result;
+}
+
+static VALUE
+cr_user_font_face_invoke_rescue (VALUE user_data, VALUE exception)
+{
+  cr_user_font_face_invoke_data_t *data;
+
+  data = (cr_user_font_face_invoke_data_t *)user_data;
+  *(data->status) = rb_cairo__exception_to_status (exception);
+
+  if (*(data->status) == -1)
+    rb_exc_raise (exception);
+
+  return Qnil;
+}
+
+static VALUE
+cr_user_font_face_invoke_func (VALUE user_data)
+{
+  return rb_rescue2 (cr_user_font_face_invoke_body, user_data,
+                     cr_user_font_face_invoke_rescue, user_data, rb_eException,
+                     (VALUE)0);
+}
+
+static VALUE
+cr_user_font_face_init_func_after (VALUE user_data)
+{
+  cr_user_font_face_invoke_data_t *data;
+  cairo_font_extents_t *extents;
+
+  data = (cr_user_font_face_invoke_data_t *)user_data;
+  extents = data->after_hook_data;
+
+  *extents = *(RVAL2CRFONTEXTENTS (data->argv[2]));
+
+  return data->result;
+}
+
+static cairo_status_t
+cr_user_font_face_init_func (cairo_scaled_font_t *scaled_font,
+                             cairo_t *cr, cairo_font_extents_t *extents)
+{
+  cairo_status_t status = CAIRO_STATUS_SUCCESS;
+  cairo_font_face_t *face;
+  VALUE self;
+  VALUE receiver = Qnil;
+  ID id_method_name = cr_id_call;
+
+  face = cairo_scaled_font_get_font_face (scaled_font);
+  self = (VALUE)cairo_font_face_get_user_data (face, &ruby_object_key);
+  receiver = rb_ivar_get (self, cr_id_init);
+  if (NIL_P (receiver) && rb_obj_respond_to (self, cr_id_init, Qtrue))
+    {
+      receiver = self;
+      id_method_name = cr_id_init;
+    }
+
+  if (!NIL_P (receiver))
+    {
+      cr_user_font_face_invoke_data_t data;
+      VALUE argv[3];
+
+      argv[0] = CRSCALEDFONT2RVAL (scaled_font);
+      argv[1] = CRCONTEXT2RVAL (cr);
+      argv[2] = CRFONTEXTENTS2RVAL (extents);
+
+      data.receiver = receiver;
+      data.method = id_method_name;
+      data.argc = 3;
+      data.argv = argv;
+      data.status = &status;
+      data.after_hook = cr_user_font_face_init_func_after;
+      data.after_hook_data = extents;
+
+      rb_cairo__invoke_callback (cr_user_font_face_invoke_func, (VALUE)&data);
+    }
+
+  return status;
+}
+
+static VALUE
+cr_user_font_face_render_glyph_func_after (VALUE user_data)
+{
+  cr_user_font_face_invoke_data_t *data;
+  cairo_text_extents_t *extents;
+
+  data = (cr_user_font_face_invoke_data_t *)user_data;
+  extents = data->after_hook_data;
+
+  *extents = *(RVAL2CRTEXTEXTENTS (data->argv[3]));
+
+  return data->result;
+}
+
+static cairo_status_t
+cr_user_font_face_render_glyph_func (cairo_scaled_font_t *scaled_font,
+                                     unsigned long glyph,
+                                     cairo_t *cr,
+                                     cairo_text_extents_t *extents)
+{
+  cairo_status_t status = CAIRO_STATUS_SUCCESS;
+  cairo_font_face_t *face;
+  VALUE self;
+  VALUE receiver = Qnil;
+  ID id_method_name = cr_id_call;
+
+  face = cairo_scaled_font_get_font_face (scaled_font);
+  self = (VALUE)cairo_font_face_get_user_data (face, &ruby_object_key);
+  receiver = rb_ivar_get (self, cr_id_render_glyph);
+  if (NIL_P (receiver) && rb_obj_respond_to (self, cr_id_render_glyph, Qtrue))
+    {
+      receiver = self;
+      id_method_name = cr_id_render_glyph;
+    }
+
+  if (!NIL_P (receiver))
+    {
+      cr_user_font_face_invoke_data_t data;
+      VALUE argv[4];
+
+      argv[0] = CRSCALEDFONT2RVAL (scaled_font);
+      argv[1] = ULONG2NUM (glyph);
+      argv[2] = CRCONTEXT2RVAL (cr);
+      argv[3] = CRTEXTEXTENTS2RVAL (extents);
+
+      data.receiver = receiver;
+      data.method = id_method_name;
+      data.argc = 4;
+      data.argv = argv;
+      data.status = &status;
+      data.after_hook = cr_user_font_face_render_glyph_func_after;
+      data.after_hook_data = extents;
+
+      rb_cairo__invoke_callback (cr_user_font_face_invoke_func, (VALUE)&data);
+    }
+
+  return status;
+}
+
+typedef struct _cr_text_to_glyphs_after_hook_data {
+  VALUE text_to_glyphs_data;
+  cairo_glyph_t **glyphs;
+  int *num_glyphs;
+  cairo_text_cluster_t **clusters;
+  int *num_clusters;
+  cairo_bool_t *backward;
+} cr_text_to_glyphs_after_hook_data_t;
+
+static VALUE
+cr_user_font_face_text_to_glyphs_func_after (VALUE user_data)
+{
+  cr_user_font_face_invoke_data_t *data;
+  cr_text_to_glyphs_after_hook_data_t *after_hook_data;
+  VALUE text_to_glyphs_data;
+
+
+  data = (cr_user_font_face_invoke_data_t *)user_data;
+  after_hook_data = data->after_hook_data;
+  text_to_glyphs_data = after_hook_data->text_to_glyphs_data;
+
+  if (after_hook_data->glyphs)
+    {
+      VALUE rb_glyphs;
+
+      rb_glyphs = rb_ivar_get (text_to_glyphs_data, cr_id_at_glyphs);
+      rb_cairo__glyphs_from_ruby_object (rb_glyphs,
+                                         after_hook_data->glyphs,
+                                         after_hook_data->num_glyphs);
+    }
+
+  if (after_hook_data->clusters)
+    {
+      VALUE rb_clusters;
+
+      rb_clusters = rb_ivar_get (text_to_glyphs_data, cr_id_at_clusters);
+      rb_cairo__text_clusters_from_ruby_object (rb_clusters,
+                                                after_hook_data->clusters,
+                                                after_hook_data->num_clusters);
+    }
+
+  if (after_hook_data->backward)
+    {
+      VALUE rb_backward;
+
+      rb_backward = rb_ivar_get (text_to_glyphs_data, cr_id_at_backward);
+      *(after_hook_data->backward) = RVAL2CBOOL (rb_backward);
+    }
+
+  return data->result;
+}
+
+static cairo_status_t
+cr_user_font_face_text_to_glyphs_func (cairo_scaled_font_t *scaled_font,
+                                       const char *utf8, int utf8_len,
+                                       cairo_glyph_t **glyphs, int *num_glyphs,
+                                       cairo_text_cluster_t **clusters,
+                                       int *num_clusters,
+                                       cairo_bool_t *backward)
+{
+  cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+  cairo_font_face_t *face;
+  VALUE self;
+  VALUE receiver = Qnil;
+  ID id_method_name = cr_id_call;
+
+  face = cairo_scaled_font_get_font_face (scaled_font);
+  self = (VALUE)cairo_font_face_get_user_data (face, &ruby_object_key);
+  receiver = rb_ivar_get (self, cr_id_text_to_glyphs);
+  if (NIL_P (receiver) && rb_obj_respond_to (self, cr_id_text_to_glyphs, Qtrue))
+    {
+      receiver = self;
+      id_method_name = cr_id_text_to_glyphs;
+    }
+
+  if (!NIL_P (receiver))
+    {
+      cr_user_font_face_invoke_data_t data;
+      cr_text_to_glyphs_after_hook_data_t after_hook_data;
+      VALUE text_to_glyphs_data;
+      VALUE argv[3];
+
+      argv[0] = CRSCALEDFONT2RVAL (scaled_font);
+      argv[1] = rb_str_new (utf8, utf8_len);
+      text_to_glyphs_data = rb_funcall (rb_cCairo_UserFontFace_TextToGlyphsData,
+                                        cr_id_new,
+                                        2,
+                                        CBOOL2RVAL (glyphs != NULL),
+                                        CBOOL2RVAL (clusters != NULL));
+      argv[2] = text_to_glyphs_data;
+
+      data.receiver = receiver;
+      data.method = id_method_name;
+      data.argc = 3;
+      data.argv = argv;
+      data.status = &status;
+      data.after_hook = cr_user_font_face_text_to_glyphs_func_after;
+      data.after_hook_data = &after_hook_data;
+
+      after_hook_data.text_to_glyphs_data = text_to_glyphs_data;
+      after_hook_data.glyphs = glyphs;
+      after_hook_data.num_glyphs = num_glyphs;
+      after_hook_data.clusters = clusters;
+      after_hook_data.num_clusters = num_clusters;
+      after_hook_data.backward = backward;
+
+      rb_cairo__invoke_callback (cr_user_font_face_invoke_func, (VALUE)&data);
+    }
+
+  return status;
+}
+
+static VALUE
+cr_user_font_face_unicode_to_glyph_func_after (VALUE user_data)
+{
+  cr_user_font_face_invoke_data_t *data;
+  unsigned long *glyph_index;
+
+  data = (cr_user_font_face_invoke_data_t *)user_data;
+  glyph_index = data->after_hook_data;
+
+  *glyph_index = NUM2ULONG (data->result);
+
+  return data->result;
+}
+
+static cairo_status_t
+cr_user_font_face_unicode_to_glyph_func (cairo_scaled_font_t *scaled_font,
+                                         unsigned long unicode,
+                                         unsigned long *glyph_index)
+{
+  cairo_status_t status = CAIRO_STATUS_SUCCESS;
+  cairo_font_face_t *face;
+  VALUE self;
+  VALUE receiver = Qnil;
+  ID id_method_name = cr_id_call;
+
+  face = cairo_scaled_font_get_font_face (scaled_font);
+  self = (VALUE)cairo_font_face_get_user_data (face, &ruby_object_key);
+  receiver = rb_ivar_get (self, cr_id_unicode_to_glyph);
+  if (NIL_P (receiver) &&
+      rb_obj_respond_to (self, cr_id_unicode_to_glyph, Qtrue))
+    {
+      receiver = self;
+      id_method_name = cr_id_unicode_to_glyph;
+    }
+
+  if (NIL_P (receiver))
+    {
+      *glyph_index = unicode;
+    }
+  else
+    {
+      cr_user_font_face_invoke_data_t data;
+      VALUE argv[2];
+
+      argv[0] = CRSCALEDFONT2RVAL (scaled_font);
+      argv[1] = ULONG2NUM (unicode);
+
+      data.receiver = receiver;
+      data.method = id_method_name;
+      data.argc = 2;
+      data.argv = argv;
+      data.status = &status;
+      data.after_hook = cr_user_font_face_unicode_to_glyph_func_after;
+      data.after_hook_data = glyph_index;
+
+      rb_cairo__invoke_callback (cr_user_font_face_invoke_func, (VALUE)&data);
+    }
+
+  return status;
+}
+
+
+static VALUE
+cr_user_font_face_initialize (VALUE self)
+{
+  cairo_font_face_t *face;
+
+  face = cairo_user_font_face_create ();
+  cr_font_face_check_status (face);
+
+  cairo_font_face_set_user_data (face, &ruby_object_key, (void *)self, NULL);
+
+  cairo_user_font_face_set_init_func
+    (face, cr_user_font_face_init_func);
+  cairo_user_font_face_set_render_glyph_func
+    (face, cr_user_font_face_render_glyph_func);
+  cairo_user_font_face_set_text_to_glyphs_func
+    (face, cr_user_font_face_text_to_glyphs_func);
+  cairo_user_font_face_set_unicode_to_glyph_func
+    (face, cr_user_font_face_unicode_to_glyph_func);
+
+  rb_ivar_set (self, cr_id_init, Qnil);
+  rb_ivar_set (self, cr_id_render_glyph, Qnil);
+  rb_ivar_set (self, cr_id_text_to_glyphs, Qnil);
+  rb_ivar_set (self, cr_id_unicode_to_glyph, Qnil);
+
+  DATA_PTR (self) = face;
+
+  return Qnil;
+}
+
+static VALUE
+cr_user_font_face_on_init (VALUE self)
+{
+  rb_ivar_set (self, cr_id_init, rb_block_proc ());
+  return self;
+}
+
+static VALUE
+cr_user_font_face_on_render_glyph (VALUE self)
+{
+  rb_ivar_set (self, cr_id_render_glyph, rb_block_proc ());
+  return self;
+}
+
+static VALUE
+cr_user_font_face_on_text_to_glyphs (VALUE self)
+{
+  rb_ivar_set (self, cr_id_text_to_glyphs, rb_block_proc ());
+  return self;
+}
+
+static VALUE
+cr_user_font_face_on_unicode_to_glyph (VALUE self)
+{
+  rb_ivar_set (self, cr_id_unicode_to_glyph, rb_block_proc ());
+  return self;
+}
+
+
+static VALUE
+cr_text_to_glyphs_data_initialize (VALUE self,
+                                   VALUE need_glyphs, VALUE need_clusters)
+{
+  rb_ivar_set (self, cr_id_at_glyphs, Qnil);
+  rb_ivar_set (self, cr_id_at_clusters, Qnil);
+  rb_ivar_set (self, cr_id_at_backward, Qfalse);
+  rb_ivar_set (self, cr_id_at_need_glyphs, need_glyphs);
+  rb_ivar_set (self, cr_id_at_need_clusters, need_clusters);
+
+  return Qnil;
+}
+
+static VALUE
+cr_text_to_glyphs_data_backward_p (VALUE self)
+{
+  return rb_ivar_get (self, cr_id_at_backward);
+}
+
+static VALUE
+cr_text_to_glyphs_data_need_glyphs (VALUE self)
+{
+  return rb_ivar_get (self, cr_id_at_need_glyphs);
+}
+
+static VALUE
+cr_text_to_glyphs_data_need_clusters (VALUE self)
+{
+  return rb_ivar_get (self, cr_id_at_need_clusters);
+}
+#endif
 
 void
 Init_cairo_font (void)
 {
+#if CAIRO_CHECK_VERSION(1, 7, 2)
+  cr_id_call = rb_intern ("call");
+  cr_id_new = rb_intern ("new");
+
+  cr_id_init = rb_intern ("init");
+  cr_id_render_glyph = rb_intern ("render_glyph");
+  cr_id_text_to_glyphs = rb_intern ("text_to_glyphs");
+  cr_id_unicode_to_glyph = rb_intern ("unicode_to_glyph");
+
+  cr_id_at_glyphs = rb_intern ("@glyphs");
+  cr_id_at_clusters = rb_intern ("@clusters");
+  cr_id_at_backward = rb_intern ("@backward");
+  cr_id_at_need_glyphs = rb_intern ("@need_glyphs");
+  cr_id_at_need_clusters = rb_intern ("@need_clusters");
+#endif
+
   rb_cCairo_FontFace =
     rb_define_class_under (rb_mCairo, "FontFace", rb_cObject);
   rb_define_alloc_func (rb_cCairo_FontFace, cr_font_face_allocate);
@@ -173,7 +636,41 @@
   rb_define_method (rb_cCairo_ToyFontFace, "weight",
                     cr_toy_font_face_get_weight, 0);
 
+
   rb_cCairo_UserFontFace =
     rb_define_class_under (rb_mCairo, "UserFontFace", rb_cCairo_FontFace);
+
+  rb_define_method (rb_cCairo_UserFontFace, "initialize",
+                    cr_user_font_face_initialize, 0);
+
+  rb_define_method (rb_cCairo_UserFontFace, "on_init",
+                    cr_user_font_face_on_init, 0);
+  rb_define_method (rb_cCairo_UserFontFace, "on_render_glyph",
+                    cr_user_font_face_on_render_glyph, 0);
+  rb_define_method (rb_cCairo_UserFontFace, "on_text_to_glyphs",
+                    cr_user_font_face_on_text_to_glyphs, 0);
+  rb_define_method (rb_cCairo_UserFontFace, "on_unicode_to_glyph",
+                    cr_user_font_face_on_unicode_to_glyph, 0);
+
+
+  rb_cCairo_UserFontFace_TextToGlyphsData =
+    rb_define_class_under (rb_cCairo_UserFontFace,
+                           "TextToGlyphsData", rb_cObject);
+  rb_attr (rb_cCairo_UserFontFace_TextToGlyphsData, rb_intern ("glyphs"),
+           CR_TRUE, CR_TRUE, CR_TRUE);
+  rb_attr (rb_cCairo_UserFontFace_TextToGlyphsData, rb_intern ("clusters"),
+           CR_TRUE, CR_TRUE, CR_TRUE);
+  rb_attr (rb_cCairo_UserFontFace_TextToGlyphsData, rb_intern ("backward"),
+           CR_FALSE, CR_TRUE, CR_TRUE);
+
+  rb_define_method (rb_cCairo_UserFontFace_TextToGlyphsData,
+                    "initialize", cr_text_to_glyphs_data_initialize, 2);
+
+  rb_define_method (rb_cCairo_UserFontFace_TextToGlyphsData,
+                    "backward?", cr_text_to_glyphs_data_backward_p, 0);
+  rb_define_method (rb_cCairo_UserFontFace_TextToGlyphsData,
+                    "need_glyphs?", cr_text_to_glyphs_data_need_glyphs, 0);
+  rb_define_method (rb_cCairo_UserFontFace_TextToGlyphsData,
+                    "need_clusters?", cr_text_to_glyphs_data_need_clusters, 0);
 #endif
 }

Index: rb_cairo_private.c
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo_private.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- rb_cairo_private.c	16 Aug 2008 08:34:18 -0000	1.8
+++ rb_cairo_private.c	16 Aug 2008 12:52:16 -0000	1.9
@@ -18,6 +18,7 @@
 static ID cr_id_objects;
 static ID cr_id_dup;
 static ID cr_id_inspect;
+static ID cr_id_exit_application;
 
 VALUE
 rb_cairo__float_array (double *values, unsigned count)
@@ -148,11 +149,19 @@
 rb_cairo__glyphs_from_ruby_object (VALUE rb_glyphs,
                                    cairo_glyph_t **glyphs, int *num_glyphs)
 {
-  int i;
+  int i, len;
 
-  *num_glyphs = RARRAY_LEN (rb_glyphs);
-  *glyphs = cairo_glyph_allocate (*num_glyphs);
-  for (i = 0; i < *num_glyphs; i++)
+  if (NIL_P (rb_glyphs))
+    {
+      *num_glyphs = 0;
+      return;
+    }
+
+  len = RARRAY_LEN (rb_glyphs);
+  if (*num_glyphs < len)
+    *glyphs = cairo_glyph_allocate (len);
+  *num_glyphs = len;
+  for (i = 0; i < len; i++)
     {
       cairo_glyph_t *glyph;
 
@@ -182,11 +191,19 @@
                                           cairo_text_cluster_t **clusters,
                                           int *num_clusters)
 {
-  int i;
+  int i, len;
 
-  *num_clusters = RARRAY_LEN (rb_clusters);
-  *clusters = cairo_text_cluster_allocate (*num_clusters);
-  for (i = 0; i < *num_clusters; i++)
+  if (NIL_P (rb_clusters))
+    {
+      *num_clusters = 0;
+      return;
+    }
+
+  len = RARRAY_LEN (rb_clusters);
+  if (*num_clusters < len)
+    *clusters = cairo_text_cluster_allocate (len);
+  *num_clusters = len;
+  for (i = 0; i < len; i++)
     {
       cairo_text_cluster_t *cluster;
 
@@ -195,6 +212,23 @@
     }
 }
 
+VALUE
+rb_cairo__invoke_callback (cr_callback_func_t func, VALUE data)
+{
+  int state = 0;
+  VALUE result, exception;
+
+  result = rb_protect (func, data, &state);
+  if (state)
+    {
+      exception = RB_ERRINFO;
+      if (exception)
+        rb_funcall (rb_mCairo, cr_id_exit_application, 2,
+                    exception, INT2NUM (EXIT_FAILURE));
+    }
+  return result;
+}
+
 void
 Init_cairo_private (void)
 {
@@ -202,4 +236,5 @@
   cr_id_objects = rb_intern ("objects");
   cr_id_dup = rb_intern ("dup");
   cr_id_inspect = rb_intern ("inspect");
+  cr_id_exit_application = rb_intern ("exit_application");
 }

Index: rb_cairo_private.h
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo_private.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- rb_cairo_private.h	16 Aug 2008 08:34:18 -0000	1.11
+++ rb_cairo_private.h	16 Aug 2008 12:52:17 -0000	1.12
@@ -17,6 +17,8 @@
 #define CR_TRUE 1
 #define CR_FALSE 0
 
+#define CAIRO_INT_STATUS_UNSUPPORTED 100
+
 #define CSTR2RVAL(str) rb_str_new2(str)
 #define RVAL2CSTR(str) StringValueCStr(str)
 
@@ -102,4 +104,9 @@
                                                cairo_text_cluster_t **clusters,
                                                int *num_clusters);
 
+cairo_status_t rb_cairo__exception_to_status (VALUE exception);
+
+typedef VALUE (*cr_callback_func_t) (VALUE user_data);
+VALUE rb_cairo__invoke_callback (cr_callback_func_t func, VALUE user_data);
+
 #endif

Index: rb_cairo_surface.c
===================================================================
RCS file: /cvs/cairo/rcairo/src/rb_cairo_surface.c,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- rb_cairo_surface.c	14 Aug 2008 08:21:57 -0000	1.40
+++ rb_cairo_surface.c	16 Aug 2008 12:52:17 -0000	1.41
@@ -159,6 +159,11 @@
   unsigned int length;
 } cr_io_callback_closure_t;
 
+typedef struct cr_invoke_data {
+  cr_callback_func_t func;
+  VALUE data;
+} cr_invoke_data_t;
+
 #if HAS_CREATE_CR_CLOSURE_SURFACE
 static cr_io_callback_closure_t *
 cr_closure_new (VALUE target)
@@ -194,6 +199,17 @@
   return Qnil;
 }
 
+static VALUE
+cr_surface_invoke_io_func (VALUE user_data)
+{
+  cr_invoke_data_t *data;
+
+  data = (cr_invoke_data_t *)user_data;
+  return rb_rescue2 (data->func, data->data,
+                     cr_surface_io_func_rescue, data->data, rb_eException,
+                     (VALUE)0);
+}
+
 /* write callback */
 static VALUE
 cr_surface_write_func_invoke (VALUE write_closure)
@@ -226,15 +242,16 @@
                        const unsigned char *data, unsigned int length)
 {
   cr_io_callback_closure_t *closure;
+  cr_invoke_data_t invoke_data;
 
   closure = (cr_io_callback_closure_t *)write_closure;
   closure->data = (unsigned char *)data;
   closure->length = length;
-  
-  rb_rescue2 (cr_surface_write_func_invoke, (VALUE) closure,
-              cr_surface_io_func_rescue, (VALUE) closure, rb_eException,
-              (VALUE)0);
-  
+
+  invoke_data.func = cr_surface_write_func_invoke;
+  invoke_data.data = (VALUE)closure;
+  rb_cairo__invoke_callback (cr_surface_invoke_io_func, (VALUE)&invoke_data);
+
   if (NIL_P (closure->error))
     return CAIRO_STATUS_SUCCESS;
   else
@@ -270,14 +287,16 @@
                       unsigned char *data, unsigned int length)
 {
   cr_io_callback_closure_t *closure;
+  cr_invoke_data_t invoke_data;
 
   closure = (cr_io_callback_closure_t *)read_closure;
   closure->data = data;
   closure->length = length;
-  rb_rescue2 (cr_surface_read_func_invoke, (VALUE) closure,
-              cr_surface_io_func_rescue, (VALUE) closure, rb_eException,
-              (VALUE)0);
-  
+
+  invoke_data.func = cr_surface_read_func_invoke;
+  invoke_data.data = (VALUE)closure;
+  rb_cairo__invoke_callback (cr_surface_invoke_io_func, (VALUE)&invoke_data);
+
   if (NIL_P (closure->error))
     return CAIRO_STATUS_SUCCESS;
   else



More information about the cairo-commit mailing list