diff --git a/src/lib/evas/Evas_Loader.h b/src/lib/evas/Evas_Loader.h index 220deabb9b..94ec424209 100644 --- a/src/lib/evas/Evas_Loader.h +++ b/src/lib/evas/Evas_Loader.h @@ -135,6 +135,17 @@ typedef struct _Evas_Image_Property Evas_Image_Property; struct _Evas_Image_Property { Emile_Image_Property info; + // Stretch region are directly encoded the way Evas excpect them internally + // 8bits is used for each step. The lower bits indicate how long the stretch region + // span. Masking with 0x80 will be true if the region is stretchable. If false, it + // will be fixed size. + struct { + struct { + uint8_t *region; + } horizontal, vertical; + } stretch; + // Where inside the image are we supposed to overlay data + Eina_Rectangle content; // need_data is set to True when to get accurate property, data need to be loaded Eina_Bool need_data; }; @@ -253,6 +264,32 @@ EAPI Eina_Bool evas_module_task_cancelled (void); /**< @since 1.19 */ EINA_MODULE_INIT(evas_##Tn##_##Name##_init); \ EINA_MODULE_SHUTDOWN(evas_##Tn##_##Name##_shutdown); +static inline Eina_Bool +evas_loader_helper_stretch_region_push(uint8_t **region, + uint8_t *offset, + Eina_Bool stretchable) +{ + uint32_t length = 0; + void *tmp; + + if (*offset == 0) return EINA_TRUE; + + while (*region && (*region)[length] != 0) + length++; + + // +1 for termination and +1 for the region being pushed + tmp = realloc(*region, sizeof (uint8_t) * (length + 2)); + if (!tmp) return EINA_FALSE; + + *region = (uint8_t *) tmp; + (*region)[length] = (*offset) | (stretchable ? 0x80 : 0); + (*region)[length + 1] = 0; + + *offset = 0; + + return EINA_TRUE; +} + #ifdef __cplusplus } #endif diff --git a/src/lib/evas/canvas/evas_image_private.h b/src/lib/evas/canvas/evas_image_private.h index 21b989aae0..664d60e684 100644 --- a/src/lib/evas/canvas/evas_image_private.h +++ b/src/lib/evas/canvas/evas_image_private.h @@ -98,6 +98,9 @@ struct _Evas_Object_Image_State Eina_Bool has_alpha :1; Eina_Bool opaque_valid : 1; Eina_Bool opaque : 1; + + Eina_Bool free_stretch : 1; // Should we free stretch region? + Eina_Bool stretch_loaded : 1; // Is the stretch region loaded from file? }; #define EVAS_IMAGE_PRELOAD_NONE 0x00 diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index ac4665e7b2..50a064a287 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -465,12 +465,77 @@ _efl_canvas_image_internal_efl_object_dbg_info_get(Eo *eo_obj, Evas_Image_Data * (uint64_t)(uintptr_t)evas_object_image_source_get(eo_obj)); } +static void +_stretch_region_load(Evas_Object_Protected_Data *obj, Evas_Image_Data *o) +{ + unsigned int i; + uint8_t *horizontal = NULL; + uint8_t *vertical = NULL; + uint32_t total, stretchable; + + if (o->cur->stretch_loaded == EINA_TRUE || + (o->cur->stretch.horizontal.region && o->cur->stretch.vertical.region)) + return ; + + ENFN->image_stretch_region_get(ENC, o->engine_data, + &horizontal, + &vertical); + + EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write) + { + state_write->stretch.horizontal.region = horizontal; + state_write->stretch.vertical.region = vertical; + state_write->free_stretch = EINA_FALSE; + state_write->stretch_loaded = EINA_TRUE; + } + EINA_COW_IMAGE_STATE_WRITE_END(o, state_write); + + if (!o->cur->stretch.horizontal.region || !o->cur->stretch.vertical.region) + return ; + + stretchable = 0; + total = 0; + for (i = 0; o->cur->stretch.horizontal.region[i]; i++) + { + total += o->cur->stretch.horizontal.region[i] & 0x7F; + if (o->cur->stretch.horizontal.region[i] & 0x80) + stretchable += o->cur->stretch.horizontal.region[i] & 0x7F; + } + + EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write) + { + state_write->stretch.horizontal.stretchable = stretchable; + state_write->stretch.horizontal.total = total; + } + EINA_COW_IMAGE_STATE_WRITE_END(o, state_write); + + stretchable = 0; + total = 0; + for (i = 0; o->cur->stretch.vertical.region[i]; i++) + { + total += o->cur->stretch.vertical.region[i] & 0x7F; + if (o->cur->stretch.vertical.region[i] & 0x80) + stretchable += o->cur->stretch.vertical.region[i] & 0x7F; + } + + EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write) + { + state_write->stretch.vertical.stretchable = stretchable; + state_write->stretch.vertical.total = total; + } + EINA_COW_IMAGE_STATE_WRITE_END(o, state_write); +} + static Eina_Rect _efl_canvas_image_internal_efl_gfx_image_content_region_get(const Eo *eo_obj, Evas_Image_Data *o) { Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); Eina_Rect r; + if (!o->cur->stretch.horizontal.region && + !o->cur->stretch.vertical.region) + _stretch_region_load(obj, o); + if (o->cur->stretch.horizontal.region && o->cur->stretch.vertical.region) { @@ -478,6 +543,15 @@ _efl_canvas_image_internal_efl_gfx_image_content_region_get(const Eo *eo_obj, Ev uint32_t hi = 0; uint32_t vi = 0; + // If the file come with a defined content zone, then return it + if (ENFN->image_content_region_get(ENC, o->engine_data, &r.rect)) + { + // Correct bottom right corner coordinate to be resized with object size + r.w = obj->cur->geometry.w - (o->cur->image.w - r.w); + r.h = obj->cur->geometry.h - (o->cur->image.h - r.h); + return r; + } + r.x = _stretch_region_accumulate(o->cur->stretch.horizontal.region, 0, &hi); r.w = o->cur->stretch.horizontal.stretchable + obj->cur->geometry.w - o->cur->image.w; @@ -681,11 +755,14 @@ _efl_canvas_image_internal_efl_gfx_image_stretch_region_set(Eo *eo_obj, Evas_Ima evas_object_async_block(obj); EINA_COW_IMAGE_STATE_WRITE_BEGIN(pd, state_write) { - free(state_write->stretch.horizontal.region); + if (state_write->free_stretch) free(state_write->stretch.horizontal.region); state_write->stretch.horizontal.region = NULL; - free(state_write->stretch.vertical.region); + if (state_write->free_stretch) free(state_write->stretch.vertical.region); state_write->stretch.vertical.region = NULL; + + state_write->free_stretch = EINA_FALSE; + state_write->stretch_loaded = EINA_FALSE; } EINA_COW_IMAGE_STATE_WRITE_END(pd, state_write); @@ -722,6 +799,8 @@ _efl_canvas_image_internal_efl_gfx_image_stretch_region_set(Eo *eo_obj, Evas_Ima state_write->stretch.vertical.region = fvsz; state_write->stretch.vertical.stretchable = vstretch; state_write->stretch.vertical.total = vtotal; + state_write->free_stretch = EINA_TRUE; + state_write->stretch_loaded = EINA_TRUE; } EINA_COW_IMAGE_STATE_WRITE_END(pd, state_write); @@ -795,6 +874,15 @@ _efl_canvas_image_internal_efl_gfx_image_stretch_region_get(const Eo *eo_obj, { Efl_Gfx_Image_Stretch_Region_Iterator *it; + if (!pd->cur->stretch.vertical.region && + !pd->cur->stretch.horizontal.region) + { + Evas_Object_Protected_Data *obj; + + obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS); + _stretch_region_load(obj, pd); + } + if (!horizontal) goto vertical_only; if (!pd->cur->stretch.horizontal.region) { @@ -1596,6 +1684,7 @@ _efl_canvas_image_internal_efl_object_destructor(Eo *eo_obj, Evas_Image_Data *o if (obj->legacy.ctor) evas_object_image_video_surface_set(eo_obj, NULL); evas_object_image_free(eo_obj, obj); + efl_gfx_image_stretch_region_set(eo_obj, NULL, NULL); efl_destructor(efl_super(eo_obj, MY_CLASS)); } @@ -2384,6 +2473,8 @@ _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, return; } + _stretch_region_load(obj, o); + ENFN->image_scale_hint_set(engine, pixels, o->scale_hint); idx = evas_object_image_figure_x_fill(eo_obj, obj, o->cur->fill.x, o->cur->fill.w, &idw); idy = evas_object_image_figure_y_fill(eo_obj, obj, o->cur->fill.y, o->cur->fill.h, &idh); diff --git a/src/lib/evas/common/evas_image_load.c b/src/lib/evas/common/evas_image_load.c index f8d00cc292..611767448e 100644 --- a/src/lib/evas/common/evas_image_load.c +++ b/src/lib/evas/common/evas_image_load.c @@ -223,6 +223,7 @@ _evas_image_file_header(Evas_Module *em, Image_Entry *ie, int *error) ie->borders.b = property.info.borders.b; ie->scale = property.info.scale; ie->flags.alpha = property.info.alpha; + ie->need_data = property.need_data; if (property.info.cspaces) ie->cspaces = property.info.cspaces; ie->flags.rotated = property.info.rotated; ie->flags.flipped = property.info.flipped; @@ -470,7 +471,17 @@ end: return EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; } - evas_image_load_func->file_data(ie->loader_data, &property, pixels, &ret); + if (ie->need_data) + { + evas_image_load_func->file_head_with_data(ie->loader_data, &property, pixels, &ret); + memcpy(&ie->content, &property.content, sizeof (Eina_Rectangle)); + ie->stretch.horizontal.region = property.stretch.horizontal.region; + ie->stretch.vertical.region = property.stretch.vertical.region; + } + else + { + evas_image_load_func->file_data(ie->loader_data, &property, pixels, &ret); + } ie->flags.alpha_sparse = property.info.alpha_sparse; diff --git a/src/lib/evas/include/evas_common_private.h b/src/lib/evas/include/evas_common_private.h index 825d83ab77..59eb800724 100644 --- a/src/lib/evas/include/evas_common_private.h +++ b/src/lib/evas/include/evas_common_private.h @@ -598,6 +598,7 @@ struct _Image_Entry unsigned char need_unload : 1; unsigned char load_failed : 1; + unsigned char need_data : 1; struct { @@ -633,6 +634,14 @@ struct _Image_Entry int connect_num; int channel; Evas_Load_Error load_error; + + struct { + struct { + uint8_t *region; + } horizontal, vertical; + } stretch; + + Eina_Rectangle content; }; struct _Engine_Image_Entry diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index d6b53bc210..751f81cd07 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -1354,6 +1354,8 @@ struct _Evas_Func Eina_Bool (*image_data_map) (void *engine, void **image, Eina_Rw_Slice *slice, int *stride, int x, int y, int w, int h, Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode, int plane); Eina_Bool (*image_data_unmap) (void *engine, void *image, const Eina_Rw_Slice *slice); int (*image_data_maps_get) (void *engine, const void *image, const Eina_Rw_Slice **slices); + Eina_Bool (*image_content_region_get) (void *engine, void *image, Eina_Rectangle *content); + Eina_Bool (*image_stretch_region_get) (void *engine, void *image, uint8_t **horizontal, uint8_t **vertical); /* new api for direct data set (not put) */ void *(*image_data_slice_add) (void *engine, void *image, const Eina_Slice *slice, Eina_Bool copy, int w, int h, int stride, Evas_Colorspace space, int plane, Eina_Bool alpha); diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 6ae8224e47..59391c4f6e 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -1050,6 +1050,48 @@ eng_image_file_colorspace_get(void *data EINA_UNUSED, void *image) return im->cache_entry.space; } +static Eina_Bool +eng_image_content_region_get(void *engine EINA_UNUSED, void *image, Eina_Rectangle *content) +{ + RGBA_Image *im = image; + + if (!im) return EINA_FALSE; + + if (!im->cache_entry.need_data) return EINA_FALSE; + + if (!im->image.data) evas_cache_image_load_data(&im->cache_entry); + + if (!im->cache_entry.content.w || + !im->cache_entry.content.h) + return EINA_FALSE; + + if (!content) return EINA_FALSE; + + memcpy(content, &im->cache_entry.content, sizeof (Eina_Rectangle)); + return EINA_TRUE; +} + +static Eina_Bool +eng_image_stretch_region_get(void *engine EINA_UNUSED, void *image, + uint8_t **horizontal, uint8_t **vertical) +{ + RGBA_Image *im = image; + + if (!im) return EINA_FALSE; + + if (!im->cache_entry.need_data) return EINA_FALSE; + + if (!im->image.data) evas_cache_image_load_data(&im->cache_entry); + + if (!im->cache_entry.stretch.horizontal.region || + !im->cache_entry.stretch.vertical.region) + return EINA_FALSE; + + *horizontal = im->cache_entry.stretch.horizontal.region; + *vertical = im->cache_entry.stretch.vertical.region; + return EINA_TRUE; +} + static Eina_Bool eng_image_data_direct_get(void *data EINA_UNUSED, void *image, int plane, Eina_Slice *slice, Evas_Colorspace *cspace, @@ -4611,6 +4653,8 @@ static Evas_Func func = eng_image_data_map, eng_image_data_unmap, eng_image_data_maps_get, + eng_image_content_region_get, + eng_image_stretch_region_get, eng_image_data_slice_add, eng_image_prepare, eng_image_surface_noscale_new,