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