#include <ruby.h>
#include "../gfxdevice.h"
#include "../gfxsource.h"
+#include "../gfxtools.h"
#include "../devices/pdf.h"
#include "../readers/swf.h"
#include "../readers/image.h"
#define RUBY_GFX_VERSION "0.9.0"
static VALUE GFX;
-static VALUE Bitmap, Document, DocumentPage, PDFClass, SWFClass, ImageClass, Device;
+static VALUE Font, Glyph, Bitmap, Document, DocumentPage, PDFClass, SWFClass, ImageClass, Device;
static ID id_doc;
typedef struct doc_internal {
+ VALUE self;
gfxsource_t*driver; // filled by alloc
gfxdocument_t*doc;
- gfxfontlist_t*list;
+ gfxfontlist_t*fontlist;
} doc_internal_t;
typedef struct page_internal {
+ doc_internal_t*doc;
gfxpage_t*page;
} page_internal_t;
typedef struct image_internal {
+ doc_internal_t*doc;
gfximage_t*image;
} image_internal_t;
+typedef struct font_internal {
+ VALUE self;
+ VALUE glyph_array;
+ gfxfont_t*font;
+} font_internal_t;
+
+typedef struct glyph_internal {
+ font_internal_t*font;
+ int nr;
+} glyph_internal_t;
+
static gfxsource_t* pdfdriver = 0;
static gfxsource_t* imagedriver = 0;
static gfxsource_t* swfdriver = 0;
Check_Type(_filename, T_STRING);
Get_Doc(doc,cls);
const char*filename = StringValuePtr(_filename);
+ doc->fontlist = gfxfontlist_create();
doc->doc = pdfdriver->open(pdfdriver, filename);
return cls;
}
return INT2FIX(doc->doc->num_pages);
}
-
static VALUE doc_get_page(VALUE cls, VALUE _nr)
{
Check_Type(_nr, T_FIXNUM);
VALUE v = page_allocate(DocumentPage);
Get_Page(page,v)
page->page = doc->doc->getpage(doc->doc, nr);
+ page->doc = doc;
if(!page->page) {
rb_raise(rb_eArgError, "No page %d in document", nr);
return;
VALUE v = page_allocate(DocumentPage);
Get_Page(page,v)
page->page = doc->doc->getpage(doc->doc, t);
+ page->doc = doc;
rb_yield(v);
}
return cls;
static void doc_mark(doc_internal_t*doc)
{
- // e.g. rb_gc_mark(z->page);
+ gfxfontlist_t*l = doc->fontlist;
+ while(l) {
+ if(l->user)
+ rb_gc_mark((VALUE)l->user);
+ l = l->next;
+ }
}
static void doc_free(doc_internal_t*doc)
{
+ gfxfontlist_free(doc->fontlist, 0);
doc->doc->destroy(doc->doc);
free(doc);
}
static VALUE doc_allocate(VALUE cls, gfxsource_t*driver)
{
doc_internal_t*doc = 0;
- VALUE v = Data_Make_Struct(cls, doc_internal_t, 0, doc_free, doc);
+ VALUE v = Data_Make_Struct(cls, doc_internal_t, doc_mark, doc_free, doc);
+ doc->self = v;
memset(doc, 0, sizeof(doc_internal_t));
doc->driver = driver;
return v;
}
free(page);
}
+static void page_mark(page_internal_t*page)
+{
+ rb_gc_mark(page->doc->self);
+}
static VALUE page_allocate(VALUE cls)
{
page_internal_t*page = 0;
- VALUE v = Data_Make_Struct(cls, page_internal_t, 0, page_free, page);
+ VALUE v = Data_Make_Struct(cls, page_internal_t, page_mark, page_free, page);
memset(page, 0, sizeof(page_internal_t));
return v;
}
{
free(image);
}
+static void image_mark(image_internal_t*image)
+{
+ rb_gc_mark(image->doc->self);
+}
static VALUE image_allocate(VALUE cls)
{
image_internal_t*image = 0;
- VALUE v = Data_Make_Struct(cls, image_internal_t, 0, image_free, image);
+ VALUE v = Data_Make_Struct(cls, image_internal_t, image_mark, image_free, image);
memset(image, 0, sizeof(image_internal_t));
return v;
}
jpeg_save(image->image->data, image->image->width, image->image->height, FIX2INT(quality), filename);
return cls;
}
-VALUE convert_image(gfximage_t*_image)
+VALUE convert_image(doc_internal_t*doc,gfximage_t*_image)
{
VALUE v = image_allocate(Bitmap);
Get_Image(image,v)
image->image = _image;
+ image->doc = doc;
return v;
}
void invalidate_image(VALUE v)
image->image = 0;
}
+// ------------------------ glyphs ------------------------------------------
+
+static VALUE convert_line(gfxline_t*line);
+
+#define Get_Glyph(glyph,cls) glyph_internal_t*glyph=0;Data_Get_Struct(cls, glyph_internal_t, glyph);
+
+static void glyph_free(glyph_internal_t*glyph)
+{
+ free(glyph);
+}
+
+static void glyph_mark(glyph_internal_t*glyph)
+{
+ rb_gc_mark(glyph->font->self);
+}
+
+static VALUE glyph_allocate(VALUE cls)
+{
+ glyph_internal_t*glyph = 0;
+ VALUE v = Data_Make_Struct(cls, glyph_internal_t, glyph_mark, glyph_free, glyph);
+ memset(glyph, 0, sizeof(glyph_internal_t));
+ return v;
+}
+
+static VALUE glyph_polygon(VALUE cls)
+{
+ Get_Glyph(glyph,cls);
+ return convert_line(glyph->font->font->glyphs[glyph->nr].line);
+}
+
+static VALUE glyph_advance(VALUE cls)
+{
+ Get_Glyph(glyph,cls);
+ return rb_float_new(glyph->font->font->glyphs[glyph->nr].advance);
+}
+
+static VALUE glyph_unicode(VALUE cls)
+{
+ Get_Glyph(glyph,cls);
+ return INT2FIX(glyph->font->font->glyphs[glyph->nr].unicode);
+}
+
+// ------------------------ font --------------------------------------------
+
+#define Get_Font(font,cls) font_internal_t*font=0;Data_Get_Struct(cls, font_internal_t, font);
+
+static void font_mark(font_internal_t*font)
+{
+ rb_gc_mark(font->glyph_array);
+}
+
+static void font_free(font_internal_t*font)
+{
+ free(font);
+}
+
+static VALUE font_allocate(VALUE cls)
+{
+ font_internal_t*font = 0;
+ VALUE v = Data_Make_Struct(cls, font_internal_t, font_mark, font_free, font);
+ memset(font, 0, sizeof(font_internal_t));
+ font->self = v;
+ return v;
+}
+
+static VALUE font_name(VALUE cls)
+{
+ Get_Font(font,cls);
+ return rb_tainted_str_new2(font->font->id);
+}
+
+static VALUE font_glyphs(VALUE cls)
+{
+ Get_Font(font,cls);
+ return font->glyph_array;
+}
+
// ------------------------ gfx device --------------------------------------
+typedef struct device_internal {
+ doc_internal_t*doc;
+ VALUE v;
+} device_internal_t;
+
static ID id_setparameter = 0;
static ID id_startpage = 0;
static ID id_startclip = 0;
gfxline_t*l = line;
while(l) {l=l->next;len++;}
- VALUE*a = malloc(sizeof(VALUE)*len);
+ volatile VALUE array = rb_ary_new2(len);
+
int pos = 0;
l = line;
while(l) {
+ volatile VALUE e;
if(l->type == gfx_moveTo) {
- a[pos] = rb_ary_new3(3, ID2SYM(id_move), rb_float_new(l->x), rb_float_new(l->y));
+ e = rb_ary_new3(3, ID2SYM(id_move), Qfalse, Qfalse);
+ rb_ary_store(array, pos, e);
+ rb_ary_store(e, 1, rb_float_new(l->x));
+ rb_ary_store(e, 2, rb_float_new(l->y));
} else if(l->type == gfx_lineTo) {
- a[pos] = rb_ary_new3(3, ID2SYM(id_line), rb_float_new(l->x), rb_float_new(l->y));
+ e = rb_ary_new3(3, ID2SYM(id_line), Qfalse, Qfalse);
+ rb_ary_store(array, pos, e);
+ rb_ary_store(e, 1, rb_float_new(l->x));
+ rb_ary_store(e, 2, rb_float_new(l->y));
} else {
- a[pos] = rb_ary_new3(5, ID2SYM(id_spline), rb_float_new(l->x), rb_float_new(l->y), rb_float_new(l->sx), rb_float_new(l->sy));
+ e = rb_ary_new3(5, ID2SYM(id_spline), Qfalse, Qfalse, Qfalse, Qfalse);
+ rb_ary_store(array, pos, e);
+ rb_ary_store(e, 1, rb_float_new(l->x));
+ rb_ary_store(e, 2, rb_float_new(l->y));
+ rb_ary_store(e, 3, rb_float_new(l->sx));
+ rb_ary_store(e, 4, rb_float_new(l->sy));
}
pos++;
l=l->next;
}
- return rb_ary_new4(len, a);
+ return array;
}
VALUE convert_color(gfxcolor_t*color)
{
}
VALUE convert_matrix(gfxmatrix_t*matrix)
{
- return rb_ary_new3(3,
- rb_ary_new3(2, rb_float_new(matrix->m00), rb_float_new(matrix->m01)),
- rb_ary_new3(2, rb_float_new(matrix->m10), rb_float_new(matrix->m11)),
- rb_ary_new3(2, rb_float_new(matrix->tx), rb_float_new(matrix->ty)));
+ volatile VALUE array = rb_ary_new2(3);
+ volatile VALUE a = rb_ary_new2(2);
+ rb_ary_store(array, 0, a);
+ rb_ary_store(a, 0, rb_float_new(matrix->m00));
+ rb_ary_store(a, 1, rb_float_new(matrix->m01));
+ a = rb_ary_new2(2);
+ rb_ary_store(array, 1, a);
+ rb_ary_store(a, 0, rb_float_new(matrix->m10));
+ rb_ary_store(a, 1, rb_float_new(matrix->m11));
+ a = rb_ary_new2(2);
+ rb_ary_store(array, 2, a);
+ rb_ary_store(a, 0, rb_float_new(matrix->tx));
+ rb_ary_store(a, 1, rb_float_new(matrix->ty));
+ return array;
+}
+static VALUE font_is_cached(device_internal_t*i, gfxfont_t*font)
+{
+ return (VALUE)gfxfontlist_getuserdata(i->doc->fontlist, font->id);
}
+static void cache_font(device_internal_t*i, gfxfont_t*font, VALUE v)
+{
+ i->doc->fontlist = gfxfontlist_addfont2(i->doc->fontlist, font, (void*)v);
+}
+static VALUE convert_font(gfxfont_t*font)
+{
+ volatile VALUE v2 = font_allocate(Font);
+ Get_Font(f, v2);
+ f->font = font;
+ f->glyph_array = rb_ary_new2(font->num_glyphs);
+
+ int t;
+ for(t=0;t<font->num_glyphs;t++) {
+ volatile VALUE a = glyph_allocate(Glyph);
+ rb_ary_store(f->glyph_array, t, a);
+ Get_Glyph(g, a);
+ g->font = f;
+ g->nr = t;
+ }
+ return v2;
+}
+#define HEAD \
+ device_internal_t*i = (device_internal_t*)dev->internal; \
+ VALUE v = i->v;
int rb_setparameter(gfxdevice_t*dev, const char*key, const char*value)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- VALUE ret = forward(v,id_setparameter,2,rb_tainted_str_new2(key),rb_tainted_str_new2(value));
+ HEAD
+ volatile VALUE v_key = rb_tainted_str_new2(key);
+ volatile VALUE v_value = rb_tainted_str_new2(value);
+ VALUE ret = forward(v,id_setparameter,2,v_key,v_value);
return 0;
}
void rb_startpage(gfxdevice_t*dev, int width, int height)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
+ HEAD
VALUE ret = forward(v,id_startpage,2,INT2FIX(width),INT2FIX(height));
}
void rb_startclip(gfxdevice_t*dev, gfxline_t*line)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- VALUE ret = forward(v,id_startclip,1,convert_line(line));
+ HEAD
+ volatile VALUE v_line = convert_line(line);
+ VALUE ret = forward(v,id_startclip,1,v_line);
}
void rb_endclip(gfxdevice_t*dev)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
+ HEAD
VALUE ret = forward(v,id_endclip,0);
}
void rb_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
+ HEAD
ID cap = 0;
if(cap_style == gfx_capButt) cap = id_butt;
else if(joint_style == gfx_joinMiter) joint = id_miter;
else if(joint_style == gfx_joinBevel) joint = id_bevel;
- forward(v, id_stroke, 6, convert_line(line), rb_float_new(width), convert_color(color), ID2SYM(cap), ID2SYM(joint), rb_float_new(miterLimit));
+ volatile VALUE v_line = convert_line(line);
+ volatile VALUE v_width = rb_float_new(width);
+ volatile VALUE v_color = convert_color(color);
+ volatile VALUE v_miter = rb_float_new(miterLimit);
+ forward(v, id_stroke, 6, v_line, v_width, v_color, ID2SYM(cap), ID2SYM(joint), v_miter);
}
void rb_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- forward(v, id_fill, 2, convert_line(line), convert_color(color));
+ HEAD
+
+ volatile VALUE v_line = convert_line(line);
+ volatile VALUE v_color = convert_color(color);
+ forward(v, id_fill, 2, v_line, v_color);
}
void rb_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- VALUE image = convert_image(img);
- forward(v, id_fillbitmap, 4, convert_line(line), image, convert_matrix(matrix), Qnil);
- invalidate_image(image);
+ HEAD
+ volatile VALUE v_image = convert_image(i->doc, img);
+ volatile VALUE v_line = convert_line(line);
+ volatile VALUE v_matrix = convert_matrix(matrix);
+ forward(v, id_fillbitmap, 4, v_line, v_image, v_matrix, Qnil);
+ invalidate_image(v_image);
}
void rb_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
+ HEAD
ID typeid = (type == gfxgradient_linear)? id_linear : id_radial;
- forward(v, id_fillgradient, 4, convert_line(line), convert_gradient(gradient), ID2SYM(typeid), convert_matrix(matrix));
+
+ volatile VALUE v_line = convert_line(line);
+ volatile VALUE v_matrix = convert_matrix(matrix);
+ volatile VALUE v_gradient = convert_gradient(gradient);
+ forward(v, id_fillgradient, 4, v_line, v_gradient, ID2SYM(typeid), v_matrix);
}
void rb_addfont(gfxdevice_t*dev, gfxfont_t*font)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- //forward(v, id_addfont, 1, convert_font(font));
+ HEAD
+
+ volatile VALUE f = font_is_cached(i, font);
+ if(!f) {f=convert_font(font);cache_font(i,font,v);}
+
+ forward(v, id_addfont, 1, f);
}
void rb_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- //forward(v, id_drawchar, 1, convert_font(font));
+ HEAD
+ volatile VALUE f = font_is_cached(i, font);
+ if(!f) {f=convert_font(font);cache_font(i,font,v);}
+
+ volatile VALUE v_color = convert_color(color);
+ volatile VALUE v_matrix = convert_matrix(matrix);
+ forward(v, id_drawchar, 4, f, INT2FIX(glyphnr), v_color, v_matrix);
}
void rb_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
- forward(v, id_drawlink, convert_line(line), rb_tainted_str_new2(action));
+ HEAD
+ volatile VALUE v_line = convert_line(line);
+ volatile VALUE v_action = rb_tainted_str_new2(action);
+ forward(v, id_drawlink, v_line, v_action);
}
void rb_endpage(gfxdevice_t*dev)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
+ HEAD
forward(v, id_endpage, 0);
}
gfxresult_t* rb_finish(gfxdevice_t*dev)
{
- VALUE v = (VALUE)(ptroff_t)dev->internal;
+ HEAD
VALUE ret = forward(v, id_endpage, 0);
gfxresult_t*r = (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t));
r->internal = (void*)(ptroff_t)ret;
Get_Page(page,cls)
gfxdevice_t dev;
- dev.internal = (void*)(ptroff_t)device;
+ device_internal_t i;
+ i.v = device;
+ i.doc = page->doc;
+
+ dev.internal = &i;
dev.setparameter = rb_setparameter;
dev.startpage = rb_startpage;
dev.startclip = rb_startclip;
dev.drawlink = rb_drawlink;
dev.endpage = rb_endpage;
dev.finish = rb_finish;
-
+
page->page->render(page->page, &dev);
return cls;
GFX = rb_define_module("GFX");
DocumentPage = rb_define_class_under(GFX, "DocumentPage", rb_cObject);
- rb_define_alloc_func(DocumentPage, page_allocate);
rb_define_method(DocumentPage, "width", page_width, 0);
rb_define_method(DocumentPage, "height", page_height, 0);
rb_define_method(DocumentPage, "nr", page_nr, 0);
rb_define_method(Document, "each_page", doc_each_page, 0);
Bitmap = rb_define_class_under(GFX, "Bitmap", rb_cObject);
- rb_define_alloc_func(Bitmap, image_allocate);
rb_define_method(Bitmap, "save_jpeg", image_save_jpeg, 2);
+ Glyph = rb_define_class_under(GFX, "Glyph", rb_cObject);
+ rb_define_method(Glyph, "polygon", glyph_polygon, 0);
+ rb_define_method(Glyph, "unicode", glyph_unicode, 0);
+ rb_define_method(Glyph, "advance", glyph_advance, 0);
+
+ Font = rb_define_class_under(GFX, "Font", rb_cObject);
+ rb_define_method(Font, "name", font_name, 0);
+ rb_define_method(Font, "glyphs", font_glyphs, 0);
+
Device = rb_define_class_under(GFX, "Device", rb_cObject);
rb_define_method(Device, "startpage", noop, -1);
rb_define_method(Device, "endpage", noop, -1);