[cairo-commit] rcairo/packages/cairo/ext rb_cairo_surface.c, 1.6, 1.7

Kouhei Sutou commit at pdx.freedesktop.org
Fri Oct 7 06:05:53 PDT 2005


Committed by: kou

Update of /cvs/cairo/rcairo/packages/cairo/ext
In directory gabe:/tmp/cvs-serv29037/packages/cairo/ext

Modified Files:
	rb_cairo_surface.c 
Log Message:
* packages/cairo/ext/rb_cairo_surface.c: Implemented
  cairo_surface_t.


Index: rb_cairo_surface.c
===================================================================
RCS file: /cvs/cairo/rcairo/packages/cairo/ext/rb_cairo_surface.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- rb_cairo_surface.c	13 Sep 2005 16:22:29 -0000	1.6
+++ rb_cairo_surface.c	7 Oct 2005 13:05:51 -0000	1.7
@@ -11,46 +11,81 @@
 #include "rb_cairo.h"
 #include "rubyio.h"
 
-#ifdef CAIRO_HAS_PDF_SURFACE
-#include <cairo-pdf.h>
+#if CAIRO_HAS_PS_SURFACE
+#include <cairo-ps.h>
 #endif
 
-#ifdef CAIRO_HAS_PNG_SURFACE
-#include <cairo-png.h>
+#if CAIRO_HAS_PDF_SURFACE
+#include <cairo-pdf.h>
 #endif
 
-#ifdef CAIRO_HAS_PS_SURFACE
-#include <cairo-ps.h>
-#endif
 
 VALUE rb_cCairo_Surface;
+VALUE rb_cCairo_SurfaceImage;
+VALUE rb_cCairo_SurfacePDF;
+VALUE rb_cCairo_SurfacePS;
+
+static ID cr_id_call;
 
 #define _SELF  (RVAL2CRSURFACE(self))
 
+static inline void
+cr_surface_check_status (cairo_surface_t *surface)
+{
+  cairo_status_t status;
+  status = cairo_surface_status (surface);
+  if (status)
+    {
+      rb_cairo_raise_exception (status);
+    }
+}
+
+/* write callback */
 static cairo_status_t
-rfile_write (void         *closure,
-             const char   *data,
-             unsigned int  length)
+cr_surface_write_func (void *closure, const unsigned char *data, unsigned int length)
 {
-  OpenFile *fptr;
-  FILE     *fp;
-  
-  fptr = closure;
-  fp   = GetWriteFile (fptr);
+  cairo_status_t status = CAIRO_STATUS_SUCCESS;
+  VALUE proc = (VALUE) closure;
 
-  if (rb_io_fwrite (data, length, fp) == length)
-    return CAIRO_STATUS_SUCCESS;
-  return CAIRO_STATUS_WRITE_ERROR;
+  if (!NIL_P(proc))
+    {
+      VALUE result;
+      result = rb_funcall (proc, cr_id_call, rb_str_new (data, length));
+      status = NUM2INT (result);
+      if (status != CAIRO_STATUS_SUCCESS && status != CAIRO_STATUS_WRITE_ERROR)
+        status = CAIRO_STATUS_WRITE_ERROR;
+    }
+  
+  return status;
 }
 
-static void
-rfile_destroy_closure (void *closure)
+/* read callback */
+static cairo_status_t
+cr_surface_read_func (void *closure, unsigned char *data, unsigned int length)
 {
-  OpenFile *fptr;
- 
-  fptr = closure;
+  cairo_status_t status = CAIRO_STATUS_SUCCESS;
+  VALUE proc = (VALUE)closure;
+  
+  if (!NIL_P(proc))
+    {
+      VALUE result, read_data;
+      result = rb_funcall (proc, cr_id_call, INT2NUM (length));
+      status = NUM2INT (rb_ary_entry (result, 0));
+      read_data = rb_ary_entry (result, 1);
+      if ((status != CAIRO_STATUS_SUCCESS &&
+           status != CAIRO_STATUS_READ_ERROR) ||
+          RSTRING (read_data)->len != length)
+        status = CAIRO_STATUS_READ_ERROR;
+
+      if (!status)
+        memcpy (data, StringValuePtr (read_data), length);
+    }
+  
+  return status;
 }
 
+
+/* constructor/de-constructor */
 cairo_surface_t *
 rb_cairo_surface_from_ruby_object (VALUE obj)
 {
@@ -73,12 +108,12 @@
 }
 
 VALUE
-rb_cairo_surface_to_ruby_object (cairo_surface_t *surface)
+rb_cairo_surface_to_ruby_object (cairo_surface_t *surface, VALUE klass)
 {
   if (surface)
     {
       cairo_surface_reference (surface);
-      return Data_Wrap_Struct (rb_cCairo_Surface, NULL, cr_surface_free, surface);
+      return Data_Wrap_Struct (klass, NULL, cr_surface_free, surface);
     }
   else
     {
@@ -86,236 +121,367 @@
     }
 }
 
-static    VALUE
-rb_cairo_surface_new (VALUE klass,
-                      VALUE format_v,
-                      VALUE width_v, VALUE height_v)
+static VALUE
+cr_surface_allocate (VALUE klass)
+{
+  return Data_Wrap_Struct (klass, NULL, cr_surface_free, NULL);
+}
+
+/* Surface manipulation */
+static VALUE
+cr_surface_create_similar (VALUE self, VALUE content, VALUE width, VALUE height)
 {
   cairo_surface_t *surface;
-  int       format;
-  int       width;
-  int       height;
+  surface = cairo_create_similar (RVAL2CRSURFACE (self),
+                                  NUM2INT (content),
+                                  NUM2DBL (width),
+                                  NUM2DBL (height));
+  cr_surface_check_status (surface);
+  return CRSURFACE2RVAL (surface, rb_obj_class (self));
+}
 
-  format = NUM2INT (format_v);
-  width = NUM2INT (width_v);
-  height = NUM2INT (height_v);
+static VALUE
+cairo_surface_finish (VALUE self)
+{
+  cairo_surface_finish (_SELF);
+  cr_surface_check_status (_SELF);
+  return self;
+}
 
-  if (format < CAIRO_FORMAT_ARGB32 || format > CAIRO_FORMAT_A1)
-    {
-      rb_raise (rb_eArgError, "invalid bitmap format");
-    }
-  if (width < 0)
-    {
-      rb_raise (rb_eArgError, "width must be positive");
-    }
-  if (height < 0)
+#if CAIRO_HAS_PNG_FUNCTIONS
+static VALUE
+cr_surface_write_to_png (int argc, VALUE *argv, VALUE self)
+{
+  cairo_status_t status;
+  VALUE filename;
+  int n;
+
+  n = rb_scan_args (argc, argv, "01", &filename);
+
+  if (n == 0)
     {
-      rb_raise (rb_eArgError, "height must be positive");
+      rb_need_block();
+      status = cairo_surface_write_to_png_stream (_SELF,
+                                                  cr_surface_write_func,
+                                                  (void *)ruby_block);
     }
-
-  surface =
-    cairo_image_surface_create ((cairo_format_t) format, width, height);
-  if (surface)
+  else if (TYPE(filename) != T_STRING || )
     {
-      VALUE rb_surface = CRSURFACE2RVAL (surface);
-      cairo_surface_destroy (surface);
-      return rb_surface;
+      rb_raise (rb_eArgError,
+                "invalid argument (expect (filename) or (&block))");
     }
   else
     {
-      rb_raise (rb_eNoMemError, "unable to allocate surface");
-      return Qundef;
+      status = cairo_surface_write_to_png (_SELF, StringValuePtr (filiename));
     }
+  
+  rb_cairo_raise_exception (status);
+  return self;
 }
+#endif
 
-
-#if XXXCAIRO_HAS_PDF_SURFACE
-static    VALUE
-rb_cairo_surface_new_pdf (VALUE klass,
-                          VALUE port,
-                          VALUE width_inches_v,      VALUE height_inches_v,
-                          VALUE x_pixels_per_inch_v, VALUE y_pixels_per_inch_v)
+static VALUE
+cr_surface_get_font_options (VALUE self)
 {
-  cairo_surface_t *surface;
-  double    width_inches;
-  double    height_inches;
-  double    x_pixels_per_inch;
-  double    y_pixels_per_inch;
+  cairo_font_options_t options;
+  cairo_surface_get_font_options (_SELF, &options);
+  cr_surface_check_status (_SELF);
+  return CRFONTOPTIONS2RVAL (cairo_font_options_copy (&options)); /* check status!*/
+}
 
-  Check_Type (port, T_FILE);
-  rb_io_check_writable (RFILE (port)->fptr);
+static VALUE
+cr_surface_flush (VALUE self)
+{
+  cairo_surface_flush (_SELF);
+  cr_surface_check_status (_SELF);
+  return self;
+}
 
-  width_inches = NUM2DBL (width_inches_v);
-  height_inches = NUM2DBL (height_inches_v);
-  x_pixels_per_inch = NUM2DBL (x_pixels_per_inch_v);
-  y_pixels_per_inch = NUM2DBL (y_pixels_per_inch_v);
+static VALUE
+cr_surface_mark_dirty (int argc, VALUE *argv, VALUE self)
+{
+  VALUE x, y, width, height;
+  int n;
+  
+  n = rb_scan_args (argc, argv, "04", &x, &y, &width, &height);
 
-  if (width_inches < 0)
-    {
-      rb_raise (rb_eArgError, "width_inches must be positive");
-    }
-  if (height_inches < 0)
+  if (n == 0)
     {
-      rb_raise (rb_eArgError, "height_inches must be positive");
+      cairo_surface_mark_dirty (_SELF);
     }
-#if 1
-  surface = cairo_pdf_surface_create (rfile_write, rfile_destroy_closure, RFILE (port)->fptr,
-                                      width_inches, height_inches,
-                                      x_pixels_per_inch, y_pixels_per_inch);
-#endif
-#if 0
-  surface = cairo_pdf_surface_create_for_file (GetWriteFile(RFILE (port)->fptr),
-        width_inches, height_inches,
-        x_pixels_per_inch, y_pixels_per_inch);
-#endif
-  
-  if (surface)
+  else if (n == 4)
     {
-      return Data_Wrap_Struct (rb_cCairo_Surface, NULL, rb_free_surface,
-                               surface);
+      cairo_surface_mark_dirty_rectangle (_SELF,
+                                          NUM2INT (x), NUM2INT (y),
+                                          NUM2INT (width), NUM2INT (height));
     }
   else
     {
-      rb_raise (rb_eNoMemError, "unable to allocate surface");
-      return Qundef;
+      rb_raise (rb_eArgError,
+                "invalid argument (expect () or (x, y, width, height))");
     }
+
+  cr_surface_check_status (_SELF);
+  return self;
+}
+
+static VALUE
+cr_surface_set_device_offset (VALUE self, VALUE x_offset, VALUE y_offset)
+{
+  cairo_surface_set_device_offset (_SELF,
+                                   NUM2DBL (x_offset),
+                                   NUM2DBL (y_offset));
+  cr_surface_check_status (_SELF);
+  return self;
+}
+
+
+/* Image-surface functions */
+static cairo_surface_t *
+cr_surface_image_create (VALUE self, VALUE format, VALUE width, VALUE height)
+{
+  return cairo_image_surface_create (NUM2INT (format),
+                                     NUM2INT (width),
+                                     NUM2INT (height));
+}
+
+static cairo_surface_t *
+cr_surface_image_create_for_data (VALUE self, VALUE data, VALUE format,
+                                  VALUE width, VALUE height, VALUE stride)
+{
+  return cairo_image_surface_create_for_data (StringValuePtr (data),
+                                              NUM2INT (format),
+                                              NUM2INT (width),
+                                              NUM2INT (height),
+                                              NUM2INT (stride));
+}
+
+#if CAIRO_HAS_PNG_FUNCTIONS
+static cairo_surface_t *
+cr_surface_image_create_from_png (VALUE self, VALUE filename)
+{
+  return cairo_image_surface_create_from_png (StringValuePtr (filename));
+}
+static cairo_surface_t *
+cr_surface_image_create_from_png_stream (VALUE self)
+{
+  return cairo_image_surface_create_from_png_stream (cr_surface_read_func,
+                                                     (void *)ruby_block);
 }
 #endif
 
-static    VALUE
-rb_cairo_surface_finish (VALUE self)
+static VALUE
+cr_surface_image_initialize (int argc, VALUE *argv, VALUE self)
 {
-  cairo_surface_finish (_SELF);
+  cairo_surface_t *surface;
+  VALUE arg1, arg2, arg3, arg4, arg5;
+  int n;
+  
+  n = rb_scan_args (argc, argv, "32", &arg1, &arg2, &arg3, &arg4, &arg5);
+
+  if (n == 3)
+    surface = cr_surface_image_create (self, arg1, arg2, arg3);
+  else if (n == 5)
+    surface =
+      cr_surface_image_create_for_data (self, arg1, arg2, arg3, arg4, arg5);
+#if CAIRO_HAS_PNG_FUNCTIONS
+  else if (n == 0 && rb_block_given_p ())
+    surface =
+      cr_surface_image_create_from_png_stream (self);
+  else if (n == 1)
+    surface = cr_surface_image_create_from_png (self, arg1);
+#endif
+  else
+    rb_raise (rb_eArgError,
+              "invalid argument (expect "
+#if CAIRO_HAS_PNG_FUNCTIONS
+              "(&block), (filename) "
+#endif
+              "(format, width, height) or "
+              "(data format width height stride))");
+
+  cr_surface_check_status (surface);
+  DATA_PTR (self) = surface;
   return Qnil;
 }
 
-#ifdef CAIRO_HAS_PNG_SURFACE
-static    VALUE
-rb_cairo_surface_new_png (VALUE klass,
-                          VALUE port,
-                          VALUE format_v,
-                          VALUE width_v, VALUE height_v)
+static VALUE
+cr_surface_image_get_width (VALUE self)
 {
-  cairo_surface_t *surface;
-  int       format;
-  int       width;
-  int       height;
+  return INT2NUM (cairo_image_surface_get_width (_SELF));
+}
 
-  Check_Type (port, T_FILE);
-  rb_io_check_writable (RFILE (port)->fptr);
+static VALUE
+cr_surface_image_get_height (VALUE self)
+{
+  return INT2NUM (cairo_image_surface_get_height (_SELF));
+}
 
-  format = NUM2INT (format_v);
-  width = NUM2INT (width_v);
-  height = NUM2INT (height_v);
 
-  if (format < CAIRO_FORMAT_ARGB32 || format > CAIRO_FORMAT_A1)
-    {
-      rb_raise (rb_eArgError, "invalid bitmap format");
-    }
-  if (width < 0)
-    {
-      rb_raise (rb_eArgError, "width must be positive");
-    }
-  if (height < 0)
-    {
-      rb_raise (rb_eArgError, "height must be positive");
-    }
+#if CAIRO_HAS_PS_SURFACE
+/* PS-surface functions */
+static cairo_surface_t *
+cr_surface_ps_create (VALUE self, VALUE filename,
+                      VALUE width_in_points, VALUE height_in_points)
+{
+  return cairo_ps_surface_create (StringValuePtr (filename),
+                                  NUM2DBL (width_in_points),
+                                  NUM2DBL (height_in_points));
+}
 
-  surface =
-    cairo_png_surface_create (GetWriteFile (RFILE (port)->fptr),
-                              (cairo_format_t) format, width, height);
-  if (surface)
-    {
-      return Data_Wrap_Struct (rb_cCairo_Surface, NULL, rb_free_surface,
-                               surface);
-    }
-  else
-    {
-      rb_raise (rb_eNoMemError, "unable to allocate surface");
-      return Qundef;
-    }
+static cairo_surface_t *
+cr_surface_ps_create_for_stream (VALUE self,
+                                 VALUE width_in_points, VALUE height_in_points)
+{
+  return cairo_ps_surface_create_for_stream (cr_surface_write_func,
+                                             (void *) ruby_block,
+                                             NUM2DBL (width_in_points),
+                                             NUM2DBL (height_in_points));
 }
-#endif
 
-#ifdef XXXCAIRO_HAS_PS_SURFACE
-static    VALUE
-rb_cairo_surface_new_ps (VALUE klass,
-                         VALUE port,
-                         VALUE width_inches_v, VALUE height_inches_v,
-                         VALUE x_pixels_per_inch_v, VALUE y_pixels_per_inch_v)
+static VALUE
+cr_surface_ps_initialize (int argc, VALUE *argv, VALUE self)
 {
   cairo_surface_t *surface;
-  double    width_inches;
-  double    height_inches;
-  double    x_pixels_per_inch;
-  double    y_pixels_per_inch;
+  VALUE arg1, arg2, arg3;
+  int n;
+  
+  n = rb_scan_args (argc, argv, "21", &arg1, &arg2, &arg3);
 
-  Check_Type (port, T_FILE);
-  rb_io_check_writable (RFILE (port)->fptr);
+  if (n == 2 && rb_block_given_p ())
+    surface = cr_surface_ps_create_for_stream (self, arg1, arg2);
+  else if (n == 3)
+    surface = cr_surface_ps_create (self, arg1, arg2, arg3);
+  else
+    rb_raise (rb_eArgError,
+              "invalid argument (expect "
+              "(width_in_points, height_in_points, &block) or "
+              "(filename, width_in_points, height_in_points))");
 
-  width_inches = NUM2DBL (width_inches_v);
-  height_inches = NUM2DBL (height_inches_v);
-  x_pixels_per_inch = NUM2DBL (x_pixels_per_inch_v);
-  y_pixels_per_inch = NUM2DBL (y_pixels_per_inch_v);
+  cr_surface_check_status (surface);
+  DATA_PTR (self) = surface;
+  return Qnil;
+}
 
-  if (width_inches < 0)
-    {
-      rb_raise (rb_eArgError, "width_inches must be positive");
-    }
-  if (height_inches < 0)
-    {
-      rb_raise (rb_eArgError, "height_inches must be positive");
-    }
+static VALUE
+cr_surface_ps_set_dpi (VALUE self, VALUE x_dpi, VALUE y_dpi)
+{
+  cairo_ps_surface_set_dpi (_SELF, NUM2DBL (x_dpi), NUM2DBL (y_dpi));
+  cr_surface_check_status (_SELF);
+  return self;
+}
+#endif
 
-  surface = cairo_ps_surface_create (GetWriteFile (RFILE (port)->fptr),
-                                     width_inches, height_inches,
-                                     x_pixels_per_inch, y_pixels_per_inch);
-  if (surface)
-    {
-      return Data_Wrap_Struct (rb_cCairo_Surface, NULL, rb_free_surface,
-                               surface);
-    }
+#if CAIRO_HAS_PDF_SURFACE
+/* PDF-surface functions */
+static cairo_surface_t *
+cr_surface_pdf_create (VALUE self, VALUE filename,
+                       VALUE width_in_points, VALUE height_in_points)
+{
+  return cairo_pdf_surface_create (StringValuePtr (filename),
+                                   NUM2DBL (width_in_points),
+                                   NUM2DBL (height_in_points));
+}
+
+static cairo_surface_t *
+cr_surface_pdf_create_for_stream (VALUE self,
+                                  VALUE width_in_points, VALUE height_in_points)
+{
+  return cairo_pdf_surface_create_for_stream (cr_surface_write_func,
+                                              (void *) ruby_block,
+                                              NUM2DBL (width_in_points),
+                                              NUM2DBL (height_in_points));
+}
+
+static VALUE
+cr_surface_pdf_initialize (int argc, VALUE *argv, VALUE self)
+{
+  cairo_surface_t *surface;
+  VALUE arg1, arg2, arg3;
+  int n;
+  
+  n = rb_scan_args (argc, argv, "21", &arg1, &arg2, &arg3);
+
+  if (n == 2 && rb_block_given_p ())
+    surface = cr_surface_pdf_create_for_stream (self, arg1, arg2);
+  else if (n == 3)
+    surface = cr_surface_pdf_create (self, arg1, arg2, arg3);
   else
-    {
-      rb_raise (rb_eNoMemError, "unable to allocate surface");
-      return Qundef;
-    }
+    rb_raise (rb_eArgError,
+              "invalid argument (expect "
+              "(width_in_points, height_in_points, &block) or "
+              "(filename, width_in_points, height_in_points))");
+
+  cr_surface_check_status (surface);
+  DATA_PTR (self) = surface;
+  return Qnil;
 }
-#endif
 
 static VALUE
-rb_cairo_surface_write_to_png (VALUE self,
-                               VALUE filename_v)
+cr_surface_pdf_set_dpi (VALUE self, VALUE x_dpi, VALUE y_dpi)
 {
-  cairo_surface_write_to_png (_SELF, STR2CSTR (filename_v));
+  cairo_pdf_surface_set_dpi (_SELF, NUM2DBL (x_dpi), NUM2DBL (y_dpi));
+  cr_surface_check_status (_SELF);
   return self;
 }
+#endif
 
 void
 Init_cairo_surface (void)
 {
+  cr_id_call = rb_intern ("call");
+  
   rb_cCairo_Surface =
     rb_define_class_under (rb_mCairo, "Surface", rb_cObject);
-  rb_define_singleton_method (rb_cCairo_Surface, "new",
-                              RUBY_METHOD_FUNC (rb_cairo_surface_new), 3);
 
+  rb_define_alloc_func (rb_cCairo_Surface, cr_surface_allocate);
+  
+  rb_define_method (rb_cCairo_Surface, "create_similar",
+                    cr_surface_create_similar, 3);
+  
+#if CAIRO_HAS_PNG_FUNCTIONS
   rb_define_method (rb_cCairo_Surface, "write_to_png",
-                              RUBY_METHOD_FUNC (rb_cairo_surface_write_to_png), 1);
-  rb_define_method (rb_cCairo_Surface, "finish",
-                              RUBY_METHOD_FUNC (rb_cairo_surface_finish), 0);
-
-#if XXXCAIRO_HAS_PDF_SURFACE
-  rb_define_singleton_method (rb_cCairo_Surface, "new_pdf",
-                              RUBY_METHOD_FUNC (rb_cairo_surface_new_pdf), 5);
+                    cr_surface_write_to_png, -1);
 #endif
+  
+  rb_define_method (rb_cCairo_Surface, "font_options",
+                    cr_surface_get_font_options, 0);
+  rb_define_method (rb_cCairo_Surface, "mark_dirty", cr_surface_mark_dirty, 0);
+  rb_define_method (rb_cCairo_Surface, "set_device_offset",
+                    cr_surface_set_device_offset, 2);
 
-#ifdef CAIRO_HAS_PNG_SURFACE
-  rb_define_singleton_method (rb_cCairo_Surface, "new_png",
-                              RUBY_METHOD_FUNC (rb_cairo_surface_new_png), 4);
+  /* Image-surface */
+  rb_cCairo_SurfaceImage =
+    rb_define_class_under (rb_mCairo, "SurfaceImage", rb_cCairo_Surface);
+  
+  rb_define_method (rb_cCairo_SurfaceImage, "initialize",
+                    cr_surface_image_initialize, -1);
+
+  rb_define_method (rb_cCairo_SurfaceImage, "width",
+                    cr_surface_image_get_width, 0);
+  rb_define_method (rb_cCairo_SurfaceImage, "height",
+                    cr_surface_image_get_height, 0);
+  
+  
+#if CAIRO_HAS_PS_SURFACE
+  /* PS-surface */
+  rb_cCairo_SurfacePS =
+    rb_define_class_under (rb_mCairo, "SurfacePS", rb_cCairo_Surface);
+
+  rb_define_method (rb_cCairo_SurfacePS, "initialize",
+                    cr_surface_ps_initialize, -1);
+  rb_define_method (rb_cCairo_SurfacePS, "set_dpi",
+                    cr_surface_ps_set_dpi, 2);
 #endif
 
-#ifdef XXXCAIRO_HAS_PS_SURFACE
-  rb_define_singleton_method (rb_cCairo_Surface, "new_ps",
-                              RUBY_METHOD_FUNC (rb_cairo_surface_new_ps), 5);
+#if CAIRO_HAS_PDF_SURFACE
+  /* PDF-surface */
+  rb_cCairo_SurfacePDF =
+    rb_define_class_under (rb_mCairo, "SurfacePDF", rb_cCairo_Surface);
+
+  rb_define_method (rb_cCairo_SurfacePDF, "initialize",
+                    cr_surface_pdf_initialize, -1);
+  rb_define_method (rb_cCairo_SurfacePDF, "set_dpi",
+                    cr_surface_pdf_set_dpi, 2);
 #endif
 }



More information about the cairo-commit mailing list