added two pass support and device filters to gfx library
authorMatthias Kramm <kramm@quiss.org>
Fri, 26 Feb 2010 02:43:16 +0000 (18:43 -0800)
committerMatthias Kramm <kramm@quiss.org>
Fri, 26 Feb 2010 02:43:16 +0000 (18:43 -0800)
installer/mkarchive.c
lib/Makefile.in
lib/devices/record.c
lib/devices/record.h
lib/gfxfilter.c [new file with mode: 0644]
lib/gfxfilter.h [new file with mode: 0644]
lib/os.c
lib/os.h
lib/pdf/BitmapOutputDev.cc
lib/pdf/GFXOutputDev.cc
swfs/Makefile.in

index 45b2a3d..7dab4e0 100644 (file)
@@ -56,6 +56,10 @@ writer_t*writer_init_filewriter(char*filename)
 {
     writer_t*w = malloc(sizeof(writer_t));
     FILE*fi = fopen(filename, "wb");
 {
     writer_t*w = malloc(sizeof(writer_t));
     FILE*fi = fopen(filename, "wb");
+    if(!fi) {
+       perror(filename);
+       return 0;
+    }
     filewrite_t *mr = (filewrite_t *)malloc(sizeof(filewrite_t));
     mr->fi = fi;
     memset(w, 0, sizeof(writer_t));
     filewrite_t *mr = (filewrite_t *)malloc(sizeof(filewrite_t));
     mr->fi = fi;
     memset(w, 0, sizeof(writer_t));
index bdd208d..e57e0ee 100644 (file)
@@ -19,7 +19,7 @@ gfxpoly_objects = gfxpoly/active.$(O) gfxpoly/convert.$(O) gfxpoly/poly.$(O) gfx
 rfxswf_modules =  modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c modules/swfalignzones.c
 
 base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O) ttf.$(O)
 rfxswf_modules =  modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c modules/swfalignzones.c
 
 base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) MD5.$(O) xml.$(O) ttf.$(O)
-gfx_objects=gfximage.$(O) gfxtools.$(O) gfxfont.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@
+gfx_objects=gfximage.$(O) gfxtools.$(O) gfxfont.$(O) gfxfilter.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@
 
 rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O)
 ocr_objects=gocr/box.$(O) gocr/database.$(O) gocr/detect.$(O) gocr/job.$(O) gocr/lines.$(O) gocr/list.$(O) gocr/ocr0.$(O) gocr/ocr0n.$(O) gocr/ocr1.$(O) gocr/otsu.$(O) gocr/output.$(O) gocr/pgm2asc.$(O) gocr/pixel.$(O) gocr/progress.$(O) gocr/remove.$(O) gocr/unicode.$(O)
 
 rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O)
 ocr_objects=gocr/box.$(O) gocr/database.$(O) gocr/detect.$(O) gocr/job.$(O) gocr/lines.$(O) gocr/list.$(O) gocr/ocr0.$(O) gocr/ocr0n.$(O) gocr/ocr1.$(O) gocr/otsu.$(O) gocr/output.$(O) gocr/pgm2asc.$(O) gocr/pixel.$(O) gocr/progress.$(O) gocr/remove.$(O) gocr/unicode.$(O)
@@ -95,6 +95,8 @@ gfxtools.$(O): gfxtools.c gfxtools.h $(top_builddir)/config.h
        $(C) gfxtools.c -o $@
 gfxfont.$(O): gfxfont.c gfxfont.h ttf.h $(top_builddir)/config.h
        $(C) gfxfont.c -o $@
        $(C) gfxtools.c -o $@
 gfxfont.$(O): gfxfont.c gfxfont.h ttf.h $(top_builddir)/config.h
        $(C) gfxfont.c -o $@
+gfxfilter.$(O): gfxfilter.c gfxfilter.h ttf.h $(top_builddir)/config.h
+       $(C) gfxfilter.c -o $@
 gfxwindow.$(O): gfxwindow_win32.c gfxwindow_unix.c gfxwindow.c gfxwindow.h
        $(C) gfxwindow.c -o $@
 
 gfxwindow.$(O): gfxwindow_win32.c gfxwindow_unix.c gfxwindow.c gfxwindow.h
        $(C) gfxwindow.c -o $@
 
index cf04db6..ae493ee 100644 (file)
 #include "../types.h"
 #include "../bitio.h"
 #include "../log.h"
 #include "../types.h"
 #include "../bitio.h"
 #include "../log.h"
+#include "../os.h"
 #include "record.h"
 
 typedef struct _internal {
     gfxfontlist_t* fontlist;
     writer_t w;
     int cliplevel;
 #include "record.h"
 
 typedef struct _internal {
     gfxfontlist_t* fontlist;
     writer_t w;
     int cliplevel;
+    char use_tempfile;
+    char*filename;
 } internal_t;
 
 typedef struct _internal_result {
 } internal_t;
 
 typedef struct _internal_result {
+    char use_tempfile;
+    char*filename;
     void*data;
     int length;
 } internal_result_t;
     void*data;
     int length;
 } internal_result_t;
@@ -418,20 +423,20 @@ static void record_drawlink(struct _gfxdevice*dev, gfxline_t*line, const char*ac
     writer_writeString(&i->w, action);
 }
 
     writer_writeString(&i->w, action);
 }
 
-static void replay(struct _gfxdevice*dev, gfxdevice_t*out, void*data, int length)
+static void replay(struct _gfxdevice*dev, gfxdevice_t*out, reader_t*r)
 {
     internal_t*i = 0;
     if(dev) {
        i = (internal_t*)dev->internal;
     }
 
 {
     internal_t*i = 0;
     if(dev) {
        i = (internal_t*)dev->internal;
     }
 
-    reader_t r2;
-    reader_t*r = &r2;
-    reader_init_memreader(r, data, length);
     gfxfontlist_t* fontlist = gfxfontlist_create();
 
     gfxfontlist_t* fontlist = gfxfontlist_create();
 
-    while(r->pos < length) {
-       unsigned char op = reader_readU8(r);
+    while(1) {
+       unsigned char op;
+       if(r->read(r, &op, 1)!=1)
+           break;
+
        switch(op) {
            case OP_END:
                goto finish;
        switch(op) {
            case OP_END:
                goto finish;
@@ -577,24 +582,38 @@ finish:
 void gfxresult_record_replay(gfxresult_t*result, gfxdevice_t*device)
 {
     internal_result_t*i = (internal_result_t*)result->internal;
 void gfxresult_record_replay(gfxresult_t*result, gfxdevice_t*device)
 {
     internal_result_t*i = (internal_result_t*)result->internal;
-    replay(0, device, i->data, i->length);
+    
+    reader_t r;
+    if(i->filename) {
+       reader_init_filereader2(&r, i->filename);
+    } else {
+       reader_init_memreader(&r, i->data, i->length);
+    }
+
+    replay(0, device, &r);
 }
 
 static void record_result_write(gfxresult_t*r, int filedesc)
 {
     internal_result_t*i = (internal_result_t*)r->internal;
 }
 
 static void record_result_write(gfxresult_t*r, int filedesc)
 {
     internal_result_t*i = (internal_result_t*)r->internal;
-    write(filedesc, i->data, i->length);
+    if(i->data) {
+       write(filedesc, i->data, i->length);
+    }
 }
 static int record_result_save(gfxresult_t*r, const char*filename)
 {
     internal_result_t*i = (internal_result_t*)r->internal;
 }
 static int record_result_save(gfxresult_t*r, const char*filename)
 {
     internal_result_t*i = (internal_result_t*)r->internal;
-    FILE*fi = fopen(filename, "wb");
-    if(!fi) {
-       fprintf(stderr, "Couldn't open file %s for writing\n", filename);
-       return -1;
+    if(i->use_tempfile) {
+       move_file(i->filename, filename);
+    } else {
+       FILE*fi = fopen(filename, "wb");
+       if(!fi) {
+           fprintf(stderr, "Couldn't open file %s for writing\n", filename);
+           return -1;
+       }
+       fwrite(i->data, i->length, 1, fi);
+       fclose(fi);
     }
     }
-    fwrite(i->data, i->length, 1, fi);
-    fclose(fi);
     return 0;
 }
 static void*record_result_get(gfxresult_t*r, const char*name)
     return 0;
 }
 static void*record_result_get(gfxresult_t*r, const char*name)
@@ -613,6 +632,9 @@ static void record_result_destroy(gfxresult_t*r)
     if(i->data) {
        free(i->data);i->data = 0;
     }
     if(i->data) {
        free(i->data);i->data = 0;
     }
+    if(i->filename) {
+       free(i->filename);
+    }
     free(r->internal);r->internal = 0;
     free(r);
 }
     free(r->internal);r->internal = 0;
     free(r);
 }
@@ -646,11 +668,17 @@ void gfxdevice_record_flush(gfxdevice_t*dev, gfxdevice_t*out)
 {
     internal_t*i = (internal_t*)dev->internal;
     if(out) {
 {
     internal_t*i = (internal_t*)dev->internal;
     if(out) {
-       int len=0;
-       void*data = writer_growmemwrite_memptr(&i->w, &len);
-       replay(dev, out, data, len);
+       if(i->use_tempfile) {
+           int len=0;
+           void*data = writer_growmemwrite_memptr(&i->w, &len);
+           reader_t r;
+           reader_init_memreader(&r, data, len);
+           replay(dev, out, &r);
+           writer_growmemwrite_reset(&i->w);
+       } else {
+           msg("<error> Flushing not supported for file based record device");
+       }
     }
     }
-    writer_growmemwrite_reset(&i->w);
 }
 
 static gfxresult_t* record_finish(struct _gfxdevice*dev)
 }
 
 static gfxresult_t* record_finish(struct _gfxdevice*dev)
@@ -667,8 +695,14 @@ static gfxresult_t* record_finish(struct _gfxdevice*dev)
     gfxfontlist_free(i->fontlist, 0);
    
     internal_result_t*ir = (internal_result_t*)rfx_calloc(sizeof(gfxresult_t));
     gfxfontlist_free(i->fontlist, 0);
    
     internal_result_t*ir = (internal_result_t*)rfx_calloc(sizeof(gfxresult_t));
-    ir->data = writer_growmemwrite_getmem(&i->w);
-    ir->length = i->w.pos;
+   
+    ir->use_tempfile = i->use_tempfile;
+    if(i->use_tempfile) {
+       ir->data = writer_growmemwrite_getmem(&i->w);
+       ir->length = i->w.pos;
+    } else {
+       ir->filename = i->filename;
+    }
     i->w.finish(&i->w);
 
     gfxresult_t*result= (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t));
     i->w.finish(&i->w);
 
     gfxresult_t*result= (gfxresult_t*)rfx_calloc(sizeof(gfxresult_t));
@@ -681,7 +715,8 @@ static gfxresult_t* record_finish(struct _gfxdevice*dev)
     
     return result;
 }
     
     return result;
 }
-void gfxdevice_record_init(gfxdevice_t*dev)
+
+void gfxdevice_record_init(gfxdevice_t*dev, char use_tempfile)
 {
     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
     memset(dev, 0, sizeof(gfxdevice_t));
 {
     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
     memset(dev, 0, sizeof(gfxdevice_t));
@@ -689,8 +724,15 @@ void gfxdevice_record_init(gfxdevice_t*dev)
     dev->name = "record";
 
     dev->internal = i;
     dev->name = "record";
 
     dev->internal = i;
-    
-    writer_init_growingmemwriter(&i->w, 1048576);
+  
+    i->use_tempfile = use_tempfile;
+    if(!use_tempfile) {
+       writer_init_growingmemwriter(&i->w, 1048576);
+    } else {
+       char buffer[128];
+       i->filename = strdup(mktempname(buffer));
+       writer_init_filewriter2(&i->w, i->filename);
+    }
     i->fontlist = gfxfontlist_create();
     i->cliplevel = 0;
 
     i->fontlist = gfxfontlist_create();
     i->cliplevel = 0;
 
index 651de5c..34fe1e4 100644 (file)
@@ -29,7 +29,9 @@
 extern "C" {
 #endif
 
 extern "C" {
 #endif
 
-void gfxdevice_record_init(gfxdevice_t*);
+void gfxdevice_record_init(gfxdevice_t*, char use_tempfile);
+
+gfxdevice_t* gfxdevice_record_new(char*filename);
 
 void gfxdevice_record_flush(gfxdevice_t*, gfxdevice_t*);
 
 
 void gfxdevice_record_flush(gfxdevice_t*, gfxdevice_t*);
 
diff --git a/lib/gfxfilter.c b/lib/gfxfilter.c
new file mode 100644 (file)
index 0000000..57d6180
--- /dev/null
@@ -0,0 +1,301 @@
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "mem.h"
+#include "gfxfilter.h"
+#include "devices/record.h"
+
+typedef struct _internal {
+    gfxfilter_t*filter;
+    gfxdevice_t*out;
+    gfxdevice_t*final_out;
+
+    /* for two pass filters: */
+    int pass;
+    int num_passes;
+    gfxdevice_t record;
+    gfxtwopassfilter_t*twopass;
+} internal_t;
+
+static int filter_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    return i->filter->setparameter(i->filter, key, value, i->out);
+}
+static void filter_startpage(gfxdevice_t*dev, int width, int height)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->startpage(i->filter, width, height, i->out);
+}
+static void filter_startclip(gfxdevice_t*dev, gfxline_t*line)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->startclip(i->filter, line, i->out);
+}
+static void filter_endclip(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->endclip(i->filter, i->out);
+}
+static void filter_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->stroke(i->filter, line, width, color, cap_style, joint_style, miterLimit, i->out);
+}
+static void filter_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->fill(i->filter, line, color, i->out);
+}
+static void filter_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->fillbitmap(i->filter, line, img, matrix, cxform, i->out);
+}
+static void filter_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->fillgradient(i->filter, line, gradient, type, matrix, i->out);
+}
+static void filter_addfont(gfxdevice_t*dev, gfxfont_t*font)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->addfont(i->filter, font, i->out);
+}
+static void filter_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->drawchar(i->filter, font, glyphnr, color, matrix, i->out);
+}
+static void filter_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->drawlink(i->filter, line, action, i->out);
+}
+static void filter_endpage(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->filter->endpage(i->filter, i->out);
+}
+static gfxresult_t* filter_finish(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    gfxresult_t*r = i->filter->finish(i->filter, i->out);
+    free(dev->internal);dev->internal=0;free(dev);
+    return r;
+}
+
+
+static int passthrough_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    return i->out->setparameter(i->out, key, value);
+}
+static void passthrough_startpage(gfxdevice_t*dev, int width, int height)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->startpage(i->out, width, height);
+}
+static void passthrough_startclip(gfxdevice_t*dev, gfxline_t*line)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->startclip(i->out, line);
+}
+static void passthrough_endclip(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->endclip(i->out);
+}
+static void passthrough_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->stroke(i->out, line, width, color, cap_style, joint_style, miterLimit);
+}
+static void passthrough_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->fill(i->out, line, color);
+}
+static void passthrough_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->fillbitmap(i->out, line, img, matrix, cxform);
+}
+static void passthrough_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->fillgradient(i->out, line, gradient, type, matrix);
+}
+static void passthrough_addfont(gfxdevice_t*dev, gfxfont_t*font)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->addfont(i->out, font);
+}
+static void passthrough_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->drawchar(i->out, font, glyphnr, color, matrix);
+}
+static void passthrough_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->drawlink(i->out, line, action);
+}
+static void passthrough_endpage(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    i->out->endpage(i->out);
+}
+gfxresult_t* passthrough_finish(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+    gfxdevice_t*out = i->out;
+    free(dev->internal);dev->internal=0;free(dev);
+    return out->finish(out);
+}
+
+int discard_setparameter(gfxdevice_t*dev, const char*key, const char*value)
+{
+    return 0;
+}
+static void discard_startpage(gfxdevice_t*dev, int width, int height)
+{
+}
+static void discard_startclip(gfxdevice_t*dev, gfxline_t*line)
+{
+}
+static void discard_endclip(gfxdevice_t*dev)
+{
+}
+static void discard_stroke(gfxdevice_t*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
+{
+}
+static void discard_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
+{
+}
+static void discard_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
+{
+}
+static void discard_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
+{
+}
+static void discard_addfont(gfxdevice_t*dev, gfxfont_t*font)
+{
+}
+static void discard_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
+{
+}
+static void discard_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
+{
+}
+static void discard_endpage(gfxdevice_t*dev)
+{
+}
+static gfxresult_t* discard_finish(gfxdevice_t*dev)
+{
+    return 0;
+}
+
+gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*out)
+{
+    internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
+    gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
+    
+    i->out = out;
+    i->filter = filter;
+    i->pass = 1;
+
+    dev->internal = i;
+    dev->name = filter->name?filter->name:"filter";
+    dev->setparameter = filter->setparameter?filter_setparameter:passthrough_setparameter;
+    dev->startpage = filter->startpage?filter_startpage:passthrough_startpage;
+    dev->startclip = filter->startclip?filter_startclip:passthrough_startclip;
+    dev->endclip = filter->endclip?filter_endclip:passthrough_endclip;
+    dev->stroke = filter->stroke?filter_stroke:passthrough_stroke;
+    dev->fill = filter->fill?filter_fill:passthrough_fill;
+    dev->fillbitmap = filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap;
+    dev->fillgradient = filter->fillgradient?filter_fillgradient:passthrough_fillgradient;
+    dev->addfont = filter->addfont?filter_addfont:passthrough_addfont;
+    dev->drawchar = filter->drawchar?filter_drawchar:passthrough_drawchar;
+    dev->drawlink = filter->drawlink?filter_drawlink:passthrough_drawlink;
+    dev->endpage = filter->endpage?filter_endpage:passthrough_endpage;
+    dev->finish = filter->finish?filter_finish:passthrough_finish;
+    return dev;
+}
+
+static void setup_twopass(gfxdevice_t*, gfxfilter_t*filter, char passthrough);
+
+static gfxresult_t* twopass_finish(gfxdevice_t*dev)
+{
+    internal_t*i = (internal_t*)dev->internal;
+  
+    assert(!strcmp(i->out->name, "record"));
+   
+    gfxresult_t*r;
+    if(i->filter->finish) {
+       r = i->filter->finish(i->filter, i->out);
+    } else {
+       r = i->out->finish(i->out);
+    }
+
+    if(i->pass == i->num_passes) {
+       /* this output device was not a record device, so we don't have
+          to do anything here (like cleanup) */
+       return r;
+    }
+
+    /* switch to next pass filter */
+    i->filter = &i->twopass->pass2;
+
+    if(i->pass == i->num_passes-1) {
+       /* we don't record in the final pass- we just stream out to the 
+          next output device */
+       i->out = i->final_out;
+    } else {
+        // this only happens for 3 passes or more
+       assert(i->num_passes>2);
+       gfxdevice_record_init(&i->record, /*use tempfile*/1);
+       i->out = &i->record;
+    }
+
+    i->pass++;
+    gfxresult_record_replay(r, i->out);
+    r = i->out->finish(i->out);
+
+    return r;
+}
+
+gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*twopass, gfxdevice_t*out)
+{
+    internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
+    gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
+   
+    gfxdevice_record_init(&i->record, /*use tempfile*/1);
+
+    i->out = &i->record;
+    i->final_out = out;
+    i->filter = &twopass->pass1;
+    i->twopass = twopass;
+    i->pass = 1;
+    i->num_passes = 2;
+       
+    dev->setparameter = i->filter->setparameter?filter_setparameter:passthrough_setparameter;
+    dev->startpage = i->filter->startpage?filter_startpage:passthrough_startpage;
+    dev->startclip = i->filter->startclip?filter_startclip:passthrough_startclip;
+    dev->endclip = i->filter->endclip?filter_endclip:passthrough_endclip;
+    dev->stroke = i->filter->stroke?filter_stroke:passthrough_stroke;
+    dev->fill = i->filter->fill?filter_fill:passthrough_fill;
+    dev->fillbitmap = i->filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap;
+    dev->fillgradient = i->filter->fillgradient?filter_fillgradient:passthrough_fillgradient;
+    dev->addfont = i->filter->addfont?filter_addfont:passthrough_addfont;
+    dev->drawchar = i->filter->drawchar?filter_drawchar:passthrough_drawchar;
+    dev->drawlink = i->filter->drawlink?filter_drawlink:passthrough_drawlink;
+    dev->endpage = i->filter->endpage?filter_endpage:passthrough_endpage;
+    dev->finish = twopass_finish;
+
+    dev->internal = i;
+    dev->name = i->filter->name?i->filter->name:"filter";
+    dev->finish = twopass_finish;
+    return dev;
+}
+
diff --git a/lib/gfxfilter.h b/lib/gfxfilter.h
new file mode 100644 (file)
index 0000000..a5d0a6c
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __gfxfilter_h__
+#define __gfxfilter_h__
+
+#include "gfxdevice.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _gfxfilter
+{
+    int num_passes;
+    const char*name;
+    int pass;
+
+    int (*setparameter)(struct _gfxfilter*in, const char*key, const char*value, struct _gfxdevice*out);
+    void (*startpage)(struct _gfxfilter*in, int width, int height, struct _gfxdevice*out);
+    void (*startclip)(struct _gfxfilter*in, gfxline_t*line, struct _gfxdevice*out);
+    void (*endclip)(struct _gfxfilter*in, struct _gfxdevice*out);
+    void (*stroke)(struct _gfxfilter*in, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit, struct _gfxdevice*out);
+    void (*fill)(struct _gfxfilter*in, gfxline_t*line, gfxcolor_t*color, struct _gfxdevice*out);
+    void (*fillbitmap)(struct _gfxfilter*in, gfxline_t*line, gfximage_t*img, gfxmatrix_t*imgcoord2devcoord, gfxcxform_t*cxform, struct _gfxdevice*out); //cxform? tiling?
+    void (*fillgradient)(struct _gfxfilter*in, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*gradcoord2devcoord, struct _gfxdevice*out); //?
+    void (*addfont)(struct _gfxfilter*in, gfxfont_t*font, struct _gfxdevice*out);
+    void (*drawchar)(struct _gfxfilter*in, gfxfont_t*font, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix, struct _gfxdevice*out);
+    void (*drawlink)(struct _gfxfilter*in, gfxline_t*line, const char*action, struct _gfxdevice*out);
+    void (*endpage)(struct _gfxfilter*in, struct _gfxdevice*out);
+    gfxresult_t* (*finish)(struct _gfxfilter*in, struct _gfxdevice*out);
+    void* internal;
+} gfxfilter_t;
+
+typedef struct _gfxtwopassfilter
+{
+    gfxfilter_t pass1;
+    gfxfilter_t pass2;
+} gfxtwopassfilter_t;
+
+gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*dev);
+gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*filter, gfxdevice_t*dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__gfxfilter_h__
index fddaee9..dacd580 100755 (executable)
--- a/lib/os.c
+++ b/lib/os.c
@@ -274,3 +274,33 @@ void memfile_close(memfile_t*file)
     free(file);
 }
 
     free(file);
 }
 
+void move_file(const char*from, const char*to)
+{
+    int result = rename(from, to);
+
+    if(result==0) return; //done!
+
+    /* if we can't rename, for some reason, copy the file
+       manually */
+    FILE*fi = fopen(from, "rb");
+    if(!fi) {
+       perror(from);
+       return;
+    }
+    FILE*fo = fopen(to, "wb");
+    if(!fo) {
+       perror(to);
+       return;
+    }
+    char buffer[16384];
+    while(1) {
+       int bytes = fread(buffer, 16384, 1, fi);
+       if(bytes<=0)
+           return;
+       fwrite(buffer, bytes, 1, to);
+    }
+
+    fclose(fo);
+    fclose(fi);
+}
+
index d7cb2a2..532aea8 100755 (executable)
--- a/lib/os.h
+++ b/lib/os.h
@@ -49,6 +49,8 @@ char* stripFilename(const char*filename, const char*newext);
 
 char* mktempname(char*buffer);
 
 
 char* mktempname(char*buffer);
 
+void move_file(const char*from, const char*to);
+
 #ifdef __cplusplus
 }
 #endif
 #ifdef __cplusplus
 }
 #endif
index 25c4c81..1a735e3 100644 (file)
@@ -75,7 +75,7 @@ BitmapOutputDev::BitmapOutputDev(InfoOutputDev*info, PDFDoc*doc)
     this->clip1dev->startDoc(this->xref);
 
     this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
     this->clip1dev->startDoc(this->xref);
 
     this->gfxoutput = (gfxdevice_t*)malloc(sizeof(gfxdevice_t));
-    gfxdevice_record_init(this->gfxoutput);
+    gfxdevice_record_init(this->gfxoutput, 0);
 
     this->gfxdev->setDevice(this->gfxoutput);
     
 
     this->gfxdev->setDevice(this->gfxoutput);
     
index c35cb39..bd6af40 100644 (file)
@@ -2663,7 +2663,7 @@ void GFXOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
     this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
     dbg("this->device now %p (old: %p)", this->device, states[statepos].olddevice);
 
     this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
     dbg("this->device now %p (old: %p)", this->device, states[statepos].olddevice);
 
-    gfxdevice_record_init(this->device);
+    gfxdevice_record_init(this->device, 0);
     
     /*if(!forSoftMask) { ////???
        state->setFillOpacity(0.0);
     
     /*if(!forSoftMask) { ////???
        state->setFillOpacity(0.0);
@@ -2760,7 +2760,7 @@ void GFXOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Funct
     }
     states[statepos].olddevice = this->device;
     this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
     }
     states[statepos].olddevice = this->device;
     this->device = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
-    gfxdevice_record_init(this->device);
+    gfxdevice_record_init(this->device, 0);
 
     dbg("softmaskrecording is %p (dev=%p) at statepos %d\n", states[statepos].softmaskrecording, this->device, statepos);
     
 
     dbg("softmaskrecording is %p (dev=%p) at statepos %d\n", states[statepos].softmaskrecording, this->device, statepos);
     
index a1c7f01..bf411ca 100644 (file)
@@ -41,9 +41,9 @@ install:
        $(INSTALL_DATA) ./PreLoaderTemplate.swf $(pkgdatadir)/swfs/PreLoaderTemplate.swf
        $(INSTALL_DATA) ./tessel_loader.swf $(pkgdatadir)/swfs/tessel_loader.swf
        $(INSTALL_DATA) ./swft_loader.swf $(pkgdatadir)/swfs/swft_loader.swf
        $(INSTALL_DATA) ./PreLoaderTemplate.swf $(pkgdatadir)/swfs/PreLoaderTemplate.swf
        $(INSTALL_DATA) ./tessel_loader.swf $(pkgdatadir)/swfs/tessel_loader.swf
        $(INSTALL_DATA) ./swft_loader.swf $(pkgdatadir)/swfs/swft_loader.swf
-       test -f $(pkgdatadir)/swfs/default_viewer.swf || \
+       test -f $(pkgdatadir)/swfs/default_viewer.swf -o -L $(pkgdatadir)/swfs/default_viewer.swf || \
            $(LN_S) $(pkgdatadir)/swfs/simple_viewer.swf $(pkgdatadir)/swfs/default_viewer.swf;
            $(LN_S) $(pkgdatadir)/swfs/simple_viewer.swf $(pkgdatadir)/swfs/default_viewer.swf;
-       test -f $(pkgdatadir)/swfs/default_loader.swf || \
+       test -f $(pkgdatadir)/swfs/default_loader.swf -o -L $(pkgdatadir)/swfs/default_loader.swf || \
            $(LN_S) $(pkgdatadir)/swfs/tessel_loader.swf $(pkgdatadir)/swfs/default_loader.swf;
                
 uninstall:
            $(LN_S) $(pkgdatadir)/swfs/tessel_loader.swf $(pkgdatadir)/swfs/default_loader.swf;
                
 uninstall: