Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "mem.h"
#include "gfxfilter.h"
#include "devices/record.h"
+#include "q.h"
typedef struct _internal {
gfxfilter_t*filter;
gfxdevice_t*out;
- gfxdevice_t*final_out;
/* for two pass filters: */
+ gfxdevice_t*final_out;
int pass;
int num_passes;
gfxdevice_t record;
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);
+ gfxresult_t*r;
+ if(i->filter->finish) {
+ r = i->filter->finish(i->filter, i->out);
+ } else {
+ r = i->out->finish(i->out);
+ }
+ if(i->filter->internal) {
+ free(i->filter->internal);
+ i->filter->internal = 0;
+ }
+ free(i->filter);i->filter=0;
free(dev->internal);dev->internal=0;free(dev);
return r;
}
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;
}
-gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*out)
+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));
+ gfxfilter_t*filter = (gfxfilter_t*)rfx_alloc(sizeof(gfxfilter_t));
+ memcpy(filter, _filter, sizeof(gfxfilter_t));
i->out = out;
i->filter = filter;
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;
+ dev->finish = filter_finish;
return dev;
}
-static void setup_twopass(gfxdevice_t*, gfxfilter_t*filter, char passthrough);
+static void setup_twopass(gfxdevice_t*dev, gfxfilter_t*filter)
+{
+ 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;
+}
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);
}
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) */
+ free(i->twopass);
+ i->twopass = 0;
+ i->filter = 0;
+ free(i);
+ dev->internal=0;
+ free(dev);
return r;
}
/* switch to next pass filter */
i->filter = &i->twopass->pass2;
+ setup_twopass(dev, i->filter);
+ dev->finish = twopass_finish;
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
+ // switch to a new tempfile- 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);
+ gfxresult_record_replay(r, dev);
+ r->destroy(r);
- return r;
+ return twopass_finish(dev);
}
-gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*twopass, gfxdevice_t*out)
+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));
+
+ gfxtwopassfilter_t*twopass = (gfxtwopassfilter_t*)rfx_alloc(sizeof(gfxtwopassfilter_t));
+ memcpy(twopass, _twopass, sizeof(gfxtwopassfilter_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";
+
+ i->filter = &twopass->pass1;
+ setup_twopass(dev, i->filter);
dev->finish = twopass_finish;
+
+ return dev;
+}
+
+gfxfilterchain_t* gfxfilterchain_parse(const char*_filterexpr)
+{
+ char*filterexpr = strdup(_filterexpr);
+ char*f = filterexpr;
+ char*end = filterexpr+strlen(filterexpr);
+ dict_t* params = dict_new2(&charptr_type);
+ char*cmd = 0;
+
+ gfxfilterchain_t*chain = 0;
+ gfxfilterchain_t*next = 0;
+
+ if(!*f)
+ return 0;
+
+ while(1) {
+ char* eq = strchr(f, '=');
+ char* colon = strchr(f, ':');
+ char lastitem = 0;
+ if(!colon) {
+ colon = end;
+ lastitem = 1;
+ }
+ *colon = 0;
+ char*newcmd = 0;
+ char param = 0;
+
+ /* fixme: change this from a dict_t to gfxparams_t? */
+ if(eq && eq < colon) { // parameter
+ *eq = 0;
+ if(!cmd) {
+ fprintf(stderr, "Error: need a filter before specifying parameters (%s=%s)\n", f, eq+1);
+ return 0;
+ }
+ dict_put(params, f, strdup(eq+1));
+ param = 1;
+ } else {
+ newcmd = f;
+ }
+ if(!param || lastitem) {
+ if(!cmd && lastitem)
+ cmd = newcmd;
+ gfxfilterbase_t*f = 0;
+ if(!strcmp(cmd, "maketransparent")) {
+ char*alphastr = dict_lookup(params, "alpha");
+ int alpha = 255;
+ if(alphastr) alpha=atoi(alphastr);
+ f = malloc(sizeof(gfxfilter_t));
+ gfxfilter_maketransparent_init((gfxfilter_t*)f, alpha);
+ } else if(!strcmp(cmd, "remove_font_transforms")) {
+ f = malloc(sizeof(gfxtwopassfilter_t));
+ gfxtwopassfilter_remove_font_transforms_init((gfxtwopassfilter_t*)f);
+ } else if(!strcmp(cmd, "one_big_font")) {
+ f = malloc(sizeof(gfxtwopassfilter_t));
+ gfxtwopassfilter_one_big_font_init((gfxtwopassfilter_t*)f);
+ } else {
+ fprintf(stderr, "Unknown filter: %s\n", cmd);
+ return 0;
+ }
+ dict_clear(params);
+ gfxfilterchain_t*n = rfx_calloc(sizeof(gfxfilterchain_t));
+ if(!chain) {
+ chain = next = n;
+ } else {
+ next->next = n;
+ next = n;
+ }
+ n->filter = f;
+
+ cmd = newcmd;
+ if(lastitem) break;
+ }
+ f = colon+1;
+ }
+ dict_destroy(params);
+ return chain;
+}
+
+gfxdevice_t* gfxfilterchain_apply(gfxfilterchain_t*chain, gfxdevice_t*dev)
+{
+ while(chain) {
+ if(chain->filter->type == gfxfilter_onepass) {
+ dev = gfxfilter_apply((gfxfilter_t*)chain->filter, dev);
+ } else if(chain->filter->type == gfxfilter_twopass) {
+ dev = gfxtwopassfilter_apply((gfxtwopassfilter_t*)chain->filter, dev);
+ } else {
+ fprintf(stderr, "Internal error in gfxfilterchain_apply- unknown filter type %d\n", chain->filter->type);
+ }
+ chain = chain->next;
+ }
return dev;
}
+void gfxfilterchain_destroy(gfxfilterchain_t*chain)
+{
+ while(chain) {
+ gfxfilterchain_t*next = chain->next;
+ free(chain);
+ chain = next;
+ }
+}