1 
2 #include "evas_image_private.h"
3 
4 #define MY_CLASS      EFL_CANVAS_IMAGE_INTERNAL_CLASS
5 #define MY_CLASS_NAME "Evas_Image"
6 
7 /* private magic number for image objects */
8 static const char o_type[] = "image";
9 
10 const char *o_image_type = o_type;
11 
12 /* private methods for image objects */
13 static Evas_Coord   evas_object_image_figure_x_fill(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret);
14 static Evas_Coord   evas_object_image_figure_y_fill(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret);
15 
16 static void         evas_object_image_init(Evas_Object *eo_obj);
17 
18 static inline uint32_t _stretch_region_accumulate(uint8_t *stretch_region, Eina_Bool mask, uint32_t *i);
19 
20 static void         evas_object_image_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
21                                              void *type_private_data,
22                                              void *engine, void *output, void *context, void *surface,
23                                              int x, int y, Eina_Bool do_async);
24 static void         _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
25                                        void *engine, void *output, void *context, void *surface,
26                                        int x, int y, int l, int t, int r, int b, Eina_Bool skip_map, Eina_Bool do_async);
27 static void         evas_object_image_free(Evas_Object *eo_obj,
28                                            Evas_Object_Protected_Data *obj);
29 static void         evas_object_image_render_pre(Evas_Object *eo_obj,
30                                                  Evas_Object_Protected_Data *obj,
31                                                  void *type_private_data);
32 static void         evas_object_image_render_post(Evas_Object *eo_obj,
33                                                   Evas_Object_Protected_Data *obj,
34                                                   void *type_private_data);
35 
36 static void        *evas_object_image_engine_data_get(Evas_Object *eo_obj);
37 
38 static int          evas_object_image_is_opaque(Evas_Object *eo_obj,
39                                                 Evas_Object_Protected_Data *obj,
40                                                 void *type_private_data);
41 static int          evas_object_image_was_opaque(Evas_Object *eo_obj,
42                                                  Evas_Object_Protected_Data *obj,
43                                                  void *type_private_data);
44 static int          evas_object_image_is_inside(Evas_Object *eo_obj,
45                                                 Evas_Object_Protected_Data *obj,
46                                                 void *type_private_data,
47                                                 Evas_Coord x, Evas_Coord y);
48 static int          evas_object_image_has_opaque_rect(Evas_Object *eo_obj,
49                                                       Evas_Object_Protected_Data *obj,
50                                                       void *type_private_data);
51 static int          evas_object_image_get_opaque_rect(Evas_Object *eo_obj,
52                                                       Evas_Object_Protected_Data *obj,
53                                                       void *type_private_data,
54                                                       Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
55 static int          evas_object_image_can_map(Evas_Object *eo_obj);
56 static void         evas_object_image_render_prepare(Evas_Object *obj, Evas_Object_Protected_Data *pd, Eina_Bool do_async);
57 
58 static void         evas_object_image_filled_resize_listener(void *data, Evas *eo_e, Evas_Object *eo_obj, void *einfo);
59 
60 static int          evas_object_image_is_on_plane(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data);
61 static int          evas_object_image_plane_changed(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data);
62 static const Evas_Object_Func object_func =
63 {
64    /* methods (compulsory) */
65    NULL,
66    evas_object_image_render,
67    evas_object_image_render_pre,
68    evas_object_image_render_post,
69    evas_object_image_engine_data_get,
70    /* these are optional. NULL = nothing */
71    NULL,
72    NULL,
73    evas_object_image_is_opaque,
74    evas_object_image_was_opaque,
75    evas_object_image_is_inside,
76    NULL,
77    NULL,
78    evas_object_image_has_opaque_rect,
79    evas_object_image_get_opaque_rect,
80    evas_object_image_can_map,
81    evas_object_image_render_prepare,   // render_prepare
82    evas_object_image_is_on_plane,
83    evas_object_image_plane_changed
84 };
85 
86 static const Evas_Object_Image_Load_Opts default_load_opts = {
87    0, 0.0, 0, 0, { 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, 0
88 };
89 
90 static const Evas_Object_Image_Pixels default_pixels = {
91    NULL, { NULL, NULL }, NULL, { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, ~0x0
92 };
93 
94 static const Evas_Object_Image_State default_state = {
95    { 0, 0, 0, 0 }, // fill
96    { 0, 0, 0 }, // image
97    { 1.0, 0, 0, 0, 0, 1 }, // border
98    { { NULL, 0, 0 }, { NULL, 0, 0 } },
99    NULL, NULL, //source, defmap
100    NULL, //f
101    NULL, //key
102    0, //frame
103    EVAS_COLORSPACE_ARGB8888,
104    EVAS_IMAGE_ORIENT_NONE,
105 
106    EINA_TRUE, // smooth
107    EINA_FALSE, // has_alpha
108    EINA_FALSE, // opaque_valid
109    EINA_FALSE // opaque
110 };
111 
112 Eina_Cow *evas_object_image_load_opts_cow = NULL;
113 Eina_Cow *evas_object_image_pixels_cow = NULL;
114 Eina_Cow *evas_object_image_state_cow = NULL;
115 
116 static void
evas_object_image_render_prepare(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj EINA_UNUSED,Eina_Bool do_async EINA_UNUSED)117 evas_object_image_render_prepare(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
118 {
119 #if 0
120    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
121 
122    // if image data not loaded or in texture then upload
123    if ((o->cur->f) || (o->written) || (o->cur->frame != 0))
124      {
125         if (o->engine_data) ENFN->image_prepare(ENC, o->engine_data);
126      }
127 #endif
128    // XXX: if image is a proxy, PREPEND to prerender list in evas canvas
129 }
130 
131 static void *
_evas_object_image_output_find(Evas_Object_Protected_Data * obj)132 _evas_object_image_output_find(Evas_Object_Protected_Data *obj)
133 {
134    Efl_Canvas_Output *output;
135    Eina_List *l;
136    const Eina_Rectangle geometry = {
137      obj->cur->geometry.x,
138      obj->cur->geometry.y,
139      obj->cur->geometry.w,
140      obj->cur->geometry.h
141    };
142 
143    EINA_LIST_FOREACH(obj->layer->evas->outputs, l, output)
144      {
145         if (eina_rectangles_intersect(&output->geometry, &geometry))
146           return output->output;
147      }
148 
149    // Always return an output, as evas rely on that even if the object is out of screen.
150    output = eina_list_data_get(obj->layer->evas->outputs);
151    return output->output;
152 }
153 
154 void
_evas_image_cleanup(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,Evas_Image_Data * o)155 _evas_image_cleanup(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
156 {
157    /* Eina_Cow doesn't know if the resulting memory has changed, better check
158       before we change it */
159    if (o->cur->opaque_valid)
160      {
161         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
162         {
163            state_write->opaque_valid = 0;
164         }
165         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
166      }
167 
168    if ((o->preload & EVAS_IMAGE_PRELOADING) && (o->engine_data))
169      {
170         o->preload = EVAS_IMAGE_PRELOAD_NONE;
171         ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
172      }
173    if (o->cur->source) _evas_image_proxy_unset(eo_obj, obj, o);
174 }
175 
176 static Eina_Bool
_init_cow(void)177 _init_cow(void)
178 {
179    if (!evas_object_image_load_opts_cow ||
180        !evas_object_image_pixels_cow ||
181        !evas_object_image_state_cow)
182      {
183         evas_object_image_load_opts_cow = eina_cow_add("Evas_Object_Image load opts",
184                                                        sizeof (Evas_Object_Image_Load_Opts),
185                                                        8,
186                                                        &default_load_opts,
187                                                        EINA_TRUE);
188         evas_object_image_pixels_cow = eina_cow_add("Evas_Object_Image pixels",
189                                                     sizeof (Evas_Object_Image_Pixels),
190                                                     8,
191                                                     &default_pixels,
192                                                     EINA_TRUE);
193         evas_object_image_state_cow = eina_cow_add("Evas_Object_Image states",
194                                                    sizeof (Evas_Object_Image_State),
195                                                    8,
196                                                    &default_state,
197                                                    EINA_TRUE);
198      }
199    if (!evas_object_image_load_opts_cow ||
200        !evas_object_image_pixels_cow ||
201        !evas_object_image_state_cow)
202      {
203         ERR("Failed to init cow.");
204         return EINA_FALSE;
205      }
206 
207    return EINA_TRUE;
208 }
209 
210 EOLIAN static Eo *
_efl_canvas_image_internal_efl_object_constructor(Eo * eo_obj,Evas_Image_Data * o)211 _efl_canvas_image_internal_efl_object_constructor(Eo *eo_obj, Evas_Image_Data *o)
212 {
213    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
214    Evas_Colorspace cspace;
215 
216    eo_obj = efl_constructor(efl_super(eo_obj, MY_CLASS));
217 
218    evas_object_image_init(eo_obj);
219 
220    if (!_init_cow())
221      return NULL;
222 
223    o->load_opts = eina_cow_alloc(evas_object_image_load_opts_cow);
224    o->pixels = eina_cow_alloc(evas_object_image_pixels_cow);
225    o->cur = eina_cow_alloc(evas_object_image_state_cow);
226    o->prev = eina_cow_alloc(evas_object_image_state_cow);
227    o->proxy_src_clip = EINA_TRUE;
228 
229    cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
230    if (cspace != o->cur->cspace)
231      {
232         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
233         state_write->cspace = cspace;
234         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
235      }
236 
237    return eo_obj;
238 }
239 
240 EOLIAN static Eo *
_efl_canvas_image_internal_efl_object_finalize(Eo * eo_obj,Evas_Image_Data * o)241 _efl_canvas_image_internal_efl_object_finalize(Eo *eo_obj, Evas_Image_Data *o)
242 {
243    if (!o->filled_set)
244      efl_gfx_fill_auto_set(eo_obj, EINA_TRUE);
245    return efl_finalize(efl_super(eo_obj, MY_CLASS));
246 }
247 
248 void
_evas_image_init_set(const Eina_File * f,const char * key,Eo * eo_obj,Evas_Object_Protected_Data * obj,Evas_Image_Data * o,Evas_Image_Load_Opts * lo)249 _evas_image_init_set(const Eina_File *f, const char *key,
250                      Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o,
251                      Evas_Image_Load_Opts *lo)
252 {
253    if (o->cur->source) _evas_image_proxy_unset(eo_obj, obj, o);
254 
255    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
256    {
257       Eina_File *tmp =  state_write->f;
258 
259       state_write->f = NULL;
260 
261       if (f) state_write->f = eina_file_dup(f);
262       eina_file_close(tmp); // close matching open (dup above) OK
263 
264       eina_stringshare_replace(&state_write->key, key);
265       state_write->opaque_valid = 0;
266    }
267    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
268 
269    if (o->prev->f != NULL || o->prev->key != NULL)
270      {
271         EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
272         {
273            state_write->f = NULL;
274            state_write->key = NULL;
275         }
276         EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
277      }
278 
279    if (o->engine_data)
280      {
281         if (o->preload & EVAS_IMAGE_PRELOADING)
282           {
283              o->preload = EVAS_IMAGE_PRELOAD_NONE;
284              ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
285           }
286         ENFN->image_free(ENC, o->engine_data);
287      }
288    o->engine_data = NULL;
289    o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_NONE;
290    if (!lo) return;
291    lo->emile.scale_down_by = o->load_opts->scale_down_by;
292    lo->emile.dpi = o->load_opts->dpi;
293    lo->emile.w = o->load_opts->w;
294    lo->emile.h = o->load_opts->h;
295    lo->emile.region.x = o->load_opts->region.x;
296    lo->emile.region.y = o->load_opts->region.y;
297    lo->emile.region.w = o->load_opts->region.w;
298    lo->emile.region.h = o->load_opts->region.h;
299    lo->emile.scale_load.src_x = o->load_opts->scale_load.src_x;
300    lo->emile.scale_load.src_y = o->load_opts->scale_load.src_y;
301    lo->emile.scale_load.src_w = o->load_opts->scale_load.src_w;
302    lo->emile.scale_load.src_h = o->load_opts->scale_load.src_h;
303    lo->emile.scale_load.dst_w = o->load_opts->scale_load.dst_w;
304    lo->emile.scale_load.dst_h = o->load_opts->scale_load.dst_h;
305    lo->emile.scale_load.smooth = o->load_opts->scale_load.smooth;
306    lo->emile.scale_load.scale_hint = o->load_opts->scale_load.scale_hint;
307    lo->emile.orientation = o->load_opts->orientation;
308    lo->emile.degree = 0;
309    lo->skip_head = o->skip_head;
310 }
311 
312 void
_evas_image_done_set(Eo * eo_obj,Evas_Object_Protected_Data * obj,Evas_Image_Data * o)313 _evas_image_done_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
314 {
315    Eina_Bool resize_call = EINA_FALSE;
316 
317    if (o->engine_data)
318      {
319         int w, h;
320         int stride;
321         Evas_Image_Orient orient;
322 
323         ENFN->image_size_get(ENC, o->engine_data, &w, &h);
324         if (ENFN->image_stride_get)
325           ENFN->image_stride_get(ENC, o->engine_data, &stride);
326         else
327           stride = w * 4;
328         orient = ENFN->image_orient_get(ENC, o->engine_data);
329 
330         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
331         {
332            state_write->has_alpha = ENFN->image_alpha_get(ENC, o->engine_data);
333            state_write->cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
334 
335            if ((o->cur->image.w != w) || (o->cur->image.h != h))
336              resize_call = EINA_TRUE;
337 
338            state_write->image.w = w;
339            state_write->image.h = h;
340            state_write->image.stride = stride;
341            state_write->orient = orient;
342         }
343         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
344      }
345    else
346      {
347         if (o->load_error == EFL_GFX_IMAGE_LOAD_ERROR_NONE)
348           o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
349 
350         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
351         {
352            state_write->has_alpha = EINA_TRUE;
353            state_write->cspace = EVAS_COLORSPACE_ARGB8888;
354 
355            if ((state_write->image.w != 0) || (state_write->image.h != 0))
356              resize_call = EINA_TRUE;
357 
358            state_write->image.w = 0;
359            state_write->image.h = 0;
360            state_write->image.stride = 0;
361            state_write->orient = EVAS_IMAGE_ORIENT_NONE;
362         }
363         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
364      }
365    o->file_size.w = 0;
366    o->file_size.h = 0;
367    o->written = EINA_FALSE;
368    o->changed = EINA_TRUE;
369    if (resize_call) evas_object_inform_call_image_resize(eo_obj);
370    evas_object_change(eo_obj, obj);
371 }
372 
373 void
_evas_image_orientation_set(Eo * eo_obj,Evas_Image_Data * o,Evas_Image_Orient orient)374 _evas_image_orientation_set(Eo *eo_obj, Evas_Image_Data *o, Evas_Image_Orient orient)
375 {
376    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
377    int iw, ih;
378 
379    if (o->cur->orient == orient) return;
380 
381    if ((o->preload & EVAS_IMAGE_PRELOADING) && (o->engine_data))
382      {
383         o->preload = EVAS_IMAGE_PRELOAD_NONE;
384         ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_TRUE);
385      }
386 
387    if (o->engine_data)
388      {
389         int stride = 0;
390 
391         o->engine_data = ENFN->image_orient_set(ENC, o->engine_data, orient);
392         if (o->engine_data)
393           {
394              ENFN->image_size_get(ENC, o->engine_data, &iw, &ih);
395 
396              if (ENFN->image_stride_get)
397                ENFN->image_stride_get(ENC, o->engine_data, &stride);
398              else
399                stride = iw * 4;
400 
401              EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
402              {
403                 state_write->image.w = iw;
404                 state_write->image.h = ih;
405                 state_write->orient = orient;
406                 state_write->image.stride = stride;
407              }
408              EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
409              o->written = EINA_TRUE;
410           }
411      }
412    o->changed = EINA_TRUE;
413    evas_object_change(eo_obj, obj);
414 }
415 
416 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_orientable_image_orientation_set(Eo * obj,Evas_Image_Data * o,Efl_Gfx_Image_Orientation efl_orient)417 _efl_canvas_image_internal_efl_gfx_image_orientable_image_orientation_set(Eo *obj, Evas_Image_Data *o, Efl_Gfx_Image_Orientation efl_orient)
418 {
419    // This array takes an Efl_Gfx_Image_Orientation and turns it into an Elm_Image_Orient
420    static const Evas_Image_Orient evas_orient[16] = {
421       EVAS_IMAGE_ORIENT_NONE,     // EFL_GFX_IMAGE_ORIENTATION_NONE
422       EVAS_IMAGE_ORIENT_90,       // EFL_GFX_IMAGE_ORIENTATION_RIGHT
423       EVAS_IMAGE_ORIENT_180,      // EFL_GFX_IMAGE_ORIENTATION_DOWN
424       EVAS_IMAGE_ORIENT_270,      // EFL_GFX_IMAGE_ORIENTATION_LEFT
425       EVAS_IMAGE_FLIP_HORIZONTAL, // EFL_GFX_IMAGE_ORIENTATION_NONE  + FLIP_HOR
426       EVAS_IMAGE_FLIP_TRANSPOSE,  // EFL_GFX_IMAGE_ORIENTATION_RIGHT + FLIP_HOR
427       EVAS_IMAGE_FLIP_VERTICAL,   // EFL_GFX_IMAGE_ORIENTATION_DOWN  + FLIP_HOR
428       EVAS_IMAGE_FLIP_TRANSVERSE, // EFL_GFX_IMAGE_ORIENTATION_LEFT  + FLIP_HOR
429       EVAS_IMAGE_FLIP_VERTICAL,   // EFL_GFX_IMAGE_ORIENTATION_NONE  + FLIP_VER
430       EVAS_IMAGE_FLIP_TRANSVERSE, // EFL_GFX_IMAGE_ORIENTATION_RIGHT + FLIP_VER
431       EVAS_IMAGE_FLIP_HORIZONTAL, // EFL_GFX_IMAGE_ORIENTATION_DOWN  + FLIP_VER
432       EVAS_IMAGE_FLIP_TRANSPOSE,  // EFL_GFX_IMAGE_ORIENTATION_LEFT  + FLIP_VER
433       EVAS_IMAGE_ORIENT_180,      // EFL_GFX_IMAGE_ORIENTATION_NONE  + FLIP_HOR + FLIP_VER
434       EVAS_IMAGE_ORIENT_270,      // EFL_GFX_IMAGE_ORIENTATION_RIGHT + FLIP_HOR + FLIP_VER
435       EVAS_IMAGE_ORIENT_0,        // EFL_GFX_IMAGE_ORIENTATION_DOWN  + FLIP_HOR + FLIP_VER
436       EVAS_IMAGE_ORIENT_90        // EFL_GFX_IMAGE_ORIENTATION_LEFT  + FLIP_HOR + FLIP_VER
437    };
438    EINA_SAFETY_ON_FALSE_RETURN(efl_orient >= 0 && efl_orient < 16);
439 
440    o->orient_value = efl_orient;
441    _evas_image_orientation_set(obj, o, evas_orient[efl_orient]);
442 }
443 
444 EOLIAN static Efl_Gfx_Image_Orientation
_efl_canvas_image_internal_efl_gfx_image_orientable_image_orientation_get(const Eo * obj EINA_UNUSED,Evas_Image_Data * o)445 _efl_canvas_image_internal_efl_gfx_image_orientable_image_orientation_get(const Eo *obj EINA_UNUSED, Evas_Image_Data *o)
446 {
447    return o->orient_value;
448 }
449 
450 EOLIAN static void
_efl_canvas_image_internal_efl_object_dbg_info_get(Eo * eo_obj,Evas_Image_Data * o,Efl_Dbg_Info * root)451 _efl_canvas_image_internal_efl_object_dbg_info_get(Eo *eo_obj, Evas_Image_Data *o, Efl_Dbg_Info *root)
452 {
453    efl_dbg_info_get(efl_super(eo_obj, MY_CLASS), root);
454    Efl_Dbg_Info *group = EFL_DBG_INFO_LIST_APPEND(root, MY_CLASS_NAME);
455 
456    const char *file, *key;
457    file = eina_file_filename_get(o->cur->f);
458    key = o->cur->key;
459 
460    EFL_DBG_INFO_APPEND(group, "Image File", EINA_VALUE_TYPE_STRING, file);
461    EFL_DBG_INFO_APPEND(group, "Key", EINA_VALUE_TYPE_STRING, key);
462    EFL_DBG_INFO_APPEND(group, "Source", EINA_VALUE_TYPE_UINT64,
463                        (uint64_t)(uintptr_t)evas_object_image_source_get(eo_obj));
464 }
465 
466 static void
_stretch_region_load(Evas_Object_Protected_Data * obj,Evas_Image_Data * o)467 _stretch_region_load(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
468 {
469    unsigned int i;
470    uint8_t *horizontal = NULL;
471    uint8_t *vertical = NULL;
472    uint32_t total, stretchable;
473 
474    if (o->cur->stretch_loaded == EINA_TRUE ||
475        (o->cur->stretch.horizontal.region && o->cur->stretch.vertical.region))
476      return ;
477 
478    ENFN->image_stretch_region_get(ENC, o->engine_data,
479                                 &horizontal,
480                                 &vertical);
481 
482    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
483    {
484       state_write->stretch.horizontal.region = horizontal;
485       state_write->stretch.vertical.region = vertical;
486       state_write->free_stretch = EINA_FALSE;
487       state_write->stretch_loaded = EINA_TRUE;
488    }
489    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
490 
491    if (!o->cur->stretch.horizontal.region || !o->cur->stretch.vertical.region)
492      return ;
493 
494    stretchable = 0;
495    total = 0;
496    for (i = 0; o->cur->stretch.horizontal.region[i]; i++)
497      {
498         total += o->cur->stretch.horizontal.region[i] & 0x7F;
499         if (o->cur->stretch.horizontal.region[i] & 0x80)
500           stretchable += o->cur->stretch.horizontal.region[i] & 0x7F;
501      }
502 
503    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
504    {
505       state_write->stretch.horizontal.stretchable = stretchable;
506       state_write->stretch.horizontal.total = total;
507    }
508    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
509 
510    stretchable = 0;
511    total = 0;
512    for (i = 0; o->cur->stretch.vertical.region[i]; i++)
513      {
514         total += o->cur->stretch.vertical.region[i] & 0x7F;
515         if (o->cur->stretch.vertical.region[i] & 0x80)
516           stretchable += o->cur->stretch.vertical.region[i] & 0x7F;
517      }
518 
519    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
520    {
521       state_write->stretch.vertical.stretchable = stretchable;
522       state_write->stretch.vertical.total = total;
523    }
524    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
525 }
526 
527 static Eina_Rect
_efl_canvas_image_internal_efl_gfx_image_content_region_get(const Eo * eo_obj,Evas_Image_Data * o)528 _efl_canvas_image_internal_efl_gfx_image_content_region_get(const Eo *eo_obj, Evas_Image_Data *o)
529 {
530    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
531    Eina_Rect r;
532 
533    if (!o->cur->stretch.horizontal.region &&
534        !o->cur->stretch.vertical.region)
535      _stretch_region_load(obj, o);
536 
537    if (o->cur->stretch.horizontal.region &&
538        o->cur->stretch.vertical.region)
539      {
540         uint32_t acc;
541         uint32_t hi = 0;
542         uint32_t vi = 0;
543 
544         // If the file come with a defined content zone, then return it
545         if (ENFN->image_content_region_get(ENC, o->engine_data, &r.rect))
546           {
547              // Correct bottom right corner coordinate to be resized with object size
548              r.w = obj->cur->geometry.w - (o->cur->image.w - r.w);
549              r.h = obj->cur->geometry.h - (o->cur->image.h - r.h);
550              return r;
551           }
552 
553         r.x = _stretch_region_accumulate(o->cur->stretch.horizontal.region, 0, &hi);
554         r.w = o->cur->stretch.horizontal.stretchable + obj->cur->geometry.w - o->cur->image.w;
555 
556         // Accumulate all the non stretch zone, except the first one and the last one
557         acc = 0;
558         while (o->cur->stretch.horizontal.region[hi])
559           {
560              // We are just ignoring all the stretchable zone as we know them already
561              _stretch_region_accumulate(o->cur->stretch.horizontal.region, 0x80, &hi);
562              r.w += acc;
563              acc = _stretch_region_accumulate(o->cur->stretch.horizontal.region, 0, &hi);
564           }
565 
566         r.y = _stretch_region_accumulate(o->cur->stretch.vertical.region, 0, &vi);
567         r.h = o->cur->stretch.vertical.stretchable + obj->cur->geometry.h - o->cur->image.h;
568 
569         // Accumulate all the stretch zone, except the last non stretching one
570         acc = 0;
571         while (o->cur->stretch.vertical.region[vi])
572           {
573              // We are just ignoring all the stretchable zone as we know them already
574              _stretch_region_accumulate(o->cur->stretch.vertical.region, 0x80, &vi);
575              r.h += acc;
576              acc = _stretch_region_accumulate(o->cur->stretch.vertical.region, 0, &vi);
577           }
578      }
579    else
580      {
581         r.x = o->cur->border.l;
582         r.y = o->cur->border.t;
583         r.w = obj->cur->geometry.w - o->cur->border.l - o->cur->border.r;
584         r.h = obj->cur->geometry.h - o->cur->border.t - o->cur->border.b;
585      }
586 
587    return r;
588 }
589 
590 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_insets_set(Eo * eo_obj,Evas_Image_Data * o,int l,int r,int t,int b)591 _efl_canvas_image_internal_efl_gfx_image_border_insets_set(Eo *eo_obj, Evas_Image_Data *o, int l, int r, int t, int b)
592 {
593    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
594 
595    if (l < 0) l = 0;
596    if (r < 0) r = 0;
597    if (t < 0) t = 0;
598    if (b < 0) b = 0;
599    if ((o->cur->border.l == l) &&
600        (o->cur->border.r == r) &&
601        (o->cur->border.t == t) &&
602        (o->cur->border.b == b)) return;
603 
604    evas_object_async_block(obj);
605    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
606    {
607       state_write->border.l = l;
608       state_write->border.r = r;
609       state_write->border.t = t;
610       state_write->border.b = b;
611    }
612    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
613    o->changed = EINA_TRUE;
614    evas_object_change(eo_obj, obj);
615 }
616 
617 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_insets_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o,int * l,int * r,int * t,int * b)618 _efl_canvas_image_internal_efl_gfx_image_border_insets_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o, int *l, int *r, int *t, int *b)
619 {
620    if (l) *l = o->cur->border.l;
621    if (r) *r = o->cur->border.r;
622    if (t) *t = o->cur->border.t;
623    if (b) *b = o->cur->border.b;
624 }
625 
626 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_center_fill_mode_set(Eo * eo_obj,Evas_Image_Data * o,Efl_Gfx_Center_Fill_Mode _fill)627 _efl_canvas_image_internal_efl_gfx_image_center_fill_mode_set(Eo *eo_obj, Evas_Image_Data *o, Efl_Gfx_Center_Fill_Mode _fill)
628 {
629    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
630    Evas_Border_Fill_Mode fill = (Evas_Border_Fill_Mode)_fill;
631 
632    if (fill == o->cur->border.fill) return;
633    evas_object_async_block(obj);
634    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
635    state_write->border.fill = fill;
636    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
637 
638    o->changed = EINA_TRUE;
639    evas_object_change(eo_obj, obj);
640 }
641 
642 EOLIAN static Efl_Gfx_Center_Fill_Mode
_efl_canvas_image_internal_efl_gfx_image_center_fill_mode_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)643 _efl_canvas_image_internal_efl_gfx_image_center_fill_mode_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
644 {
645    return (Efl_Gfx_Center_Fill_Mode)o->cur->border.fill;
646 }
647 
648 static void
_toggle_fill_listener(Eo * eo_obj,Evas_Image_Data * o)649 _toggle_fill_listener(Eo *eo_obj, Evas_Image_Data *o)
650 {
651    if (!o->filled)
652      evas_object_event_callback_del(eo_obj, EVAS_CALLBACK_RESIZE,
653                                     evas_object_image_filled_resize_listener);
654    else
655      evas_object_event_callback_add(eo_obj, EVAS_CALLBACK_RESIZE,
656                                     evas_object_image_filled_resize_listener,
657                                     NULL);
658 }
659 
660 static inline Eina_Bool
_efl_canvas_image_internal_stretch_region_push(uint8_t ** stretch_region,uint32_t * stretch_region_length,const uint8_t region)661 _efl_canvas_image_internal_stretch_region_push(uint8_t **stretch_region,
662                                                uint32_t *stretch_region_length,
663                                                const uint8_t region)
664 {
665    uint8_t *tmp;
666 
667    tmp = realloc(*stretch_region, (*stretch_region_length + 1) * sizeof (uint8_t));
668    if (!tmp) return EINA_FALSE;
669    *stretch_region = tmp;
670    (*stretch_region)[*stretch_region_length] = region;
671    (*stretch_region_length) += 1;
672 
673    return EINA_TRUE;
674 }
675 
676 static inline Eina_Error
_efl_canvas_image_internal_stretch_region_build(uint8_t ** stretch_region,uint32_t * stretch_region_length,uint32_t value,uint8_t mask)677 _efl_canvas_image_internal_stretch_region_build(uint8_t **stretch_region,
678                                                 uint32_t *stretch_region_length,
679                                                 uint32_t value, uint8_t mask)
680 {
681    while (value > 0x7F)
682      {
683         if (!_efl_canvas_image_internal_stretch_region_push(stretch_region,
684                                                           stretch_region_length,
685                                                           mask | 0x7F))
686           {
687              free(*stretch_region);
688              return ENOMEM;
689           }
690 
691         value -= 0x7F;
692      }
693 
694    if (!value) return 0;
695 
696    if (!_efl_canvas_image_internal_stretch_region_push(stretch_region,
697                                                      stretch_region_length,
698                                                      mask | value))
699      {
700         free(*stretch_region);
701         return ENOMEM;
702      }
703 
704    return 0;
705 }
706 
707 static inline uint8_t *
_efl_canvas_image_internal_stretch_region_iterate(Eina_Iterator * it)708 _efl_canvas_image_internal_stretch_region_iterate(Eina_Iterator *it)
709 {
710    Efl_Gfx_Image_Stretch_Region sz;
711    uint8_t *stretch_region = NULL;
712    uint32_t stretch_region_length = 0;
713 
714    EINA_ITERATOR_FOREACH(it, sz)
715      {
716         if (_efl_canvas_image_internal_stretch_region_build(&stretch_region,
717                                                           &stretch_region_length,
718                                                           sz.offset, 0))
719           return NULL;
720 
721         // The upper bit means stretchable region if set
722         if (_efl_canvas_image_internal_stretch_region_build(&stretch_region,
723                                                           &stretch_region_length,
724                                                           sz.length, 0x80))
725           return NULL;
726      }
727 
728    if (!_efl_canvas_image_internal_stretch_region_push(&stretch_region,
729                                                      &stretch_region_length,
730                                                      0))
731      {
732         free(stretch_region);
733         return NULL;
734      }
735 
736    return stretch_region;
737 }
738 
739 static Eina_Error
_efl_canvas_image_internal_efl_gfx_image_stretch_region_set(Eo * eo_obj,Evas_Image_Data * pd,Eina_Iterator * horizontal,Eina_Iterator * vertical)740 _efl_canvas_image_internal_efl_gfx_image_stretch_region_set(Eo *eo_obj, Evas_Image_Data *pd,
741                                                             Eina_Iterator *horizontal,
742                                                             Eina_Iterator *vertical)
743 {
744    uint8_t *fhsz = NULL, *fvsz = NULL, *walk;
745    uint32_t hstretch = 0, vstretch = 0;
746    uint32_t htotal = 0, vtotal = 0;
747    Eina_Error err = EINVAL;
748    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
749 
750    // We do not duplicate the stretch region in memory, just move pointer. So when
751    // we do change it, we have to make sure nobody is accessing them anymore by
752    // blocking rendering.
753    evas_object_async_block(obj);
754    if (pd->cur->stretch.horizontal.region ||
755        pd->cur->stretch.vertical.region)
756      {
757         EINA_COW_IMAGE_STATE_WRITE_BEGIN(pd, state_write)
758         {
759            if (state_write->free_stretch) free(state_write->stretch.horizontal.region);
760            state_write->stretch.horizontal.region = NULL;
761 
762            if (state_write->free_stretch) free(state_write->stretch.vertical.region);
763            state_write->stretch.vertical.region = NULL;
764 
765            state_write->free_stretch = EINA_FALSE;
766            state_write->stretch_loaded = EINA_FALSE;
767         }
768         EINA_COW_IMAGE_STATE_WRITE_END(pd, state_write);
769      }
770 
771    if (!horizontal && !vertical) return 0;
772    if (!horizontal || !vertical) goto on_error;
773 
774    err = ENOMEM;
775 
776    fhsz = _efl_canvas_image_internal_stretch_region_iterate(horizontal);
777    if (!fhsz) goto on_error;
778    fvsz = _efl_canvas_image_internal_stretch_region_iterate(vertical);
779    if (!fvsz) goto on_error;
780 
781    for (walk = fhsz; *walk; walk++)
782      {
783         if ((*walk & 0x80)) hstretch += *walk & 0x7F;
784         htotal += *walk & 0x7F;
785      }
786 
787    for (walk = fvsz; *walk; walk++)
788      {
789         if ((*walk & 0x80)) vstretch += *walk & 0x7F;
790         vtotal += *walk & 0x7F;
791      }
792 
793    eina_iterator_free(horizontal);
794    eina_iterator_free(vertical);
795 
796    EINA_COW_IMAGE_STATE_WRITE_BEGIN(pd, state_write)
797    {
798       state_write->stretch.horizontal.region = fhsz;
799       state_write->stretch.horizontal.stretchable = hstretch;
800       state_write->stretch.horizontal.total = htotal;
801       state_write->stretch.vertical.region = fvsz;
802       state_write->stretch.vertical.stretchable = vstretch;
803       state_write->stretch.vertical.total = vtotal;
804       state_write->free_stretch = EINA_TRUE;
805       state_write->stretch_loaded = EINA_TRUE;
806    }
807    EINA_COW_IMAGE_STATE_WRITE_END(pd, state_write);
808 
809    return 0;
810 
811  on_error:
812    eina_iterator_free(horizontal);
813    eina_iterator_free(vertical);
814    free(fhsz);
815    free(fvsz);
816 
817    return err;
818 }
819 
820 typedef struct _Efl_Gfx_Image_Stretch_Region_Iterator Efl_Gfx_Image_Stretch_Region_Iterator;
821 struct _Efl_Gfx_Image_Stretch_Region_Iterator
822 {
823    Eina_Iterator iterator;
824 
825    Efl_Gfx_Image_Stretch_Region sz;
826 
827    uint8_t *stretch_region;
828    unsigned int next;
829 };
830 
831 static Eina_Bool
_efl_gfx_image_stretch_region_iterator_next(Eina_Iterator * iterator,void ** data)832 _efl_gfx_image_stretch_region_iterator_next(Eina_Iterator *iterator, void **data)
833 {
834    Efl_Gfx_Image_Stretch_Region_Iterator *it = (Efl_Gfx_Image_Stretch_Region_Iterator*) iterator;
835 
836    *data = &it->sz;
837    if (!it->stretch_region[it->next]) return EINA_FALSE;
838 
839    it->sz.offset = 0;
840    it->sz.length = 0;
841 
842    // Count offset before next stretch region
843    while (!(it->stretch_region[it->next] & 0x80) && it->stretch_region[it->next])
844      {
845         it->sz.offset += it->stretch_region[it->next] & 0x7F;
846         it->next++;
847      }
848 
849    // Count length of the stretch region
850    while ((it->stretch_region[it->next] & 0x80) && it->stretch_region[it->next])
851      {
852         it->sz.length += it->stretch_region[it->next] & 0x7F;
853         it->next++;
854      }
855 
856    return EINA_TRUE;
857 }
858 
859 static void *
_efl_gfx_image_stretch_region_iterator_container(Eina_Iterator * it EINA_UNUSED)860 _efl_gfx_image_stretch_region_iterator_container(Eina_Iterator *it EINA_UNUSED)
861 {
862    return NULL;
863 }
864 
865 static void
_efl_gfx_image_stretch_region_iterator_free(Eina_Iterator * it)866 _efl_gfx_image_stretch_region_iterator_free(Eina_Iterator *it)
867 {
868    free(it);
869 }
870 
871 static void
_efl_canvas_image_internal_efl_gfx_image_stretch_region_get(const Eo * eo_obj,Evas_Image_Data * pd,Eina_Iterator ** horizontal,Eina_Iterator ** vertical)872 _efl_canvas_image_internal_efl_gfx_image_stretch_region_get(const Eo *eo_obj,
873                                                             Evas_Image_Data *pd,
874                                                             Eina_Iterator **horizontal,
875                                                             Eina_Iterator **vertical)
876 {
877    Efl_Gfx_Image_Stretch_Region_Iterator *it;
878 
879    if (!pd->cur->stretch.vertical.region &&
880        !pd->cur->stretch.horizontal.region)
881      {
882         Evas_Object_Protected_Data *obj;
883 
884         obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
885         _stretch_region_load(obj, pd);
886      }
887 
888    if (!horizontal) goto vertical_only;
889    if (!pd->cur->stretch.horizontal.region)
890      {
891         *horizontal = NULL;
892         goto vertical_only;
893      }
894 
895    it = calloc(1, sizeof (Efl_Gfx_Image_Stretch_Region_Iterator));
896    if (!it) return;
897 
898    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
899 
900    it->stretch_region = pd->cur->stretch.horizontal.region;
901 
902    it->iterator.version = EINA_ITERATOR_VERSION;
903    it->iterator.next = FUNC_ITERATOR_NEXT(_efl_gfx_image_stretch_region_iterator_next);
904    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
905        _efl_gfx_image_stretch_region_iterator_container);
906    it->iterator.free = FUNC_ITERATOR_FREE(_efl_gfx_image_stretch_region_iterator_free);
907 
908    *horizontal = &it->iterator;
909 
910  vertical_only:
911    if (!vertical) return;
912    if (!pd->cur->stretch.vertical.region)
913      {
914         *vertical = NULL;
915         return;
916      }
917 
918    it = calloc(1, sizeof (Efl_Gfx_Image_Stretch_Region_Iterator));
919    if (!it) return;
920 
921    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
922 
923    it->stretch_region = pd->cur->stretch.vertical.region;
924 
925    it->iterator.version = EINA_ITERATOR_VERSION;
926    it->iterator.next = FUNC_ITERATOR_NEXT(_efl_gfx_image_stretch_region_iterator_next);
927    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
928        _efl_gfx_image_stretch_region_iterator_container);
929    it->iterator.free = FUNC_ITERATOR_FREE(_efl_gfx_image_stretch_region_iterator_free);
930 
931    *vertical = &it->iterator;
932 }
933 
934 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_fill_fill_auto_set(Eo * eo_obj,Evas_Image_Data * o,Eina_Bool setting)935 _efl_canvas_image_internal_efl_gfx_fill_fill_auto_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool setting)
936 {
937    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
938    Eina_Size2D sz;
939    setting = !!setting;
940    o->filled_set = 1;
941    if (o->filled == setting) return;
942 
943    evas_object_async_block(obj);
944    o->filled = setting;
945 
946    _toggle_fill_listener(eo_obj, o);
947 
948    if (!o->filled) return;
949 
950    sz = efl_gfx_entity_size_get(eo_obj);
951    _evas_image_fill_set(eo_obj, o, 0, 0, sz.w, sz.h);
952 }
953 
954 EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_gfx_fill_fill_auto_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)955 _efl_canvas_image_internal_efl_gfx_fill_fill_auto_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
956 {
957    return o->filled;
958 }
959 
960 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_border_insets_scale_set(Eo * eo_obj,Evas_Image_Data * o,double scale)961 _efl_canvas_image_internal_efl_gfx_image_border_insets_scale_set(Eo *eo_obj, Evas_Image_Data *o, double scale)
962 {
963    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
964 
965    if (EINA_DBL_EQ(scale, o->cur->border.scale)) return;
966    evas_object_async_block(obj);
967    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
968    state_write->border.scale = scale;
969    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
970 
971    o->changed = EINA_TRUE;
972    evas_object_change(eo_obj, obj);
973 }
974 
975 EOLIAN static double
_efl_canvas_image_internal_efl_gfx_image_border_insets_scale_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)976 _efl_canvas_image_internal_efl_gfx_image_border_insets_scale_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
977 {
978    return o->cur->border.scale;
979 }
980 
981 void
_evas_image_fill_set(Eo * eo_obj,Evas_Image_Data * o,int x,int y,int w,int h)982 _evas_image_fill_set(Eo *eo_obj, Evas_Image_Data *o, int x, int y, int w, int h)
983 {
984    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
985 
986    if (w == 0) return;
987    if (h == 0) return;
988    if (w < 0) w = -w;
989    if (h < 0) h = -h;
990 
991    if ((o->cur->fill.x == x) &&
992        (o->cur->fill.y == y) &&
993        (o->cur->fill.w == w) &&
994        (o->cur->fill.h == h)) return;
995 
996    evas_object_async_block(obj);
997    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
998    {
999       state_write->fill.x = x;
1000       state_write->fill.y = y;
1001       state_write->fill.w = w;
1002       state_write->fill.h = h;
1003       state_write->opaque_valid = 0;
1004    }
1005    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1006 
1007    o->changed = EINA_TRUE;
1008    evas_object_change(eo_obj, obj);
1009 }
1010 
1011 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_fill_fill_set(Eo * eo_obj,Evas_Image_Data * o,Eina_Rect fill)1012 _efl_canvas_image_internal_efl_gfx_fill_fill_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Rect fill)
1013 {
1014    // Should (0,0,0,0) reset the filled flag to true?
1015    o->filled = EINA_FALSE;
1016    o->filled_set = EINA_TRUE;
1017    _toggle_fill_listener(eo_obj, o);
1018    _evas_image_fill_set(eo_obj, o, fill.x, fill.y, fill.w, fill.h);
1019 }
1020 
1021 EOLIAN static Eina_Rect
_efl_canvas_image_internal_efl_gfx_fill_fill_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1022 _efl_canvas_image_internal_efl_gfx_fill_fill_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1023 {
1024    return (Eina_Rect) o->cur->fill;
1025 }
1026 
1027 EOLIAN static Eina_Size2D
_efl_canvas_image_internal_efl_gfx_image_image_size_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1028 _efl_canvas_image_internal_efl_gfx_image_image_size_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1029 {
1030    return EINA_SIZE2D(o->file_size.w, o->file_size.h);
1031 }
1032 
1033 EOLIAN static Eina_Size2D
_efl_canvas_image_internal_efl_gfx_view_view_size_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1034 _efl_canvas_image_internal_efl_gfx_view_view_size_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1035 {
1036    int uvw, uvh;
1037    Evas_Object_Protected_Data *source = NULL;
1038 
1039    if (o->cur->source)
1040      source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
1041 
1042    if (!o->cur->source)
1043      {
1044         uvw = o->cur->image.w;
1045         uvh = o->cur->image.h;
1046      }
1047    else if (source->proxy->surface && !source->proxy->redraw)
1048      {
1049         uvw = source->proxy->w;
1050         uvh = source->proxy->h;
1051      }
1052    else if (source->type == o_type &&
1053             ((Evas_Image_Data *)efl_data_scope_get(o->cur->source, MY_CLASS))->engine_data)
1054      {
1055         uvw = source->cur->geometry.w;
1056         uvh = source->cur->geometry.h;
1057      }
1058    else
1059      {
1060         uvw = source->proxy->w;
1061         uvh = source->proxy->h;
1062      }
1063 
1064    return EINA_SIZE2D(uvw, uvh);
1065 }
1066 
1067 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_buffer_buffer_update_add(Eo * eo_obj,Evas_Image_Data * o,const Eina_Rect * region)1068 _efl_canvas_image_internal_efl_gfx_buffer_buffer_update_add(Eo *eo_obj, Evas_Image_Data *o, const Eina_Rect *region)
1069 {
1070    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1071    Eina_Rectangle *r;
1072    Eo *eo_obj2;
1073    Eina_List *l;
1074    int x, y, w, h;
1075    int cnt;
1076 
1077    if (region)
1078      {
1079         x = region->x;
1080         y = region->y;
1081         w = region->w;
1082         h = region->h;
1083      }
1084    else
1085      {
1086         x = y = 0;
1087         w = o->cur->image.w;
1088         h = o->cur->image.h;
1089      }
1090 
1091    RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, o->cur->image.w, o->cur->image.h);
1092    if ((w <= 0) || (h <= 0)) return;
1093    if (obj->cur->snapshot)
1094      {
1095         obj->snapshot_no_obscure = EINA_TRUE;
1096         evas_object_change(eo_obj, obj);
1097         return;
1098      }
1099    if (!o->written) return;
1100    evas_object_async_block(obj);
1101    cnt = eina_list_count(o->pixels->pixel_updates);
1102    if (cnt == 1) // detect single blob case already there to do a nop
1103      {
1104         if ((r = o->pixels->pixel_updates->data)) // already a single full rect there.
1105           {
1106              if ((r->x == 0) && (r->y == 0) && (r->w == o->cur->image.w) && (r->h == o->cur->image.h))
1107                return;
1108           }
1109      }
1110    if ((cnt >= 512) ||
1111        (((x == 0) && (y == 0) && (w == o->cur->image.w) && (h == o->cur->image.h)))) // too many update rects - just make a single blob update
1112      {
1113         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
1114         {
1115            EINA_LIST_FREE(pixi_write->pixel_updates, r)
1116              eina_rectangle_free(r);
1117            NEW_RECT(r, 0, 0, o->cur->image.w, o->cur->image.h);
1118            if (r) pixi_write->pixel_updates = eina_list_append(pixi_write->pixel_updates, r);
1119         }
1120         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
1121      }
1122    else
1123      {
1124         NEW_RECT(r, x, y, w, h);
1125         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
1126         if (r) pixi_write->pixel_updates = eina_list_append(pixi_write->pixel_updates, r);
1127         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
1128      }
1129 
1130    o->changed = EINA_TRUE;
1131    evas_object_change(eo_obj, obj);
1132 
1133    EINA_LIST_FOREACH(obj->proxy->proxies, l, eo_obj2)
1134      {
1135         Evas_Object_Protected_Data *obj2 = efl_data_scope_get(eo_obj2, EFL_CANVAS_OBJECT_CLASS);
1136         evas_object_change(eo_obj2, obj2);
1137      }
1138 }
1139 
1140 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_buffer_alpha_set(Eo * eo_obj,Evas_Image_Data * o,Eina_Bool has_alpha)1141 _efl_canvas_image_internal_efl_gfx_buffer_alpha_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool has_alpha)
1142 {
1143    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1144 
1145    has_alpha = !!has_alpha;
1146    if (has_alpha == o->cur->has_alpha)
1147      return;
1148 
1149    evas_object_async_block(obj);
1150    if ((o->preload & EVAS_IMAGE_PRELOADING) && (o->engine_data))
1151      {
1152         o->preload = EVAS_IMAGE_PRELOAD_NONE;
1153         ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_TRUE);
1154      }
1155 
1156    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1157    {
1158       state_write->has_alpha = has_alpha;
1159       state_write->opaque_valid = 0;
1160    }
1161    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1162 
1163    if (o->engine_data)
1164      {
1165         int stride = 0;
1166 
1167         o->engine_data = ENFN->image_alpha_set(ENC, o->engine_data, o->cur->has_alpha);
1168         if (ENFN->image_scale_hint_set)
1169           ENFN->image_scale_hint_set(ENC, o->engine_data, o->scale_hint);
1170         if (ENFN->image_content_hint_set)
1171           ENFN->image_content_hint_set(ENC, o->engine_data, o->content_hint);
1172         if (ENFN->image_stride_get)
1173           ENFN->image_stride_get(ENC, o->engine_data, &stride);
1174         else
1175           stride = o->cur->image.w * 4;
1176 
1177         if (o->cur->image.stride != stride)
1178           {
1179              EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1180              state_write->image.stride = stride;
1181              EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1182           }
1183         o->written = EINA_TRUE;
1184      }
1185    efl_gfx_buffer_update_add(eo_obj, NULL);
1186    EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
1187 }
1188 
1189 EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_gfx_buffer_alpha_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1190 _efl_canvas_image_internal_efl_gfx_buffer_alpha_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1191 {
1192    return o->cur->has_alpha;
1193 }
1194 
1195 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_smooth_scale_set(Eo * eo_obj,Evas_Image_Data * o,Eina_Bool smooth_scale)1196 _efl_canvas_image_internal_efl_gfx_image_smooth_scale_set(Eo *eo_obj, Evas_Image_Data *o, Eina_Bool smooth_scale)
1197 {
1198    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1199 
1200    evas_object_async_block(obj);
1201    if (((smooth_scale) && (o->cur->smooth_scale)) ||
1202        ((!smooth_scale) && (!o->cur->smooth_scale)))
1203      return;
1204    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1205    state_write->smooth_scale = smooth_scale;
1206    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1207 
1208    o->changed = EINA_TRUE;
1209    evas_object_change(eo_obj, obj);
1210 }
1211 
1212 EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_gfx_image_smooth_scale_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1213 _efl_canvas_image_internal_efl_gfx_image_smooth_scale_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1214 {
1215    return o->cur->smooth_scale;
1216 }
1217 
1218 EOLIAN static double
_efl_canvas_image_internal_efl_gfx_image_ratio_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1219 _efl_canvas_image_internal_efl_gfx_image_ratio_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1220 {
1221    if (!o->cur->image.h) return 1.0;
1222    return (double)o->cur->image.w / (double)o->cur->image.h;
1223 }
1224 
1225 EOLIAN static Eina_Error
_efl_canvas_image_internal_efl_gfx_image_image_load_error_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1226 _efl_canvas_image_internal_efl_gfx_image_image_load_error_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1227 {
1228    return o->load_error;
1229 }
1230 
1231 EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_file_save_save(const Eo * eo_obj,Evas_Image_Data * o,const char * file,const char * key,const Efl_File_Save_Info * info)1232 _efl_canvas_image_internal_efl_file_save_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file, const char *key, const Efl_File_Save_Info *info)
1233 {
1234    int quality = 80, compress = 9, ok = 0;
1235    const char *encoding = NULL;
1236    Image_Entry *ie;
1237    Evas_Colorspace cspace = EVAS_COLORSPACE_ARGB8888;
1238    Evas_Colorspace want_cspace = EVAS_COLORSPACE_ARGB8888;
1239    Evas_Object_Protected_Data *obj;
1240    Eina_Bool unmap_it = EINA_FALSE;
1241    Eina_Bool tofree = EINA_FALSE;
1242    int imagew, imageh, uvw, uvh;
1243    Eina_Rw_Slice slice = {};
1244    DATA32 *data = NULL;
1245    void *pixels;
1246    void *output;
1247 
1248    obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1249 
1250    EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
1251    evas_object_async_block(obj);
1252 
1253    output = _evas_object_image_output_find(obj);
1254    pixels = _evas_image_pixels_get((Eo *)eo_obj, obj, ENC, output, NULL, NULL,
1255                                    0, 0,
1256                                    &imagew, &imageh, &uvw, &uvh, EINA_TRUE, EINA_TRUE);
1257    if (!pixels) goto no_pixels;
1258 
1259    cspace = ENFN->image_file_colorspace_get(ENC, pixels);
1260    want_cspace = cspace;
1261    if (info)
1262      {
1263         encoding = info->encoding;
1264         quality = info->quality;
1265         compress = info->compression;
1266      }
1267 
1268    if (encoding)
1269      {
1270         const char *ext = strrchr(file, '.');
1271         if (ext && !strcasecmp(ext, ".tgv"))
1272           {
1273              if (!strcmp(encoding, "auto"))
1274                want_cspace = cspace;
1275              else if (!strcmp(encoding, "etc1"))
1276                want_cspace = EVAS_COLORSPACE_ETC1;
1277              else if (!strcmp(encoding, "etc2"))
1278                {
1279                   if (!ENFN->image_alpha_get(ENC, pixels))
1280                     want_cspace = EVAS_COLORSPACE_RGB8_ETC2;
1281                   else
1282                     want_cspace = EVAS_COLORSPACE_RGBA8_ETC2_EAC;
1283                }
1284              else if (!strcmp(encoding, "etc1+alpha"))
1285                want_cspace = EVAS_COLORSPACE_ETC1_ALPHA;
1286           }
1287      }
1288 
1289    if (ENFN->image_data_direct_get && (o->cur->orient == EVAS_IMAGE_ORIENT_NONE))
1290      {
1291         Evas_Colorspace cs;
1292         Eina_Slice sl;
1293 
1294         ok = ENFN->image_data_direct_get(ENC, pixels, 0, &sl, &cs, EINA_TRUE, &tofree);
1295         if (ok && (cs == want_cspace))
1296           data = (DATA32 *)sl.mem;
1297      }
1298 
1299    if (!data)
1300      {
1301         int stride;
1302 
1303         cspace = EVAS_COLORSPACE_ARGB8888;
1304         ok = ENFN->image_data_map(ENC, &pixels, &slice, &stride, 0, 0, imagew, imageh,
1305                                   cspace, EFL_GFX_BUFFER_ACCESS_MODE_READ, 0);
1306         if (!ok || !slice.mem) goto no_pixels;
1307         unmap_it = EINA_TRUE;
1308         data = slice.mem;
1309 
1310         if (stride != (imagew * 4))
1311           WRN("Invalid stride: saved image may look wrong!");
1312      }
1313 
1314    ie = evas_cache_image_data(evas_common_image_cache_get(),
1315                               imagew, imageh, data, o->cur->has_alpha, cspace);
1316    if (ie)
1317      {
1318         RGBA_Image *im = (RGBA_Image *)ie;
1319 
1320         ok = evas_common_save_image_to_file(im, file, key, quality, compress, encoding);
1321         evas_cache_image_drop(ie);
1322      }
1323    else ok = EINA_FALSE;
1324 
1325    if (unmap_it)
1326      ENFN->image_data_unmap(ENC, pixels, &slice);
1327 
1328    if (tofree) free(data);
1329 
1330    if (!ok) ERR("Image save failed.");
1331    return ok;
1332 
1333 no_pixels:
1334    ERR("Could not get image pixels for saving.");
1335    return EINA_FALSE;
1336 }
1337 
1338 EOLIAN static Efl_Gfx_Colorspace
_efl_canvas_image_internal_efl_gfx_buffer_colorspace_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1339 _efl_canvas_image_internal_efl_gfx_buffer_colorspace_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1340 {
1341    return (Efl_Gfx_Colorspace)o->cur->cspace;
1342 }
1343 
1344 static void
_on_image_native_surface_del(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * einfo EINA_UNUSED)1345 _on_image_native_surface_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *einfo EINA_UNUSED)
1346 {
1347    evas_object_image_native_surface_set(obj, NULL);
1348 }
1349 
1350 Eina_Bool
_evas_image_native_surface_set(Eo * eo_obj,Evas_Native_Surface * surf)1351 _evas_image_native_surface_set(Eo *eo_obj, Evas_Native_Surface *surf)
1352 {
1353    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1354    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1355    evas_object_async_block(obj);
1356    evas_object_event_callback_del_full
1357      (eo_obj, EVAS_CALLBACK_DEL, _on_image_native_surface_del, NULL);
1358    if (surf) // We need to unset native surf on del to remove shared hash refs
1359      evas_object_event_callback_add
1360        (eo_obj, EVAS_CALLBACK_DEL, _on_image_native_surface_del, NULL);
1361 
1362    o->can_scanout = EINA_FALSE;
1363 
1364    evas_render_rendering_wait(obj->layer->evas);
1365    _evas_image_cleanup(eo_obj, obj, o);
1366    if (!ENFN->image_native_set) return EINA_FALSE;
1367    if ((surf) &&
1368        ((surf->version < 2) ||
1369         (surf->version > EVAS_NATIVE_SURFACE_VERSION))) return EINA_FALSE;
1370    o->engine_data = ENFN->image_native_set(ENC, o->engine_data, surf);
1371 
1372    if (surf && surf->version > 4)
1373      {
1374         switch (surf->type)
1375           {
1376            case EVAS_NATIVE_SURFACE_WL_DMABUF:
1377              if (surf->data.wl_dmabuf.scanout.handler)
1378                o->can_scanout = EINA_TRUE;
1379              break;
1380 
1381            default:
1382              break;
1383           }
1384      }
1385    return o->engine_data != NULL;
1386 }
1387 
1388 Evas_Native_Surface *
_evas_image_native_surface_get(const Evas_Object * eo_obj)1389 _evas_image_native_surface_get(const Evas_Object *eo_obj)
1390 {
1391    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1392    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1393    Evas_Native_Surface *surf = NULL;
1394 
1395    if (ENFN->image_native_get)
1396      surf = ENFN->image_native_get(ENC, o->engine_data);
1397 
1398    return surf;
1399 }
1400 
1401 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_scale_hint_set(Eo * eo_obj,Evas_Image_Data * o,Efl_Gfx_Image_Scale_Hint hint)1402 _efl_canvas_image_internal_efl_gfx_image_scale_hint_set(Eo *eo_obj, Evas_Image_Data *o, Efl_Gfx_Image_Scale_Hint hint)
1403 {
1404    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1405    evas_object_async_block(obj);
1406    if (o->scale_hint == hint) return;
1407    o->scale_hint = hint;
1408    if (o->engine_data)
1409      {
1410         int stride = 0;
1411 
1412         if (ENFN->image_scale_hint_set)
1413           ENFN->image_scale_hint_set(ENC, o->engine_data, o->scale_hint);
1414         if (ENFN->image_stride_get)
1415           ENFN->image_stride_get(ENC, o->engine_data, &stride);
1416         else
1417           stride = o->cur->image.w * 4;
1418 
1419         if (o->cur->image.stride != stride)
1420           {
1421              EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1422              state_write->image.stride = stride;
1423              EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1424           }
1425      }
1426 }
1427 
1428 EOLIAN static Efl_Gfx_Image_Scale_Hint
_efl_canvas_image_internal_efl_gfx_image_scale_hint_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1429 _efl_canvas_image_internal_efl_gfx_image_scale_hint_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1430 {
1431    return o->scale_hint;
1432 }
1433 
1434 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_image_content_hint_set(Eo * eo_obj,Evas_Image_Data * o,Efl_Gfx_Image_Content_Hint hint)1435 _efl_canvas_image_internal_efl_gfx_image_content_hint_set(Eo *eo_obj, Evas_Image_Data *o, Efl_Gfx_Image_Content_Hint hint)
1436 {
1437    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1438    evas_object_async_block(obj);
1439    if (o->content_hint == hint) return;
1440    o->content_hint = hint;
1441    if (o->engine_data)
1442      {
1443         int stride = 0;
1444 
1445         if (ENFN->image_content_hint_set)
1446           ENFN->image_content_hint_set(ENC, o->engine_data, o->content_hint);
1447         if (ENFN->image_stride_get)
1448           ENFN->image_stride_get(ENC, o->engine_data, &stride);
1449         else
1450           stride = o->cur->image.w * 4;
1451 
1452         if (o->cur->image.stride != stride)
1453           {
1454              EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1455              state_write->image.stride = stride;
1456              EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1457           }
1458      }
1459 }
1460 
1461 EOLIAN static Efl_Gfx_Image_Content_Hint
_efl_canvas_image_internal_efl_gfx_image_content_hint_get(const Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o)1462 _efl_canvas_image_internal_efl_gfx_image_content_hint_get(const Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
1463 {
1464    return o->content_hint;
1465 }
1466 
1467 void
_evas_image_unload(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,Eina_Bool dirty)1468 _evas_image_unload(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool dirty)
1469 {
1470    Evas_Image_Data *o;
1471    Eina_Bool resize_call = EINA_FALSE;
1472 
1473    o = efl_data_scope_get(eo_obj, MY_CLASS);
1474    if ((!o->cur->f) ||
1475        (o->pixels_checked_out > 0)) return;
1476 
1477    evas_object_async_block(obj);
1478    if (dirty)
1479      {
1480         if (o->engine_data)
1481           o->engine_data = ENFN->image_dirty_region(ENC, o->engine_data,
1482                                                     0, 0,
1483                                                     o->cur->image.w, o->cur->image.h);
1484      }
1485    if (o->engine_data)
1486      {
1487         if (o->preload & EVAS_IMAGE_PRELOADING)
1488           {
1489              o->preload = EVAS_IMAGE_PRELOAD_NONE;
1490              ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
1491           }
1492         ENFN->image_free(ENC, o->engine_data);
1493      }
1494    o->engine_data = NULL;
1495    o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_NONE;
1496 
1497    EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1498    {
1499       state_write->has_alpha = EINA_TRUE;
1500       state_write->cspace = EVAS_COLORSPACE_ARGB8888;
1501       if ((state_write->image.w != 0) || (state_write->image.h != 0)) resize_call = EINA_TRUE;
1502       state_write->image.w = 0;
1503       state_write->image.h = 0;
1504       state_write->image.stride = 0;
1505    }
1506    EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1507    if (resize_call) evas_object_inform_call_image_resize(eo_obj);
1508 }
1509 
1510 void
_evas_image_load(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,Evas_Image_Data * o)1511 _evas_image_load(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
1512 {
1513    Evas_Image_Load_Opts lo;
1514    int load_error = 0;
1515 
1516    if (o->engine_data) return;
1517 
1518    lo.emile.scale_down_by = o->load_opts->scale_down_by;
1519    lo.emile.dpi = o->load_opts->dpi;
1520    lo.emile.w = o->load_opts->w;
1521    lo.emile.h = o->load_opts->h;
1522    lo.emile.region.x = o->load_opts->region.x;
1523    lo.emile.region.y = o->load_opts->region.y;
1524    lo.emile.region.w = o->load_opts->region.w;
1525    lo.emile.region.h = o->load_opts->region.h;
1526    lo.emile.scale_load.src_x = o->load_opts->scale_load.src_x;
1527    lo.emile.scale_load.src_y = o->load_opts->scale_load.src_y;
1528    lo.emile.scale_load.src_w = o->load_opts->scale_load.src_w;
1529    lo.emile.scale_load.src_h = o->load_opts->scale_load.src_h;
1530    lo.emile.scale_load.dst_w = o->load_opts->scale_load.dst_w;
1531    lo.emile.scale_load.dst_h = o->load_opts->scale_load.dst_h;
1532    lo.emile.scale_load.smooth = o->load_opts->scale_load.smooth;
1533    lo.emile.scale_load.scale_hint = o->load_opts->scale_load.scale_hint;
1534    lo.emile.orientation = o->load_opts->orientation;
1535    lo.emile.degree = 0;
1536    lo.skip_head = o->skip_head;
1537    o->engine_data = ENFN->image_mmap(ENC, o->cur->f, o->cur->key, &load_error, &lo);
1538    o->load_error = _evas_load_error_to_efl_gfx_image_load_error(load_error);
1539 
1540    if (o->engine_data)
1541      {
1542         int w, h;
1543         int stride = 0;
1544         Eina_Bool resize_call = EINA_FALSE;
1545 
1546         ENFN->image_size_get(ENC, o->engine_data, &w, &h);
1547         if (ENFN->image_stride_get)
1548           ENFN->image_stride_get(ENC, o->engine_data, &stride);
1549         else
1550           stride = w * 4;
1551 
1552         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1553         {
1554            state_write->has_alpha = ENFN->image_alpha_get(ENC, o->engine_data);
1555            state_write->cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
1556            if ((state_write->image.w != w) || (state_write->image.h != h))
1557              resize_call = EINA_TRUE;
1558            state_write->image.w = w;
1559            state_write->image.h = h;
1560            state_write->image.stride = stride;
1561         }
1562         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1563         if (resize_call) evas_object_inform_call_image_resize(eo_obj);
1564      }
1565    else
1566      {
1567         o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
1568      }
1569 }
1570 
1571 void
_evas_image_load_post_update(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj)1572 _evas_image_load_post_update(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
1573 {
1574    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1575 
1576    if (o->engine_data)
1577      {
1578         int w, h;
1579         int stride = 0;
1580         Eina_Bool resize_call = EINA_FALSE;
1581 
1582         ENFN->image_size_get(ENC, o->engine_data, &w, &h);
1583         if (ENFN->image_stride_get)
1584           ENFN->image_stride_get(ENC, o->engine_data, &stride);
1585         else
1586           stride = w * 4;
1587 
1588         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1589         {
1590            state_write->has_alpha = ENFN->image_alpha_get(ENC, o->engine_data);
1591            state_write->cspace = ENFN->image_colorspace_get(ENC, o->engine_data);
1592            if ((state_write->image.w != w) || (state_write->image.h != h))
1593              resize_call = EINA_TRUE;
1594            state_write->image.w = w;
1595            state_write->image.h = h;
1596            state_write->image.stride = stride;
1597         }
1598         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1599         o->changed = EINA_TRUE;
1600         o->preload = EVAS_IMAGE_PRELOADED;
1601         if (resize_call) evas_object_inform_call_image_resize(eo_obj);
1602         evas_object_change(eo_obj, obj);
1603 
1604         //preloading error check
1605         if (ENFN->image_load_error_get)
1606           o->load_error = _evas_load_error_to_efl_gfx_image_load_error(ENFN->image_load_error_get(ENC, o->engine_data));
1607      }
1608    else
1609      {
1610         o->preload = EVAS_IMAGE_PRELOAD_NONE;
1611         o->load_error = EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
1612      }
1613 }
1614 
1615 static Evas_Coord
evas_object_image_figure_x_fill(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,Evas_Coord start,Evas_Coord size,Evas_Coord * size_ret)1616 evas_object_image_figure_x_fill(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret)
1617 {
1618    Evas_Coord w;
1619 
1620    w = ((size * obj->layer->evas->output.w) /
1621         (Evas_Coord)obj->layer->evas->viewport.w);
1622    if (size <= 0) size = 1;
1623    if (start > 0)
1624      {
1625         while (start - size > 0)
1626           start -= size;
1627      }
1628    else if (start < 0)
1629      {
1630         while (start < 0)
1631           start += size;
1632      }
1633    start = ((start * obj->layer->evas->output.w) /
1634             (Evas_Coord)obj->layer->evas->viewport.w);
1635    *size_ret = w;
1636    return start;
1637 }
1638 
1639 static Evas_Coord
evas_object_image_figure_y_fill(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,Evas_Coord start,Evas_Coord size,Evas_Coord * size_ret)1640 evas_object_image_figure_y_fill(Evas_Object *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret)
1641 {
1642    Evas_Coord h;
1643 
1644    h = ((size * obj->layer->evas->output.h) /
1645         (Evas_Coord)obj->layer->evas->viewport.h);
1646    if (size <= 0) size = 1;
1647    if (start > 0)
1648      {
1649         while (start - size > 0)
1650           start -= size;
1651      }
1652    else if (start < 0)
1653      {
1654         while (start < 0)
1655           start += size;
1656      }
1657    start = ((start * obj->layer->evas->output.h) /
1658             (Evas_Coord)obj->layer->evas->viewport.h);
1659    *size_ret = h;
1660    return start;
1661 }
1662 
1663 static void
evas_object_image_init(Evas_Object * eo_obj)1664 evas_object_image_init(Evas_Object *eo_obj)
1665 {
1666    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1667    /* set up methods (compulsory) */
1668    obj->func = &object_func;
1669    obj->private_data = efl_data_ref(eo_obj, MY_CLASS);
1670    obj->type = o_type;
1671    obj->is_image_object = EINA_TRUE;
1672 }
1673 
1674 EOLIAN static void
_efl_canvas_image_internal_efl_object_destructor(Eo * eo_obj,Evas_Image_Data * o)1675 _efl_canvas_image_internal_efl_object_destructor(Eo *eo_obj, Evas_Image_Data *o)
1676 {
1677    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1678 
1679    // To avoid unecessary GC storage triggered during shutdown, we mark the content as dynamic
1680    o->content_hint = EFL_GFX_IMAGE_CONTENT_HINT_DYNAMIC;
1681 
1682    if (obj->legacy.ctor)
1683      evas_object_image_video_surface_set(eo_obj, NULL);
1684    efl_gfx_image_stretch_region_set(eo_obj, NULL, NULL);
1685    evas_object_image_free(eo_obj, obj);
1686    efl_destructor(efl_super(eo_obj, MY_CLASS));
1687 }
1688 
1689 void
_evas_object_image_free(Evas_Object * obj)1690 _evas_object_image_free(Evas_Object *obj)
1691 {
1692    Evas_Image_Data *o;
1693 
1694    EINA_SAFETY_ON_FALSE_RETURN(efl_isa(obj, MY_CLASS));
1695 
1696    o = efl_data_scope_get(obj, MY_CLASS);
1697 
1698    // eina_cow_free reset the pointer to the default read only state
1699    eina_cow_free(evas_object_image_load_opts_cow, (const Eina_Cow_Data **)&o->load_opts);
1700    eina_cow_free(evas_object_image_pixels_cow, (const Eina_Cow_Data **)&o->pixels);
1701    eina_cow_free(evas_object_image_state_cow, (const Eina_Cow_Data **)&o->cur);
1702    eina_cow_free(evas_object_image_state_cow, (const Eina_Cow_Data **)&o->prev);
1703 }
1704 
1705 static void
evas_object_image_free(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj)1706 evas_object_image_free(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
1707 {
1708    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
1709    Eina_Rectangle *r;
1710 
1711    /* free obj */
1712    if (o->cur->key)
1713      {
1714         eina_stringshare_del(o->cur->key);
1715         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1716         state_write->key = NULL;
1717         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1718      }
1719    if (o->cur->source)
1720      {
1721         _evas_image_proxy_unset(eo_obj, obj, o);
1722         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1723         state_write->source = NULL;
1724         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1725      }
1726    if (o->cur->f)
1727      {
1728         eina_file_close(o->cur->f); // close matching open (dup in _evas_image_init_set) OK
1729         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
1730         state_write->f = NULL;
1731         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
1732      }
1733    if (obj->layer && obj->layer->evas)
1734      {
1735         if (o->engine_data && ENC)
1736           {
1737              if (o->preload & EVAS_IMAGE_PRELOADING)
1738                {
1739                   o->preload = EVAS_IMAGE_PRELOAD_NONE;
1740                   ENFN->image_data_preload_cancel(ENC, o->engine_data, eo_obj, EINA_FALSE);
1741                }
1742              ENFN->image_free(ENC, o->engine_data);
1743           }
1744         if (o->engine_data_prep && ENC)
1745           {
1746              ENFN->image_free(ENC, o->engine_data_prep);
1747           }
1748         if (o->video_surface)
1749           {
1750              o->video_surface = EINA_FALSE;
1751              obj->layer->evas->video_objects = eina_list_remove(obj->layer->evas->video_objects, eo_obj);
1752           }
1753      }
1754    o->engine_data = NULL;
1755    o->engine_data_prep = NULL;
1756    if (o->pixels->images_to_free)
1757      {
1758         eina_hash_free(o->pixels->images_to_free);
1759         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
1760         pixi_write->images_to_free = NULL;
1761         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
1762      }
1763    if (o->pixels->pixel_updates)
1764      {
1765         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
1766         {
1767            EINA_LIST_FREE(pixi_write->pixel_updates, r)
1768              eina_rectangle_free(r);
1769         }
1770         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
1771      }
1772 }
1773 
1774 static void
_draw_image(Evas_Object_Protected_Data * obj,void * engine,void * data,void * context,void * surface,void * image,int src_x,int src_y,int src_w,int src_h,int dst_x,int dst_y,int dst_w,int dst_h,int smooth,Eina_Bool do_async)1775 _draw_image(Evas_Object_Protected_Data *obj,
1776             void *engine, void *data, void *context, void *surface, void *image,
1777             int src_x, int src_y, int src_w, int src_h, int dst_x,
1778             int dst_y, int dst_w, int dst_h, int smooth,
1779             Eina_Bool do_async)
1780 {
1781    Eina_Bool async_unref;
1782 
1783    async_unref = ENFN->image_draw(engine, data, context, surface,
1784                                   image, src_x, src_y,
1785                                   src_w, src_h, dst_x,
1786                                   dst_y, dst_w, dst_h,
1787                                   smooth, do_async);
1788    if (do_async && async_unref)
1789      {
1790         evas_cache_image_ref((Image_Entry *)image);
1791 
1792         evas_unref_queue_image_put(obj->layer->evas, image);
1793      }
1794 }
1795 
1796 void
evas_draw_image_map_async_check(Evas_Object_Protected_Data * obj,void * engine,void * data,void * context,void * surface,void * image,RGBA_Map * m,int smooth,int level,Eina_Bool do_async)1797 evas_draw_image_map_async_check(Evas_Object_Protected_Data *obj,
1798                                 void *engine, void *data, void *context, void *surface,
1799                                 void *image, RGBA_Map *m, int smooth, int level,
1800                                 Eina_Bool do_async)
1801 {
1802    Eina_Bool async_unref;
1803    obj->layer->evas->engine.func->context_anti_alias_set(engine, context,
1804                                                          obj->cur->anti_alias);
1805    async_unref = ENFN->image_map_draw(engine, data, context,
1806                                       surface, image, m,
1807                                       smooth, level,
1808                                       do_async);
1809    if (do_async && async_unref)
1810      {
1811         evas_cache_image_ref((Image_Entry *)image);
1812 
1813         evas_unref_queue_image_put(obj->layer->evas, image);
1814      }
1815 }
1816 
1817 void
evas_object_pixels_get_force(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj)1818 evas_object_pixels_get_force(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
1819 {
1820    Evas_Image_Data *o = obj->private_data;
1821 
1822    o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, eo_obj);
1823 }
1824 
1825 static void *
evas_process_dirty_pixels(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,Evas_Image_Data * o,void * engine,void * output,void * surface,void * pixels)1826 evas_process_dirty_pixels(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Evas_Image_Data *o,
1827                           void *engine, void *output, void *surface, void *pixels)
1828 {
1829    Eina_Bool direct_override = EINA_FALSE, direct_force_off = EINA_FALSE;
1830 
1831    if (o->dirty_pixels)
1832      {
1833         if (o->pixels->func.get_pixels)
1834           {
1835              Evas_Coord x, y, w, h;
1836 
1837              if (ENFN->image_native_get)
1838                {
1839                   Evas_Native_Surface *ns;
1840 
1841                   ns = ENFN->image_native_get(engine, o->engine_data);
1842                   if (ns)
1843                     {
1844                        Eina_Bool direct_renderable = EINA_FALSE;
1845 
1846                        // Check if we can do direct rendering...
1847                        if (ENFN->gl_direct_override_get)
1848                          ENFN->gl_direct_override_get(engine, &direct_override, &direct_force_off);
1849                        if (ENFN->gl_surface_direct_renderable_get)
1850                          direct_renderable = ENFN->gl_surface_direct_renderable_get(engine, output, ns, &direct_override, surface);
1851 
1852                        if (((direct_override) ||
1853                             ((direct_renderable) &&
1854                              (obj->cur->geometry.w == o->cur->image.w) &&
1855                              (obj->cur->geometry.h == o->cur->image.h) &&
1856                              (obj->cur->color.r == 255) &&
1857                              (obj->cur->color.g == 255) &&
1858                              (obj->cur->color.b == 255) &&
1859                              (obj->cur->color.a == 255) &&
1860                              (obj->cur->cache.clip.r == 255) &&
1861                              (obj->cur->cache.clip.g == 255) &&
1862                              (obj->cur->cache.clip.b == 255) &&
1863                              (obj->cur->cache.clip.a == 255) &&
1864                              (!obj->map->cur.map))
1865                             ) && (!direct_force_off))
1866                          {
1867                             if (ENFN->gl_get_pixels_set)
1868                               ENFN->gl_get_pixels_set(engine, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj);
1869                             if (ENFN->gl_image_direct_set)
1870                               ENFN->gl_image_direct_set(engine, o->engine_data, EINA_TRUE);
1871                             o->direct_render = EINA_TRUE;
1872                          }
1873                        else
1874                          o->direct_render = EINA_FALSE;
1875                     }
1876 
1877                   if ((ns) &&
1878                       (ns->type == EVAS_NATIVE_SURFACE_X11))
1879                     {
1880                        if (ENFN->context_flush)
1881                          ENFN->context_flush(engine);
1882                     }
1883                }
1884 
1885              x = obj->cur->geometry.x;
1886              y = obj->cur->geometry.y;
1887              w = obj->cur->geometry.w;
1888              h = obj->cur->geometry.h;
1889 
1890              if (!o->direct_render)
1891                {
1892                   if (ENFN->gl_get_pixels_pre)
1893                     ENFN->gl_get_pixels_pre(engine, output);
1894                   o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, eo_obj);
1895                   if (ENFN->gl_get_pixels_post)
1896                     ENFN->gl_get_pixels_post(engine, output);
1897                }
1898 
1899              if (!(obj->cur->geometry.x == x &&
1900                    obj->cur->geometry.y == y &&
1901                    obj->cur->geometry.w == w &&
1902                    obj->cur->geometry.h == h))
1903                CRI("Evas_Image_Data geometry did change during pixels get callback !");
1904 
1905              o->engine_data = ENFN->image_dirty_region
1906                  (engine, o->engine_data,
1907                  0, 0, o->cur->image.w, o->cur->image.h);
1908              if (o->engine_data != pixels)
1909                pixels = o->engine_data;
1910           }
1911         o->dirty_pixels = EINA_FALSE;
1912      }
1913    else
1914      {
1915         // Check if the it's not dirty but it has direct rendering
1916         if (o->direct_render && ENFN->image_native_get)
1917           {
1918              Evas_Native_Surface *ns;
1919              ns = ENFN->image_native_get(engine, o->engine_data);
1920 
1921              if (ENFN->gl_direct_override_get)
1922                ENFN->gl_direct_override_get(engine, &direct_override, &direct_force_off);
1923              if (ENFN->gl_surface_direct_renderable_get)
1924                ENFN->gl_surface_direct_renderable_get(engine, output, ns, &direct_override, surface);
1925 
1926              if (direct_override && !direct_force_off)
1927                {
1928                   // always use direct rendering
1929                   if (ENFN->gl_get_pixels_set)
1930                     ENFN->gl_get_pixels_set(engine, o->pixels->func.get_pixels, o->pixels->func.get_pixels_data, eo_obj);
1931                   if (ENFN->gl_image_direct_set)
1932                     ENFN->gl_image_direct_set(engine, o->engine_data, EINA_TRUE);
1933                }
1934              else
1935                {
1936                   // Auto-fallback to FBO rendering (for perf & power consumption)
1937                   if (ENFN->gl_get_pixels_pre)
1938                     ENFN->gl_get_pixels_pre(engine, output);
1939                   o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, obj->object);
1940                   if (ENFN->gl_get_pixels_post)
1941                     ENFN->gl_get_pixels_post(engine, output);
1942                   o->direct_render = EINA_FALSE;
1943                }
1944           }
1945      }
1946 
1947    return pixels;
1948 }
1949 
1950 EOLIAN static void
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_dirty(Eo * eo_obj,Evas_Image_Data * o)1951 _efl_canvas_image_internal_efl_canvas_filter_internal_filter_dirty(Eo *eo_obj, Evas_Image_Data *o)
1952 {
1953    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1954 
1955    o->changed = EINA_TRUE;
1956    evas_object_change(eo_obj, obj);
1957    o->changed_filter = EINA_TRUE;
1958 }
1959 
1960 EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_alpha(Eo * eo_obj EINA_UNUSED,Evas_Image_Data * o EINA_UNUSED)1961 _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_alpha(
1962   Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o EINA_UNUSED)
1963 {
1964    return EINA_FALSE;
1965 }
1966 
1967 EOLIAN static void
_efl_canvas_image_internal_efl_gfx_filter_filter_program_set(Eo * obj,Evas_Image_Data * pd,const char * code,const char * name)1968 _efl_canvas_image_internal_efl_gfx_filter_filter_program_set(Eo *obj, Evas_Image_Data *pd,
1969                                                              const char *code, const char *name)
1970 {
1971    pd->has_filter = (code != NULL);
1972    efl_gfx_filter_program_set(efl_super(obj, MY_CLASS), code, name);
1973 }
1974 
1975 EOLIAN static void
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_state_prepare(Eo * eo_obj,Evas_Image_Data * o EINA_UNUSED,Efl_Canvas_Filter_State * state,void * data EINA_UNUSED)1976 _efl_canvas_image_internal_efl_canvas_filter_internal_filter_state_prepare(
1977   Eo *eo_obj, Evas_Image_Data *o EINA_UNUSED, Efl_Canvas_Filter_State *state, void *data EINA_UNUSED)
1978 {
1979    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1980 
1981    memset(&state->text, 0, sizeof(state->text));
1982 #define STATE_COLOR(dst, src) dst.r = src.r; dst.g = src.g; dst.b = src.b; dst.a = src.a
1983    STATE_COLOR(state->color, obj->cur->color);
1984 #undef STATE_COLOR
1985 
1986    state->w = obj->cur->geometry.w;
1987    state->h = obj->cur->geometry.h;
1988    state->scale = obj->cur->scale;
1989 }
1990 
1991 static inline Eina_Bool
_image_has_border(Evas_Object_Protected_Data * obj EINA_UNUSED,Evas_Image_Data * o)1992 _image_has_border(Evas_Object_Protected_Data *obj EINA_UNUSED, Evas_Image_Data *o)
1993 {
1994    return o->cur->border.l || o->cur->border.r || o->cur->border.t ||
1995           o->cur->border.b || (o->cur->border.fill == 0);
1996 }
1997 
1998 static inline Eina_Bool
_image_is_filled(Evas_Object_Protected_Data * obj,Evas_Image_Data * o)1999 _image_is_filled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
2000 {
2001    if (o->filled) return EINA_TRUE;
2002    return !o->cur->fill.x && !o->cur->fill.y &&
2003           (o->cur->fill.w == obj->cur->geometry.w) &&
2004           (o->cur->fill.h == obj->cur->geometry.h);
2005 }
2006 
2007 static inline Eina_Bool
_image_is_scaled(Evas_Object_Protected_Data * obj,Evas_Image_Data * o)2008 _image_is_scaled(Evas_Object_Protected_Data *obj, Evas_Image_Data *o)
2009 {
2010    return (obj->cur->geometry.w != o->cur->image.w) ||
2011           (obj->cur->geometry.h != o->cur->image.h);
2012 }
2013 
2014 EOLIAN static Eina_Bool
_efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(Eo * eo_obj,Evas_Image_Data * o,void * _filter,void * engine,void * output,void * context,void * data EINA_UNUSED,int l,int r EINA_UNUSED,int t,int b EINA_UNUSED,int x,int y,Eina_Bool do_async)2015 _efl_canvas_image_internal_efl_canvas_filter_internal_filter_input_render(
2016   Eo *eo_obj, Evas_Image_Data *o,
2017   void *_filter, void *engine, void *output, void *context, void *data EINA_UNUSED,
2018   int l, int r EINA_UNUSED, int t, int b EINA_UNUSED,
2019   int x, int y, Eina_Bool do_async)
2020 {
2021    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2022    Evas_Filter_Context *filter = _filter;
2023    void *surface, *ctx;
2024    Eina_Bool ok;
2025    int W, H;
2026 
2027    W = obj->cur->geometry.w;
2028    H = obj->cur->geometry.h;
2029 
2030    // FIXME: In GL we could use the image even if scaled
2031    if (!(ENFN->image_native_get && ENFN->image_native_get(engine, o->engine_data)) &&
2032        !_image_has_border(obj, o) && _image_is_filled(obj, o) && !_image_is_scaled(obj, o))
2033      {
2034         int imagew, imageh, uvw, uvh;
2035 
2036         surface = _evas_image_pixels_get(eo_obj, obj, engine, output, context, NULL, x, y,
2037                                          &imagew, &imageh, &uvw, &uvh, EINA_FALSE, EINA_FALSE);
2038 
2039         ok = evas_filter_buffer_backing_set(filter, EVAS_FILTER_BUFFER_INPUT_ID, surface);
2040         if (ok) return EINA_TRUE;
2041      }
2042 
2043    surface = evas_filter_buffer_backing_get(filter, EVAS_FILTER_BUFFER_INPUT_ID, EINA_TRUE);
2044    EINA_SAFETY_ON_NULL_RETURN_VAL(surface, EINA_FALSE);
2045 
2046    if (!o->filled)
2047      {
2048         l = 0;
2049         t = 0;
2050         r = 0;
2051         b = 0;
2052      }
2053 
2054    ctx = ENFN->context_new(engine);
2055 
2056    if (o->cur->has_alpha && !obj->cur->snapshot)
2057      {
2058         ENFN->context_color_set(engine, ctx, 0, 0, 0, 0);
2059         ENFN->context_render_op_set(engine, ctx, EVAS_RENDER_COPY);
2060         ENFN->rectangle_draw(engine, output, ctx, surface, 0, 0, W, H, do_async);
2061         ENFN->context_color_set(engine, ctx, 255, 255, 255, 255);
2062         ENFN->context_render_op_set(engine, ctx, EVAS_RENDER_BLEND);
2063      }
2064 
2065    _evas_image_render(eo_obj, obj,
2066                       engine, output, ctx, surface,
2067                       x + l - obj->cur->geometry.x,
2068                       y + t - obj->cur->geometry.y,
2069                       l, t, r, b, EINA_TRUE, do_async);
2070 
2071    ENFN->context_free(engine, ctx);
2072    ENFN->image_free(engine, surface);
2073 
2074    return EINA_TRUE;
2075 }
2076 
2077 void
_evas_object_image_plane_release(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,Efl_Canvas_Output * output)2078 _evas_object_image_plane_release(Evas_Object *eo_obj EINA_UNUSED,
2079                                  Evas_Object_Protected_Data *obj,
2080                                  Efl_Canvas_Output *output)
2081 {
2082    Evas_Image_Data *o;
2083 
2084    if (!obj) return;
2085 
2086    o = obj->private_data;
2087 
2088    if (!o->engine_data) return;
2089 
2090    if (!o->plane) return;
2091 
2092    ENFN->image_plane_release(output->output, o->engine_data, o->plane);
2093    output->planes = eina_list_remove(output->planes, obj);
2094    o->plane = NULL;
2095 }
2096 
2097 Eina_Bool
_evas_object_image_can_use_plane(Evas_Object_Protected_Data * obj,Efl_Canvas_Output * output)2098 _evas_object_image_can_use_plane(Evas_Object_Protected_Data *obj,
2099                                  Efl_Canvas_Output *output)
2100 {
2101    Evas_Native_Surface *ns;
2102    Evas_Image_Data *o = obj->private_data;
2103 
2104    /* Let the video surface code handle this one... */
2105    if (o->video_surface)
2106      return EINA_TRUE;
2107 
2108    if (!o->can_scanout)
2109      return EINA_FALSE;
2110 
2111    if (!o->engine_data)
2112      return EINA_FALSE;
2113 
2114    if (!ENFN->image_plane_assign)
2115      return EINA_FALSE;
2116 
2117    if (!ENFN->image_native_get)
2118      return EINA_FALSE;
2119 
2120    ns = ENFN->image_native_get(ENC, o->engine_data);
2121    if (!ns) return EINA_FALSE;
2122 
2123    // FIXME: adjust position with output offset.
2124    o->plane = ENFN->image_plane_assign(output->output, o->engine_data,
2125                                        obj->cur->geometry.x,
2126                                        obj->cur->geometry.y);
2127 
2128    if (!o->plane)
2129      return EINA_FALSE;
2130 
2131    output->planes = eina_list_append(output->planes, obj);
2132    return EINA_TRUE;
2133 }
2134 
2135 static int
evas_object_image_is_on_plane(Evas_Object * obj EINA_UNUSED,Evas_Object_Protected_Data * pd EINA_UNUSED,void * type_private_data)2136 evas_object_image_is_on_plane(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data)
2137 {
2138    Evas_Image_Data *o = type_private_data;
2139 
2140    if (o->plane) return 1;
2141    return 0;
2142 }
2143 
2144 static int
evas_object_image_plane_changed(Evas_Object * obj EINA_UNUSED,Evas_Object_Protected_Data * pd EINA_UNUSED,void * type_private_data)2145 evas_object_image_plane_changed(Evas_Object *obj EINA_UNUSED, Evas_Object_Protected_Data *pd EINA_UNUSED, void *type_private_data)
2146 {
2147    Evas_Image_Data *o = type_private_data;
2148 
2149    if (!!o->plane != o->plane_status)
2150      {
2151         o->plane_status = !!o->plane;
2152         return 1;
2153      }
2154 
2155    return 0;
2156 }
2157 
2158 static void
evas_object_image_render(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data,void * engine,void * output,void * context,void * surface,int x,int y,Eina_Bool do_async)2159 evas_object_image_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, void *type_private_data,
2160                          void *engine, void *output, void *context, void *surface, int x, int y, Eina_Bool do_async)
2161 {
2162    Evas_Image_Data *o = type_private_data;
2163 
2164    /* image is not ready yet, skip rendering. Leave it to next frame */
2165    if (o->preload == EVAS_IMAGE_PRELOADING) return;
2166 
2167    if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1))
2168      return;  /* no error message, already printed in pre_render */
2169 
2170    /* Proxy sanity */
2171    if (o->proxyrendering)
2172      {
2173         _evas_image_proxy_error(eo_obj, engine, output, context, surface, x, y, EINA_FALSE);
2174         return;
2175      }
2176 
2177    /* Mask sanity */
2178    if (obj->mask->is_mask && (surface != obj->mask->surface))
2179      {
2180         ERR("Drawing a mask to another surface? Something's wrong...");
2181         return;
2182      }
2183 
2184    if (o->engine_data_prep)
2185      {
2186         ENFN->context_multiplier_unset(engine, context);
2187         ENFN->context_render_op_set(engine, context, obj->cur->render_op);
2188         ENFN->image_draw(engine, output, context, surface, o->engine_data_prep,
2189                          0, 0, obj->cur->geometry.w, obj->cur->geometry.h,
2190                          obj->cur->geometry.x + x, obj->cur->geometry.y + y,
2191                          obj->cur->geometry.w, obj->cur->geometry.h,
2192                          0, do_async);
2193         return;
2194      }
2195 
2196    if (o->plane)
2197      {
2198         /* We must call pixels get because enlightenment uses it for internal
2199          * bookkeeping and won't send frame callbacks to wayland clients if we
2200          * don't
2201          */
2202         evas_object_pixels_get_force(eo_obj, obj);
2203 #if 0
2204         Evas_Native_Surface *ns;
2205 
2206         /* Draw a bright red rectangle where the object replaced by
2207          * a hardware plane would have been.
2208          */
2209         ns = ENFN->image_native_get(ENC, o->engine_data);
2210         if (ns && ns->type == EVAS_NATIVE_SURFACE_WL_DMABUF)
2211           {
2212              ENFN->context_color_set(output, context, 255, 0, 0, 255);
2213              ENFN->context_multiplier_unset(output, context);
2214              ENFN->context_render_op_set(output, context, EVAS_RENDER_COPY);
2215              ENFN->rectangle_draw(engine, output, context, surface,
2216                                   obj->cur->geometry.x + x,
2217                                   obj->cur->geometry.y + y,
2218                                   obj->cur->geometry.w,
2219                                   obj->cur->geometry.h,
2220                                   do_async);
2221           }
2222 #endif
2223         return;
2224      }
2225    /* We are displaying the overlay */
2226    if (o->video_visible)
2227      {
2228         /* Create a transparent rectangle */
2229         ENFN->context_color_set(engine, context, 0, 0, 0, 0);
2230         ENFN->context_multiplier_unset(engine, context);
2231         ENFN->context_render_op_set(engine, context, EVAS_RENDER_COPY);
2232         ENFN->rectangle_draw(engine, output, context, surface,
2233                              obj->cur->geometry.x + x, obj->cur->geometry.y + y,
2234                              obj->cur->geometry.w, obj->cur->geometry.h,
2235                              do_async);
2236 
2237         return;
2238      }
2239 
2240    ENFN->context_color_set(engine, context, 255, 255, 255, 255);
2241 
2242    if ((obj->cur->cache.clip.r == 255) &&
2243        (obj->cur->cache.clip.g == 255) &&
2244        (obj->cur->cache.clip.b == 255) &&
2245        (obj->cur->cache.clip.a == 255))
2246      {
2247         ENFN->context_multiplier_unset(engine, context);
2248      }
2249    else
2250      ENFN->context_multiplier_set(engine, context,
2251                                   obj->cur->cache.clip.r,
2252                                   obj->cur->cache.clip.g,
2253                                   obj->cur->cache.clip.b,
2254                                   obj->cur->cache.clip.a);
2255 
2256    ENFN->context_render_op_set(engine, context, obj->cur->render_op);
2257 
2258    // Clear out the pixel get stuff..
2259    if (ENFN->gl_get_pixels_set)
2260      ENFN->gl_get_pixels_set(engine, NULL, NULL, NULL);
2261    if (ENFN->gl_image_direct_set)
2262      ENFN->gl_image_direct_set(engine, o->engine_data, EINA_FALSE);
2263 
2264    /* Render filter */
2265    if (o->has_filter)
2266      {
2267         if (evas_filter_object_render(eo_obj, obj, engine, output, context, surface, x, y, do_async, EINA_FALSE))
2268           return;
2269      }
2270 
2271    _evas_image_render(eo_obj, obj, engine, output, context, surface, x, y, 0, 0, 0, 0, EINA_FALSE, do_async);
2272 }
2273 
2274 void *
_evas_image_pixels_get(Eo * eo_obj,Evas_Object_Protected_Data * obj,void * engine,void * output,void * context,void * surface,int x,int y,int * imagew,int * imageh,int * uvw,int * uvh,Eina_Bool filtered,Eina_Bool needs_post_render)2275 _evas_image_pixels_get(Eo *eo_obj, Evas_Object_Protected_Data *obj,
2276                        void *engine, void *output, void *context, void *surface,
2277                        int x, int y,
2278                        int *imagew, int *imageh, int *uvw, int *uvh,
2279                        Eina_Bool filtered, Eina_Bool needs_post_render)
2280 {
2281    Evas_Image_Data *o = obj->private_data, *oi = NULL;
2282    Evas_Object_Protected_Data *source = NULL;
2283    void *pixels = NULL;
2284 
2285    EVAS_OBJECT_DATA_ALIVE_CHECK(obj, NULL);
2286 
2287    if (filtered && o->has_filter)
2288      pixels = evas_filter_output_buffer_get(eo_obj);
2289    else
2290      needs_post_render = EINA_FALSE;
2291 
2292    if (!pixels && o->cur->source)
2293      {
2294         source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
2295         if (source && (source->type == o_type))
2296           oi = efl_data_scope_get(o->cur->source, MY_CLASS);
2297      }
2298 
2299    if (pixels)
2300      {
2301         ENFN->image_size_get(engine, pixels, imagew, imageh);
2302         *uvw = *imagew;
2303         *uvh = *imageh;
2304      }
2305    else if (obj->cur->snapshot)
2306      {
2307         pixels = o->engine_data;
2308         *imagew = o->cur->image.w;
2309         *imageh = o->cur->image.h;
2310         *uvw = *imagew;
2311         *uvh = *imageh;
2312      }
2313    else if (!o->cur->source || !source)
2314      {
2315         // normal image (from file or user pixel set)
2316         needs_post_render = EINA_FALSE;
2317         if (output && surface)
2318           pixels = evas_process_dirty_pixels(eo_obj, obj, o, engine, output, surface, o->engine_data);
2319         else
2320           pixels = o->engine_data;
2321         *imagew = o->cur->image.w;
2322         *imageh = o->cur->image.h;
2323         *uvw = *imagew;
2324         *uvh = *imageh;
2325      }
2326    else if (source->proxy->surface && !source->proxy->redraw)
2327      {
2328         pixels = source->proxy->surface;
2329         *imagew = source->proxy->w;
2330         *imageh = source->proxy->h;
2331         *uvw = *imagew;
2332         *uvh = *imageh;
2333      }
2334    else if (oi && oi->engine_data &&
2335             (!o->cur->source || o->load_opts->region.w == 0 || o->load_opts->region.h == 0))
2336      {
2337         if (oi->has_filter)
2338           pixels = evas_filter_output_buffer_get(source->object);
2339         if (!pixels)
2340           pixels = oi->engine_data;
2341         *imagew = oi->cur->image.w;
2342         *imageh = oi->cur->image.h;
2343         *uvw = source->cur->geometry.w;
2344         *uvh = source->cur->geometry.h;
2345         /* check source_clip since we skip proxy_subrender here */
2346         if (context && o->proxy_src_clip && source->cur->clipper)
2347           {
2348              ENFN->context_clip_clip(engine, context,
2349                                      source->cur->clipper->cur->cache.clip.x + x,
2350                                      source->cur->clipper->cur->cache.clip.y + y,
2351                                      source->cur->clipper->cur->cache.clip.w,
2352                                      source->cur->clipper->cur->cache.clip.h);
2353           }
2354      }
2355    else
2356      {
2357         o->proxyrendering = EINA_TRUE;
2358         evas_render_proxy_subrender(obj->layer->evas->evas, output, o->cur->source,
2359                                     eo_obj, obj, o->proxy_src_clip, EINA_FALSE);
2360         pixels = source->proxy->surface;
2361         *imagew = source->proxy->w;
2362         *imageh = source->proxy->h;
2363         *uvw = *imagew;
2364         *uvh = *imageh;
2365         o->proxyrendering = EINA_FALSE;
2366      }
2367 
2368    if (needs_post_render && !obj->layer->evas->inside_post_render)
2369      {
2370         ERR("Can not save or map this image now! Proxies, snapshots and "
2371             "filtered images support those operations only from inside a "
2372             "post-render event.");
2373         return NULL;
2374      }
2375 
2376    return pixels;
2377 }
2378 
2379 static inline uint32_t
_stretch_region_accumulate(uint8_t * stretch_region,Eina_Bool mask,uint32_t * i)2380 _stretch_region_accumulate(uint8_t *stretch_region, Eina_Bool mask, uint32_t *i)
2381 {
2382    uint32_t acc;
2383 
2384    for (acc = 0;
2385         ((stretch_region[*i] & 0x80) == mask) && stretch_region[*i];
2386         (*i)++)
2387      acc += stretch_region[*i] & 0x7F;
2388 
2389    return acc;
2390 }
2391 
2392 static void
_evas_image_render_hband(Evas_Object_Protected_Data * obj,Evas_Image_Data * o,void * engine,void * output,void * context,void * surface,void * pixels,const int * imw,const int * imh EINA_UNUSED,int stretchw,int stretchh EINA_UNUSED,int * inx,int * iny,int * inw,int * inh,int * outx,int * outy,int * outw,int * outh,Eina_Bool do_async)2393 _evas_image_render_hband(Evas_Object_Protected_Data *obj, Evas_Image_Data *o,
2394                          void *engine, void *output, void *context,
2395                          void *surface, void *pixels,
2396                          const int *imw, const int *imh EINA_UNUSED,
2397                          int stretchw, int stretchh EINA_UNUSED,
2398                          int *inx, int *iny, int *inw, int *inh,
2399                          int *outx, int *outy, int *outw, int *outh,
2400                          Eina_Bool do_async)
2401 {
2402    uint32_t hacc;
2403    uint32_t hi;
2404 
2405    if (*inh == 0 || *outh == 0) goto end;
2406 
2407    hi = 0;
2408    while (o->cur->stretch.horizontal.region[hi])
2409      {
2410         // Not stretched horizontal
2411         hacc = _stretch_region_accumulate(o->cur->stretch.horizontal.region,
2412                                         0, &hi);
2413         *inw = hacc;
2414         *outw = hacc;
2415 
2416         if (*inw && *outw)
2417           _draw_image(obj, engine, output, context, surface, pixels,
2418                       *inx, *iny, *inw, *inh,
2419                       *outx, *outy, *outw, *outh,
2420                       o->cur->smooth_scale, do_async);
2421 
2422         // We always step before starting the new region
2423         *inx += *inw;
2424         *outx += *outw;
2425 
2426         // Horizontal stretched
2427         hacc = _stretch_region_accumulate(o->cur->stretch.horizontal.region,
2428                                         0x80, &hi);
2429         *inw = hacc;
2430         *outw = hacc * stretchw / o->cur->stretch.horizontal.stretchable;
2431 
2432         if (*inw)
2433           _draw_image(obj, engine, output, context, surface, pixels,
2434                       *inx, *iny, *inw, *inh,
2435                       *outx, *outy, *outw, *outh,
2436                       o->cur->smooth_scale, do_async);
2437 
2438         // We always step before starting the new region
2439         *inx += *inw;
2440         *outx += *outw;
2441      }
2442    // Finish end of image, not horizontally stretched
2443    *inw = *imw - *inx;
2444    *outw = *inw; // If my math are correct, this should be equal
2445 
2446    if (*inw)
2447      _draw_image(obj, engine, output, context, surface, pixels,
2448                  *inx, *iny, *inw, *inh,
2449                  *outx, *outy, *outw, *outh,
2450                  o->cur->smooth_scale, do_async);
2451 
2452  end:
2453    *iny += *inh; // We always step before starting the next region
2454    *outy += *outh;
2455 }
2456 
2457 static void
_evas_image_render(Eo * eo_obj,Evas_Object_Protected_Data * obj,void * engine,void * output,void * context,void * surface,int x,int y,int l,int t,int r,int b,Eina_Bool skip_map,Eina_Bool do_async)2458 _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
2459                    void *engine, void *output, void *context, void *surface, int x, int y,
2460                    int l, int t, int r, int b, Eina_Bool skip_map, Eina_Bool do_async)
2461 {
2462    Evas_Image_Data *o = obj->private_data;
2463    int imagew, imageh, uvw, uvh, cw, ch;
2464    int ix, iy, iw, ih, offx, offy;
2465    int idw, idh, idx, idy;
2466    void *pixels;
2467 
2468    pixels = _evas_image_pixels_get(eo_obj, obj, engine, output, context, surface, x, y,
2469                                    &imagew, &imageh, &uvw, &uvh, EINA_FALSE, EINA_FALSE);
2470 
2471    if (!pixels) return;
2472    if (ENFN->context_clip_get(engine, context, NULL, NULL, &cw, &ch) && (!cw || !ch))
2473      return;
2474 
2475    if (!skip_map && (obj->map->cur.map) && (obj->map->cur.map->count > 3)
2476        && (obj->map->cur.usemap))
2477      {
2478         evas_object_map_update(eo_obj, x, y, imagew, imageh, uvw, uvh);
2479 
2480         evas_draw_image_map_async_check(
2481           obj, engine, output, context, surface, pixels, obj->map->spans,
2482           o->cur->smooth_scale | obj->map->cur.map->smooth, 0, do_async);
2483 
2484         return;
2485      }
2486 
2487    _stretch_region_load(obj, o);
2488 
2489    ENFN->image_scale_hint_set(engine, pixels, o->scale_hint);
2490    idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw);
2491    idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh);
2492    if (idw < 1) idw = 1;
2493    if (idh < 1) idh = 1;
2494    if (idx > 0) idx -= idw;
2495    if (idy > 0) idy -= idh;
2496 
2497    offx = obj->cur->geometry.x + x;
2498    offy = obj->cur->geometry.y + y;
2499 
2500    while (idx < obj->cur->geometry.w)
2501      {
2502         int ydy, dobreak_w = 0;
2503 
2504         ydy = idy;
2505         ix = idx;
2506         if ((o->cur->fill.w == obj->cur->geometry.w) &&
2507             (o->cur->fill.x == 0))
2508           {
2509              dobreak_w = 1;
2510              iw = obj->cur->geometry.w;
2511           }
2512         else
2513           iw = idx + idw - ix;
2514 
2515         // Filter stuff
2516         if (o->filled)
2517           {
2518              iw -= l + r;
2519              if (iw <= 0) break;
2520           }
2521 
2522         while (idy < obj->cur->geometry.h)
2523           {
2524              int dobreak_h = 0;
2525 
2526              iy = idy;
2527              if ((o->cur->fill.h == obj->cur->geometry.h) &&
2528                  (o->cur->fill.y == 0))
2529                {
2530                   ih = obj->cur->geometry.h;
2531                   dobreak_h = 1;
2532                }
2533              else
2534                ih = idy + idh - iy;
2535 
2536              // Filter stuff
2537              if (o->filled)
2538                {
2539                   ih -= t + b;
2540                   if (ih <= 0) break;
2541                }
2542 
2543              if (o->cur->stretch.horizontal.region &&
2544                  o->cur->stretch.vertical.region)
2545                {
2546                   int inx, iny, inw, inh, outx, outy, outw, outh;
2547                   int ox, oy;
2548                   int imw, imh;
2549                   int stretchh, stretchw;
2550                   uint32_t vacc;
2551                   uint32_t vi;
2552 
2553                   imw = imagew;
2554                   imh = imageh;
2555                   ox = offx + ix;
2556                   oy = offy + iy;
2557                   iny = 0;
2558                   outy = oy;
2559 
2560                   // Check that the image is something we can deal with
2561                   if (imw < (int) o->cur->stretch.horizontal.total ||
2562                       imh < (int) o->cur->stretch.vertical.total)
2563                     break;
2564 
2565                   // Calculate the amount to stretch, by removing from the targetted size
2566                   // the amount that should not stretch from the source image
2567                   stretchw = iw - (imw - o->cur->stretch.horizontal.stretchable);
2568                   stretchh = ih - (imh - o->cur->stretch.vertical.stretchable);
2569 
2570                   // Check we have room to stretch
2571                   if (stretchh < 0) stretchh = 0;
2572                   if (stretchw < 0) stretchw = 0;
2573 
2574                   for (vi = 0; o->cur->stretch.vertical.region[vi]; )
2575                     {
2576                        vacc = _stretch_region_accumulate(o->cur->stretch.vertical.region, 0, &vi);
2577                        inx = 0;
2578                        outx = ox;
2579 
2580                        // Not stretching vertically step
2581                        inh = vacc;
2582                        outh = vacc;
2583 
2584                        _evas_image_render_hband(obj, o, engine, output, context,
2585                                                 surface, pixels,
2586                                                 &imw, &imh, stretchw, stretchh,
2587                                                 &inx, &iny, &inw, &inh,
2588                                                 &outx, &outy, &outw, &outh,
2589                                                 do_async);
2590 
2591                        // Stretching vertically step
2592                        vacc = _stretch_region_accumulate(o->cur->stretch.vertical.region, 0x80, &vi);
2593                        inx = 0;
2594                        outx = ox;
2595                        inh = vacc;
2596                        outh = vacc * stretchh / o->cur->stretch.vertical.stretchable;
2597 
2598                        _evas_image_render_hband(obj, o, engine, output, context,
2599                                                 surface, pixels,
2600                                                 &imw, &imh, stretchw, stretchh,
2601                                                 &inx, &iny, &inw, &inh,
2602                                                 &outx, &outy, &outw, &outh,
2603                                                 do_async);
2604                     }
2605                   // Finish end of image, not stretched vertical, not stretched horizontal
2606                   inx = 0;
2607                   outx = ox;
2608                   inh = imh - iny;
2609                   outh = inh; // Again, if my math are correct, this should be the same
2610 
2611                   _evas_image_render_hband(obj, o, engine, output, context,
2612                                            surface, pixels,
2613                                            &imw, &imh, stretchw, stretchh,
2614                                            &inx, &iny, &inw, &inh,
2615                                            &outx, &outy, &outw, &outh,
2616                                            do_async);
2617                }
2618              else if ((o->cur->border.l == 0) && (o->cur->border.r == 0) &&
2619                  (o->cur->border.t == 0) && (o->cur->border.b == 0) &&
2620                  (o->cur->border.fill != 0))
2621                {
2622                   _draw_image(obj, engine, output, context, surface, pixels,
2623                               0, 0, imagew, imageh,
2624                               offx + ix, offy + iy, iw, ih,
2625                               o->cur->smooth_scale, do_async);
2626                }
2627              else
2628                {
2629                   int inx, iny, inw, inh, outx, outy, outw, outh;
2630                   int bl, br, bt, bb, bsl, bsr, bst, bsb;
2631                   int imw, imh, ox, oy;
2632 
2633                   ox = offx + ix;
2634                   oy = offy + iy;
2635                   imw = imagew;
2636                   imh = imageh;
2637                   bl = o->cur->border.l;
2638                   br = o->cur->border.r;
2639                   bt = o->cur->border.t;
2640                   bb = o->cur->border.b;
2641                   // fix impossible border settings if img pixels not enough
2642                   if ((bl + br) > 0)
2643                     {
2644                        if ((bl + br) > imw)
2645                          {
2646                             bl = (bl * imw) / (bl + br);
2647                             br = imw - bl;
2648                          }
2649                        if ((bl + br) == imw)
2650                          {
2651                             if (bl < br) br--;
2652                             else bl--;
2653                          }
2654                     }
2655                   if ((bt + bb) > 0)
2656                     {
2657                        if ((bt + bb) > imh)
2658                          {
2659                             bt = (bt * imh) / (bt + bb);
2660                             bb = imh - bt;
2661                          }
2662                        if ((bt + bb) == imh)
2663                          {
2664                             if (bt < bb) bb--;
2665                             else bt--;
2666                          }
2667                     }
2668                   if (!EINA_DBL_EQ(o->cur->border.scale, 1.0))
2669                     {
2670                        bsl = ((double)bl * o->cur->border.scale);
2671                        bsr = ((double)br * o->cur->border.scale);
2672                        bst = ((double)bt * o->cur->border.scale);
2673                        bsb = ((double)bb * o->cur->border.scale);
2674                     }
2675                   else
2676                     {
2677                        bsl = bl; bsr = br; bst = bt; bsb = bb;
2678                     }
2679                   // adjust output border rendering if it doesnt fit
2680                   if ((bsl + bsr) > iw)
2681                     {
2682                        int b0 = bsl, b1 = bsr;
2683 
2684                        if ((bsl + bsr) > 0)
2685                          {
2686                             bsl = (bsl * iw) / (bsl + bsr);
2687                             bsr = iw - bsl;
2688                          }
2689                        if (b0 > 0) bl = (bl * bsl) / b0;
2690                        else bl = 0;
2691                        if (b1 > 0) br = (br * bsr) / b1;
2692                        else br = 0;
2693                     }
2694                   if ((bst + bsb) > ih)
2695                     {
2696                        int b0 = bst, b1 = bsb;
2697 
2698                        if ((bst + bsb) > 0)
2699                          {
2700                             bst = (bst * ih) / (bst + bsb);
2701                             bsb = ih - bst;
2702                          }
2703                        if (b0 > 0) bt = (bt * bst) / b0;
2704                        else bt = 0;
2705                        if (b1 > 0) bb = (bb * bsb) / b1;
2706                        else bb = 0;
2707                     }
2708                   // #--.
2709                   // |  |
2710                   // '--'
2711                   inx = 0; iny = 0;
2712                   inw = bl; inh = bt;
2713                   outx = ox; outy = oy;
2714                   outw = bsl; outh = bst;
2715                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2716                   // .##.
2717                   // |  |
2718                   // '--'
2719                   inx = bl; iny = 0;
2720                   inw = imw - bl - br; inh = bt;
2721                   outx = ox + bsl; outy = oy;
2722                   outw = iw - bsl - bsr; outh = bst;
2723                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2724                   // .--#
2725                   // |  |
2726                   // '--'
2727                   inx = imw - br; iny = 0;
2728                   inw = br; inh = bt;
2729                   outx = ox + iw - bsr; outy = oy;
2730                   outw = bsr; outh = bst;
2731                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2732                   // .--.
2733                   // #  |
2734                   // '--'
2735                   inx = 0; iny = bt;
2736                   inw = bl; inh = imh - bt - bb;
2737                   outx = ox; outy = oy + bst;
2738                   outw = bsl; outh = ih - bst - bsb;
2739                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2740                   // .--.
2741                   // |##|
2742                   // '--'
2743                   if (o->cur->border.fill > EVAS_BORDER_FILL_NONE)
2744                     {
2745                        inx = bl; iny = bt;
2746                        inw = imw - bl - br; inh = imh - bt - bb;
2747                        outx = ox + bsl; outy = oy + bst;
2748                        outw = iw - bsl - bsr; outh = ih - bst - bsb;
2749                        if ((o->cur->border.fill == EVAS_BORDER_FILL_SOLID) &&
2750                            (obj->cur->cache.clip.a == 255) &&
2751                            (!obj->clip.mask) &&
2752                            (obj->cur->render_op == EVAS_RENDER_BLEND))
2753                          {
2754                             ENFN->context_render_op_set(engine, context, EVAS_RENDER_COPY);
2755                             _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2756                             ENFN->context_render_op_set(engine, context, obj->cur->render_op);
2757                          }
2758                        else
2759                          _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2760                     }
2761                   // .--.
2762                   // |  #
2763                   // '--'
2764                   inx = imw - br; iny = bt;
2765                   inw = br; inh = imh - bt - bb;
2766                   outx = ox + iw - bsr; outy = oy + bst;
2767                   outw = bsr; outh = ih - bst - bsb;
2768                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2769                   // .--.
2770                   // |  |
2771                   // #--'
2772                   inx = 0; iny = imh - bb;
2773                   inw = bl; inh = bb;
2774                   outx = ox; outy = oy + ih - bsb;
2775                   outw = bsl; outh = bsb;
2776                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2777                   // .--.
2778                   // |  |
2779                   // '##'
2780                   inx = bl; iny = imh - bb;
2781                   inw = imw - bl - br; inh = bb;
2782                   outx = ox + bsl; outy = oy + ih - bsb;
2783                   outw = iw - bsl - bsr; outh = bsb;
2784                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2785                   // .--.
2786                   // |  |
2787                   // '--#
2788                   inx = imw - br; iny = imh - bb;
2789                   inw = br; inh = bb;
2790                   outx = ox + iw - bsr; outy = oy + ih - bsb;
2791                   outw = bsr; outh = bsb;
2792                   _draw_image(obj, engine, output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur->smooth_scale, do_async);
2793                }
2794              idy += idh;
2795              if (dobreak_h) break;
2796           }
2797         idx += idw;
2798         idy = ydy;
2799         if (dobreak_w) break;
2800      }
2801 }
2802 
2803 static void
evas_object_image_render_pre(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data)2804 evas_object_image_render_pre(Evas_Object *eo_obj,
2805                              Evas_Object_Protected_Data *obj,
2806                              void *type_private_data)
2807 {
2808    Evas_Image_Data *o = type_private_data;
2809    int is_v = 0, was_v = 0;
2810    Eina_Bool changed_prep = EINA_TRUE;
2811 
2812    /* image is not ready yet, skip rendering. Leave it to next frame */
2813    if (o->preload & EVAS_IMAGE_PRELOADING) return;
2814    /* dont pre-render the obj twice! */
2815    if (obj->pre_render_done) return;
2816    obj->pre_render_done = EINA_TRUE;
2817    /* pre-render phase. this does anything an object needs to do just before */
2818    /* rendering. this could mean loading the image data, retrieving it from */
2819    /* elsewhere, decoding video etc. */
2820    /* then when this is done the object needs to figure if it changed and */
2821    /* if so what and where and add the appropriate redraw rectangles */
2822    Evas_Public_Data *e = obj->layer->evas;
2823 
2824    if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1)) return;
2825 
2826    /* if someone is clipping this obj - go calculate the clipper */
2827    if (obj->cur->clipper)
2828      {
2829         if (obj->cur->cache.clip.dirty)
2830           evas_object_clip_recalc(obj->cur->clipper);
2831         obj->cur->clipper->func->render_pre(obj->cur->clipper->object,
2832                                             obj->cur->clipper,
2833                                             obj->cur->clipper->private_data);
2834      }
2835    /* Proxy: Do it early */
2836    if (o->cur->source)
2837      {
2838         Evas_Object_Protected_Data *source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
2839         if (source->proxy->redraw || source->changed)
2840           {
2841              /* XXX: Do I need to sort out the map here? */
2842              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2843              goto done;
2844           }
2845      }
2846 
2847    /* now figure what changed and add draw rects */
2848    /* if it just became visible or invisible */
2849    is_v = evas_object_is_visible(obj);
2850    was_v = evas_object_was_visible(obj);
2851    if (is_v != was_v)
2852      {
2853         evas_object_render_pre_visible_change(&e->clip_changes, eo_obj, is_v, was_v);
2854         goto done;
2855      }
2856    if (obj->changed_map || obj->changed_src_visible)
2857      {
2858         evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2859         goto done;
2860      }
2861    /* it's not visible - we accounted for it appearing or not so just abort */
2862    if (!is_v) goto done;
2863    /* clipper changed this is in addition to anything else for obj */
2864    if (was_v)
2865      evas_object_render_pre_clipper_change(&e->clip_changes, eo_obj);
2866    /* if we restacked (layer or just within a layer) and don't clip anyone */
2867    if (obj->restack)
2868      {
2869         evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2870         goto done;
2871      }
2872    /* if it changed color */
2873    if ((obj->cur->color.r != obj->prev->color.r) ||
2874        (obj->cur->color.g != obj->prev->color.g) ||
2875        (obj->cur->color.b != obj->prev->color.b) ||
2876        (obj->cur->color.a != obj->prev->color.a) ||
2877        (obj->cur->cache.clip.r != obj->prev->cache.clip.r) ||
2878        (obj->cur->cache.clip.g != obj->prev->cache.clip.g) ||
2879        (obj->cur->cache.clip.b != obj->prev->cache.clip.b) ||
2880        (obj->cur->cache.clip.a != obj->prev->cache.clip.a))
2881      {
2882         evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2883         goto done;
2884      }
2885    if ((obj->cur->render_op != obj->prev->render_op) ||  /* if it changed render op */
2886        (obj->cur->anti_alias != obj->prev->anti_alias))  /* if it changed anti_alias */
2887      {
2888         evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2889         goto done;
2890      }
2891    if (o->changed)
2892      {
2893         if (o->changed_filter)
2894           {
2895              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2896              goto done;
2897           }
2898         if (((o->cur->f) && (!o->prev->f)) ||
2899             ((!o->cur->f) && (o->prev->f)) ||
2900             ((o->cur->key) && (!o->prev->key)) ||
2901             ((!o->cur->key) && (o->prev->key))
2902             )
2903           {
2904              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2905              goto done;
2906           }
2907         if ((o->cur->image.w != o->prev->image.w) ||
2908             (o->cur->image.h != o->prev->image.h) ||
2909             (o->cur->has_alpha != o->prev->has_alpha) ||
2910             (o->cur->cspace != o->prev->cspace) ||
2911             (o->cur->smooth_scale != o->prev->smooth_scale))
2912           {
2913              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2914              goto done;
2915           }
2916         if ((o->cur->border.l != o->prev->border.l) ||
2917             (o->cur->border.r != o->prev->border.r) ||
2918             (o->cur->border.t != o->prev->border.t) ||
2919             (o->cur->border.b != o->prev->border.b) ||
2920             (o->cur->border.fill != o->prev->border.fill) ||
2921             (!EINA_DBL_EQ(o->cur->border.scale, o->prev->border.scale)))
2922           {
2923              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2924              goto done;
2925           }
2926         if ((o->cur->frame != o->prev->frame) ||
2927             (o->cur->orient != o->prev->orient) ||
2928              /* Legacy compatibility (invalid behaviour): dirty_set() used to
2929               * trigger full image redraw, even though this was not correct. */
2930             (o->dirty_pixels && !o->pixels->pixel_updates))
2931           {
2932              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2933              goto done;
2934           }
2935         //pre-loading is finished
2936         if (o->preload == EVAS_IMAGE_PRELOADED)
2937           {
2938              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2939              o->preload = EVAS_IMAGE_PRELOAD_NONE;
2940              goto done;
2941           }
2942      }
2943    if (((obj->cur->geometry.x != obj->prev->geometry.x) ||
2944         (obj->cur->geometry.y != obj->prev->geometry.y) ||
2945         (obj->cur->geometry.w != obj->prev->geometry.w) ||
2946         (obj->cur->geometry.h != obj->prev->geometry.h))
2947        )
2948      {
2949         if ((obj->cur->geometry.w == obj->prev->geometry.w) &&
2950             (obj->cur->geometry.h == obj->prev->geometry.h))
2951           {
2952              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2953           }
2954         else
2955           {
2956              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2957              goto done;
2958           }
2959      }
2960    if (o->changed)
2961      {
2962         if ((o->cur->fill.x != o->prev->fill.x) ||
2963             (o->cur->fill.y != o->prev->fill.y) ||
2964             (o->cur->fill.w != o->prev->fill.w) ||
2965             (o->cur->fill.h != o->prev->fill.h))
2966           {
2967              evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj, obj);
2968              goto done;
2969           }
2970         if (o->pixels->pixel_updates)
2971           {
2972              if ((o->cur->border.l == 0) &&
2973                  (o->cur->border.r == 0) &&
2974                  (o->cur->border.t == 0) &&
2975                  (o->cur->border.b == 0) &&
2976                  (o->cur->image.w > 0) &&
2977                  (o->cur->image.h > 0) &&
2978                  (!((obj->map->cur.map) && (obj->map->cur.usemap))))
2979                {
2980                   Eina_Rectangle *rr;
2981 
2982                   if ((!o->cur->has_alpha) &&
2983                       (evas_object_is_opaque(obj)) &&
2984                       (obj->cur->color.a == 255))
2985                     {
2986                        Evas_Coord x, y, w, h;
2987 
2988                        x = obj->cur->cache.clip.x;
2989                        y = obj->cur->cache.clip.y;
2990                        w = obj->cur->cache.clip.w;
2991                        h = obj->cur->cache.clip.h;
2992                        if (obj->cur->clipper)
2993                          {
2994                             if (obj->cur->clipper->cur->cache.clip.a != 255)
2995                               w = 0;
2996                             else
2997                               {
2998                                  RECTS_CLIP_TO_RECT(x, y, w, h,
2999                                                     obj->cur->clipper->cur->cache.clip.x,
3000                                                     obj->cur->clipper->cur->cache.clip.y,
3001                                                     obj->cur->clipper->cur->cache.clip.w,
3002                                                     obj->cur->clipper->cur->cache.clip.h);
3003                               }
3004                          }
3005                        if ((w > 0) && (h > 0))
3006                          evas_render_update_del(e,
3007                                                 x + e->framespace.x,
3008                                                 y + e->framespace.y,
3009                                                 w, h);
3010                     }
3011                   EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
3012                   {
3013                      EINA_LIST_FREE(pixi_write->pixel_updates, rr)
3014                        {
3015                           Evas_Coord idw, idh, idx, idy;
3016                           int x, y, w, h;
3017                           e->engine.func->image_dirty_region(ENC, o->engine_data, rr->x, rr->y, rr->w, rr->h);
3018 
3019                           idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw);
3020                           idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh);
3021 
3022                           if (idw < 1) idw = 1;
3023                           if (idh < 1) idh = 1;
3024                           if (idx > 0) idx -= idw;
3025                           if (idy > 0) idy -= idh;
3026                           while (idx < obj->cur->geometry.w)
3027                             {
3028                                Evas_Coord ydy;
3029 
3030                                ydy = idy;
3031                                x = idx;
3032                                w = ((int)(idx + idw)) - x;
3033                                while (idy < obj->cur->geometry.h)
3034                                  {
3035                                     Eina_Rectangle r;
3036 
3037                                     y = idy;
3038                                     h = ((int)(idy + idh)) - y;
3039 
3040                                     r.x = (rr->x * w) / o->cur->image.w;
3041                                     r.y = (rr->y * h) / o->cur->image.h;
3042                                     r.w = ((rr->w * w) + (o->cur->image.w * 2) - 1) / o->cur->image.w;
3043                                     r.h = ((rr->h * h) + (o->cur->image.h * 2) - 1) / o->cur->image.h;
3044                                     r.x += obj->cur->geometry.x + x;
3045                                     r.y += obj->cur->geometry.y + y;
3046                                     RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h,
3047                                                        obj->cur->cache.clip.x, obj->cur->cache.clip.y,
3048                                                        obj->cur->cache.clip.w, obj->cur->cache.clip.h);
3049                                     evas_add_rect(&e->clip_changes, r.x, r.y, r.w, r.h);
3050                                     idy += h;
3051                                  }
3052                                idx += idw;
3053                                idy = ydy;
3054                             }
3055                           eina_rectangle_free(rr);
3056                        }
3057                   }
3058                   EINA_COW_PIXEL_WRITE_END(o, pixi_write);
3059                }
3060              else
3061                {
3062                   if ((o->cur->image.w > 0) &&
3063                       (o->cur->image.h > 0) &&
3064                       (o->cur->image.w == obj->cur->geometry.w) &&
3065                       (o->cur->image.h == obj->cur->geometry.h) &&
3066                       (o->cur->fill.x == 0) &&
3067                       (o->cur->fill.y == 0) &&
3068                       (o->cur->fill.w == o->cur->image.w) &&
3069                       (o->cur->fill.h == o->cur->image.h) &&
3070                       (!((obj->map->cur.map) && (obj->map->cur.usemap))))
3071                     {
3072                        Eina_Rectangle *rr;
3073 
3074                        if ((!o->cur->has_alpha) &&
3075                            (evas_object_is_opaque(obj)) &&
3076                            (obj->cur->color.a == 255))
3077                          {
3078                             Evas_Coord x, y, w, h;
3079 
3080                             x = obj->cur->cache.clip.x;
3081                             y = obj->cur->cache.clip.y;
3082                             w = obj->cur->cache.clip.w;
3083                             h = obj->cur->cache.clip.h;
3084                             if (obj->cur->clipper)
3085                               {
3086                                  if (obj->cur->clipper->cur->cache.clip.a != 255)
3087                                    w = 0;
3088                                  else
3089                                    {
3090                                       RECTS_CLIP_TO_RECT(x, y, w, h,
3091                                                          obj->cur->clipper->cur->cache.clip.x,
3092                                                          obj->cur->clipper->cur->cache.clip.y,
3093                                                          obj->cur->clipper->cur->cache.clip.w,
3094                                                          obj->cur->clipper->cur->cache.clip.h);
3095                                    }
3096                               }
3097                             if ((w > 0) && (h > 0))
3098                               evas_render_update_del(e,
3099                                                      x + e->framespace.x,
3100                                                      y + e->framespace.y,
3101                                                      w, h);
3102                          }
3103                        else if ((o->cur->border.fill == EVAS_BORDER_FILL_SOLID) &&
3104                                 (obj->cur->color.a == 255))
3105                          {
3106                             Evas_Coord x, y, w, h;
3107 
3108                             x = obj->cur->geometry.x + o->cur->border.l;
3109                             y = obj->cur->geometry.y + o->cur->border.t;
3110                             w = obj->cur->geometry.w - o->cur->border.l - o->cur->border.r;
3111                             h = obj->cur->geometry.h - o->cur->border.t - o->cur->border.b;
3112                             if (obj->cur->clipper)
3113                               {
3114                                  if (obj->cur->clipper->cur->cache.clip.a != 255)
3115                                    w = 0;
3116                                  else
3117                                    {
3118                                       RECTS_CLIP_TO_RECT(x, y, w, h,
3119                                                          obj->cur->clipper->cur->cache.clip.x,
3120                                                          obj->cur->clipper->cur->cache.clip.y,
3121                                                          obj->cur->clipper->cur->cache.clip.w,
3122                                                          obj->cur->clipper->cur->cache.clip.h);
3123                                    }
3124                               }
3125                             if ((w > 0) && (h > 0))
3126                               evas_render_update_del(e,
3127                                                      x + e->framespace.x,
3128                                                      y + e->framespace.y,
3129                                                      w, h);
3130                          }
3131                        EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
3132                        {
3133                           EINA_LIST_FREE(pixi_write->pixel_updates, rr)
3134                             {
3135                                Eina_Rectangle r;
3136 
3137                                e->engine.func->image_dirty_region(ENC, o->engine_data, rr->x, rr->y, rr->w, rr->h);
3138                                r.x = rr->x;
3139                                r.y = rr->y;
3140                                r.w = rr->w;
3141                                r.h = rr->h;
3142                                r.x += obj->cur->geometry.x;
3143                                r.y += obj->cur->geometry.y;
3144                                RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h,
3145                                                   obj->cur->cache.clip.x, obj->cur->cache.clip.y,
3146                                                   obj->cur->cache.clip.w, obj->cur->cache.clip.h);
3147                                evas_add_rect(&e->clip_changes, r.x, r.y, r.w, r.h);
3148                                eina_rectangle_free(rr);
3149                             }
3150                        }
3151                        EINA_COW_PIXEL_WRITE_END(o, pixi_write);
3152                     }
3153                   else
3154                     {
3155                        Eina_Rectangle *r;
3156 
3157                        EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
3158                        {
3159                           EINA_LIST_FREE(pixi_write->pixel_updates, r)
3160                             eina_rectangle_free(r);
3161                        }
3162                        EINA_COW_PIXEL_WRITE_END(o, pixi_write);
3163                        e->engine.func->image_dirty_region(ENC, o->engine_data, 0, 0, o->cur->image.w, o->cur->image.h);
3164 
3165                        evas_object_render_pre_prev_cur_add(&e->clip_changes, eo_obj,
3166                                                            obj);
3167                     }
3168                }
3169              goto done;
3170           }
3171      }
3172    /* it obviously didn't change - add a NO obscure - this "unupdates"  this */
3173    /* area so if there were updates for it they get wiped. don't do it if we */
3174    /* aren't fully opaque and we are visible */
3175    if (evas_object_is_opaque(obj))
3176      {
3177         Evas_Coord x, y, w, h;
3178 
3179         x = obj->cur->cache.clip.x;
3180         y = obj->cur->cache.clip.y;
3181         w = obj->cur->cache.clip.w;
3182         h = obj->cur->cache.clip.h;
3183         if (obj->cur->clipper)
3184           {
3185              RECTS_CLIP_TO_RECT(x, y, w, h,
3186                                 obj->cur->clipper->cur->cache.clip.x,
3187                                 obj->cur->clipper->cur->cache.clip.y,
3188                                 obj->cur->clipper->cur->cache.clip.w,
3189                                 obj->cur->clipper->cur->cache.clip.h);
3190           }
3191         evas_render_update_del(e,
3192                                x + e->framespace.x,
3193                                y + e->framespace.y,
3194                                w, h);
3195         changed_prep = EINA_FALSE;
3196      }
3197    else
3198      changed_prep = EINA_FALSE;
3199 done:
3200    evas_object_render_pre_effect_updates(&e->clip_changes, eo_obj, is_v, was_v);
3201    if (o->pixels->pixel_updates)
3202      {
3203         Eina_Rectangle *rr;
3204 
3205         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
3206         {
3207            EINA_LIST_FREE(pixi_write->pixel_updates, rr)
3208              {
3209                 eina_rectangle_free(rr);
3210              }
3211         }
3212         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
3213      }
3214    if (changed_prep)
3215      {
3216         if (o->engine_data_prep)
3217           {
3218              ENFN->image_free(ENC, o->engine_data_prep);
3219              o->engine_data_prep = NULL;
3220           }
3221      }
3222    o->changed = EINA_FALSE;
3223    o->changed_filter = EINA_FALSE;
3224 }
3225 
3226 static void
evas_object_image_render_post(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data)3227 evas_object_image_render_post(Evas_Object *eo_obj EINA_UNUSED,
3228                               Evas_Object_Protected_Data *obj,
3229                               void *type_private_data)
3230 {
3231    Evas_Image_Data *o = type_private_data;
3232    Eina_Rectangle *r;
3233 
3234    /* image is not ready yet, skip rendering. Leave it to next frame */
3235    if (o->preload & EVAS_IMAGE_PRELOADING) return;
3236 
3237    /* this moves the current data to the previous state parts of the object */
3238    /* in whatever way is safest for the object. also if we don't need object */
3239    /* data anymore we can free it if the object deems this is a good idea */
3240    /* remove those pesky changes */
3241    evas_object_clip_changes_clean(obj);
3242 
3243    if (o->pixels->pixel_updates)
3244      {
3245         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
3246         {
3247            EINA_LIST_FREE(pixi_write->pixel_updates, r)
3248              eina_rectangle_free(r);
3249         }
3250         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
3251      }
3252 
3253    /* move cur to prev safely for object data */
3254    evas_object_cur_prev(obj);
3255    eina_cow_memcpy(evas_object_image_state_cow, (const Eina_Cow_Data **)&o->prev, o->cur);
3256    /* FIXME: copy strings across */
3257 
3258    //Somehow(preloading cancelled) image has been changed, need to redraw.
3259    if (o->changed) evas_render_post_change_object_push(obj);
3260 }
3261 
3262 static void *
evas_object_image_engine_data_get(Evas_Object * eo_obj)3263 evas_object_image_engine_data_get(Evas_Object *eo_obj)
3264 {
3265    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
3266    if (!o) return NULL;
3267    return o->engine_data;
3268 }
3269 
3270 static int
evas_object_image_is_opaque(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data)3271 evas_object_image_is_opaque(Evas_Object *eo_obj EINA_UNUSED,
3272                             Evas_Object_Protected_Data *obj,
3273                             void *type_private_data)
3274 {
3275    /* this returns 1 if the internal object data implies that the object is */
3276    /* currently fully opaque over the entire rectangle it occupies */
3277 /*  disable caching due tyo maps screwing with this
3278     o->cur.opaque_valid = 0;*/
3279    Evas_Image_Data *o = type_private_data;
3280 
3281    if (o->preload == EVAS_IMAGE_PRELOADING) return 0;
3282 
3283    if (o->cur->opaque_valid)
3284      {
3285         if (!o->cur->opaque) return 0;
3286      }
3287    else
3288      {
3289         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
3290         {
3291            state_write->opaque = 0;
3292            state_write->opaque_valid = 1;
3293         }
3294         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
3295 
3296         if ((o->cur->fill.w < 1) || (o->cur->fill.h < 1))
3297           return o->cur->opaque;
3298         if (((o->cur->border.l != 0) ||
3299              (o->cur->border.r != 0) ||
3300              (o->cur->border.t != 0) ||
3301              (o->cur->border.b != 0)) &&
3302             (!o->cur->border.fill))
3303           return o->cur->opaque;
3304         if (!o->engine_data)
3305           return o->cur->opaque;
3306         if (o->has_filter)
3307           return o->cur->opaque;
3308 
3309         // FIXME: use proxy
3310         if (o->cur->source)
3311           {
3312              Evas_Object_Protected_Data *cur_source = efl_data_scope_get(o->cur->source, EFL_CANVAS_OBJECT_CLASS);
3313              EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
3314              {
3315                 state_write->opaque = evas_object_is_opaque(cur_source);
3316              }
3317              EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
3318              return o->cur->opaque; /* FIXME: Should go poke at the object */
3319           }
3320         if (o->cur->has_alpha)
3321           return o->cur->opaque;
3322 
3323         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
3324         {
3325            state_write->opaque = 1;
3326         }
3327         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
3328      }
3329 
3330    if ((obj->map->cur.map) && (obj->map->cur.usemap))
3331      {
3332         Evas_Map *m = obj->map->cur.map;
3333 
3334         if ((m->points[0].a == 255) &&
3335             (m->points[1].a == 255) &&
3336             (m->points[2].a == 255) &&
3337             (m->points[3].a == 255))
3338           {
3339              if (((EINA_DBL_EQ(m->points[0].x, m->points[3].x)) &&
3340                   (EINA_DBL_EQ(m->points[1].x, m->points[2].x)) &&
3341                   (EINA_DBL_EQ(m->points[0].y, m->points[1].y)) &&
3342                   (EINA_DBL_EQ(m->points[2].y, m->points[3].y))) ||
3343                  ((EINA_DBL_EQ(m->points[0].x, m->points[1].x)) &&
3344                   (EINA_DBL_EQ(m->points[2].x, m->points[3].x)) &&
3345                   (EINA_DBL_EQ(m->points[0].y, m->points[3].y)) &&
3346                   (EINA_DBL_EQ(m->points[1].y, m->points[2].y))))
3347                {
3348                   if ((EINA_DBL_EQ(m->points[0].x, obj->cur->geometry.x)) &&
3349                       (EINA_DBL_EQ(m->points[0].y, obj->cur->geometry.y)) &&
3350                       (EINA_DBL_EQ(m->points[2].x,
3351                                    obj->cur->geometry.x + obj->cur->geometry.w)) &&
3352                       (EINA_DBL_EQ(m->points[2].y,
3353                                    obj->cur->geometry.y + obj->cur->geometry.h)))
3354                     return o->cur->opaque;
3355                }
3356           }
3357 
3358         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
3359         {
3360            state_write->opaque = 0;
3361         }
3362         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
3363 
3364         return o->cur->opaque;
3365      }
3366    if (obj->cur->render_op == EVAS_RENDER_COPY)
3367      {
3368         EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
3369         {
3370            state_write->opaque = 1;
3371         }
3372         EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
3373 
3374         return o->cur->opaque;
3375      }
3376    return o->cur->opaque;
3377 }
3378 
3379 static int
evas_object_image_was_opaque(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data)3380 evas_object_image_was_opaque(Evas_Object *eo_obj EINA_UNUSED,
3381                              Evas_Object_Protected_Data *obj,
3382                              void *type_private_data)
3383 {
3384    Evas_Image_Data *o = type_private_data;
3385 
3386    /* this returns 1 if the internal object data implies that the object was */
3387    /* previously fully opaque over the entire rectangle it occupies */
3388    if (o->prev->opaque_valid)
3389      {
3390         if (!o->prev->opaque) return 0;
3391      }
3392    else
3393      {
3394         EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
3395         {
3396            state_write->opaque = 0;
3397            state_write->opaque_valid = 1;
3398         }
3399         EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
3400 
3401         if ((o->prev->fill.w < 1) || (o->prev->fill.h < 1))
3402           return o->prev->opaque;
3403         if (((o->prev->border.l != 0) ||
3404              (o->prev->border.r != 0) ||
3405              (o->prev->border.t != 0) ||
3406              (o->prev->border.b != 0)) &&
3407             (!o->prev->border.fill))
3408           return o->prev->opaque;
3409         if (!o->engine_data)
3410           return o->prev->opaque;
3411 
3412         // FIXME: use proxy
3413         if (o->prev->source)
3414           return o->prev->opaque;  /* FIXME: Should go poke at the object */
3415         if (o->prev->has_alpha)
3416           return o->prev->opaque;
3417         if (o->has_filter)
3418           return o->cur->opaque;
3419 
3420         EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
3421         {
3422            state_write->opaque = 1;
3423         }
3424         EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
3425      }
3426    if (obj->map->prev.usemap)
3427      {
3428         Evas_Map *m = obj->map->prev.map;
3429 
3430         if ((m->points[0].a == 255) &&
3431             (m->points[1].a == 255) &&
3432             (m->points[2].a == 255) &&
3433             (m->points[3].a == 255))
3434           {
3435              if (((EINA_DBL_EQ(m->points[0].x, m->points[3].x)) &&
3436                   (EINA_DBL_EQ(m->points[1].x, m->points[2].x)) &&
3437                   (EINA_DBL_EQ(m->points[0].y, m->points[1].y)) &&
3438                   (EINA_DBL_EQ(m->points[2].y, m->points[3].y))) ||
3439                  ((EINA_DBL_EQ(m->points[0].x, m->points[1].x)) &&
3440                   (EINA_DBL_EQ(m->points[2].x, m->points[3].x)) &&
3441                   (EINA_DBL_EQ(m->points[0].y, m->points[3].y)) &&
3442                   (EINA_DBL_EQ(m->points[1].y, m->points[2].y))))
3443                {
3444                   if ((EINA_DBL_EQ(m->points[0].x, obj->prev->geometry.x)) &&
3445                       (EINA_DBL_EQ(m->points[0].y, obj->prev->geometry.y)) &&
3446                       (EINA_DBL_EQ(m->points[2].x,
3447                                    obj->prev->geometry.x + obj->prev->geometry.w)) &&
3448                       (EINA_DBL_EQ(m->points[2].y,
3449                                    obj->prev->geometry.y + obj->prev->geometry.h)))
3450                     return o->prev->opaque;
3451                }
3452           }
3453 
3454         EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
3455         {
3456            state_write->opaque = 0;
3457         }
3458         EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
3459 
3460         return o->prev->opaque;
3461      }
3462    if (obj->prev->render_op == EVAS_RENDER_COPY)
3463      {
3464         EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
3465         {
3466            state_write->opaque = 1;
3467         }
3468         EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
3469 
3470         return o->prev->opaque;
3471      }
3472    if (obj->prev->render_op != EVAS_RENDER_BLEND)
3473      {
3474         EINA_COW_WRITE_BEGIN(evas_object_image_state_cow, o->prev, Evas_Object_Image_State, state_write)
3475         {
3476            state_write->opaque = 0;
3477         }
3478         EINA_COW_WRITE_END(evas_object_image_state_cow, o->prev, state_write);
3479 
3480         return o->prev->opaque;
3481      }
3482    return o->prev->opaque;
3483 }
3484 
3485 static int
evas_object_image_is_inside(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * type_private_data,Evas_Coord px,Evas_Coord py)3486 evas_object_image_is_inside(Evas_Object *eo_obj,
3487                             Evas_Object_Protected_Data *obj,
3488                             void *type_private_data,
3489                             Evas_Coord px, Evas_Coord py)
3490 {
3491    Evas_Image_Data *o = type_private_data;
3492    int imagew, imageh, uvw, uvh, ix, iy, iw, ih, idw, idh, idx, idy;
3493    int is_inside = 0;
3494    void *pixels;
3495    void *output;
3496 
3497    // FIXME: The below loop is incredibly dubious and probably should be simplified.
3498    // We're looking for one single pixel, not a random series of positions.
3499    // Original comment:
3500    /* the following code is similar to evas_object_image_render(), but doesn't
3501     * draw, just get the pixels so we can check the transparency.
3502     */
3503    output = _evas_object_image_output_find(obj);
3504    pixels = _evas_image_pixels_get(eo_obj, obj, ENC, output, NULL, NULL, 0, 0,
3505                                    &imagew, &imageh, &uvw, &uvh, EINA_TRUE, EINA_FALSE);
3506    if (!pixels) return is_inside;
3507 
3508    if (o->dirty_pixels)
3509      {
3510         if (o->pixels->func.get_pixels)
3511           {
3512              if (ENFN->gl_get_pixels_pre)
3513                ENFN->gl_get_pixels_pre(ENC, output);
3514              o->pixels->func.get_pixels(o->pixels->func.get_pixels_data, eo_obj);
3515              if (ENFN->gl_get_pixels_post)
3516                ENFN->gl_get_pixels_post(ENC, output);
3517              pixels = _evas_image_pixels_get(eo_obj, obj, ENC, output, NULL, NULL, 0, 0,
3518                                              &imagew, &imageh, &uvw, &uvh, EINA_TRUE, EINA_FALSE);
3519              if (!pixels) return is_inside;
3520           }
3521      }
3522 
3523    /* TODO: not handling map, need to apply map to point */
3524    if ((obj->map->cur.map) && (obj->map->cur.map->count > 3) && (obj->map->cur.usemap))
3525      {
3526         evas_object_map_update(eo_obj, 0, 0, imagew, imageh, uvw, uvh);
3527 
3528         ERR("map not supported");
3529         return is_inside;
3530      }
3531 
3532    idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw);
3533    idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh);
3534    if (idw < 1) idw = 1;
3535    if (idh < 1) idh = 1;
3536    if (idx > 0) idx -= idw;
3537    if (idy > 0) idy -= idh;
3538 
3539    while (idx < obj->cur->geometry.w)
3540      {
3541         int ydy, dobreak_w = 0;
3542 
3543         ydy = idy;
3544         ix = idx;
3545         if ((o->cur->fill.w == obj->cur->geometry.w) &&
3546             (o->cur->fill.x == 0))
3547           {
3548              dobreak_w = 1;
3549              iw = obj->cur->geometry.w;
3550           }
3551         else
3552           iw = idx + idw - ix;
3553 
3554         while (idy < obj->cur->geometry.h)
3555           {
3556              int dobreak_h = 0;
3557              DATA8 alpha = 0;
3558 
3559              iy = idy;
3560              if ((o->cur->fill.h == obj->cur->geometry.h) &&
3561                  (o->cur->fill.y == 0))
3562                {
3563                   ih = obj->cur->geometry.h;
3564                   dobreak_h = 1;
3565                }
3566              else
3567                ih = idy + idh - iy;
3568 
3569              if ((o->cur->border.l == 0) && (o->cur->border.r == 0) &&
3570                  (o->cur->border.t == 0) && (o->cur->border.b == 0) &&
3571                  (o->cur->border.fill != 0))
3572                {
3573                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3574                                             0, 0, imagew, imageh,
3575                                             obj->cur->geometry.x + ix,
3576                                             obj->cur->geometry.y + iy,
3577                                             iw, ih))
3578                     {
3579                        is_inside = alpha > 0;
3580                        dobreak_h = 1;
3581                        dobreak_w = 1;
3582                        break;
3583                     }
3584                }
3585              else
3586                {
3587                   int inx, iny, inw, inh, outx, outy, outw, outh;
3588                   int bl, br, bt, bb, bsl, bsr, bst, bsb;
3589                   int imw, imh, ox, oy;
3590 
3591                   ox = obj->cur->geometry.x + ix;
3592                   oy = obj->cur->geometry.y + iy;
3593                   imw = imagew;
3594                   imh = imageh;
3595                   bl = o->cur->border.l;
3596                   br = o->cur->border.r;
3597                   bt = o->cur->border.t;
3598                   bb = o->cur->border.b;
3599                   if ((bl + br) > iw)
3600                     {
3601                        bl = iw / 2;
3602                        br = iw - bl;
3603                     }
3604                   if ((bl + br) > imw)
3605                     {
3606                        bl = imw / 2;
3607                        br = imw - bl;
3608                     }
3609                   if ((bt + bb) > ih)
3610                     {
3611                        bt = ih / 2;
3612                        bb = ih - bt;
3613                     }
3614                   if ((bt + bb) > imh)
3615                     {
3616                        bt = imh / 2;
3617                        bb = imh - bt;
3618                     }
3619                   if (!EINA_DBL_EQ(o->cur->border.scale, 1.0))
3620                     {
3621                        bsl = ((double)bl * o->cur->border.scale);
3622                        bsr = ((double)br * o->cur->border.scale);
3623                        bst = ((double)bt * o->cur->border.scale);
3624                        bsb = ((double)bb * o->cur->border.scale);
3625                     }
3626                   else
3627                     {
3628                        bsl = bl; bsr = br; bst = bt; bsb = bb;
3629                     }
3630                   // #--
3631                   // |
3632                   inx = 0; iny = 0;
3633                   inw = bl; inh = bt;
3634                   outx = ox; outy = oy;
3635                   outw = bsl; outh = bst;
3636                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3637                                             inx, iny, inw, inh,
3638                                             outx, outy, outw, outh))
3639                     {
3640                        is_inside = alpha > 0;
3641                        dobreak_h = 1;
3642                        dobreak_w = 1;
3643                        break;
3644                     }
3645 
3646                   // .##
3647                   // |
3648                   inx = bl; iny = 0;
3649                   inw = imw - bl - br; inh = bt;
3650                   outx = ox + bsl; outy = oy;
3651                   outw = iw - bsl - bsr; outh = bst;
3652                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3653                                             inx, iny, inw, inh,
3654                                             outx, outy, outw, outh))
3655                     {
3656                        is_inside = alpha > 0;
3657                        dobreak_h = 1;
3658                        dobreak_w = 1;
3659                        break;
3660                     }
3661                   // --#
3662                   //   |
3663                   inx = imw - br; iny = 0;
3664                   inw = br; inh = bt;
3665                   outx = ox + iw - bsr; outy = oy;
3666                   outw = bsr; outh = bst;
3667                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3668                                             inx, iny, inw, inh,
3669                                             outx, outy, outw, outh))
3670                     {
3671                        is_inside = alpha > 0;
3672                        dobreak_h = 1;
3673                        dobreak_w = 1;
3674                        break;
3675                     }
3676                   // .--
3677                   // #
3678                   inx = 0; iny = bt;
3679                   inw = bl; inh = imh - bt - bb;
3680                   outx = ox; outy = oy + bst;
3681                   outw = bsl; outh = ih - bst - bsb;
3682                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3683                                             inx, iny, inw, inh,
3684                                             outx, outy, outw, outh))
3685                     {
3686                        is_inside = alpha > 0;
3687                        dobreak_h = 1;
3688                        dobreak_w = 1;
3689                        break;
3690                     }
3691                   // .--.
3692                   // |##|
3693                   if (o->cur->border.fill > EVAS_BORDER_FILL_NONE)
3694                     {
3695                        inx = bl; iny = bt;
3696                        inw = imw - bl - br; inh = imh - bt - bb;
3697                        outx = ox + bsl; outy = oy + bst;
3698                        outw = iw - bsl - bsr; outh = ih - bst - bsb;
3699                        if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3700                                                  inx, iny, inw, inh,
3701                                                  outx, outy, outw, outh))
3702                          {
3703                             is_inside = alpha > 0;
3704                             dobreak_h = 1;
3705                             dobreak_w = 1;
3706                             break;
3707                          }
3708                     }
3709                   // --.
3710                   //   #
3711                   inx = imw - br; iny = bt;
3712                   inw = br; inh = imh - bt - bb;
3713                   outx = ox + iw - bsr; outy = oy + bst;
3714                   outw = bsr; outh = ih - bst - bsb;
3715                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3716                                             inx, iny, inw, inh,
3717                                             outx, outy, outw, outh))
3718                     {
3719                        is_inside = alpha > 0;
3720                        dobreak_h = 1;
3721                        dobreak_w = 1;
3722                        break;
3723                     }
3724                   // |
3725                   // #--
3726                   inx = 0; iny = imh - bb;
3727                   inw = bl; inh = bb;
3728                   outx = ox; outy = oy + ih - bsb;
3729                   outw = bsl; outh = bsb;
3730                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3731                                             inx, iny, inw, inh,
3732                                             outx, outy, outw, outh))
3733                     {
3734                        is_inside = alpha > 0;
3735                        dobreak_h = 1;
3736                        dobreak_w = 1;
3737                        break;
3738                     }
3739                   // |
3740                   // .##
3741                   inx = bl; iny = imh - bb;
3742                   inw = imw - bl - br; inh = bb;
3743                   outx = ox + bsl; outy = oy + ih - bsb;
3744                   outw = iw - bsl - bsr; outh = bsb;
3745                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3746                                             inx, iny, inw, inh,
3747                                             outx, outy, outw, outh))
3748                     {
3749                        is_inside = alpha > 0;
3750                        dobreak_h = 1;
3751                        dobreak_w = 1;
3752                        break;
3753                     }
3754                   //   |
3755                   // --#
3756                   inx = imw - br; iny = imh - bb;
3757                   inw = br; inh = bb;
3758                   outx = ox + iw - bsr; outy = oy + ih - bsb;
3759                   outw = bsr; outh = bsb;
3760                   if (ENFN->pixel_alpha_get(pixels, px, py, &alpha,
3761                                             inx, iny, inw, inh,
3762                                             outx, outy, outw, outh))
3763                     {
3764                        is_inside = alpha > 0;
3765                        dobreak_h = 1;
3766                        dobreak_w = 1;
3767                        break;
3768                     }
3769                }
3770              idy += idh;
3771              if (dobreak_h) break;
3772           }
3773         idx += idw;
3774         idy = ydy;
3775         if (dobreak_w) break;
3776      }
3777 
3778    return is_inside;
3779 }
3780 
3781 static int
evas_object_image_has_opaque_rect(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data)3782 evas_object_image_has_opaque_rect(Evas_Object *eo_obj EINA_UNUSED,
3783                                   Evas_Object_Protected_Data *obj,
3784                                   void *type_private_data)
3785 {
3786    Evas_Image_Data *o = type_private_data;
3787 
3788    if ((obj->map->cur.map) && (obj->map->cur.usemap)) return 0;
3789    if (((o->cur->border.l | o->cur->border.r | o->cur->border.t | o->cur->border.b) != 0) &&
3790        (o->cur->border.fill == EVAS_BORDER_FILL_SOLID) &&
3791        (obj->cur->render_op == EVAS_RENDER_BLEND) &&
3792        (obj->cur->cache.clip.a == 255) &&
3793        (o->cur->fill.x == 0) &&
3794        (o->cur->fill.y == 0) &&
3795        (o->cur->fill.w == obj->cur->geometry.w) &&
3796        (o->cur->fill.h == obj->cur->geometry.h)
3797        ) return 1;
3798    return 0;
3799 }
3800 
3801 static int
evas_object_image_get_opaque_rect(Evas_Object * eo_obj EINA_UNUSED,Evas_Object_Protected_Data * obj,void * type_private_data,Evas_Coord * x,Evas_Coord * y,Evas_Coord * w,Evas_Coord * h)3802 evas_object_image_get_opaque_rect(Evas_Object *eo_obj EINA_UNUSED,
3803                                   Evas_Object_Protected_Data *obj,
3804                                   void *type_private_data,
3805                                   Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3806 {
3807    Evas_Image_Data *o = type_private_data;
3808 
3809    if (!o->cur->has_alpha)
3810      {
3811         *x = obj->cur->geometry.x;
3812         *y = obj->cur->geometry.y;
3813         *w = obj->cur->geometry.w;
3814         *h = obj->cur->geometry.h;
3815      }
3816    else if (o->cur->border.fill == EVAS_BORDER_FILL_SOLID)
3817      {
3818         *x = obj->cur->geometry.x + (o->cur->border.l * o->cur->border.scale);
3819         *y = obj->cur->geometry.y + (o->cur->border.t * o->cur->border.scale);
3820         *w = obj->cur->geometry.w - ((o->cur->border.l * o->cur->border.scale)
3821                                      + (o->cur->border.r * o->cur->border.scale));
3822         if (*w < 0) *w = 0;
3823         *h = obj->cur->geometry.h - ((o->cur->border.t * o->cur->border.scale)
3824                                      + (o->cur->border.b * o->cur->border.scale));
3825         if (*h < 0) *h = 0;
3826      }
3827    else
3828      {
3829         *w = 0;
3830         *h = 0;
3831      }
3832    return 1;
3833 }
3834 
3835 static int
evas_object_image_can_map(Evas_Object * obj EINA_UNUSED)3836 evas_object_image_can_map(Evas_Object *obj EINA_UNUSED)
3837 {
3838    return 1;
3839 }
3840 
3841 void *
_evas_image_data_convert_internal(Evas_Image_Data * o,void * data,Evas_Colorspace to_cspace)3842 _evas_image_data_convert_internal(Evas_Image_Data *o, void *data, Evas_Colorspace to_cspace)
3843 {
3844    void *out = NULL;
3845 
3846    if (!data)
3847      return NULL;
3848 
3849    switch (o->cur->cspace)
3850      {
3851       case EVAS_COLORSPACE_ARGB8888:
3852         out = evas_common_convert_argb8888_to(data,
3853                                               o->cur->image.w,
3854                                               o->cur->image.h,
3855                                               o->cur->image.stride >> 2,
3856                                               o->cur->has_alpha,
3857                                               to_cspace);
3858         break;
3859 
3860       case EVAS_COLORSPACE_RGB565_A5P:
3861         out = evas_common_convert_rgb565_a5p_to(data,
3862                                                 o->cur->image.w,
3863                                                 o->cur->image.h,
3864                                                 o->cur->image.stride >> 1,
3865                                                 o->cur->has_alpha,
3866                                                 to_cspace);
3867         break;
3868 
3869       case EVAS_COLORSPACE_YCBCR422601_PL:
3870         out = evas_common_convert_yuv_422_601_to(data,
3871                                                  o->cur->image.w,
3872                                                  o->cur->image.h,
3873                                                  to_cspace);
3874         break;
3875 
3876       case EVAS_COLORSPACE_YCBCR422P601_PL:
3877         out = evas_common_convert_yuv_422P_601_to(data,
3878                                                   o->cur->image.w,
3879                                                   o->cur->image.h,
3880                                                   to_cspace);
3881         break;
3882 
3883       case EVAS_COLORSPACE_YCBCR420NV12601_PL:
3884         out = evas_common_convert_yuv_420_601_to(data,
3885                                                  o->cur->image.w,
3886                                                  o->cur->image.h,
3887                                                  to_cspace);
3888         break;
3889 
3890       case EVAS_COLORSPACE_YCBCR420TM12601_PL:
3891         out = evas_common_convert_yuv_420T_601_to(data,
3892                                                   o->cur->image.w,
3893                                                   o->cur->image.h,
3894                                                   to_cspace);
3895         break;
3896 
3897       case EVAS_COLORSPACE_AGRY88:
3898         out = evas_common_convert_agry88_to(data,
3899                                             o->cur->image.w,
3900                                             o->cur->image.h,
3901                                             o->cur->image.stride,
3902                                             o->cur->has_alpha,
3903                                             to_cspace);
3904         break;
3905 
3906       case EVAS_COLORSPACE_GRY8:
3907         out = evas_common_convert_gry8_to(data,
3908                                           o->cur->image.w,
3909                                           o->cur->image.h,
3910                                           o->cur->image.stride,
3911                                           o->cur->has_alpha,
3912                                           to_cspace);
3913         break;
3914 
3915       default:
3916         WRN("unknown colorspace: %i\n", o->cur->cspace);
3917         break;
3918      }
3919 
3920    return out;
3921 }
3922 
3923 static void
evas_object_image_filled_resize_listener(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * einfo EINA_UNUSED)3924 evas_object_image_filled_resize_listener(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *einfo EINA_UNUSED)
3925 {
3926    Evas_Image_Data *o = efl_data_scope_get(obj, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
3927    Eina_Size2D sz;
3928 
3929    sz = efl_gfx_entity_size_get(obj);
3930    if (sz.w < 1) sz.w = 1;
3931    if (sz.h < 1) sz.h = 1;
3932    _evas_image_fill_set(obj, o, 0, 0, sz.w, sz.h);
3933 }
3934 
3935 Eina_Bool
_evas_object_image_preloading_get(const Evas_Object * eo_obj)3936 _evas_object_image_preloading_get(const Evas_Object *eo_obj)
3937 {
3938    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
3939    return o->preload;
3940 }
3941 
3942 Evas_Object *
_evas_object_image_video_parent_get(Evas_Object * eo_obj)3943 _evas_object_image_video_parent_get(Evas_Object *eo_obj)
3944 {
3945    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
3946    return o->video_surface ? o->pixels->video.parent : NULL;
3947 }
3948 
3949 void
_evas_object_image_video_overlay_show(Evas_Object * eo_obj)3950 _evas_object_image_video_overlay_show(Evas_Object *eo_obj)
3951 {
3952    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
3953    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
3954 
3955    if (obj->cur->cache.clip.x != obj->prev->cache.clip.x ||
3956        obj->cur->cache.clip.y != obj->prev->cache.clip.y ||
3957        o->created || !o->video_visible)
3958      o->delayed.video_move = EINA_TRUE;
3959 
3960    if (obj->cur->cache.clip.w != obj->prev->cache.clip.w ||
3961        obj->cur->cache.clip.h != obj->prev->cache.clip.h ||
3962        o->created || !o->video_visible)
3963      o->delayed.video_resize = EINA_TRUE;
3964 
3965    if (!o->video_visible || o->created)
3966      {
3967         o->delayed.video_show = EINA_TRUE;
3968         o->delayed.video_hide = EINA_FALSE;
3969      }
3970    else
3971      {
3972         /* Cancel dirty on the image */
3973         Eina_Rectangle *r;
3974 
3975         o->dirty_pixels = EINA_FALSE;
3976 
3977         EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write)
3978         {
3979            EINA_LIST_FREE(pixi_write->pixel_updates, r)
3980              eina_rectangle_free(r);
3981         }
3982         EINA_COW_PIXEL_WRITE_END(o, pixi_write);
3983      }
3984    o->video_visible = EINA_TRUE;
3985    o->created = EINA_FALSE;
3986 }
3987 
3988 void
_evas_object_image_video_overlay_hide(Evas_Object * eo_obj)3989 _evas_object_image_video_overlay_hide(Evas_Object *eo_obj)
3990 {
3991    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
3992    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
3993 
3994    if (o->video_visible || o->created)
3995      {
3996         o->delayed.video_hide = EINA_TRUE;
3997         o->delayed.video_show = EINA_FALSE;
3998      }
3999    if (evas_object_is_visible(obj))
4000      o->pixels->video.update_pixels(o->pixels->video.data, eo_obj, &o->pixels->video);
4001    o->video_visible = EINA_FALSE;
4002    o->created = EINA_FALSE;
4003 }
4004 
4005 void
_evas_object_image_video_overlay_do(Evas_Object * eo_obj)4006 _evas_object_image_video_overlay_do(Evas_Object *eo_obj)
4007 {
4008    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
4009    Evas_Image_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
4010    Evas_Public_Data *e = obj->layer->evas;
4011 
4012    if (o->delayed.video_move)
4013      o->pixels->video.move(o->pixels->video.data, eo_obj, &o->pixels->video,
4014                            obj->cur->cache.clip.x + e->framespace.x,
4015                            obj->cur->cache.clip.y + e->framespace.y);
4016 
4017    if (o->delayed.video_resize)
4018      o->pixels->video.resize(o->pixels->video.data, eo_obj,
4019                              &o->pixels->video,
4020                              obj->cur->cache.clip.w,
4021                              obj->cur->cache.clip.h);
4022 
4023    if (o->delayed.video_show)
4024      o->pixels->video.show(o->pixels->video.data, eo_obj, &o->pixels->video);
4025    else if (o->delayed.video_hide)
4026      o->pixels->video.hide(o->pixels->video.data, eo_obj, &o->pixels->video);
4027 
4028    o->delayed.video_move = EINA_FALSE;
4029    o->delayed.video_resize = EINA_FALSE;
4030    o->delayed.video_show = EINA_FALSE;
4031    o->delayed.video_hide = EINA_FALSE;
4032 }
4033 
4034 void *
_evas_object_image_surface_get(Evas_Object_Protected_Data * obj,Eina_Bool create)4035 _evas_object_image_surface_get(Evas_Object_Protected_Data *obj, Eina_Bool create)
4036 {
4037    Evas_Image_Data *pd = obj->private_data;
4038 
4039    if (pd->engine_data &&
4040        (pd->cur->image.w == obj->cur->geometry.w) &&
4041        (pd->cur->image.h == obj->cur->geometry.h))
4042      return pd->engine_data;
4043 
4044    if (pd->engine_data)
4045      {
4046         ENFN->image_free(ENC, pd->engine_data);
4047         pd->engine_data = NULL;
4048      }
4049 
4050    if (!create) return pd->engine_data;
4051 
4052    // FIXME: alpha forced to 1 for now, need to figure out Evas alpha here
4053    EINA_COW_IMAGE_STATE_WRITE_BEGIN(pd, state_write)
4054    {
4055       pd->engine_data = ENFN->image_map_surface_new(ENC,
4056                                                     obj->cur->geometry.w,
4057                                                     obj->cur->geometry.h,
4058                                                     1);
4059       state_write->image.w = obj->cur->geometry.w;
4060       state_write->image.h = obj->cur->geometry.h;
4061    }
4062    EINA_COW_IMAGE_STATE_WRITE_END(pd, state_write);
4063 
4064    return pd->engine_data;
4065 }
4066 
4067 EOLIAN static void
_efl_canvas_image_internal_efl_object_debug_name_override(Eo * eo_obj,Evas_Image_Data * o,Eina_Strbuf * sb)4068 _efl_canvas_image_internal_efl_object_debug_name_override(Eo *eo_obj, Evas_Image_Data *o, Eina_Strbuf *sb)
4069 {
4070    efl_debug_name_override(efl_super(eo_obj, MY_CLASS), sb);
4071    if (o->cur->f)
4072      {
4073         const char *fname = eina_file_filename_get(o->cur->f);
4074         eina_strbuf_append_printf(sb, ":file='%s',key='%s'", fname, o->cur->key);
4075      }
4076    else if (o->pixels && o->pixels->func.get_pixels)
4077      {
4078         eina_strbuf_append_printf(sb, ":get_pixels=%p:dirty=%d",
4079                                   o->pixels->func.get_pixels, o->dirty_pixels);
4080      }
4081    else if (o->cur->source)
4082      {
4083         eina_strbuf_append_printf(sb, ":proxy_source=%p", o->cur->source);
4084      }
4085    else
4086      {
4087         eina_strbuf_append_printf(sb, ":unknown_image");
4088      }
4089 }
4090 
4091 #define EFL_CANVAS_IMAGE_INTERNAL_EXTRA_OPS \
4092   EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_canvas_image_internal_efl_object_dbg_info_get)
4093 
4094 #include "canvas/efl_canvas_image_internal.eo.c"
4095 
4096 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
4097