58dadda76ef305fa97eb37a0d49ad589271e43c5
[framework/uifw/evas.git] / src / lib / canvas / evas_object_proxy.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 #include <stdbool.h>
5
6 /* Switch this to not always use the map.
7  * Tested using map, which is a little slower */
8 #define ALWAYS_MAP   1
9
10 /* Magic number for Proxy objects */
11 static const char o_type[] = "proxy";
12
13 /* Internal object data */
14 typedef struct _Evas_Object_Proxy
15 {
16    DATA32   magic;
17
18    Evas_Object *source;
19
20    void *engine_data;
21
22    Evas_Map *defmap;
23    Eina_Bool mapupdate;
24 } Evas_Object_Proxy;
25
26
27 /* Helpers */
28 static void evas_object_proxy_init(Evas_Object *obj);
29 static Evas_Object_Proxy *evas_object_proxy_new(void);
30 static void _proxy_unset(Evas_Object *proxy);
31 static void _proxy_set(Evas_Object *proxy, Evas_Object *src);
32 static void _proxy_subrender(Evas *e, Evas_Object *source);
33
34 /* Engine Functions */
35 static void _proxy_free(Evas_Object *obj);
36 static void _proxy_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y);
37 static void _proxy_render_pre(Evas_Object *obj);
38 static void _proxy_render_post(Evas_Object *obj);
39 static unsigned int _proxy_id_get(Evas_Object *obj);
40 static unsigned int _proxy_visual_id_get(Evas_Object *obj);
41 static void *_proxy_engine_data_get(Evas_Object *obj);
42
43 static int _proxy_is_opaque(Evas_Object *obj);
44 static int _proxy_was_opaque(Evas_Object *obj);
45 static int _proxy_can_map(Evas_Object *obj);
46
47 /*
48    void _proxy_store (Evas_Object *obj);
49    void _proxy_unstore (Evas_Object *obj);
50
51    int  _proxy_is_visible (Evas_Object *obj);
52    int  _proxy_was_visible (Evas_Object *obj);
53
54    int  _proxy_is_inside (Evas_Object *obj, Evas_Coord x, Evas_Coord y);
55    int  _proxy_was_inside (Evas_Object *obj, Evas_Coord x, Evas_Coord y);
56
57    void _proxy_coords_recalc (Evas_Object *obj);
58    void _proxy_scale_update (Evas_Object *obj);
59
60    int _proxy_has_opaque_rect (Evas_Object *obj);
61    int _proxy_get_opaque_rect (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
62 */
63
64
65
66 static const Evas_Object_Func object_func =
67 {
68   /* Required */
69   .free = _proxy_free,
70   .render = _proxy_render,
71   .render_pre = _proxy_render_pre,
72   .render_post = _proxy_render_post,
73
74   .type_id_get = _proxy_id_get,
75   .visual_id_get = _proxy_visual_id_get,
76   .engine_data_get = _proxy_engine_data_get,
77
78   .is_opaque = _proxy_is_opaque,
79   .was_opaque = _proxy_was_opaque,
80
81   /* Optional
82   .store =
83
84   .is_visible =
85   .was_visible =
86
87   .is_inside =
88   .was_inside =
89
90   .coords_recalc =
91   .scale_update =
92
93   .has_opaque_rect =
94   .get_opaque_rect =
95   */
96
97   .can_map = _proxy_can_map,
98 };
99
100
101 EAPI Evas_Object *
102 evas_object_proxy_add(Evas *e)
103 {
104    Evas_Object *obj;
105    Evas_Object_Proxy *o;
106
107    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
108       return NULL;
109    MAGIC_CHECK_END();
110
111    obj = evas_object_new(e);
112    evas_object_proxy_init(obj);
113    evas_object_inject(obj, e);
114
115    o = obj->object_data;
116
117    /* Do stuff here */
118
119    return obj;
120 }
121
122 EAPI Eina_Bool
123 evas_object_proxy_source_set(Evas_Object *obj, Evas_Object *src)
124 {
125    Evas_Object_Proxy *o,*so;
126
127    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
128    return false;
129    MAGIC_CHECK_END();
130    o = obj->object_data;
131    MAGIC_CHECK(o, Evas_Object_Proxy, MAGIC_OBJ_PROXY);
132    return false;
133    MAGIC_CHECK_END();
134
135    if (o->source == src) return true;
136
137    if (src)
138      {
139         MAGIC_CHECK(src, Evas_Object, MAGIC_OBJ);
140         return false;
141         MAGIC_CHECK_END();
142         so = src->object_data;
143         /* Stop the loop _now_ */
144         /* FIXME: Should I check for smarts that contain proxies too? */
145         if (so->magic == MAGIC_OBJ_PROXY)
146            return false;
147      }
148
149    if (o->source)
150      {
151         _proxy_unset(obj);
152      }
153
154    if (src)
155      {
156         _proxy_set(obj, src);
157      }
158
159    return true;
160 }
161
162 EAPI Evas_Object *
163 evas_object_proxy_source_get(Evas_Object *obj)
164 {
165    Evas_Object_Proxy *o;
166
167    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
168    return NULL;
169    MAGIC_CHECK_END();
170    o = obj->object_data;
171    MAGIC_CHECK(o, Evas_Object_Proxy, MAGIC_OBJ_PROXY);
172    return NULL;
173    MAGIC_CHECK_END();
174
175    return o->source;
176 }
177
178 EAPI Eina_Bool
179 evas_object_proxy_source_unset(Evas_Object *o)
180 {
181    return evas_object_proxy_source_set(o, NULL);
182 }
183
184
185
186
187 /* Internal helpers */
188 static void
189 evas_object_proxy_init(Evas_Object *obj)
190 {
191    obj->object_data = evas_object_proxy_new();
192    obj->cur.color.r =obj->cur.color.g =obj->cur.color.b =obj->cur.color.a = 255;
193    obj->cur.geometry.x = obj->cur.geometry.y = 0;
194    obj->cur.geometry.w = obj->cur.geometry.h = 0;
195    obj->cur.layer = 0;
196    obj->cur.anti_alias = 0;
197    obj->cur.render_op = EVAS_RENDER_BLEND;
198    obj->prev = obj->cur;
199
200    obj->func = &object_func;
201    obj->type = o_type;
202 }
203
204 static Evas_Object_Proxy *
205 evas_object_proxy_new(void)
206 {
207    Evas_Object_Proxy *o;
208
209    o = calloc(1,sizeof(Evas_Object_Proxy));
210    o->magic = MAGIC_OBJ_PROXY;
211    o->source = NULL;
212    return o;
213 }
214
215
216 static void
217 _proxy_unset(Evas_Object *proxy)
218 {
219    Evas_Object_Proxy *o;
220
221    o = proxy->object_data;
222    if (!o->source) return;
223
224    o->source->proxy.proxies = eina_list_remove(o->source->proxy.proxies, proxy);
225
226    o->source = NULL;
227 }
228
229
230 static void
231 _proxy_set(Evas_Object *proxy, Evas_Object *src)
232 {
233    Evas_Object_Proxy *o;
234
235    o = proxy->object_data;
236
237    o->source = src;
238
239    src->proxy.proxies = eina_list_append(src->proxy.proxies, proxy);
240    src->proxy.redraw = EINA_TRUE;
241    o->mapupdate = EINA_TRUE;
242 }
243
244
245
246 static void
247 _proxy_free(Evas_Object *obj)
248 {
249    Evas_Object_Proxy *o;
250
251    o = obj->object_data;
252    MAGIC_CHECK(o, Evas_Object_Proxy, MAGIC_OBJ_PROXY);
253       return;
254    MAGIC_CHECK_END();
255
256    if (o->source) _proxy_unset(obj);
257    if (o->defmap) evas_map_free(o->defmap);
258    o->magic = 0;
259    free(o);
260 }
261
262 static void
263 _proxy_map_update(Evas_Object *obj)
264 {
265    Evas_Object_Proxy *o;
266    int x,y, w, h;
267    int sw,sh;
268    Evas_Map *m;
269
270    o = obj->object_data;
271
272    if (!o->source) return;
273    o->mapupdate = EINA_FALSE;
274
275
276    x = obj->cur.geometry.x;
277    y = obj->cur.geometry.y;
278    w = obj->cur.geometry.w;
279    h = obj->cur.geometry.h;
280    sw = o->source->proxy.w;
281    sh = o->source->proxy.h;
282
283    if (!o->defmap)
284       o->defmap = evas_map_new(4);
285    m = o->defmap;
286
287    evas_map_point_coord_set   (m, 0, x, y, 0);
288    evas_map_point_image_uv_set(m, 0, 0, 0);
289    evas_map_point_color_set   (m, 0, 255, 255, 255, 255);
290
291    evas_map_point_coord_set   (m, 1, x + w, y, 0);
292    evas_map_point_image_uv_set(m, 1, sw, 0);
293    evas_map_point_color_set   (m, 1, 255, 255, 255, 255);
294
295    evas_map_point_coord_set   (m, 2, x + w, y + h, 0);
296    evas_map_point_image_uv_set(m, 2, sw, sh);
297    evas_map_point_color_set   (m, 2, 255, 255, 255, 255);
298
299    evas_map_point_coord_set   (m, 3, x, y + h, 0);
300    evas_map_point_image_uv_set(m, 3, 0, sh);
301    evas_map_point_color_set   (m, 3, 255, 255, 255, 255);
302
303 }
304
305
306 static void
307 _proxy_render(Evas_Object *obj, void *output, void *context,
308               void *surface, int x, int y)
309 {
310    Evas_Object_Proxy *o;
311    void *pixels;
312    int w,h;
313
314    o = obj->object_data;
315
316    if (!o->source) return;
317
318 //   ENFN->context_multiplier_unset(output, context);
319   // ENFN->context_render_op_set(output, context, obj->cur.render_op);
320
321    if (o->source->proxy.surface && o->source->proxy.redraw == EINA_FALSE)
322      {
323          pixels = o->source->proxy.surface;
324      }
325    /* Making this faster would be nice... */
326    else if (strcmp(evas_object_type_get(o->source),"image") == 0)
327      {
328         pixels = o->source->func->engine_data_get(o->source);
329         evas_object_image_size_get(o->source, &o->source->proxy.w,
330                                    &o->source->proxy.h);
331      }
332    else
333      {
334          _proxy_subrender(obj->layer->evas, o->source);
335          pixels = o->source->proxy.surface;
336      }
337
338    if (o->mapupdate) _proxy_map_update(obj);
339
340    if (!pixels)
341      {
342         return;
343      }
344
345    w = obj->cur.geometry.w;
346    h = obj->cur.geometry.h;
347
348    /* If we have a map: Use that */
349    if (ALWAYS_MAP ||
350        ((obj->cur.map) && (obj->cur.map->count == 4) && (obj->cur.usemap)))
351      {
352         const Evas_Map_Point *p, *p_end;
353         RGBA_Map_Point pts[4], *pt;
354         Evas_Map *map;
355
356         if (!obj->cur.usemap || !obj->cur.map)
357            map = o->defmap;
358         else
359            map = obj->cur.map;
360
361         p = map->points;
362         p_end = p + 4;
363         pt = pts;
364
365         pts[0].px = map->persp.px << FP;
366         pts[0].py = map->persp.py << FP;
367         pts[0].foc = map->persp.foc << FP;
368         pts[0].z0 = map->persp.z0 << FP;
369
370         pts[0].px = map->persp.px << FP;
371         pts[0].py = map->persp.py << FP;
372         pts[0].foc = map->persp.foc << FP;
373         pts[0].z0 = map->persp.z0 << FP;
374         // draw geom +x +y
375         for (; p < p_end; p++, pt++)
376           {
377              pt->x = (p->x + x) << FP;
378              pt->y = (p->y + y) << FP;
379              pt->z = (p->z)     << FP;
380              pt->x3 = p->px << FP;
381              pt->y3 = p->py << FP;
382              pt->u = p->u * FP1;
383              pt->v = p->v * FP1;
384              pt->col = ARGB_JOIN(p->a, p->r, p->g, p->b);
385           }
386         obj->layer->evas->engine.func->image_map4_draw
387            (output, context, surface, pixels, pts, map->smooth, 0);
388      }
389    else
390      {
391         obj->layer->evas->engine.func->image_draw(output, context,
392                                              surface, pixels,
393                                              0, 0,
394                                              w, h,
395                                              obj->cur.geometry.x + /*ix +*/ x,
396                                              obj->cur.geometry.y + /*iy +*/ y,
397                                              w, h,/* was iw,ih */
398                                              1);
399      }
400 }
401
402 /**
403  * Render the subobject
404  */
405 static void
406 _proxy_subrender(Evas *e, Evas_Object *source)
407 {
408    void *ctx;
409    Evas_Object *obj2;
410    int w,h;
411
412    if (!source) return;
413
414    w = source->cur.geometry.w;
415    h = source->cur.geometry.h;
416
417    source->proxy.redraw = EINA_FALSE;
418
419    /* We need to redraw surface then */
420    if (source->proxy.surface && (source->proxy.w != w || source->proxy.h != h))
421      {
422         e->engine.func->image_map_surface_free(e->engine.data.output,
423                                                source->proxy.surface);
424         source->proxy.surface = NULL;
425      }
426
427    /* FIXME: Hardcoded alpha 'on' */
428    /* FIXME (cont): Should see if the object has alpha */
429    if (!source->proxy.surface)
430      {
431         source->proxy.surface = e->engine.func->image_map_surface_new(
432            e->engine.data.output, w, h, 1);
433         source->proxy.w = w;
434         source->proxy.h = w;
435      }
436
437    ctx = e->engine.func->context_new(e->engine.data.output);
438    e->engine.func->context_color_set(e->engine.data.output, ctx, 0, 0, 0, 0);
439    e->engine.func->context_render_op_set(e->engine.data.output, ctx, EVAS_RENDER_COPY);
440    e->engine.func->rectangle_draw(e->engine.data.output, ctx,
441                                   source->proxy.surface, 0, 0, w, h);
442    e->engine.func->context_free(e->engine.data.output, ctx);
443
444    ctx = e->engine.func->context_new(e->engine.data.output);
445    if (source->smart.smart)
446      {
447         EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(source), obj2){
448            obj2->func->render(obj2, e->engine.data.output, ctx,
449                               source->proxy.surface,
450                               -source->cur.geometry.x,
451                               -source->cur.geometry.y);
452         }
453      }
454    else
455      {
456         source->func->render(source, e->engine.data.output, ctx,
457                                     source->proxy.surface,
458                                     -source->cur.geometry.x,
459                                     -source->cur.geometry.y);
460      }
461    e->engine.func->context_free(e->engine.data.output, ctx);
462
463 }
464
465 static void
466 _proxy_render_pre(Evas_Object *obj)
467 {
468    Evas_Object_Proxy *o;
469    Evas *e;
470    int was_v, is_v;
471
472    if (obj->pre_render_done) return;
473    obj->pre_render_done = 1;
474
475    e = obj->layer->evas;
476    o = obj->object_data;
477
478    is_v = evas_object_is_visible(obj);
479    was_v = evas_object_was_visible(obj);
480
481    if (is_v != was_v)
482      {
483         evas_object_render_pre_visible_change(&e->clip_changes, obj, is_v, was_v);
484      }
485    if (((obj->cur.geometry.x != obj->prev.geometry.x) ||
486         (obj->cur.geometry.y != obj->prev.geometry.y) ||
487         (obj->cur.geometry.w != obj->prev.geometry.w) ||
488         (obj->cur.geometry.h != obj->prev.geometry.h))
489        )
490      {
491         evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
492         o->mapupdate = EINA_TRUE;
493      }
494
495    if (o->source && o->source->proxy.redraw)
496      {
497         evas_add_rect(&e->clip_changes,
498                       obj->cur.geometry.x, obj->cur.geometry.y,
499                       obj->cur.geometry.w, obj->cur.geometry.h);
500         o->mapupdate = EINA_TRUE;
501      }
502
503    evas_object_render_pre_effect_updates(&e->clip_changes, obj, is_v, was_v);
504 }
505 static void
506 _proxy_render_post(Evas_Object *obj)
507 {
508    Evas_Object_Proxy *o;
509
510    o = obj->object_data;
511
512    evas_object_clip_changes_clean(obj);
513    /* move cur to prev safely for object data */
514    obj->prev = obj->cur;
515    obj->changed = 0;
516 }
517 static unsigned int
518 _proxy_id_get(Evas_Object *obj)
519 {
520    return obj->object_data ? MAGIC_OBJ_PROXY : 0;
521 }
522 static unsigned int
523 _proxy_visual_id_get(Evas_Object *obj)
524 {
525    return obj->object_data ? MAGIC_OBJ_PROXY : 0;
526 }
527
528 static void *
529 _proxy_engine_data_get(Evas_Object *obj)
530 {
531    return ((Evas_Object_Proxy *)obj->object_data)->engine_data;
532 }
533
534
535 static int
536 _proxy_is_opaque(Evas_Object *obj)
537 {
538    Evas_Object_Proxy *o = obj->object_data;
539
540    /* No source: Sure, it's opaque */
541    if (!o->source) return 1;
542    return 0;
543 }
544
545 static int
546 _proxy_was_opaque(Evas_Object *obj)
547 {
548    Evas_Object_Proxy *o = obj->object_data;
549
550    /* No source: Sure, it's opaque */
551    if (!o->source) return 1;
552    return 0;
553 }
554
555 static int
556 _proxy_can_map (Evas_Object *obj)
557 {
558    /* Of course it can: that's the bloody point */
559    return 1;
560 }
561
562
563
564
565
566
567
568
569
570 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/