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