evas: add infrastructure to feed 9 patch information from file loader to image object.

This is just the plumbing that feed data provided along android 9 patch image for example
into Evas object image new stretch and content region infrastructure for rendering them
properly.

Reviewed-by: Hermet Park <hermetpark@gmail.com>
Differential Revision: https://phab.enlightenment.org/D9102
This commit is contained in:
Cedric BAIL 2019-06-13 15:34:09 -07:00
parent ce076d1323
commit 6a93e2ef3d
7 changed files with 200 additions and 3 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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,