3 Part of the swftools package.
5 Copyright (c) 2010 Matthias Kramm <kramm@quiss.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
26 #include "gfxfilter.h"
27 #include "devices/record.h"
30 typedef struct _internal {
34 /* for two pass filters: */
35 gfxdevice_t*final_out;
39 gfxtwopassfilter_t*twopass;
42 static int filter_setparameter(gfxdevice_t*dev, const char*key, const char*value)
44 internal_t*i = (internal_t*)dev->internal;
45 return i->filter->setparameter(i->filter, key, value, i->out);
47 static void filter_startpage(gfxdevice_t*dev, int width, int height)
49 internal_t*i = (internal_t*)dev->internal;
50 i->filter->startpage(i->filter, width, height, i->out);
52 static void filter_startclip(gfxdevice_t*dev, gfxline_t*line)
54 internal_t*i = (internal_t*)dev->internal;
55 i->filter->startclip(i->filter, line, i->out);
57 static void filter_endclip(gfxdevice_t*dev)
59 internal_t*i = (internal_t*)dev->internal;
60 i->filter->endclip(i->filter, i->out);
62 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)
64 internal_t*i = (internal_t*)dev->internal;
65 i->filter->stroke(i->filter, line, width, color, cap_style, joint_style, miterLimit, i->out);
67 static void filter_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
69 internal_t*i = (internal_t*)dev->internal;
70 i->filter->fill(i->filter, line, color, i->out);
72 static void filter_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
74 internal_t*i = (internal_t*)dev->internal;
75 i->filter->fillbitmap(i->filter, line, img, matrix, cxform, i->out);
77 static void filter_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
79 internal_t*i = (internal_t*)dev->internal;
80 i->filter->fillgradient(i->filter, line, gradient, type, matrix, i->out);
82 static void filter_addfont(gfxdevice_t*dev, gfxfont_t*font)
84 internal_t*i = (internal_t*)dev->internal;
85 i->filter->addfont(i->filter, font, i->out);
87 static void filter_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
89 internal_t*i = (internal_t*)dev->internal;
90 i->filter->drawchar(i->filter, font, glyphnr, color, matrix, i->out);
92 static void filter_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
94 internal_t*i = (internal_t*)dev->internal;
95 i->filter->drawlink(i->filter, line, action, i->out);
97 static void filter_endpage(gfxdevice_t*dev)
99 internal_t*i = (internal_t*)dev->internal;
100 i->filter->endpage(i->filter, i->out);
102 static gfxresult_t* filter_finish(gfxdevice_t*dev)
104 internal_t*i = (internal_t*)dev->internal;
106 if(i->filter->finish) {
107 r = i->filter->finish(i->filter, i->out);
109 r = i->out->finish(i->out);
111 if(i->filter->internal) {
112 free(i->filter->internal);
113 i->filter->internal = 0;
115 free(i->filter);i->filter=0;
116 free(dev->internal);dev->internal=0;free(dev);
121 static int passthrough_setparameter(gfxdevice_t*dev, const char*key, const char*value)
123 internal_t*i = (internal_t*)dev->internal;
124 return i->out->setparameter(i->out, key, value);
126 static void passthrough_startpage(gfxdevice_t*dev, int width, int height)
128 internal_t*i = (internal_t*)dev->internal;
129 i->out->startpage(i->out, width, height);
131 static void passthrough_startclip(gfxdevice_t*dev, gfxline_t*line)
133 internal_t*i = (internal_t*)dev->internal;
134 i->out->startclip(i->out, line);
136 static void passthrough_endclip(gfxdevice_t*dev)
138 internal_t*i = (internal_t*)dev->internal;
139 i->out->endclip(i->out);
141 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)
143 internal_t*i = (internal_t*)dev->internal;
144 i->out->stroke(i->out, line, width, color, cap_style, joint_style, miterLimit);
146 static void passthrough_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
148 internal_t*i = (internal_t*)dev->internal;
149 i->out->fill(i->out, line, color);
151 static void passthrough_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
153 internal_t*i = (internal_t*)dev->internal;
154 i->out->fillbitmap(i->out, line, img, matrix, cxform);
156 static void passthrough_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
158 internal_t*i = (internal_t*)dev->internal;
159 i->out->fillgradient(i->out, line, gradient, type, matrix);
161 static void passthrough_addfont(gfxdevice_t*dev, gfxfont_t*font)
163 internal_t*i = (internal_t*)dev->internal;
164 i->out->addfont(i->out, font);
166 static void passthrough_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
168 internal_t*i = (internal_t*)dev->internal;
169 i->out->drawchar(i->out, font, glyphnr, color, matrix);
171 static void passthrough_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
173 internal_t*i = (internal_t*)dev->internal;
174 i->out->drawlink(i->out, line, action);
176 static void passthrough_endpage(gfxdevice_t*dev)
178 internal_t*i = (internal_t*)dev->internal;
179 i->out->endpage(i->out);
182 int discard_setparameter(gfxdevice_t*dev, const char*key, const char*value)
186 static void discard_startpage(gfxdevice_t*dev, int width, int height)
189 static void discard_startclip(gfxdevice_t*dev, gfxline_t*line)
192 static void discard_endclip(gfxdevice_t*dev)
195 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)
198 static void discard_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
201 static void discard_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
204 static void discard_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
207 static void discard_addfont(gfxdevice_t*dev, gfxfont_t*font)
210 static void discard_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
213 static void discard_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
216 static void discard_endpage(gfxdevice_t*dev)
219 static gfxresult_t* discard_finish(gfxdevice_t*dev)
224 gfxdevice_t*gfxfilter_apply(gfxfilter_t*_filter, gfxdevice_t*out)
226 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
227 gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
228 gfxfilter_t*filter = (gfxfilter_t*)rfx_alloc(sizeof(gfxfilter_t));
229 memcpy(filter, _filter, sizeof(gfxfilter_t));
236 dev->name = filter->name?filter->name:"filter";
237 dev->setparameter = filter->setparameter?filter_setparameter:passthrough_setparameter;
238 dev->startpage = filter->startpage?filter_startpage:passthrough_startpage;
239 dev->startclip = filter->startclip?filter_startclip:passthrough_startclip;
240 dev->endclip = filter->endclip?filter_endclip:passthrough_endclip;
241 dev->stroke = filter->stroke?filter_stroke:passthrough_stroke;
242 dev->fill = filter->fill?filter_fill:passthrough_fill;
243 dev->fillbitmap = filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap;
244 dev->fillgradient = filter->fillgradient?filter_fillgradient:passthrough_fillgradient;
245 dev->addfont = filter->addfont?filter_addfont:passthrough_addfont;
246 dev->drawchar = filter->drawchar?filter_drawchar:passthrough_drawchar;
247 dev->drawlink = filter->drawlink?filter_drawlink:passthrough_drawlink;
248 dev->endpage = filter->endpage?filter_endpage:passthrough_endpage;
249 dev->finish = filter_finish;
253 static void setup_twopass(gfxdevice_t*dev, gfxfilter_t*filter)
255 dev->name = filter->name?filter->name:"filter";
256 dev->setparameter = filter->setparameter?filter_setparameter:passthrough_setparameter;
257 dev->startpage = filter->startpage?filter_startpage:passthrough_startpage;
258 dev->startclip = filter->startclip?filter_startclip:passthrough_startclip;
259 dev->endclip = filter->endclip?filter_endclip:passthrough_endclip;
260 dev->stroke = filter->stroke?filter_stroke:passthrough_stroke;
261 dev->fill = filter->fill?filter_fill:passthrough_fill;
262 dev->fillbitmap = filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap;
263 dev->fillgradient = filter->fillgradient?filter_fillgradient:passthrough_fillgradient;
264 dev->addfont = filter->addfont?filter_addfont:passthrough_addfont;
265 dev->drawchar = filter->drawchar?filter_drawchar:passthrough_drawchar;
266 dev->drawlink = filter->drawlink?filter_drawlink:passthrough_drawlink;
267 dev->endpage = filter->endpage?filter_endpage:passthrough_endpage;
270 static gfxresult_t* twopass_finish(gfxdevice_t*dev)
272 internal_t*i = (internal_t*)dev->internal;
275 if(i->filter->finish) {
276 r = i->filter->finish(i->filter, i->out);
278 r = i->out->finish(i->out);
281 if(i->pass == i->num_passes) {
291 /* switch to next pass filter */
292 i->filter = &i->twopass->pass2;
293 setup_twopass(dev, i->filter);
294 dev->finish = twopass_finish;
296 if(i->pass == i->num_passes-1) {
297 /* we don't record in the final pass- we just stream out to the
298 next output device */
299 i->out = i->final_out;
301 // switch to a new tempfile- this only happens for 3 passes or more
302 assert(i->num_passes>2);
303 gfxdevice_record_init(&i->record, /*use tempfile*/1);
308 gfxresult_record_replay(r, dev, 0);
311 return twopass_finish(dev);
314 gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*_twopass, gfxdevice_t*out)
316 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
317 gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
319 gfxtwopassfilter_t*twopass = (gfxtwopassfilter_t*)rfx_alloc(sizeof(gfxtwopassfilter_t));
320 memcpy(twopass, _twopass, sizeof(gfxtwopassfilter_t));
322 gfxdevice_record_init(&i->record, /*use tempfile*/1);
326 i->twopass = twopass;
332 i->filter = &twopass->pass1;
333 setup_twopass(dev, i->filter);
334 dev->finish = twopass_finish;
339 gfxfilterchain_t* gfxfilterchain_parse(const char*_filterexpr)
341 char*filterexpr = strdup(_filterexpr);
343 char*end = filterexpr+strlen(filterexpr);
344 dict_t* params = dict_new2(&charptr_type);
347 gfxfilterchain_t*chain = 0;
348 gfxfilterchain_t*next = 0;
354 char* eq = strchr(f, '=');
355 char* colon = strchr(f, ':');
365 /* fixme: change this from a dict_t to gfxparams_t? */
366 if(eq && eq < colon) { // parameter
369 fprintf(stderr, "Error: need a filter before specifying parameters (%s=%s)\n", f, eq+1);
372 dict_put(params, f, strdup(eq+1));
377 if(!param || lastitem) {
381 gfxfilterbase_t*f = 0;
382 if(!strcmp(cmd, "maketransparent")) {
383 char*alphastr = dict_lookup(params, "alpha");
385 if(alphastr) alpha=atoi(alphastr);
386 f = malloc(sizeof(gfxfilter_t));
387 gfxfilter_maketransparent_init((gfxfilter_t*)f, alpha);
388 } else if(!strcmp(cmd, "remove_font_transforms")) {
389 f = malloc(sizeof(gfxtwopassfilter_t));
390 gfxtwopassfilter_remove_font_transforms_init((gfxtwopassfilter_t*)f);
391 } else if(!strcmp(cmd, "vectors_to_glyphs")) {
392 f = malloc(sizeof(gfxtwopassfilter_t));
393 gfxtwopassfilter_vectors_to_glyphs_init((gfxtwopassfilter_t*)f);
394 } else if(!strcmp(cmd, "one_big_font")) {
395 f = malloc(sizeof(gfxtwopassfilter_t));
396 gfxtwopassfilter_one_big_font_init((gfxtwopassfilter_t*)f);
398 fprintf(stderr, "Unknown filter: %s\n", cmd);
402 gfxfilterchain_t*n = rfx_calloc(sizeof(gfxfilterchain_t));
416 dict_destroy(params);
420 gfxdevice_t* gfxfilterchain_apply(gfxfilterchain_t*chain, gfxdevice_t*dev)
423 if(chain->filter->type == gfxfilter_onepass) {
424 dev = gfxfilter_apply((gfxfilter_t*)chain->filter, dev);
425 } else if(chain->filter->type == gfxfilter_twopass) {
426 dev = gfxtwopassfilter_apply((gfxtwopassfilter_t*)chain->filter, dev);
428 fprintf(stderr, "Internal error in gfxfilterchain_apply- unknown filter type %d\n", chain->filter->type);
435 void gfxfilterchain_destroy(gfxfilterchain_t*chain)
438 gfxfilterchain_t*next = chain->next;