move around - flatter.
[profile/ivi/evas.git] / src / lib / engines / common / evas_draw_main.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #include "evas_common.h"
6 #include "evas_convert_main.h"
7
8 EAPI Cutout_Rects*
9 evas_common_draw_context_cutouts_new(void)
10 {
11    Cutout_Rects *rects;
12
13    rects = malloc(sizeof(Cutout_Rects));
14    rects->rects = NULL;
15    rects->active = 0;
16    rects->max = 0;
17
18    return rects;
19 }
20
21 EAPI void
22 evas_common_draw_context_cutouts_free(Cutout_Rects* rects)
23 {
24    rects->active = 0;
25 }
26
27 static Cutout_Rect*
28 evas_common_draw_context_cutouts_add(Cutout_Rects* rects,
29                                      int x, int y, int w, int h)
30 {
31    Cutout_Rect* rect;
32
33    if (rects->max < (rects->active + 1))
34      {
35         rects->max += 32;
36         rects->rects = realloc(rects->rects, sizeof(Cutout_Rect) * rects->max);
37      }
38
39    rect = rects->rects + rects->active;
40    rect->x = x;
41    rect->y = y;
42    rect->w = w;
43    rect->h = h;
44    rects->active++;
45
46    return rect;
47 }
48
49 EAPI void
50 evas_common_draw_context_cutouts_del(Cutout_Rects* rects,
51                                      int index)
52 {
53    if ((index >= 0) && (index < rects->active))
54      {
55         Cutout_Rect*    rect;
56
57         rect = rects->rects + index;
58         memmove(rect, rect + 1,
59                 sizeof(Cutout_Rect) * (rects->active - index - 1));
60         rects->active--;
61      }
62 }
63
64 void
65 evas_common_init(void)
66 {
67    evas_common_cpu_init();
68
69    evas_common_blend_init();
70    evas_common_image_init();
71    evas_common_convert_init();
72    evas_common_scale_init();
73    evas_common_rectangle_init();
74    evas_common_gradient_init();
75    evas_common_polygon_init();
76    evas_common_line_init();
77    evas_common_font_init();
78    evas_common_draw_init();
79    evas_common_tilebuf_init();
80 }
81
82 void
83 evas_common_shutdown(void)
84 {
85    evas_font_dir_cache_free();
86    evas_common_image_cache_free();
87 }
88
89 EAPI void
90 evas_common_draw_init(void)
91 {
92 }
93
94 EAPI RGBA_Draw_Context *
95 evas_common_draw_context_new(void)
96 {
97    RGBA_Draw_Context *dc;
98
99    dc = calloc(1, sizeof(RGBA_Draw_Context));
100    dc->sli.h = 1;
101    return dc;
102 }
103
104 EAPI void
105 evas_common_draw_context_free(RGBA_Draw_Context *dc)
106 {
107    if (!dc) return;
108
109    evas_common_draw_context_apply_clean_cutouts(&dc->cutout);
110    free(dc);
111 }
112
113 EAPI void
114 evas_common_draw_context_clear_cutouts(RGBA_Draw_Context *dc)
115 {
116    evas_common_draw_context_apply_clean_cutouts(&dc->cutout);
117 }
118
119 EAPI void
120 evas_common_draw_context_font_ext_set(RGBA_Draw_Context *dc,
121                                       void *data,
122                                       void *(*gl_new)  (void *data, RGBA_Font_Glyph *fg),
123                                       void  (*gl_free) (void *ext_dat),
124                                       void  (*gl_draw) (void *data, void *dest, void *context, RGBA_Font_Glyph *fg, int x, int y))
125 {
126    dc->font_ext.data = data;
127    dc->font_ext.func.gl_new = gl_new;
128    dc->font_ext.func.gl_free = gl_free;
129    dc->font_ext.func.gl_draw = gl_draw;
130 }
131
132 EAPI void
133 evas_common_draw_context_clip_clip(RGBA_Draw_Context *dc, int x, int y, int w, int h)
134 {
135    if (dc->clip.use)
136      {
137         RECTS_CLIP_TO_RECT(dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h,
138                            x, y, w, h);
139      }
140    else
141      evas_common_draw_context_set_clip(dc, x, y, w, h);
142 }
143
144 EAPI void
145 evas_common_draw_context_set_clip(RGBA_Draw_Context *dc, int x, int y, int w, int h)
146 {
147    dc->clip.use = 1;
148    dc->clip.x = x;
149    dc->clip.y = y;
150    dc->clip.w = w;
151    dc->clip.h = h;
152 }
153
154 EAPI void
155 evas_common_draw_context_unset_clip(RGBA_Draw_Context *dc)
156 {
157    dc->clip.use = 0;
158 }
159
160 EAPI void
161 evas_common_draw_context_set_color(RGBA_Draw_Context *dc, int r, int g, int b, int a)
162 {
163    R_VAL(&(dc->col.col)) = (DATA8)r;
164    G_VAL(&(dc->col.col)) = (DATA8)g;
165    B_VAL(&(dc->col.col)) = (DATA8)b;
166    A_VAL(&(dc->col.col)) = (DATA8)a;
167 }
168
169 EAPI void
170 evas_common_draw_context_set_multiplier(RGBA_Draw_Context *dc, int r, int g, int b, int a)
171 {
172    dc->mul.use = 1;
173    R_VAL(&(dc->mul.col)) = (DATA8)r;
174    G_VAL(&(dc->mul.col)) = (DATA8)g;
175    B_VAL(&(dc->mul.col)) = (DATA8)b;
176    A_VAL(&(dc->mul.col)) = (DATA8)a;
177 }
178
179 EAPI void
180 evas_common_draw_context_unset_multiplier(RGBA_Draw_Context *dc)
181 {
182    dc->mul.use = 0;
183 }
184
185 EAPI void
186 evas_common_draw_context_add_cutout(RGBA_Draw_Context *dc, int x, int y, int w, int h)
187 {
188    if (dc->clip.use)
189      {
190         RECTS_CLIP_TO_RECT(x, y, w, h,
191                            dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h);
192         if ((w < 1) || (h < 1)) return;
193      }
194    evas_common_draw_context_cutouts_add(&dc->cutout, x, y, w, h);
195 }
196
197 int
198 evas_common_draw_context_cutout_split(Cutout_Rects* res, int index, Cutout_Rect *split)
199 {
200    /* 1 input rect, multiple out */
201    Cutout_Rect  in = res->rects[index];
202
203    /* this is to save me a LOT of typing */
204 #define INX1 (in.x)
205 #define INX2 (in.x + in.w)
206 #define SPX1 (split->x)
207 #define SPX2 (split->x + split->w)
208 #define INY1 (in.y)
209 #define INY2 (in.y + in.h)
210 #define SPY1 (split->y)
211 #define SPY2 (split->y + split->h)
212 #define X1_IN (in.x < split->x)
213 #define X2_IN ((in.x + in.w) > (split->x + split->w))
214 #define Y1_IN (in.y < split->y)
215 #define Y2_IN ((in.y + in.h) > (split->y + split->h))
216 #define R_NEW(_r, _x, _y, _w, _h) { evas_common_draw_context_cutouts_add(_r, _x, _y, _w, _h); }
217    if (!RECTS_INTERSECT(in.x, in.y, in.w, in.h,
218                         split->x, split->y, split->w, split->h))
219      {
220         /* No colision => no clipping, don't touch it. */
221         return 1;
222      }
223
224    /* S    = split (ie cut out rect) */
225    /* +--+ = in (rect to be cut) */
226
227    /*
228     *  +---+
229     *  |   |
230     *  | S |
231     *  |   |
232     *  +---+
233     *
234     */
235    if (X1_IN && X2_IN && Y1_IN && Y2_IN)
236      {
237         R_NEW(res, in.x, in.y, in.w, SPY1 - in.y);
238         R_NEW(res, in.x, SPY1, SPX1 - in.x, SPY2 - SPY1);
239         R_NEW(res, SPX2, SPY1, INX2 - SPX2, SPY2 - SPY1);
240         /* out => (in.x, SPY2, in.w, INY2 - SPY2) */
241         res->rects[index].h = INY2 - SPY2;
242         res->rects[index].y = SPY2;
243         return 1;
244      }
245    /* SSSSSSS
246     * S+---+S
247     * S|SSS|S
248     * S|SSS|S
249     * S|SSS|S
250     * S+---+S
251     * SSSSSSS
252     */
253    if (!X1_IN && !X2_IN && !Y1_IN && !Y2_IN)
254      {
255         evas_common_draw_context_cutouts_del(res, index);
256         return 0;
257      }
258    /* SSS
259     * S+---+
260     * S|S  |
261     * S|S  |
262     * S|S  |
263     * S+---+
264     * SSS
265     */
266    if (!X1_IN && X2_IN && !Y1_IN && !Y2_IN)
267      {
268         /* in => (SPX2, in.y, INX2 - SPX2, in.h) */
269         res->rects[index].w = INX2 - SPX2;
270         res->rects[index].x = SPX2;
271         return 1;
272      }
273    /*    S
274     *  +---+
275     *  | S |
276     *  | S |
277     *  | S |
278     *  +---+
279     *    S
280     */
281    if (X1_IN && X2_IN && !Y1_IN && !Y2_IN)
282      {
283         R_NEW(res, in.x, in.y, SPX1 - in.x, in.h);
284         /* in => (SPX2, in.y, INX2 - SPX2, in.h) */
285         res->rects[index].w = INX2 - SPX2;
286         res->rects[index].x = SPX2;
287         return 1;
288      }
289    /*     SSS
290     *  +---+S
291     *  |  S|S
292     *  |  S|S
293     *  |  S|S
294     *  +---+S
295     *     SSS
296     */
297    if (X1_IN && !X2_IN && !Y1_IN && !Y2_IN)
298      {
299         /* in => (in.x, in.y, SPX1 - in.x, in.h) */
300         res->rects[index].w = SPX1 - in.x;
301         return 1;
302      }
303    /* SSSSSSS
304     * S+---+S
305     * S|SSS|S
306     *  |   |
307     *  |   |
308     *  +---+
309     *
310     */
311    if (!X1_IN && !X2_IN && !Y1_IN && Y2_IN)
312      {
313         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
314         res->rects[index].h = INY2 - SPY2;
315         res->rects[index].y = SPY2;
316         return 1;
317      }
318    /*
319     *  +---+
320     *  |   |
321     * S|SSS|S
322     *  |   |
323     *  +---+
324     *
325     */
326    if (!X1_IN && !X2_IN && Y1_IN && Y2_IN)
327      {
328         R_NEW(res, in.x, SPY2, in.w, INY2 - SPY2);
329         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
330         res->rects[index].h = SPY1 - in.y;
331         return 1;
332      }
333    /*
334     *  +---+
335     *  |   |
336     *  |   |
337     * S|SSS|S
338     * S+---+S
339     * SSSSSSS
340     */
341    if (!X1_IN && !X2_IN && Y1_IN && !Y2_IN)
342      {
343         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
344         res->rects[index].h = SPY1 - in.y;
345         return 1;
346      }
347    /* SSS
348     * S+---+
349     * S|S  |
350     *  |   |
351     *  |   |
352     *  +---+
353     *
354     */
355    if (!X1_IN && X2_IN && !Y1_IN && Y2_IN)
356      {
357         R_NEW(res, SPX2, in.y, INX2 - SPX2, SPY2 - in.y);
358         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
359         res->rects[index].h = INY2 - SPY2;
360         res->rects[index].y = SPY2;
361         return 1;
362      }
363    /*    S
364     *  +---+
365     *  | S |
366     *  |   |
367     *  |   |
368     *  +---+
369     *
370     */
371    if (X1_IN && X2_IN && !Y1_IN && Y2_IN)
372      {
373         R_NEW(res, in.x, in.y, SPX1 - in.x, SPY2 - in.y);
374         R_NEW(res, SPX2, in.y, INX2 - SPX2, SPY2 - in.y);
375         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
376         res->rects[index].h = INY2 - SPY2;
377         res->rects[index].y = SPY2;
378         return 1;
379      }
380    /*     SSS
381     *  +---+S
382     *  |  S|S
383     *  |   |
384     *  |   |
385     *  +---+
386     *
387     */
388    if (X1_IN && !X2_IN && !Y1_IN && Y2_IN)
389      {
390         R_NEW(res, in.x, in.y, SPX1 - in.x, SPY2 - in.y);
391         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
392         res->rects[index].h = INY2 - SPY2;
393         res->rects[index].y = SPY2;
394         return 1;
395      }
396    /*
397     *  +---+
398     *  |   |
399     * S|S  |
400     *  |   |
401     *  +---+
402     *
403     */
404    if (!X1_IN && X2_IN && Y1_IN && Y2_IN)
405      {
406         R_NEW(res, in.x, SPY2, in.w, INY2 - SPY2);
407         R_NEW(res, SPX2, SPY1, INX2 - SPX2, SPY2 - SPY1);
408         /* in => (in.x, SPY2, in.w, INY2 - SPY2) */
409         res->rects[index].h = SPY1 - in.y;
410         return 1;
411      }
412    /*
413     *  +---+
414     *  |   |
415     *  |  S|S
416     *  |   |
417     *  +---+
418     *
419     */
420    if (X1_IN && !X2_IN && Y1_IN && Y2_IN)
421      {
422         R_NEW(res, in.x, SPY2, in.w, INY2 - SPY2);
423         R_NEW(res, in.x, SPY1, SPX1 - in.x, SPY2 - SPY1);
424         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
425         res->rects[index].h = SPY1 - in.y;
426         return 1;
427      }
428    /*
429     *  +---+
430     *  |   |
431     *  |   |
432     * S|S  |
433     * S+---+
434     * SSS
435     */
436    if (!X1_IN && X2_IN && Y1_IN && !Y2_IN)
437      {
438         R_NEW(res, SPX2, SPY1, INX2 - SPX2, INY2 - SPY1);
439         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
440         res->rects[index].h = SPY1 - in.y;
441         return 1;
442      }
443    /*
444     *  +---+
445     *  |   |
446     *  |   |
447     *  | S |
448     *  +---+
449     *    S
450     */
451    if (X1_IN && X2_IN && Y1_IN && !Y2_IN)
452      {
453         R_NEW(res, in.x, SPY1, SPX1 - in.x, INY2 - SPY1);
454         R_NEW(res, SPX2, SPY1, INX2 - SPX2, INY2 - SPY1);
455         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
456         res->rects[index].h = SPY1 - in.y;
457         return 1;
458      }
459    /*
460     *  +---+
461     *  |   |
462     *  |   |
463     *  |  S|S
464     *  +---+S
465     *     SSS
466     */
467    if (X1_IN && !X2_IN && Y1_IN && !Y2_IN)
468      {
469         R_NEW(res, in.x, SPY1, SPX1 - in.x, INY2 - SPY1);
470         /* in => (in.x, in.y, in.w, SPY1 - in.y) */
471         res->rects[index].h = SPY1 - in.y;
472         return 1;
473      }
474    evas_common_draw_context_cutouts_del(res, index);
475    return 0;
476 #undef INX1
477 #undef INX2
478 #undef SPX1
479 #undef SPX2
480 #undef INY1
481 #undef INY2
482 #undef SPY1
483 #undef SPY2
484 #undef X1_IN
485 #undef X2_IN
486 #undef Y1_IN
487 #undef Y2_IN
488 #undef R_NEW
489 }
490
491 EAPI Cutout_Rects*
492 evas_common_draw_context_apply_cutouts(RGBA_Draw_Context *dc)
493 {
494    Cutout_Rects*        res;
495    int                  i;
496    int                  j;
497
498    if (!dc->clip.use) return NULL;
499    if ((dc->clip.w <= 0) || (dc->clip.h <= 0)) return NULL;
500
501    res = evas_common_draw_context_cutouts_new();
502    evas_common_draw_context_cutouts_add(res, dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h);
503
504    for (i = 0; i < dc->cutout.active; ++i)
505      {
506         /* Don't loop on the element just added to the list as they are already correctly clipped. */
507         int active = res->active;
508
509         for (j = 0; j < active; )
510           {
511              if (evas_common_draw_context_cutout_split(res, j, dc->cutout.rects + i))
512                ++j;
513              else
514                active--;
515           }
516      }
517    return res;
518 }
519
520 EAPI void
521 evas_common_draw_context_apply_clear_cutouts(Cutout_Rects* rects)
522 {
523    evas_common_draw_context_apply_clean_cutouts(rects);
524    free(rects);
525 }
526
527 EAPI void
528 evas_common_draw_context_apply_clean_cutouts(Cutout_Rects* rects)
529 {
530    free(rects->rects);
531    rects->rects = NULL;
532    rects->active = 0;
533    rects->max = 0;
534 }
535
536 EAPI void
537 evas_common_draw_context_set_anti_alias(RGBA_Draw_Context *dc , unsigned char aa)
538 {
539    dc->anti_alias = !!aa;
540 }
541
542 EAPI void
543 evas_common_draw_context_set_color_interpolation(RGBA_Draw_Context *dc, int color_space)
544 {
545    dc->interpolation.color_space = color_space;
546 }
547
548 EAPI void
549 evas_common_draw_context_set_render_op(RGBA_Draw_Context *dc , int op)
550 {
551    dc->render_op = op;
552 }
553
554 EAPI void
555 evas_common_draw_context_set_sli(RGBA_Draw_Context *dc, int y, int h)
556 {
557    dc->sli.y = y;
558    dc->sli.h = h;
559 }