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
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;
};
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
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
(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)
{
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;
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);
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);
{
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)
{
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));
}
}
+ _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);
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;
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;
unsigned char need_unload : 1;
unsigned char load_failed : 1;
+ unsigned char need_data : 1;
struct
{
int channel;
int num_palette;
Evas_Load_Error load_error;
+
+ struct {
+ struct {
+ uint8_t *region;
+ } horizontal, vertical;
+ } stretch;
+
+ Eina_Rectangle content;
};
struct _Engine_Image_Entry
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);
}
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,
Eina_Bool load, Eina_Bool *tofree)
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,