1 #include <cstdlib>
2 #include <cstdio>
3 
4 #include "config.h"
5 #include "filter.h"
6 /*#define DEBUG */
create_queue(struct filter * f)7 struct queue *create_queue(struct filter *f)
8 {
9     struct queue *q = (struct queue *)calloc(1, sizeof(struct queue));
10     q->first = q->last = f;
11     f->queue = q;
12     f->next = f->previous = NULL;
13     return (q);
14 }
15 
insertfilter(struct filter * f1,struct filter * f2)16 void insertfilter(struct filter *f1, struct filter *f2)
17 {
18     f1->next = f2;
19     f1->queue = f2->queue;
20     f1->queue->isinitialized = 0;
21     f1->previous = f2->previous;
22     if (f2->previous != NULL)
23         f2->previous->next = f1;
24     else
25         f2->queue->first = f1;
26     f2->previous = f1;
27 }
28 
addfilter(struct filter * f1,struct filter * f2)29 void addfilter(struct filter *f1, struct filter *f2)
30 {
31     f1->previous = f2;
32     f1->queue = f2->queue;
33     f1->queue->isinitialized = 0;
34     f1->next = f2->next;
35     if (f2->next != NULL)
36         f2->next->previous = f1;
37     else
38         f2->queue->last = f1;
39     f2->next = f1;
40 }
41 
removefilter(struct filter * f)42 void removefilter(struct filter *f)
43 {
44     if (f->action->removefilter != NULL)
45         f->action->removefilter(f);
46     if (f->previous != NULL)
47         f->previous->next = f->next;
48     else
49         f->queue->first = f->next;
50     if (f->next != NULL)
51         f->next->previous = f->previous;
52     else
53         f->queue->last = f->previous;
54     f->queue->isinitialized = 0;
55 }
56 
initqueue(struct queue * q)57 int initqueue(struct queue *q)
58 {
59     struct requirements noreq = {0, ALLMASK, 0};
60     struct initdata init = {NULL, NULL, NULL, 0};
61 #ifdef DEBUG
62     printf("\n\nInitializing queue\n");
63 #endif
64     q->palettechg = NULL;
65     if (!q->first->action->requirement(q->first, &noreq))
66         return 0;
67     if (!q->last->action->initialize(q->last, &init))
68         return 0;
69     q->isinitialized = 1;
70 #ifdef DEBUG
71     printf("Correctly initialized\n");
72 #endif
73     return 1;
74 }
75 
reqimage(struct filter * f,struct requirements * req,int supportedmask,int flags)76 int reqimage(struct filter *f, struct requirements *req, int supportedmask,
77              int flags)
78 {
79     f->req = *req;
80     req->supportedmask &= supportedmask;
81     if (!req->supportedmask)
82         return 0;
83     if (flags & TOUCHIMAGE && req->flags & IMAGEDATA) {
84         req->flags = flags;
85     } else
86         req->flags &= flags;
87     return 1;
88 }
89 
90 /* An function helping to filter create new image.
91  * It should be called by filter in initialization. Filter passes
92  * width, height, pixelwidth, pixelheight
93  * and palette it wants to pass to its child and flags defining how it works
94  * with the image (IMAGEDATA if it requires data from previous frames (like blur
95  * filter, TOUCHIMAGE if it changes data in image (like blur or stereogram
96  * filter but unlike interlace and NEWIMAGE if it strictly requires to create
97  * new image)
98  *
99  * As palette it should pass NULL to keep parents palette. Same as
100  * (pixel)width/height should be passed 0;
101  *
102  * Function then applies some heruistic in order to minimize memory
103  * requirements. So it should share image, create image that shares image data
104  * or create new image)
105  *
106  * fills f->image, f->childimage and returns 1 if success and 0 if fail(usually
107  * out of memory or it is unable to fit child's requirements)
108  * and prepares data for child call.
109  */
inherimage(struct filter * f,struct initdata * data,int flags,int width,int height,struct palette * palette,float pixelwidth,float pixelheight)110 int inherimage(struct filter *f, struct initdata *data, int flags, int width,
111                int height, struct palette *palette, float pixelwidth,
112                float pixelheight)
113 {
114     int newimage = 0;
115     int subimage = 1;
116     int sharedimage = 1;
117     struct image *i;
118 
119     int ddatalost = 0;
120     if (width == 0)
121         width = data->image->width;
122     if (height == 0)
123         height = data->image->height;
124 #ifdef DEBUG
125     printf("Inherimage:%s %i %i imagedata:%i %i\n", f->name, width, height,
126            flags & IMAGEDATA, flags & PROTECTBUFFERS);
127 #endif
128     if (pixelwidth == 0)
129         pixelwidth = data->image->pixelwidth;
130     if (pixelheight == 0)
131         pixelheight = data->image->pixelheight;
132     if (palette == NULL)
133         palette = data->image->palette;
134     if (!(palette->type & f->req.supportedmask)) {
135 #ifdef DEBUG
136         printf(
137             "Initialization of filter %s failed due to unsupported type by child %s-%i,%i\n",
138             f->name, f->previous->name, f->req.supportedmask, palette->type);
139 #endif
140         f->image = data->image;
141         return 0;
142     }
143 
144     if (flags & NEWIMAGE)
145         newimage = 1, sharedimage = 0, subimage = 0;
146     if ((flags & IMAGEDATA) /*|| (data->image->flags & PROTECTBUFFERS) */)
147         subimage = 0, sharedimage = 0, newimage = 1;
148     /*if filter touches data but child requires them, create separated image */
149     if ((flags & TOUCHIMAGE) &&
150         ((f->req.flags & IMAGEDATA) || (data->image->flags & PROTECTBUFFERS)))
151         subimage = 0, newimage = 1, sharedimage = 0;
152     /*if required image differs in size or so */
153     if (width != data->image->width || height != data->image->height ||
154         palette != data->image->palette)
155         newimage = 1, sharedimage = 0;
156 
157     if (f->childimage != NULL && (f->flags & ALLOCEDIMAGE)) {
158         /*is an old child image still usable for us purposes? if not burn it
159          * it! */
160         /*We should share image? Why alloc new?? */
161         if (!newimage && (f->flags & ALLOCEDIMAGE))
162             destroyinheredimage(f), ddatalost = 1;
163         /*We should share data? but child image don't do that! */
164         if (subimage && !(f->flags & SHAREDDATA))
165             destroyinheredimage(f), ddatalost = 1;
166         /*We can't share data but child image does that? */
167         if (!subimage && (f->flags & SHAREDDATA))
168             destroyinheredimage(f), ddatalost = 1;
169         /*When image changed, child image must be recreated too */
170         if (f->flags & SHAREDDATA && ((data->flags & DATALOST) ||
171                                       f->imageversion != data->image->version))
172             destroyinheredimage(f), ddatalost = 1;
173         /*We should share image with filter? Why keep created new one? */
174         if (sharedimage)
175             destroyinheredimage(f), ddatalost = 1;
176         /*When child image don't fit out needs */
177         if (f->childimage != NULL &&
178             (f->childimage->width != width || f->childimage->height != height ||
179              f->childimage->palette != palette ||
180              f->childimage->bytesperpixel != bytesperpixel(palette->type) ||
181              f->childimage->nimages < f->req.nimages))
182             destroyinheredimage(f), ddatalost = 1;
183         /*Well now child image seems to be heavily probed */
184     }
185     i = f->childimage;
186     if (newimage) { /*Create new image when required */
187         if (!(f->flags & ALLOCEDIMAGE)) {
188             if (subimage) {
189                 i = create_subimage(data->image, width, height, f->req.nimages,
190                                     palette, pixelwidth, pixelheight);
191                 f->flags |= ALLOCEDIMAGE | SHAREDDATA;
192                 ddatalost = 1;
193             } else {
194                 i = create_image_mem(width, height, f->req.nimages, palette,
195                                      pixelwidth, pixelheight);
196                 f->flags |= ALLOCEDIMAGE;
197                 ddatalost = 1;
198             }
199             // Fix crash when saving png because inherited images
200             // didn't inherit the data field (which now contains a pointer to
201             // the QImage used to save the png.
202             i->data = data->image->data;
203         }
204     }
205 #ifdef DEBUG
206     printf("Filter:%s newimage:%i subimage:%i sharedimage:%i\n", f->name,
207            newimage, subimage, sharedimage);
208 #endif
209     if (i == NULL) {
210         f->image = data->image;
211         return 0;
212     }
213     if (sharedimage)
214         i = data->image,
215         ddatalost = (data->flags & DATALOST) || (f->childimage != data->image);
216     if (sharedimage && datalost(f, data))
217         ddatalost = 1;
218     else if ((f->flags & SHAREDDATA) && datalost(f, data) &&
219              !(i->flags & FREEDATA))
220         ddatalost = 1;
221     if (ddatalost)
222         data->flags |= DATALOST;
223     else
224         data->flags &= ~DATALOST;
225     f->image = data->image;
226     f->childimage = i;
227     f->imageversion = data->image->version;
228     data->image = i;
229 #ifdef DEBUG
230     printf("OK %i datalost:%i\n", f->flags, ddatalost);
231 #endif
232 #ifdef DEBUG
233     printf("Inherimage2:%s %i %i\n", f->name, width, height);
234 #endif
235     return 1;
236 }
237 
destroyinheredimage(struct filter * f)238 void destroyinheredimage(struct filter *f)
239 {
240     if (f->flags & ALLOCEDIMAGE)
241         destroy_image(f->childimage), f->flags &= ~(ALLOCEDIMAGE | SHAREDDATA),
242             f->childimage = NULL;
243 }
244 
updateinheredimage(struct filter * f)245 void updateinheredimage(struct filter *f)
246 {
247     if ((f->flags & SHAREDDATA) && f->childimage) {
248         if (f->childimage->nimages == 2 &&
249             f->image->currimage != f->childimage->currimage)
250             f->childimage->flip(f->childimage); /*Hack for interlace filter */
251     }
252 }
253 
inhermisc(struct filter * f,const struct initdata * data)254 void inhermisc(struct filter *f, const struct initdata *data)
255 {
256     f->wait_function = data->wait_function;
257     f->fractalc = data->fractalc;
258 }
259 
createfilter(const struct filteraction * fa)260 struct filter *createfilter(const struct filteraction *fa)
261 {
262     struct filter *f = (struct filter *)calloc(1, sizeof(struct filter));
263     if (f == NULL)
264         return NULL;
265     f->queue = NULL;
266     f->next = NULL;
267     f->childimage = NULL;
268     f->flags = 0;
269     f->previous = NULL;
270     f->action = fa;
271     f->image = NULL;
272     f->req.nimages = 1;
273     f->data = NULL;
274     return (f);
275 }
276 
convertupgeneric(struct filter * f,int * x,int * y)277 void convertupgeneric(struct filter *f, int *x, int *y)
278 {
279     if (f->next != NULL)
280         f->next->action->convertup(f->next, x, y);
281 }
282 
convertdowngeneric(struct filter * f,int * x,int * y)283 void convertdowngeneric(struct filter *f, int *x, int *y)
284 {
285     if (f->previous != NULL)
286         f->previous->action->convertdown(f->previous, x, y);
287 }
288