1 #include <cstdlib>
2 #include <cstring>
3 #include <cassert>
4 
5 #include "config.h"
6 #include "filter.h"
7 #include "ui_helper.h"
8 #include "grlib.h"
9 
10 /* The "windows" implemented here are just regions of the image, not user
11  * interface windows.  They are used to save the pixels that are going to
12  * be drawn over (e.g., with a text message) so they can be restored when the
13  * overlay should disappear. Windows are redrawn every frame and removed before
14  * calculation.
15  */
16 
uih_registerw(struct uih_context * uih,uih_getposfunc getpos,uih_drawfunc draw,void * data,int flags)17 struct uih_window *uih_registerw(struct uih_context *uih, uih_getposfunc getpos,
18                                  uih_drawfunc draw, void *data, int flags)
19 {
20     struct uih_window *w =
21         (struct uih_window *)calloc(1, sizeof(struct uih_window));
22     struct uih_window *w1;
23     assert(uih != NULL && getpos != NULL && draw != NULL && flags >= 0);
24     if (w == NULL)
25         return NULL;
26     uih_clearwindows(uih);
27     w1 = uih->wtop;
28     w->getpos = getpos;
29     w->draw = draw;
30     w->data = data;
31     w->flags = flags;
32     w->savedline = -1;
33     w->saveddata = NULL;
34     w->next = NULL;
35     if (w1 == NULL) {
36         uih->wtop = w;
37     } else {
38         while (w1->next != NULL)
39             w1 = w1->next;
40         w1->next = w;
41     }
42     w->previous = w1;
43     w->x = -65536;
44     return w;
45 }
46 
uih_setline(struct uih_context * uih,struct uih_window * w,int color,int x1,int y1,int x2,int y2)47 void uih_setline(struct uih_context *uih, struct uih_window *w, int color,
48                  int x1, int y1, int x2, int y2)
49 {
50     if (w->savedline != color || w->x != x1 || w->y != y1 ||
51         w->width != x2 - x1 || w->height != y2 - y1) {
52         uih_clearwindows(uih);
53         uih->display = 1;
54         w->savedline = color;
55         w->x = x1;
56         w->y = y1;
57         w->width = x2 - x1;
58         w->height = y2 - y1;
59     }
60 }
61 
uih_registerline(struct uih_context * uih,int color,int x1,int y1,int x2,int y2)62 struct uih_window *uih_registerline(struct uih_context *uih, int color, int x1,
63                                     int y1, int x2, int y2)
64 {
65     struct uih_window *w =
66         (struct uih_window *)calloc(1, sizeof(struct uih_window));
67     struct uih_window *w1;
68     if (w == NULL)
69         return NULL;
70     uih_clearwindows(uih);
71     w1 = uih->wtop;
72     uih->display = 1;
73     w->getpos = NULL;
74     w->savedline = color;
75     w->flags = 0;
76     w->x = x1;
77     w->y = y1;
78     w->width = x2 - x1;
79     w->height = y2 - y1;
80     w->saveddata = NULL;
81     w->next = NULL;
82     if (w1 == NULL) {
83         uih->wtop = w;
84     } else {
85         while (w1->next != NULL)
86             w1 = w1->next;
87         w1->next = w;
88     }
89     w->previous = w1;
90     return w;
91 }
92 
uih_removew(struct uih_context * uih,struct uih_window * w)93 void uih_removew(struct uih_context *uih, struct uih_window *w)
94 {
95     uih_clearwindows(uih);
96     assert(uih->wtop != NULL);
97     assert(w != NULL);
98     uih->display = 1;
99 
100     if (w->previous == NULL) {
101         assert(uih->wtop == w);
102         uih->wtop = w->next;
103     } else {
104         w->previous->next = w->next;
105     }
106     if (w->next != NULL) {
107         w->next->previous = w->previous;
108     }
109     free(w);
110 }
111 
112 /*Remove all drawn windows from screen */
uih_clearwindows(struct uih_context * uih)113 void uih_clearwindows(struct uih_context *uih)
114 {
115     struct uih_window *w = uih->wtop;
116     int savedline = 0;
117     int savedpos = 0;
118     int destwidth = uih->image->width * uih->image->bytesperpixel;
119     if (!uih->wdisplayed)
120         return;
121     if (!uih->image->bytesperpixel) {
122         destwidth = (w->x + uih->image->width + 7) / 8;
123     }
124     uih->wdisplayed = 0;
125     if (uih->wflipped)
126         uih->image->flip(uih->image), uih->wflipped = 0;
127     while (w) {
128         if (w->getpos == NULL) {
129             if (w->saveddata != NULL) {
130                 xrestoreline(uih->image, w->saveddata, w->x, w->y,
131                              w->width + w->x, w->height + w->y);
132                 free(w->saveddata);
133                 w->saveddata = NULL;
134             }
135         } else {
136             if (w->savedline != -1 || w->saveddata != NULL) {
137                 int i;
138                 int xskip = w->x * uih->image->bytesperpixel;
139                 int width = w->width * uih->image->bytesperpixel;
140                 if (!uih->image->bytesperpixel) {
141                     xskip = w->x / 8;
142                     width = (w->x + w->width + 7) / 8 - xskip;
143                 }
144                 assert(w->width);
145                 assert(w->height);
146                 assert(w->x >= 0);
147                 assert(w->y >= 0);
148                 assert(w->x + w->width <= uih->image->width);
149                 assert(w->y + w->height <= uih->image->height);
150                 if (w->savedline != -1) {
151                     savedline = w->savedline;
152                     savedpos = w->savedpos;
153                     for (i = w->y; i < w->y + w->height; i++) {
154                         unsigned char *data = uih->image->currlines[i] + xskip;
155                         assert(savedline < uih->image->height);
156                         assert(savedline >= 0);
157                         assert(savedpos >= 0 && savedpos <= destwidth);
158                         if (width + savedpos > destwidth) {
159                             int width1;
160                             memcpy(data,
161                                    uih->image->oldlines[savedline] + savedpos,
162                                    destwidth - savedpos);
163                             savedline++;
164                             width1 = width - destwidth + savedpos;
165                             memcpy(data + (destwidth - savedpos),
166                                    uih->image->oldlines[savedline], width1);
167                             savedpos = width1;
168                         } else
169                             memcpy(data,
170                                    uih->image->oldlines[savedline] + savedpos,
171                                    width),
172                                 savedpos += width;
173                     }
174                     w->savedline = -1;
175                 } else {
176                     assert(w->saveddata);
177                     for (i = w->y; i < w->y + w->height; i++) {
178                         unsigned char *data = uih->image->currlines[i] + xskip;
179                         memcpy(data, w->saveddata + (i - w->y) * width, width);
180                     }
181                     free(w->saveddata);
182                     w->saveddata = NULL;
183                 }
184             }
185         }
186         w = w->next;
187     }
188 }
189 
uih_drawwindows(struct uih_context * uih)190 void uih_drawwindows(struct uih_context *uih)
191 {
192     struct uih_window *w = uih->wtop;
193     struct image *img = uih->image;
194     int size = 0;
195     int nocopy = 0;
196     int savedline = 0;
197     int savedpos = 0;
198     int destwidth = uih->image->width * uih->image->bytesperpixel;
199     if (!uih->image->bytesperpixel) {
200         destwidth = (w->x + uih->image->width + 7) / 8;
201     }
202     if (uih->wdisplayed)
203         return;
204     uih->wdisplayed = 1;
205     while (w) {
206         if (w->getpos != NULL) {
207             w->getpos(uih, &w->x, &w->y, &w->width, &w->height, w->data);
208             if (w->x < 0)
209                 w->width -= w->x, w->x = 0;
210             if (w->y < 0)
211                 w->height -= w->y, w->y = 0;
212             if (w->x > img->width)
213                 w->width = 0, w->height = 0, w->x = 0;
214             if (w->y > img->height)
215                 w->width = 0, w->height = 0, w->y = 0;
216             if (w->x + w->width > img->width)
217                 w->width = img->width - w->x;
218             if (w->y + w->height > img->height)
219                 w->height = img->height - w->y;
220             if (w->width < 0)
221                 w->width = 0;
222             if (w->height < 0)
223                 w->height = 0;
224             size += w->width * w->height;
225             if (w->x == 0 && w->y == 0 && w->width == img->width &&
226                 w->height == img->height)
227                 nocopy = 1;
228             assert(w->width >= 0);
229             assert(w->height >= 0);
230             assert(w->x >= 0);
231             assert(w->y >= 0);
232             assert(w->x + w->width <= uih->image->width);
233             assert(w->y + w->height <= uih->image->height);
234         }
235         w = w->next;
236     }
237     if (size > img->width * img->height / 2) {
238         int i;
239         int width = img->width * img->bytesperpixel;
240         if (!width)
241             width = (img->width + 7) / 8;
242         uih->wflipped = 1;
243         if (!nocopy)
244             for (i = 0; i < img->height; i++)
245                 memcpy(img->oldlines[i], img->currlines[i], width);
246         uih->image->flip(uih->image);
247     } else {
248         int savedminx = -1;
249         int savedmaxx = -1;
250         int savedminy = -1;
251         int savedmaxy = -1;
252         uih->wflipped = 0;
253         w = uih->wtop;
254         while (w) {
255             int i;
256             assert(w->saveddata == NULL);
257             if (w->getpos == NULL) {
258                 if ((w->x < savedminx || w->y < savedminy ||
259                      w->x + w->width > savedmaxx ||
260                      w->x + w->height > savedmaxy ||
261                      w->x + w->width < savedminx ||
262                      w->y + w->height < savedminy || w->x > savedmaxx ||
263                      w->y > savedmaxy)) {
264                     w->saveddata = xsaveline(uih->image, w->x, w->y,
265                                              w->width + w->x, w->height + w->y);
266                 }
267             } else {
268                 assert(w->savedline == -1);
269                 if (w->width && w->height &&
270                     (w->x < savedminx || w->y < savedminy ||
271                      w->x + w->width > savedmaxx ||
272                      w->y + w->height > savedmaxy)) {
273                     int xskip = w->x * uih->image->bytesperpixel;
274                     int width = w->width * uih->image->bytesperpixel;
275                     savedminx = w->x;
276                     savedminy = w->y;
277                     savedmaxx = w->x + w->width;
278                     savedmaxy = w->y + w->height;
279                     if (!uih->image->bytesperpixel) {
280                         xskip = w->x / 8;
281                         width = (w->x + w->width + 7) / 8 - xskip;
282                     }
283                     if (uih->image->flags & PROTECTBUFFERS) {
284                         w->saveddata = (char *)malloc(width * w->height + 1);
285                         if (w->saveddata != NULL)
286                             for (i = w->y; i < w->y + w->height; i++) {
287                                 unsigned char *data = img->currlines[i] + xskip;
288                                 memcpy(w->saveddata + (i - w->y) * width, data,
289                                        width);
290                             }
291 
292                     } else {
293                         w->savedline = savedline;
294                         w->savedpos = savedpos;
295                         for (i = w->y; i < w->y + w->height; i++) {
296                             unsigned char *data = img->currlines[i] + xskip;
297                             if (width + savedpos > destwidth) {
298                                 int width1;
299                                 memcpy(uih->image->oldlines[savedline] +
300                                            savedpos,
301                                        data, destwidth - savedpos);
302                                 savedline++;
303                                 width1 = width - destwidth + savedpos;
304                                 memcpy(uih->image->oldlines[savedline],
305                                        data + (destwidth - savedpos), width1);
306                                 savedpos = width1;
307                             } else
308                                 memcpy(uih->image->oldlines[savedline] +
309                                            savedpos,
310                                        data, width),
311                                     savedpos += width;
312                         }
313                     }
314                 }
315             }
316             w = w->next;
317         }
318     }
319     w = uih->wtop;
320     while (w) {
321         if (w->getpos == NULL) {
322 #define lwi 0
323 #define lwj 0
324             xline(uih->image, w->x + lwi, w->y + lwj, w->width + w->x + lwi,
325                   w->height + w->y + lwj, w->savedline);
326         } else if (w->width && w->height) {
327             w->draw(uih, w->data);
328         }
329         w = w->next;
330     }
331 }
332