evas: add infrastructure to feed 9 patch information from file loader to image object.
authorCedric BAIL <cedric.bail@free.fr>
Thu, 13 Jun 2019 22:34:09 +0000 (15:34 -0700)
committerTaehyub Kim <taehyub.kim@samsung.com>
Wed, 17 Jul 2019 07:21:41 +0000 (16:21 +0900)
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

src/lib/evas/Evas_Loader.h
src/lib/evas/canvas/evas_image_private.h
src/lib/evas/canvas/evas_object_image.c
src/lib/evas/common/evas_image_load.c
src/lib/evas/include/evas_common_private.h
src/lib/evas/include/evas_private.h
src/modules/evas/engines/software_generic/evas_engine.c

index ee2e6a3..35e0e17 100644 (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;
 };
@@ -256,6 +267,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
index 7fe7443..5c95e0b 100755 (executable)
@@ -109,6 +109,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
index 9a302ba..56f19cd 100755 (executable)
@@ -479,12 +479,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)
      {
@@ -492,6 +557,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;
 
@@ -702,11 +776,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);
 
@@ -743,6 +820,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);
 
@@ -816,6 +895,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)
      {
@@ -1623,6 +1711,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));
 }
 
@@ -2576,6 +2665,8 @@ _evas_image_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
      }
 
 
+   _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);
index bd38aef..fb27ea4 100644 (file)
@@ -224,6 +224,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;
@@ -471,7 +472,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;
 
index 9616f06..fdbece3 100755 (executable)
@@ -630,6 +630,7 @@ struct _Image_Entry
 
    unsigned char          need_unload : 1;
    unsigned char          load_failed : 1;
+   unsigned char          need_data : 1;
 
    struct
      {
@@ -674,6 +675,14 @@ struct _Image_Entry
    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
index 21a9069..1f9f3fa 100755 (executable)
@@ -1357,6 +1357,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);
index fdf7d69..aba5907 100755 (executable)
@@ -1051,6 +1051,48 @@ eng_image_file_colorspace_get(void *data EINA_UNUSED, void *image)
 }
 
 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)
@@ -4688,6 +4730,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,