Efl.Gfx.Buffer: Introduce buffer_set/get/copy_set
authorJean-Philippe Andre <jp.andre@samsung.com>
Fri, 4 Mar 2016 06:57:36 +0000 (15:57 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Tue, 15 Mar 2016 02:11:59 +0000 (11:11 +0900)
Hopefully the doc and signature are better than the current
evas image equivalents data_get/data_set.

Those APIs are not like map/unmap so we need to decide which
model we prefer.

src/lib/efl/interfaces/efl_gfx_buffer.eo
src/lib/evas/Evas_Legacy.h
src/lib/evas/canvas/evas_image.eo
src/lib/evas/canvas/evas_object_image.c

index f74e801..0b19b98 100644 (file)
@@ -47,7 +47,7 @@ interface Efl.Gfx.Buffer ()
          }
       }
 
-      @property buffer_stride {
+      @property stride {
          [[Length in bytes of one row of pixels in memory.
 
            Usually this will be equal to width * 4, with a plain BGRA image.
@@ -62,7 +62,7 @@ interface Efl.Gfx.Buffer ()
          }
       }
 
-      buffer_update_region_add {
+      buffer_update_add {
          [[Mark a sub-region of the given image object to be redrawn.
 
            This function schedules a particular rectangular region of an
@@ -131,34 +131,116 @@ interface Efl.Gfx.Buffer ()
             @in length: uint; [[Must be the same as returned by map.]]
          }
       }
+      /* note: not a property because the refcount needs to be explicit
+       * between set and get */
+      /* FIXME: not bindable to JS, potentially tricky to bind to Lua */
       buffer_set {
          [[Set the pixels for this buffer, or allocate a new memory region.
 
-           EFL will copy the $pixels to an internal buffer, and update the
-           GPU-side texture if required. This will mark the image as dirty.
+           EFL will use $pixels directly, and update the GPU-side texture
+           if required. This will mark the image as dirty.
 
            If $pixels is $null, then a new empty buffer will be allocated.
+           If the buffer already had pixel data, the previous image data will
+           be dropped. This is the same as @.buffer_copy_set.
+
+           If $pixels is the return value of @.buffer_get then EFL will
+           decrement its internal reference count on the buffer data. Call
+           @.buffer_update_add to flush updates and indicate changes in
+           the pixel data.
+
+           The memory buffer $pixels must be large enough to hold
+           $width x $height pixels encoded in the colorspace $cspace.
+           Alternatively $pixels must be larger than $height x $stride
+           in bytes.
+
+           See also @.buffer_copy_set if you want EFL to copy the input buffer
+           internally.
+         ]]
+         params {
+            @in pixels: void* @nullable; [[If $null, allocates an empty buffer]]
+            @in width: int;
+            @in height: int;
+            @in stride: int @optional; [[If 0, automatically guessed from the $width.]]
+            @in cspace: Efl.Gfx.Colorspace @optional; [[argb8888 by default.]]
+            @in alpha: bool; [[$true if the alpha channel is used.]]
+            @in l: uint @optional; [[Left border pixels, usually 0 or 1. Not supported yet!]]
+            @in r: uint @optional; [[Right border pixels, usually 0 or 1. Not supported yet!]]
+            @in t: uint @optional; [[Top border pixels, usually 0 or 1. Not supported yet!]]
+            @in b: uint @optional; [[Bottom border pixels, usually 0 or 1. Not supported yet!]]
+            /* FIXME: do we need writable flag? */
+         }
+         return: bool @warn_unused; [[This function returns $false in case of failure.]]
+      }
+      buffer_copy_set {
+         [[Set the pixels for this buffer by copying them, or allocate
+           a new memory region.
+
+           This will allocate a new buffer in memory and copy the input
+           $pixels to it. The internal colorspace is not guaranteed to
+           be preserved, and colorspace conversion may happen internally.
 
+           If $pixels is $null, then a new empty buffer will be allocated.
            If the buffer already had pixel data, the previous image data will
-           be dropped and the internal buffer may be resized to fit the new
-           pixel data.
+           be dropped. This is the same as @.buffer_set.
+
+           The memory buffer $pixels must be large enough to hold
+           $width x $height pixels encoded in the colorspace $cspace.
+           Alternatively $pixels must be larger than $height x $stride
+           in bytes.
+
+           $pixels should not be the return value of @.buffer_get.
 
-           Note: Use @Efl.Gfx.Buffer.buffer_size.set and @.buffer_map to
-           request EFL to allocate the buffer itself, instead of using this
-           function.
+           There is no copy equivalent to this function, as you can easily
+           call @.buffer_get and allocate the proper buffer on your side,
+           followed by a memory copy and @.buffer_set.
          ]]
          params {
-            @in pixels: ubyte*; [[If $null, allocates an empty buffer]]
+            @in pixels: const(void)* @nullable; [[If $null, allocates an empty buffer]]
             @in width: int;
             @in height: int;
-            @in stride: int @optional; [[If 0, automatically guessed from the width.]]
+            @in stride: int @optional; [[If 0, automatically guessed from the $width.]]
             @in cspace: Efl.Gfx.Colorspace @optional; [[argb8888 by default.]]
-            @in l: uint @optional; [[Left border pixels, usually 0 or 1]]
-            @in r: uint @optional; [[Right border pixels, usually 0 or 1]]
-            @in t: uint @optional; [[Top border pixels, usually 0 or 1]]
-            @in b: uint @optional; [[Bottom border pixels, usually 0 or 1]]
+            @in alpha: bool; [[$true if the alpha channel is used.]]
+            @in l: uint @optional; [[Left border pixels, usually 0 or 1. Not supported yet!]]
+            @in r: uint @optional; [[Right border pixels, usually 0 or 1. Not supported yet!]]
+            @in t: uint @optional; [[Top border pixels, usually 0 or 1. Not supported yet!]]
+            @in b: uint @optional; [[Bottom border pixels, usually 0 or 1. Not supported yet!]]
+         }
+         return: bool @warn_unused; [[This function returns $false in case of failure.]]
+      }
+      buffer_get {
+         [[Get a direct pointer to the internal pixel data.
+
+           This will increment an internal reference counter on the internal
+           buffer.
+
+           If $to_write is $true, this may trigger a copy of the internal
+           pixel data, and return a writable memory block.
+
+           Call @.buffer_size.get and @.buffer_borders.get to determine the
+           value of width, height and l, r, t, b.
+
+           Warning: @.buffer_set MUST be called as soon as possible after
+           calling @.buffer_get. @.buffer_update_add should be called after
+           @.buffer_set if $to_write was $true and the pixel data has been
+           modified. Once @.buffer_set is called, the pointer return from
+           @.buffer_get is not valid anymore.
+         ]]
+         params {
+            @in to_write: bool; [[If $true, requests write access]]
+            @out length: uint @optional; [[Size of the buffer in bytes.]]
+            @out width: int @optional;
+            @out height: int @optional;
+            @out stride: int @optional; [[Returns the length of one row of pixels in bytes.]]
+            @out cspace: Efl.Gfx.Colorspace @optional; [[Pixel encoding of the returned buffer.]]
+            @out alpha: bool; [[$true if the alpha channel is used.]]
+            @out l: uint @optional; [[Left border pixels, usually 0 or 1. Not supported yet!]]
+            @out r: uint @optional; [[Right border pixels, usually 0 or 1. Not supported yet!]]
+            @out t: uint @optional; [[Top border pixels, usually 0 or 1. Not supported yet!]]
+            @out b: uint @optional; [[Bottom border pixels, usually 0 or 1. Not supported yet!]]
          }
-         return: bool;
+         return: void* @warn_unused;
       }
       /* Note: border, span and buffer flags not imported from ector buffer */
    }
index f5d91a4..73baa1a 100644 (file)
@@ -3360,6 +3360,74 @@ EAPI Evas_Colorspace evas_object_image_colorspace_get(const Evas_Object *obj);
 EAPI int evas_object_image_stride_get(const Evas_Object *obj) EINA_WARN_UNUSED_RESULT;
 
 /**
+ * @brief Replaces the raw image data of the given image object.
+ *
+ * This function lets the application replace an image object's internal pixel
+ * buffer with an user-allocated one. For best results, you should generally
+ * first call @ref evas_object_image_size_set with the width and height for the
+ * new buffer.
+ *
+ * This call is best suited for when you will be using image data with
+ * different dimensions than the existing image data, if any. If you only need
+ * to modify the existing image in some fashion, then using
+ * @ref evas_object_image_data_get is probably what you are after.
+ *
+ * Note that the caller is responsible for freeing the buffer when finished
+ * with it, as user-set image data will not be automatically freed when the
+ * image object is deleted.
+ *
+ * @param[in] data The raw data to replace.
+ *
+ * @ingroup Evas_Image
+ */
+EAPI void evas_object_image_data_copy_set(Evas_Object *obj, void *data);
+
+/**
+ * @brief Sets the raw image data of the given image object.
+ *
+ * Note that the raw data must be of the same size (see @ref
+ * evas_object_image_size_set, which has to be called before this one) and
+ * colorspace (see @Evas.Image.colorspace.set) of the image. If data is
+ * @c null, the current image data will be freed. Naturally, if one does not
+ * set an image object's data manually, it will still have one, allocated by
+ * Evas.
+ *
+ * @param[in] data The raw data, or @c null.
+ *
+ * @ingroup Evas_Image
+ */
+EAPI void evas_object_image_data_set(Evas_Object *obj, void *data);
+
+/**
+ * @brief Get a pointer to the raw image data of the given image object.
+ *
+ * This function returns a pointer to an image object's internal pixel buffer,
+ * for reading only or read/write. If you request it for writing, the image
+ * will be marked dirty so that it gets redrawn at the next update.
+ *
+ * Each time you call this function on an image object, its data buffer will
+ * have an internal reference counter incremented. Decrement it back by using
+ * @ref evas_object_image_data_set.
+ *
+ * This is best suited for when you want to modify an existing image, without
+ * changing its dimensions.
+ *
+ * @note The contents' format returned by it depend on the color space of the
+ * given image object.
+ *
+ * @note You may want to use @Evas.Image.data_update_add to inform data
+ * changes, if you did any.
+ *
+ * @param[in] for_writing Whether the data being retrieved will be modified
+ * ($true) or not ($false).
+ *
+ * @return The raw image data.
+ *
+ * @ingroup Evas_Image
+ */
+EAPI void *evas_object_image_data_get(const Evas_Object *obj, Eina_Bool for_writing) EINA_WARN_UNUSED_RESULT;
+
+/**
  * @brief Mark a sub-region of the given image object to be redrawn.
  *
  * This function schedules a particular rectangular region of an image object
index 31acd3a..2e0d89b 100644 (file)
@@ -249,30 +249,6 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image, Efl.Image_Load, Efl.Image_An
             surf: Evas.Native_Surface* @nonull; [[The native surface.]]
          }
       }
-      @property data_copy {
-         set {
-            [[Replaces the raw image data of the given image object.
-
-              This function lets the application replace an image object's
-              internal pixel buffer with an user-allocated one. For best
-              results, you should generally first call
-              \@ref evas_object_image_size_set with the width and height
-              for the new buffer.
-
-              This call is best suited for when you will be using image
-              data with different dimensions than the existing image data,
-              if any. If you only need to modify the existing image in some
-              fashion, then using @.data_get is probably what you are after.
-
-              Note that the caller is responsible for freeing the buffer
-              when finished with it, as user-set image data will not be
-              automatically freed when the image object is deleted.
-            ]]
-         }
-         values {
-            data: void *; [[The raw data to replace.]]
-         }
-      }
 
       /* 3d */
       @property scene {
@@ -319,47 +295,6 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image, Efl.Image_Load, Efl.Image_An
                        the Evas_Object_Image.]]
          }
       }
-      data_set {
-         [[Sets the raw image data of the given image object.
-
-           Note that the raw data must be of the same size (see
-           \@ref evas_object_image_size_set, which has to be called before
-           this one) and colorspace (see \@.colorspace.set) of the image.
-           If data is $null, the current image data will be freed.
-           Naturally, if one does not set an image object's data
-           manually, it will still have one, allocated by Evas.
-         ]]
-         params {
-            @in data: void *; [[The raw data, or $null.]]
-         }
-      }
-      data_get @const {
-         [[Get a pointer to the raw image data of the given image object.
-
-           This function returns a pointer to an image object's internal
-           pixel buffer, for reading only or read/write. If you request
-           it for writing, the image will be marked dirty so that it gets
-           redrawn at the next update.
-
-           Each time you call this function on an image object, its data
-           buffer will have an internal reference counter incremented.
-           Decrement it back by using @.data_set.
-
-           This is best suited for when you want to modify an existing
-           image, without changing its dimensions.
-
-           Note: The contents' format returned by it depend on the color
-           space of the given image object.
-
-           Note: You may want to use \@.data_update_add to inform data
-           changes, if you did any.
-         ]]
-         return: void * @warn_unused; [[ The raw image data.]]
-         params {
-            @in for_writing: bool; [[Whether the data being retrieved will
-                                     be modified ($true) or not ($false).]]
-         }
-      }
    }
    implements {
       Eo.Base.constructor;
@@ -405,16 +340,15 @@ class Evas.Image (Evas.Object, Efl.File, Efl.Image, Efl.Image_Load, Efl.Image_An
       Efl.Image_Load.load_region.get;
       Efl.Image_Load.load_region.set;
       Efl.Image_Load.load_region_support.get;
-      Efl.Gfx.Buffer.buffer_update_region_add;
-      Efl.Gfx.Buffer.buffer_stride.get;
+      Efl.Gfx.Buffer.buffer_update_add;
+      Efl.Gfx.Buffer.stride.get;
       Efl.Gfx.Buffer.colorspace.get;
       Efl.Gfx.Fill.fill.set;
       Efl.Gfx.Fill.fill.get;
       Efl.Gfx.Fill.filled.get;
       Efl.Gfx.Fill.filled.set;
-      Efl.Gfx.View.view_size.set;
-      Efl.Gfx.View.view_size.get;
       Efl.Gfx.Filter.filter_program.set;
+      Efl.Gfx.View.view_size.get;
       Evas.Filter.filter_input_alpha;
       Evas.Filter.filter_input_render;
       Evas.Filter.filter_dirty;
index 10fa5e8..4046b35 100644 (file)
@@ -1013,10 +1013,12 @@ _evas_image_efl_gfx_fill_fill_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o,
    if (h) *h = o->cur->fill.h;
 }
 
-EOLIAN static void
-_evas_image_efl_gfx_view_view_size_set(Eo *eo_obj, Evas_Image_Data *o, int w, int h)
+/* eo equivalent: pixels_set(null, w, h) to (re)allocate an image */
+EAPI void
+evas_object_image_size_set(Eo *eo_obj, int w, int h)
 {
    Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+   Evas_Image_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
 
    int stride = 0;
 
@@ -1120,7 +1122,7 @@ _evas_image_efl_gfx_view_view_size_get(Eo *eo_obj, Evas_Image_Data *o, int *w, i
 }
 
 EOLIAN static int
-_evas_image_efl_gfx_buffer_buffer_stride_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
+_evas_image_efl_gfx_buffer_stride_get(Eo *eo_obj EINA_UNUSED, Evas_Image_Data *o)
 {
    return o->cur->image.stride;
 }
@@ -1168,137 +1170,6 @@ evas_object_image_data_convert(Evas_Object *eo_obj, Evas_Colorspace to_cspace)
    return result;
 }
 
-EOLIAN static void
-_evas_image_data_set(Eo *eo_obj, Evas_Image_Data *o, void *data)
-{
-   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
-   void *p_data;
-   Eina_Bool resize_call = EINA_FALSE;
-
-
-   evas_object_async_block(obj);
-   evas_render_rendering_wait(obj->layer->evas);
-
-   _evas_object_image_cleanup(eo_obj, obj, o);
-   p_data = o->engine_data;
-   if (data)
-     {
-        if (o->engine_data)
-          {
-             o->engine_data = ENFN->image_data_put(ENDT, o->engine_data, data);
-          }
-        else
-          {
-             o->engine_data = ENFN->image_new_from_data(ENDT,
-                                                        o->cur->image.w,
-                                                        o->cur->image.h,
-                                                        data,
-                                                        o->cur->has_alpha,
-                                                        o->cur->cspace);
-          }
-        if (o->engine_data)
-          {
-             int stride = 0;
-
-             if (ENFN->image_scale_hint_set)
-               ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
-
-             if (ENFN->image_content_hint_set)
-               ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
-
-             if (ENFN->image_stride_get)
-               ENFN->image_stride_get(ENDT, o->engine_data, &stride);
-             else
-               stride = o->cur->image.w * 4;
-
-             if (o->cur->image.stride != stride)
-               {
-                  EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
-                    state_write->image.stride = stride;
-                  EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
-               }
-         }
-       o->written = EINA_TRUE;
-     }
-   else
-     {
-        if (o->engine_data)
-          ENFN->image_free(ENDT, o->engine_data);
-        o->load_error = EVAS_LOAD_ERROR_NONE;
-        if ((o->cur->image.w != 0) || (o->cur->image.h != 0))
-          resize_call = EINA_TRUE;
-
-        EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
-          {
-             state_write->image.w = 0;
-             state_write->image.h = 0;
-             state_write->image.stride = 0;
-          }
-        EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
-
-        o->engine_data = NULL;
-     }
-/* FIXME - in engine call above
-   if (o->engine_data)
-     o->engine_data = ENFN->image_alpha_set(ENDT, o->engine_data, o->cur->has_alpha);
-*/
-   if (o->pixels_checked_out > 0) o->pixels_checked_out--;
-   if (p_data != o->engine_data)
-     {
-        EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
-        o->pixels_checked_out = 0;
-     }
-   if (resize_call) evas_object_inform_call_image_resize(eo_obj);
-}
-
-EOLIAN static void*
-_evas_image_data_get(const Eo *eo_obj, Evas_Image_Data *_pd EINA_UNUSED, Eina_Bool for_writing)
-{
-   Evas_Image_Data *o = (Evas_Image_Data *) _pd;
-   int stride = 0;
-   void *pixels;
-   DATA32 *data;
-
-   if (!o->engine_data) return NULL;
-
-   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
-
-   if (for_writing) evas_object_async_block(obj);
-   if (for_writing) evas_render_rendering_wait(obj->layer->evas);
-
-   data = NULL;
-   if (ENFN->image_scale_hint_set)
-     ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
-   if (ENFN->image_content_hint_set)
-     ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
-   pixels = ENFN->image_data_get(ENDT, o->engine_data, for_writing, &data, &o->load_error, NULL);
-
-   /* if we fail to get engine_data, we have to return NULL */
-   if (!pixels) return NULL;
-
-   o->engine_data = pixels;
-   if (ENFN->image_stride_get)
-     ENFN->image_stride_get(ENDT, o->engine_data, &stride);
-   else
-     stride = o->cur->image.w * 4;
-
-   if (o->cur->image.stride != stride)
-     {
-        EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
-          state_write->image.stride = stride;
-        EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
-     }
-
-   o->pixels_checked_out++;
-   if (for_writing)
-     {
-        o->written = EINA_TRUE;
-        EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
-     }
-
-   return data;
-}
-
 static void
 _image_preload_internal(Eo *eo_obj, void *_pd, Eina_Bool cancel)
 {
@@ -1348,52 +1219,7 @@ _evas_image_efl_image_load_load_async_cancel(Eo *eo_obj, Evas_Image_Data *_pd EI
 }
 
 EOLIAN static void
-_evas_image_data_copy_set(Eo *eo_obj, Evas_Image_Data *o, void *data)
-{
-   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
-
-   if (!data) return;
-   evas_object_async_block(obj);
-   _evas_object_image_cleanup(eo_obj, obj, o);
-   if ((o->cur->image.w <= 0) ||
-       (o->cur->image.h <= 0)) return;
-   if (o->engine_data)
-     ENFN->image_free(ENDT, o->engine_data);
-   o->engine_data = ENFN->image_new_from_copied_data(ENDT,
-                                                     o->cur->image.w,
-                                                     o->cur->image.h,
-                                                     data,
-                                                     o->cur->has_alpha,
-                                                     o->cur->cspace);
-   if (o->engine_data)
-     {
-        int stride = 0;
-
-        o->engine_data =
-          ENFN->image_alpha_set(ENDT, o->engine_data, o->cur->has_alpha);
-        if (ENFN->image_scale_hint_set)
-          ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
-        if (ENFN->image_content_hint_set)
-          ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
-        if (ENFN->image_stride_get)
-          ENFN->image_stride_get(ENDT, o->engine_data, &stride);
-        else
-          stride = o->cur->image.w * 4;
-
-        if (o->cur->image.stride != stride)
-          {
-             EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
-               state_write->image.stride = stride;
-             EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
-          }
-        o->written = EINA_TRUE;
-     }
-   o->pixels_checked_out = 0;
-   EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
-}
-
-EOLIAN static void
-_evas_image_efl_gfx_buffer_buffer_update_region_add(Eo *eo_obj, Evas_Image_Data *o, int x, int y, int w, int h)
+_evas_image_efl_gfx_buffer_buffer_update_add(Eo *eo_obj, Evas_Image_Data *o, int x, int y, int w, int h)
 {
    Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
    Eina_Rectangle *r;
@@ -3146,7 +2972,7 @@ _evas_image_evas_filter_filter_input_alpha(Eo *eo_obj EINA_UNUSED, Evas_Image_Da
 }
 
 EOLIAN static void
-_evas_image_efl_gfx_filter_filter_program_set(Eo *obj, Evas_Image_Data *pd EINA_UNUSED,
+_evas_image_efl_gfx_filter_filter_program_set(Eo *obj, Evas_Image_Data *pd,
                                               const char *code, const char *name)
 {
    pd->has_filter = (code != NULL);
@@ -4844,6 +4670,186 @@ _evas_object_image_surface_get(Evas_Object *eo, Evas_Object_Protected_Data *obj)
    return pd->engine_data;
 }
 
+/* Legacy deprecated functions */
+
+EAPI void
+evas_object_image_data_set(Eo *eo_obj, void *data)
+{
+   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+   Evas_Image_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+   void *p_data;
+   Eina_Bool resize_call = EINA_FALSE;
+
+
+   evas_object_async_block(obj);
+   evas_render_rendering_wait(obj->layer->evas);
+
+   _evas_object_image_cleanup(eo_obj, obj, o);
+   p_data = o->engine_data;
+   if (data)
+     {
+        if (o->engine_data)
+          {
+             o->engine_data = ENFN->image_data_put(ENDT, o->engine_data, data);
+          }
+        else
+          {
+             o->engine_data = ENFN->image_new_from_data(ENDT,
+                                                        o->cur->image.w,
+                                                        o->cur->image.h,
+                                                        data,
+                                                        o->cur->has_alpha,
+                                                        o->cur->cspace);
+          }
+        if (o->engine_data)
+          {
+             int stride = 0;
+
+             if (ENFN->image_scale_hint_set)
+               ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
+
+             if (ENFN->image_content_hint_set)
+               ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
+
+             if (ENFN->image_stride_get)
+               ENFN->image_stride_get(ENDT, o->engine_data, &stride);
+             else
+               stride = o->cur->image.w * 4;
+
+             if (o->cur->image.stride != stride)
+               {
+                  EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
+                    state_write->image.stride = stride;
+                  EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
+               }
+         }
+       o->written = EINA_TRUE;
+     }
+   else
+     {
+        if (o->engine_data)
+          ENFN->image_free(ENDT, o->engine_data);
+        o->load_error = EVAS_LOAD_ERROR_NONE;
+        if ((o->cur->image.w != 0) || (o->cur->image.h != 0))
+          resize_call = EINA_TRUE;
+
+        EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
+          {
+             state_write->image.w = 0;
+             state_write->image.h = 0;
+             state_write->image.stride = 0;
+          }
+        EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
+
+        o->engine_data = NULL;
+     }
+/* FIXME - in engine call above
+   if (o->engine_data)
+     o->engine_data = ENFN->image_alpha_set(ENDT, o->engine_data, o->cur->has_alpha);
+*/
+   if (o->pixels_checked_out > 0) o->pixels_checked_out--;
+   if (p_data != o->engine_data)
+     {
+        EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
+        o->pixels_checked_out = 0;
+     }
+   if (resize_call) evas_object_inform_call_image_resize(eo_obj);
+}
+
+EAPI void*
+evas_object_image_data_get(const Eo *eo_obj, Eina_Bool for_writing)
+{
+   Evas_Image_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+   int stride = 0;
+   void *pixels;
+   DATA32 *data;
+
+   if (!o->engine_data) return NULL;
+
+   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+
+   if (for_writing) evas_object_async_block(obj);
+   if (for_writing) evas_render_rendering_wait(obj->layer->evas);
+
+   data = NULL;
+   if (ENFN->image_scale_hint_set)
+     ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
+   if (ENFN->image_content_hint_set)
+     ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
+   pixels = ENFN->image_data_get(ENDT, o->engine_data, for_writing, &data, &o->load_error, NULL);
+
+   /* if we fail to get engine_data, we have to return NULL */
+   if (!pixels) return NULL;
+
+   o->engine_data = pixels;
+   if (ENFN->image_stride_get)
+     ENFN->image_stride_get(ENDT, o->engine_data, &stride);
+   else
+     stride = o->cur->image.w * 4;
+
+   if (o->cur->image.stride != stride)
+     {
+        EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
+          state_write->image.stride = stride;
+        EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
+     }
+
+   o->pixels_checked_out++;
+   if (for_writing)
+     {
+        o->written = EINA_TRUE;
+        EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
+     }
+
+   return data;
+}
+
+EAPI void
+evas_object_image_data_copy_set(Eo *eo_obj, void *data)
+{
+   Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
+   Evas_Image_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
+
+   if (!data) return;
+   evas_object_async_block(obj);
+   _evas_object_image_cleanup(eo_obj, obj, o);
+   if ((o->cur->image.w <= 0) ||
+       (o->cur->image.h <= 0)) return;
+   if (o->engine_data)
+     ENFN->image_free(ENDT, o->engine_data);
+   o->engine_data = ENFN->image_new_from_copied_data(ENDT,
+                                                     o->cur->image.w,
+                                                     o->cur->image.h,
+                                                     data,
+                                                     o->cur->has_alpha,
+                                                     o->cur->cspace);
+   if (o->engine_data)
+     {
+        int stride = 0;
+
+        o->engine_data =
+          ENFN->image_alpha_set(ENDT, o->engine_data, o->cur->has_alpha);
+        if (ENFN->image_scale_hint_set)
+          ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
+        if (ENFN->image_content_hint_set)
+          ENFN->image_content_hint_set(ENDT, o->engine_data, o->content_hint);
+        if (ENFN->image_stride_get)
+          ENFN->image_stride_get(ENDT, o->engine_data, &stride);
+        else
+          stride = o->cur->image.w * 4;
+
+        if (o->cur->image.stride != stride)
+          {
+             EINA_COW_IMAGE_STATE_WRITE_BEGIN(o, state_write)
+               state_write->image.stride = stride;
+             EINA_COW_IMAGE_STATE_WRITE_END(o, state_write);
+          }
+        o->written = EINA_TRUE;
+     }
+   o->pixels_checked_out = 0;
+   EVAS_OBJECT_WRITE_IMAGE_FREE_FILE_AND_KEY(o);
+}
+
 /* Legacy wrappers */
 
 EAPI Evas_Object *
@@ -4963,13 +4969,7 @@ evas_object_image_border_center_fill_get(const Evas_Object *obj)
 EAPI void
 evas_object_image_size_get(const Evas_Image *obj, int *w, int *h)
 {
-   efl_gfx_view_size_get((Evas_Image *)obj, w, h);
-}
-
-EAPI void
-evas_object_image_size_set(Evas_Image *obj, int w, int h)
-{
-   efl_gfx_view_size_set(obj, w, h);
+   efl_gfx_view_size_get(obj, w, h);
 }
 
 EAPI Evas_Colorspace
@@ -4987,7 +4987,7 @@ evas_object_image_stride_get(const Evas_Object *obj)
 EAPI void
 evas_object_image_data_update_add(Evas_Object *obj, int x, int y, int w, int h)
 {
-   efl_gfx_buffer_update_region_add(obj, x, y, w, h);
+   efl_gfx_buffer_update_add(obj, x, y, w, h);
 }
 
 EAPI void