added alpha and font filter drafts
[swftools.git] / lib / gfxfilter.c
1 /* gfxfilter.c
2
3    Part of the swftools package.
4
5    Copyright (c) 2010 Matthias Kramm <kramm@quiss.org> 
6  
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.
11
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.
16
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 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include "mem.h"
25 #include "gfxfilter.h"
26 #include "devices/record.h"
27
28 typedef struct _internal {
29     gfxfilter_t*filter;
30     gfxdevice_t*out;
31     gfxdevice_t*final_out;
32
33     /* for two pass filters: */
34     int pass;
35     int num_passes;
36     gfxdevice_t record;
37     gfxtwopassfilter_t*twopass;
38 } internal_t;
39
40 static int filter_setparameter(gfxdevice_t*dev, const char*key, const char*value)
41 {
42     internal_t*i = (internal_t*)dev->internal;
43     return i->filter->setparameter(i->filter, key, value, i->out);
44 }
45 static void filter_startpage(gfxdevice_t*dev, int width, int height)
46 {
47     internal_t*i = (internal_t*)dev->internal;
48     i->filter->startpage(i->filter, width, height, i->out);
49 }
50 static void filter_startclip(gfxdevice_t*dev, gfxline_t*line)
51 {
52     internal_t*i = (internal_t*)dev->internal;
53     i->filter->startclip(i->filter, line, i->out);
54 }
55 static void filter_endclip(gfxdevice_t*dev)
56 {
57     internal_t*i = (internal_t*)dev->internal;
58     i->filter->endclip(i->filter, i->out);
59 }
60 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)
61 {
62     internal_t*i = (internal_t*)dev->internal;
63     i->filter->stroke(i->filter, line, width, color, cap_style, joint_style, miterLimit, i->out);
64 }
65 static void filter_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
66 {
67     internal_t*i = (internal_t*)dev->internal;
68     i->filter->fill(i->filter, line, color, i->out);
69 }
70 static void filter_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
71 {
72     internal_t*i = (internal_t*)dev->internal;
73     i->filter->fillbitmap(i->filter, line, img, matrix, cxform, i->out);
74 }
75 static void filter_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
76 {
77     internal_t*i = (internal_t*)dev->internal;
78     i->filter->fillgradient(i->filter, line, gradient, type, matrix, i->out);
79 }
80 static void filter_addfont(gfxdevice_t*dev, gfxfont_t*font)
81 {
82     internal_t*i = (internal_t*)dev->internal;
83     i->filter->addfont(i->filter, font, i->out);
84 }
85 static void filter_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
86 {
87     internal_t*i = (internal_t*)dev->internal;
88     i->filter->drawchar(i->filter, font, glyphnr, color, matrix, i->out);
89 }
90 static void filter_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
91 {
92     internal_t*i = (internal_t*)dev->internal;
93     i->filter->drawlink(i->filter, line, action, i->out);
94 }
95 static void filter_endpage(gfxdevice_t*dev)
96 {
97     internal_t*i = (internal_t*)dev->internal;
98     i->filter->endpage(i->filter, i->out);
99 }
100 static gfxresult_t* filter_finish(gfxdevice_t*dev)
101 {
102     internal_t*i = (internal_t*)dev->internal;
103     gfxresult_t*r = i->filter->finish(i->filter, i->out);
104     free(dev->internal);dev->internal=0;free(dev);
105     return r;
106 }
107
108
109 static int passthrough_setparameter(gfxdevice_t*dev, const char*key, const char*value)
110 {
111     internal_t*i = (internal_t*)dev->internal;
112     return i->out->setparameter(i->out, key, value);
113 }
114 static void passthrough_startpage(gfxdevice_t*dev, int width, int height)
115 {
116     internal_t*i = (internal_t*)dev->internal;
117     i->out->startpage(i->out, width, height);
118 }
119 static void passthrough_startclip(gfxdevice_t*dev, gfxline_t*line)
120 {
121     internal_t*i = (internal_t*)dev->internal;
122     i->out->startclip(i->out, line);
123 }
124 static void passthrough_endclip(gfxdevice_t*dev)
125 {
126     internal_t*i = (internal_t*)dev->internal;
127     i->out->endclip(i->out);
128 }
129 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)
130 {
131     internal_t*i = (internal_t*)dev->internal;
132     i->out->stroke(i->out, line, width, color, cap_style, joint_style, miterLimit);
133 }
134 static void passthrough_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
135 {
136     internal_t*i = (internal_t*)dev->internal;
137     i->out->fill(i->out, line, color);
138 }
139 static void passthrough_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
140 {
141     internal_t*i = (internal_t*)dev->internal;
142     i->out->fillbitmap(i->out, line, img, matrix, cxform);
143 }
144 static void passthrough_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
145 {
146     internal_t*i = (internal_t*)dev->internal;
147     i->out->fillgradient(i->out, line, gradient, type, matrix);
148 }
149 static void passthrough_addfont(gfxdevice_t*dev, gfxfont_t*font)
150 {
151     internal_t*i = (internal_t*)dev->internal;
152     i->out->addfont(i->out, font);
153 }
154 static void passthrough_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
155 {
156     internal_t*i = (internal_t*)dev->internal;
157     i->out->drawchar(i->out, font, glyphnr, color, matrix);
158 }
159 static void passthrough_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
160 {
161     internal_t*i = (internal_t*)dev->internal;
162     i->out->drawlink(i->out, line, action);
163 }
164 static void passthrough_endpage(gfxdevice_t*dev)
165 {
166     internal_t*i = (internal_t*)dev->internal;
167     i->out->endpage(i->out);
168 }
169 gfxresult_t* passthrough_finish(gfxdevice_t*dev)
170 {
171     internal_t*i = (internal_t*)dev->internal;
172     gfxdevice_t*out = i->out;
173     free(dev->internal);dev->internal=0;free(dev);
174     return out->finish(out);
175 }
176
177 int discard_setparameter(gfxdevice_t*dev, const char*key, const char*value)
178 {
179     return 0;
180 }
181 static void discard_startpage(gfxdevice_t*dev, int width, int height)
182 {
183 }
184 static void discard_startclip(gfxdevice_t*dev, gfxline_t*line)
185 {
186 }
187 static void discard_endclip(gfxdevice_t*dev)
188 {
189 }
190 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)
191 {
192 }
193 static void discard_fill(gfxdevice_t*dev, gfxline_t*line, gfxcolor_t*color)
194 {
195 }
196 static void discard_fillbitmap(gfxdevice_t*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
197 {
198 }
199 static void discard_fillgradient(gfxdevice_t*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
200 {
201 }
202 static void discard_addfont(gfxdevice_t*dev, gfxfont_t*font)
203 {
204 }
205 static void discard_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
206 {
207 }
208 static void discard_drawlink(gfxdevice_t*dev, gfxline_t*line, const char*action)
209 {
210 }
211 static void discard_endpage(gfxdevice_t*dev)
212 {
213 }
214 static gfxresult_t* discard_finish(gfxdevice_t*dev)
215 {
216     return 0;
217 }
218
219 gfxdevice_t*gfxfilter_apply(gfxfilter_t*filter, gfxdevice_t*out)
220 {
221     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
222     gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
223     
224     i->out = out;
225     i->filter = filter;
226     i->pass = 1;
227
228     dev->internal = i;
229     dev->name = filter->name?filter->name:"filter";
230     dev->setparameter = filter->setparameter?filter_setparameter:passthrough_setparameter;
231     dev->startpage = filter->startpage?filter_startpage:passthrough_startpage;
232     dev->startclip = filter->startclip?filter_startclip:passthrough_startclip;
233     dev->endclip = filter->endclip?filter_endclip:passthrough_endclip;
234     dev->stroke = filter->stroke?filter_stroke:passthrough_stroke;
235     dev->fill = filter->fill?filter_fill:passthrough_fill;
236     dev->fillbitmap = filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap;
237     dev->fillgradient = filter->fillgradient?filter_fillgradient:passthrough_fillgradient;
238     dev->addfont = filter->addfont?filter_addfont:passthrough_addfont;
239     dev->drawchar = filter->drawchar?filter_drawchar:passthrough_drawchar;
240     dev->drawlink = filter->drawlink?filter_drawlink:passthrough_drawlink;
241     dev->endpage = filter->endpage?filter_endpage:passthrough_endpage;
242     dev->finish = filter->finish?filter_finish:passthrough_finish;
243     return dev;
244 }
245
246 static void setup_twopass(gfxdevice_t*, gfxfilter_t*filter, char passthrough);
247
248 static gfxresult_t* twopass_finish(gfxdevice_t*dev)
249 {
250     internal_t*i = (internal_t*)dev->internal;
251   
252     assert(!strcmp(i->out->name, "record"));
253    
254     gfxresult_t*r;
255     if(i->filter->finish) {
256         r = i->filter->finish(i->filter, i->out);
257     } else {
258         r = i->out->finish(i->out);
259     }
260
261     if(i->pass == i->num_passes) {
262         /* this output device was not a record device, so we don't have
263            to do anything here (like cleanup) */
264         return r;
265     }
266
267     /* switch to next pass filter */
268     i->filter = &i->twopass->pass2;
269
270     if(i->pass == i->num_passes-1) {
271         /* we don't record in the final pass- we just stream out to the 
272            next output device */
273         i->out = i->final_out;
274     } else {
275         // this only happens for 3 passes or more
276         assert(i->num_passes>2);
277         gfxdevice_record_init(&i->record, /*use tempfile*/1);
278         i->out = &i->record;
279     }
280
281     i->pass++;
282     gfxresult_record_replay(r, i->out);
283     r = i->out->finish(i->out);
284
285     return r;
286 }
287
288 gfxdevice_t*gfxtwopassfilter_apply(gfxtwopassfilter_t*twopass, gfxdevice_t*out)
289 {
290     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
291     gfxdevice_t*dev = (gfxdevice_t*)rfx_calloc(sizeof(gfxdevice_t));
292    
293     gfxdevice_record_init(&i->record, /*use tempfile*/1);
294
295     i->out = &i->record;
296     i->final_out = out;
297     i->filter = &twopass->pass1;
298     i->twopass = twopass;
299     i->pass = 1;
300     i->num_passes = 2;
301         
302     dev->setparameter = i->filter->setparameter?filter_setparameter:passthrough_setparameter;
303     dev->startpage = i->filter->startpage?filter_startpage:passthrough_startpage;
304     dev->startclip = i->filter->startclip?filter_startclip:passthrough_startclip;
305     dev->endclip = i->filter->endclip?filter_endclip:passthrough_endclip;
306     dev->stroke = i->filter->stroke?filter_stroke:passthrough_stroke;
307     dev->fill = i->filter->fill?filter_fill:passthrough_fill;
308     dev->fillbitmap = i->filter->fillbitmap?filter_fillbitmap:passthrough_fillbitmap;
309     dev->fillgradient = i->filter->fillgradient?filter_fillgradient:passthrough_fillgradient;
310     dev->addfont = i->filter->addfont?filter_addfont:passthrough_addfont;
311     dev->drawchar = i->filter->drawchar?filter_drawchar:passthrough_drawchar;
312     dev->drawlink = i->filter->drawlink?filter_drawlink:passthrough_drawlink;
313     dev->endpage = i->filter->endpage?filter_endpage:passthrough_endpage;
314     dev->finish = twopass_finish;
315
316     dev->internal = i;
317     dev->name = i->filter->name?i->filter->name:"filter";
318     dev->finish = twopass_finish;
319     return dev;
320 }
321