1 #include "evas_common_private.h"
2 #include "evas_convert_main.h"
3 #include "evas_private.h"
4 
5 EAPI Cutout_Rects *
evas_common_draw_context_cutouts_new(void)6 evas_common_draw_context_cutouts_new(void)
7 {
8    Cutout_Rects *rects;
9 
10    rects = calloc(1, sizeof(Cutout_Rects));
11    return rects;
12 }
13 
14 static void
evas_common_draw_context_cutouts_dup(Cutout_Rects * rects2,const Cutout_Rects * rects)15 evas_common_draw_context_cutouts_dup(Cutout_Rects *rects2, const Cutout_Rects *rects)
16 {
17    if (!rects) return;
18    rects2->active = rects->active;
19    rects2->max = rects->active;
20    rects2->last_add = rects->last_add;
21    if (rects2->max > 0)
22      {
23         const size_t sz = sizeof(Cutout_Rect) * rects2->max;
24         rects2->rects = malloc(sz);
25         memcpy(rects2->rects, rects->rects, sz);
26         return;
27      }
28    else rects2->rects = NULL;
29 }
30 
31 EAPI void
evas_common_draw_context_cutouts_free(Cutout_Rects * rects)32 evas_common_draw_context_cutouts_free(Cutout_Rects* rects)
33 {
34    if (!rects) return;
35    rects->active = 0;
36    rects->last_add.w = 0;
37 }
38 
39 EAPI void
evas_common_draw_context_cutouts_real_free(Cutout_Rects * rects)40 evas_common_draw_context_cutouts_real_free(Cutout_Rects* rects)
41 {
42    if (!rects) return;
43    free(rects->rects);
44    free(rects);
45 }
46 
47 EAPI void
evas_common_draw_context_cutouts_del(Cutout_Rects * rects,int idx)48 evas_common_draw_context_cutouts_del(Cutout_Rects* rects, int idx)
49 {
50    if ((idx >= 0) && (idx < rects->active))
51      {
52         Cutout_Rect *rect;
53 
54         rect = rects->rects + idx;
55         memmove(rect, rect + 1,
56                 sizeof(Cutout_Rect) * (rects->active - idx - 1));
57         rects->active--;
58         rects->last_add.w = 0;
59      }
60 }
61 
62 static int _init_count = 0;
63 static Eina_Trash *_ctxt_spares = NULL;
64 static int _ctxt_spares_count = 0;
65 static SLK(_ctx_spares_lock);
66 
67 static void
_evas_common_draw_context_real_free(RGBA_Draw_Context * dc)68 _evas_common_draw_context_real_free(RGBA_Draw_Context *dc)
69 {
70 #ifdef HAVE_PIXMAN
71 # if defined(PIXMAN_FONT) || defined(PIXMAN_RECT) || defined(PIXMAN_LINE) || defined(PIXMAN_POLY)
72    if (dc->col.pixman_color_image)
73      pixman_image_unref(dc->col.pixman_color_image);
74 # endif
75 #endif
76    evas_common_draw_context_apply_clean_cutouts(&dc->cutout);
77    evas_common_draw_context_cutouts_real_free(dc->cache.rects);
78    free(dc);
79 }
80 
81 static void
_evas_common_draw_context_stash(RGBA_Draw_Context * dc)82 _evas_common_draw_context_stash(RGBA_Draw_Context *dc)
83 {
84    if (_ctxt_spares_count >= 8)
85      {
86         _evas_common_draw_context_real_free(dc);
87         return ;
88      }
89 
90 #ifdef HAVE_PIXMAN
91 # if defined(PIXMAN_FONT) || defined(PIXMAN_RECT) || defined(PIXMAN_LINE) || defined(PIXMAN_POLY)
92    if (dc->col.pixman_color_image)
93      {
94         pixman_image_unref(dc->col.pixman_color_image);
95         dc->col.pixman_color_image = NULL;
96      }
97 # endif
98 #endif
99    evas_common_draw_context_apply_clean_cutouts(&dc->cutout);
100    evas_common_draw_context_cutouts_real_free(dc->cache.rects);
101    SLKL(_ctx_spares_lock);
102    eina_trash_push(&_ctxt_spares, dc);
103    _ctxt_spares_count++;
104    SLKU(_ctx_spares_lock);
105 }
106 
107 static RGBA_Draw_Context *
_evas_common_draw_context_find(void)108 _evas_common_draw_context_find(void)
109 {
110    RGBA_Draw_Context *dc = NULL;
111 
112    if (_ctxt_spares)
113      {
114         SLKL(_ctx_spares_lock);
115         dc = eina_trash_pop(&_ctxt_spares);
116         _ctxt_spares_count--;
117         SLKU(_ctx_spares_lock);
118      }
119 
120    if (!dc) dc = malloc(sizeof(RGBA_Draw_Context));
121 
122    return dc;
123 }
124 
125 EAPI void
evas_common_init(void)126 evas_common_init(void)
127 {
128    if (_init_count++) return;
129 
130    SLKI(_ctx_spares_lock);
131    evas_common_cpu_init();
132 
133    evas_common_blend_init();
134    evas_common_image_init();
135    evas_common_convert_init();
136    evas_common_scale_init();
137    evas_common_scale_sample_init();
138    evas_common_rectangle_init();
139    evas_common_polygon_init();
140    evas_common_line_init();
141    evas_common_font_init();
142    evas_common_draw_init();
143    evas_common_tilebuf_init();
144 }
145 
146 EAPI void
evas_common_shutdown(void)147 evas_common_shutdown(void)
148 {
149    if (--_init_count) return;
150 
151    evas_font_dir_cache_free();
152    evas_common_font_shutdown();
153    evas_common_image_shutdown();
154    evas_common_image_cache_free();
155    evas_common_scale_sample_shutdown();
156 // just in case any thread is still doing things... don't del this here
157 //   RGBA_Draw_Context *dc;
158 //   SLKL(_ctx_spares_lock);
159 //   EINA_LIST_FREE(_ctxt_spares, dc) _evas_common_draw_context_real_free(dc);
160 //   _ctxt_spares_count = 0;
161 //   SLKU(_ctx_spares_lock);
162 //   SLKD(_ctx_spares_lock);
163 }
164 
165 EAPI void
evas_common_draw_init(void)166 evas_common_draw_init(void)
167 {
168 }
169 
170 EAPI RGBA_Draw_Context *
evas_common_draw_context_new(void)171 evas_common_draw_context_new(void)
172 {
173    RGBA_Draw_Context *dc;
174    dc = _evas_common_draw_context_find();
175    if (!dc) return NULL;
176    memset(dc, 0, sizeof(RGBA_Draw_Context));
177    return dc;
178 }
179 
180 EAPI RGBA_Draw_Context *
evas_common_draw_context_dup(RGBA_Draw_Context * dc)181 evas_common_draw_context_dup(RGBA_Draw_Context *dc)
182 {
183    RGBA_Draw_Context *dc2 = _evas_common_draw_context_find();
184 
185    if (!dc) return dc2;
186    memcpy(dc2, dc, sizeof(RGBA_Draw_Context));
187    evas_common_draw_context_cutouts_dup(&dc2->cutout, &dc->cutout);
188 #ifdef HAVE_PIXMAN
189 # if defined(PIXMAN_FONT) || defined(PIXMAN_RECT) || defined(PIXMAN_LINE) || defined(PIXMAN_POLY)
190    dc2->col.pixman_color_image = NULL;
191 # endif
192 #endif
193    dc2->cache.rects = NULL;
194    dc2->cache.used = 0;
195    return dc2;
196 }
197 
198 EAPI void
evas_common_draw_context_free(RGBA_Draw_Context * dc)199 evas_common_draw_context_free(RGBA_Draw_Context *dc)
200 {
201    if (!dc) return;
202    _evas_common_draw_context_stash(dc);
203 }
204 
205 EAPI void
evas_common_draw_context_clear_cutouts(RGBA_Draw_Context * dc)206 evas_common_draw_context_clear_cutouts(RGBA_Draw_Context *dc)
207 {
208    evas_common_draw_context_cutouts_free(&dc->cutout);
209 }
210 
211 EAPI void
evas_common_draw_context_font_ext_set(RGBA_Draw_Context * dc,void * data,void * (* gl_new)(void * data,RGBA_Font_Glyph * fg),void (* gl_free)(void * ext_dat),void (* gl_draw)(void * data,void * dest,void * context,RGBA_Font_Glyph * fg,int x,int y,int w,int h),void * (* gl_image_new)(void * gc,RGBA_Font_Glyph * fg,int alpha,Evas_Colorspace cspace),void (* gl_image_free)(void * image),void (* gl_image_draw)(void * gc,void * im,int dx,int dy,int dw,int dh,int smooth))212 evas_common_draw_context_font_ext_set(RGBA_Draw_Context *dc,
213                                       void *data,
214                                       void *(*gl_new)  (void *data, RGBA_Font_Glyph *fg),
215                                       void  (*gl_free) (void *ext_dat),
216                                       void  (*gl_draw) (void *data, void *dest, void *context, RGBA_Font_Glyph *fg, int x, int y, int w, int h),
217                                       void *(*gl_image_new) (void *gc, RGBA_Font_Glyph *fg, int alpha, Evas_Colorspace cspace),
218                                       void  (*gl_image_free) (void *image),
219                                       void  (*gl_image_draw) (void *gc, void *im, int dx, int dy, int dw, int dh, int smooth))
220 {
221    dc->font_ext.data = data;
222    dc->font_ext.func.gl_new = gl_new;
223    dc->font_ext.func.gl_free = gl_free;
224    dc->font_ext.func.gl_draw = gl_draw;
225    dc->font_ext.func.gl_image_new = gl_image_new;
226    dc->font_ext.func.gl_image_free = gl_image_free;
227    dc->font_ext.func.gl_image_draw = gl_image_draw;
228 }
229 
230 EAPI void
evas_common_draw_context_clip_clip(RGBA_Draw_Context * dc,int x,int y,int w,int h)231 evas_common_draw_context_clip_clip(RGBA_Draw_Context *dc, int x, int y, int w, int h)
232 {
233    if (dc->clip.use)
234      {
235 	RECTS_CLIP_TO_RECT(dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h,
236 			   x, y, w, h);
237      }
238    else
239      evas_common_draw_context_set_clip(dc, x, y, w, h);
240 }
241 
242 EAPI void
evas_common_draw_context_set_clip(RGBA_Draw_Context * dc,int x,int y,int w,int h)243 evas_common_draw_context_set_clip(RGBA_Draw_Context *dc, int x, int y, int w, int h)
244 {
245    dc->clip.use = 1;
246    dc->clip.x = x;
247    dc->clip.y = y;
248    dc->clip.w = w;
249    dc->clip.h = h;
250 }
251 
252 EAPI void
evas_common_draw_context_unset_clip(RGBA_Draw_Context * dc)253 evas_common_draw_context_unset_clip(RGBA_Draw_Context *dc)
254 {
255    dc->clip.use = 0;
256 }
257 
258 EAPI void
evas_common_draw_context_set_color(RGBA_Draw_Context * dc,int r,int g,int b,int a)259 evas_common_draw_context_set_color(RGBA_Draw_Context *dc, int r, int g, int b, int a)
260 {
261    R_VAL(&(dc->col.col)) = (DATA8)r;
262    G_VAL(&(dc->col.col)) = (DATA8)g;
263    B_VAL(&(dc->col.col)) = (DATA8)b;
264    A_VAL(&(dc->col.col)) = (DATA8)a;
265 #ifdef HAVE_PIXMAN
266 #if defined(PIXMAN_FONT) || defined(PIXMAN_RECT) || defined(PIXMAN_LINE) || defined(PIXMAN_POLY)
267    if (dc->col.pixman_color_image)
268      pixman_image_unref(dc->col.pixman_color_image);
269 
270    pixman_color_t pixman_color;
271 
272    pixman_color.alpha =  (dc->col.col & 0xff000000) >> 16;
273    pixman_color.red = (dc->col.col & 0x00ff0000) >> 8;
274    pixman_color.green = (dc->col.col & 0x0000ff00);
275    pixman_color.blue = (dc->col.col & 0x000000ff) << 8;
276 
277    dc->col.pixman_color_image = pixman_image_create_solid_fill(&pixman_color);
278 #endif
279 #endif
280 
281 }
282 
283 EAPI void
evas_common_draw_context_set_multiplier(RGBA_Draw_Context * dc,int r,int g,int b,int a)284 evas_common_draw_context_set_multiplier(RGBA_Draw_Context *dc, int r, int g, int b, int a)
285 {
286    dc->mul.use = 1;
287    R_VAL(&(dc->mul.col)) = (DATA8)r;
288    G_VAL(&(dc->mul.col)) = (DATA8)g;
289    B_VAL(&(dc->mul.col)) = (DATA8)b;
290    A_VAL(&(dc->mul.col)) = (DATA8)a;
291 }
292 
293 EAPI void
evas_common_draw_context_unset_multiplier(RGBA_Draw_Context * dc)294 evas_common_draw_context_unset_multiplier(RGBA_Draw_Context *dc)
295 {
296    dc->mul.use = 0;
297 }
298 
299 
300 EAPI void
evas_common_draw_context_add_cutout(RGBA_Draw_Context * dc,int x,int y,int w,int h)301 evas_common_draw_context_add_cutout(RGBA_Draw_Context *dc, int x, int y, int w, int h)
302 {
303 //   if (dc->cutout.rects > 512) return;
304    if (dc->clip.use)
305      {
306 #if 1 // this is a bit faster
307         int x1, x2, y1, y2;
308         int cx1, cx2, cy1, cy2;
309 
310         x2 = x + w;
311         cx1 = dc->clip.x;
312         if (x2 <= cx1) return;
313         x1 = x;
314         cx2 = cx1 + dc->clip.w;
315         if (x1 >= cx2) return;
316 
317         if (x1 < cx1) x1 = cx1;
318         if (x2 > cx2) x2 = cx2;
319 
320         y2 = y + h;
321         cy1 = dc->clip.y;
322         if (y2 <= cy1) return;
323         y1 = y;
324         cy2 = cy1 + dc->clip.h;
325         if (y1 >= cy2) return;
326 
327         if (y1 < cy1) y1 = cy1;
328         if (y2 > cy2) y2 = cy2;
329 
330         x = x1;
331         y = y1;
332         w = x2 - x1;
333         h = y2 - y1;
334 #else
335         RECTS_CLIP_TO_RECT(x, y, w, h,
336                            dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h);
337 #endif
338      }
339    if ((w * h) <= (8 * 8)) return;
340    if (dc->cutout.last_add.w > 0)
341      {
342         if ((dc->cutout.last_add.x == x) && (dc->cutout.last_add.y == y) &&
343             (dc->cutout.last_add.w == w) && (dc->cutout.last_add.h == h)) return;
344      }
345    dc->cutout.last_add.x = x;
346    dc->cutout.last_add.y = y;
347    dc->cutout.last_add.w = w;
348    dc->cutout.last_add.h = h;
349    evas_common_draw_context_cutouts_add(&dc->cutout, x, y, w, h);
350 }
351 
352 static int
evas_common_draw_context_cutout_split(Cutout_Rects * res,int idx,Cutout_Rect * split)353 evas_common_draw_context_cutout_split(Cutout_Rects *res, int idx, Cutout_Rect *split)
354 {
355    /* 1 input rect, multiple out */
356    Cutout_Rect in = res->rects[idx];
357 
358    /* this is to save me a LOT of typing */
359 #define INX1 (in.x)
360 #define INX2 (in.x + in.w)
361 #define SPX1 (split->x)
362 #define SPX2 (split->x + split->w)
363 #define INY1 (in.y)
364 #define INY2 (in.y + in.h)
365 #define SPY1 (split->y)
366 #define SPY2 (split->y + split->h)
367 #define X1_IN (in.x < split->x)
368 #define X2_IN ((in.x + in.w) > (split->x + split->w))
369 #define Y1_IN (in.y < split->y)
370 #define Y2_IN ((in.y + in.h) > (split->y + split->h))
371 #define R_NEW(_r, _x, _y, _w, _h) { evas_common_draw_context_cutouts_add(_r, _x, _y, _w, _h); }
372    if (!RECTS_INTERSECT(in.x, in.y, in.w, in.h,
373 			split->x, split->y, split->w, split->h))
374      {
375         /* No colision => no clipping, don't touch it. */
376 	return 1;
377      }
378 
379    /* S    = split (ie cut out rect) */
380    /* +--+ = in (rect to be cut) */
381 
382    /*
383     *  +---+
384     *  |   |
385     *  | S |
386     *  |   |
387     *  +---+
388     *
389     */
390    if (X1_IN && X2_IN && Y1_IN && Y2_IN)
391      {
392         R_NEW(res, in.x, in.y, in.w, SPY1 - in.y);
393 	R_NEW(res, in.x, SPY1, SPX1 - in.x, SPY2 - SPY1);
394 	R_NEW(res, SPX2, SPY1, INX2 - SPX2, SPY2 - SPY1);
395         /* out => (in.x, SPY2, in.w, INY2 - SPY2) */
396         res->rects[idx].h = INY2 - SPY2;
397         res->rects[idx].y = SPY2;
398 	return 1;
399      }
400    /* SSSSSSS
401     * S+---+S
402     * S|SSS|S
403     * S|SSS|S
404     * S|SSS|S
405     * S+---+S
406     * SSSSSSS
407     */
408    if (!X1_IN && !X2_IN && !Y1_IN && !Y2_IN)
409      {
410         evas_common_draw_context_cutouts_del(res, idx);
411 	return 0;
412      }
413    /* SSS
414     * S+---+
415     * S|S  |
416     * S|S  |
417     * S|S  |
418     * S+---+
419     * SSS
420     */
421    if (!X1_IN && X2_IN && !Y1_IN && !Y2_IN)
422      {
423         /* in => (SPX2, in.y, INX2 - SPX2, in.h) */
424         res->rects[idx].w = INX2 - SPX2;
425         res->rects[idx].x = SPX2;
426 	return 1;
427      }
428    /*    S
429     *  +---+
430     *  | S |
431     *  | S |
432     *  | S |
433     *  +---+
434     *    S
435     */
436    if (X1_IN && X2_IN && !Y1_IN && !Y2_IN)
437      {
438         R_NEW(res, in.x, in.y, SPX1 - in.x, in.h);
439         /* in => (SPX2, in.y, INX2 - SPX2, in.h) */
440         res->rects[idx].w = INX2 - SPX2;
441         res->rects[idx].x = SPX2;
442 	return 1;
443      }
444    /*     SSS
445     *  +---+S
446     *  |  S|S
447     *  |  S|S
448     *  |  S|S
449     *  +---+S
450     *     SSS
451     */
452    if (X1_IN && !X2_IN && !Y1_IN && !Y2_IN)
453      {
454         /* in => (in.x, in.y, SPX1 - in.x, in.h) */
455         res->rects[idx].w = SPX1 - in.x;
456 	return 1;
457      }
458    /* SSSSSSS
459     * S+---+S
460     * S|SSS|S
461     *  |   |
462     *  |   |
463     *  +---+
464     *
465     */
466    if (!X1_IN && !X2_IN && !Y1_IN && Y2_IN)
467      {
468         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
469         res->rects[idx].h = INY2 - SPY2;
470         res->rects[idx].y = SPY2;
471 	return 1;
472      }
473    /*
474     *  +---+
475     *  |   |
476     * S|SSS|S
477     *  |   |
478     *  +---+
479     *
480     */
481    if (!X1_IN && !X2_IN && Y1_IN && Y2_IN)
482      {
483         R_NEW(res, in.x, SPY2, in.w, INY2 - SPY2);
484         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
485         res->rects[idx].h = SPY1 - in.y;
486 	return 1;
487      }
488    /*
489     *  +---+
490     *  |   |
491     *  |   |
492     * S|SSS|S
493     * S+---+S
494     * SSSSSSS
495     */
496    if (!X1_IN && !X2_IN && Y1_IN && !Y2_IN)
497      {
498         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
499         res->rects[idx].h = SPY1 - in.y;
500 	return 1;
501      }
502    /* SSS
503     * S+---+
504     * S|S  |
505     *  |   |
506     *  |   |
507     *  +---+
508     *
509     */
510    if (!X1_IN && X2_IN && !Y1_IN && Y2_IN)
511      {
512 	R_NEW(res, SPX2, in.y, INX2 - SPX2, SPY2 - in.y);
513         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
514         res->rects[idx].h = INY2 - SPY2;
515         res->rects[idx].y = SPY2;
516 	return 1;
517      }
518    /*    S
519     *  +---+
520     *  | S |
521     *  |   |
522     *  |   |
523     *  +---+
524     *
525     */
526    if (X1_IN && X2_IN && !Y1_IN && Y2_IN)
527      {
528 	R_NEW(res, in.x, in.y, SPX1 - in.x, SPY2 - in.y);
529 	R_NEW(res, SPX2, in.y, INX2 - SPX2, SPY2 - in.y);
530         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
531         res->rects[idx].h = INY2 - SPY2;
532         res->rects[idx].y = SPY2;
533 	return 1;
534      }
535    /*     SSS
536     *  +---+S
537     *  |  S|S
538     *  |   |
539     *  |   |
540     *  +---+
541     *
542     */
543    if (X1_IN && !X2_IN && !Y1_IN && Y2_IN)
544      {
545 	R_NEW(res, in.x, in.y, SPX1 - in.x, SPY2 - in.y);
546         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
547         res->rects[idx].h = INY2 - SPY2;
548         res->rects[idx].y = SPY2;
549 	return 1;
550      }
551    /*
552     *  +---+
553     *  |   |
554     * S|S  |
555     *  |   |
556     *  +---+
557     *
558     */
559    if (!X1_IN && X2_IN && Y1_IN && Y2_IN)
560      {
561 	R_NEW(res, in.x, SPY2, in.w, INY2 - SPY2);
562 	R_NEW(res, SPX2, SPY1, INX2 - SPX2, SPY2 - SPY1);
563         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
564         res->rects[idx].h = SPY1 - in.y;
565 	return 1;
566      }
567    /*
568     *  +---+
569     *  |   |
570     *  |  S|S
571     *  |   |
572     *  +---+
573     *
574     */
575    if (X1_IN && !X2_IN && Y1_IN && Y2_IN)
576      {
577 	R_NEW(res, in.x, SPY2, in.w, INY2 - SPY2);
578 	R_NEW(res, in.x, SPY1, SPX1 - in.x, SPY2 - SPY1);
579         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
580         res->rects[idx].h = SPY1 - in.y;
581 	return 1;
582      }
583    /*
584     *  +---+
585     *  |   |
586     *  |   |
587     * S|S  |
588     * S+---+
589     * SSS
590     */
591    if (!X1_IN && X2_IN && Y1_IN && !Y2_IN)
592      {
593         R_NEW(res, SPX2, SPY1, INX2 - SPX2, INY2 - SPY1);
594         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
595         res->rects[idx].h = SPY1 - in.y;
596 	return 1;
597      }
598    /*
599     *  +---+
600     *  |   |
601     *  |   |
602     *  | S |
603     *  +---+
604     *    S
605     */
606    if (X1_IN && X2_IN && Y1_IN && !Y2_IN)
607      {
608 	R_NEW(res, in.x, SPY1, SPX1 - in.x, INY2 - SPY1);
609         R_NEW(res, SPX2, SPY1, INX2 - SPX2, INY2 - SPY1);
610         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
611         res->rects[idx].h = SPY1 - in.y;
612 	return 1;
613      }
614    /*
615     *  +---+
616     *  |   |
617     *  |   |
618     *  |  S|S
619     *  +---+S
620     *     SSS
621     */
622    if (X1_IN && !X2_IN && Y1_IN && !Y2_IN)
623      {
624         R_NEW(res, in.x, SPY1, SPX1 - in.x, INY2 - SPY1);
625         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
626         res->rects[idx].h = SPY1 - in.y;
627 	return 1;
628      }
629    evas_common_draw_context_cutouts_del(res, idx);
630    return 0;
631 #undef INX1
632 #undef INX2
633 #undef SPX1
634 #undef SPX2
635 #undef INY1
636 #undef INY2
637 #undef SPY1
638 #undef SPY2
639 #undef X1_IN
640 #undef X2_IN
641 #undef Y1_IN
642 #undef Y2_IN
643 #undef R_NEW
644 }
645 
646 EAPI void
evas_common_draw_context_target_set(RGBA_Draw_Context * dc,int x,int y,int w,int h)647 evas_common_draw_context_target_set(RGBA_Draw_Context *dc, int x, int y, int w, int h)
648 {
649    dc->cutout_target.x = x;
650    dc->cutout_target.y = y;
651    dc->cutout_target.w = w;
652    dc->cutout_target.h = h;
653 }
654 
655 static int
_srt_y(const void * d1,const void * d2)656 _srt_y(const void *d1, const void *d2)
657 {
658    const Cutout_Rect *r1 = d1, *r2 = d2;
659    if (r1->y == r2->y) return r1->x - r2->x;
660    return r1->y - r2->y;
661 }
662 
663 static int
_srt_x(const void * d1,const void * d2)664 _srt_x(const void *d1, const void *d2)
665 {
666    const Cutout_Rect *r1 = d1, *r2 = d2;
667    if (r1->x == r2->x) return r1->y - r2->y;
668    return r1->x - r2->x;
669 }
670 
671 EAPI Cutout_Rects *
evas_common_draw_context_apply_cutouts(RGBA_Draw_Context * dc,Cutout_Rects * reuse)672 evas_common_draw_context_apply_cutouts(RGBA_Draw_Context *dc, Cutout_Rects *reuse)
673 {
674    Cutout_Rects        *res = NULL;
675    int                  i, j, active, found = 0;
676 
677    if (!dc->clip.use) return NULL;
678    if ((dc->clip.w <= 0) || (dc->clip.h <= 0)) return NULL;
679 
680    if (!reuse) res = evas_common_draw_context_cutouts_new();
681    else
682      {
683         evas_common_draw_context_cutouts_free(reuse);
684         res = reuse;
685      }
686    // this avoids a nasty case of O(n^2)/2 below with lots of rectangles
687    // to merge so only do this merging if the number of rects is small enough
688    // not to blow out into insanity
689    evas_common_draw_context_cutouts_add(res, dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h);
690    for (i = 0; i < dc->cutout.active; i++)
691      {
692         if ((dc->cutout_target.w != 0) &&
693             (!RECTS_INTERSECT(dc->cutout.rects[i].x, dc->cutout.rects[i].y,
694                               dc->cutout.rects[i].w, dc->cutout.rects[i].h,
695                               dc->cutout_target.x, dc->cutout_target.y,
696                               dc->cutout_target.w, dc->cutout_target.h)))
697           continue;
698         // Don't loop on the element just added to the list as they are
699         // already correctly clipped.
700         active = res->active;
701         for (j = 0; j < active; )
702           {
703              if (evas_common_draw_context_cutout_split
704                  (res, j, dc->cutout.rects + i)) j++;
705              else active--;
706           }
707      }
708    /* merge rects */
709 #define RI res->rects[i]
710 #define RJ res->rects[j]
711    if (res->active > 1)
712      {
713         if (res->active > 5)
714           {
715              // fast path for larger numbers of rects to merge by using
716              // qsort to sort by y and x to limit the number of rects
717              // we have to walk as rects that have a different y cannot
718              // be merged anyway (or x).
719              qsort(res->rects, res->active, sizeof(res->rects[0]), _srt_y);
720              for (i = 0; i < res->active; i++)
721                {
722                   if (RI.w == 0) continue; // skip empty rect
723                   for (j = i + 1; j < res->active; j++)
724                     {
725                        if (RJ.y != RI.y) break; // new line, sorted thus skip
726                        if (RJ.w == 0) continue; // skip empty rect
727                        // if J is the same height (could be merged)
728                        if (RJ.h == RI.h)
729                          {
730                             // if J is immediately to the right of I
731                             if (RJ.x == (RI.x + RI.w))
732                               {
733                                  RI.w = (RJ.x + RJ.w) - RI.x; // expand RI
734                                  RJ.w = 0; // invalidate
735                                  found++;
736                               }
737                             // since we sort y and THEN x, if height matches
738                             // but it's not immediately adjacent, no more
739                             // rects exists that can be merged
740                             else break;
741                          }
742                     }
743                }
744              qsort(res->rects, res->active, sizeof(res->rects[0]), _srt_x);
745              for (i = 0; i < res->active; i++)
746                {
747                   if (RI.w == 0) continue; // skip empty rect
748                   for (j = i + 1; j < res->active; j++)
749                     {
750                        if (RJ.x != RI.x) break; // new line, sorted thus skip
751                        if (RJ.w == 0) continue; // skip empty rect
752                        // if J is the same height (could be merged)
753                        if (RJ.w == RI.w)
754                          {
755                             // if J is immediately to the right of I
756                             if (RJ.y == (RI.y + RI.h))
757                               {
758                                  RI.h = (RJ.y + RJ.h) - RI.y; // expand RI
759                                  RJ.w = 0; // invalidate
760                                  found++;
761                               }
762                             // since we sort y and THEN x, if height matches
763                             // but it's not immediately adjacent, no more
764                             // rects exists that can be merged
765                             else break;
766                          }
767                     }
768                }
769           }
770         else
771           {
772              // for a small number of rects, keep things simple as the count
773              // is small and big-o complexity isnt a problem yet
774              found = 1;
775              while (found)
776                {
777                   found = 0;
778                   for (i = 0; i < res->active; i++)
779                     {
780                        for (j = i + 1; j < res->active; j++)
781                          {
782                             // skip empty rects we are removing
783                             if (RJ.w == 0) continue;
784                             // check if its same width, immediately above or below
785                             if ((RJ.w == RI.w) && (RJ.x == RI.x))
786                               {
787                                  if ((RJ.y + RJ.h) == RI.y) // above
788                                    {
789                                       RI.y = RJ.y;
790                                       RI.h += RJ.h;
791                                       RJ.w = 0;
792                                       found++;
793                                    }
794                                  else if ((RI.y + RI.h) == RJ.y) // below
795                                    {
796                                       RI.h += RJ.h;
797                                       RJ.w = 0;
798                                       found++;
799                                    }
800                               }
801                             // check if its same height, immediately left or right
802                             else if ((RJ.h == RI.h) && (RJ.y == RI.y))
803                               {
804                                  if ((RJ.x + RJ.w) == RI.x) // left
805                                    {
806                                       RI.x = RJ.x;
807                                       RI.w += RJ.w;
808                                       RJ.w = 0;
809                                       found++;
810                                    }
811                                  else if ((RI.x + RI.w) == RJ.x) // right
812                                    {
813                                       RI.w += RJ.w;
814                                       RJ.w = 0;
815                                       found++;
816                                    }
817                               }
818                          }
819                     }
820                }
821           }
822 
823         // Repack the cutout
824         j = 0;
825         for (i = 0; i < res->active; i++)
826           {
827              if (RI.w == 0) continue;
828              if (i != j) RJ = RI;
829              j++;
830           }
831         res->active = j;
832      }
833    return res;
834 }
835 
836 EAPI void
evas_common_draw_context_apply_clear_cutouts(Cutout_Rects * rects)837 evas_common_draw_context_apply_clear_cutouts(Cutout_Rects *rects)
838 {
839    evas_common_draw_context_apply_clean_cutouts(rects);
840    free(rects);
841 }
842 
843 EAPI void
evas_common_draw_context_apply_clean_cutouts(Cutout_Rects * rects)844 evas_common_draw_context_apply_clean_cutouts(Cutout_Rects *rects)
845 {
846    free(rects->rects);
847    rects->rects = NULL;
848    rects->active = 0;
849    rects->max = 0;
850    rects->last_add.w = 0;
851 }
852 
853 EAPI void
evas_common_draw_context_set_anti_alias(RGBA_Draw_Context * dc,unsigned char aa)854 evas_common_draw_context_set_anti_alias(RGBA_Draw_Context *dc , unsigned char aa)
855 {
856    dc->anti_alias = !!aa;
857 }
858 
859 EAPI void
evas_common_draw_context_set_color_interpolation(RGBA_Draw_Context * dc,int color_space)860 evas_common_draw_context_set_color_interpolation(RGBA_Draw_Context *dc, int color_space)
861 {
862    dc->interpolation.color_space = color_space;
863 }
864 
865 EAPI void
evas_common_draw_context_set_render_op(RGBA_Draw_Context * dc,int op)866 evas_common_draw_context_set_render_op(RGBA_Draw_Context *dc , int op)
867 {
868    dc->render_op = op;
869 }
870