jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=26e74c421967eb1e9fa8016bdf81e1c597b709b6

commit 26e74c421967eb1e9fa8016bdf81e1c597b709b6
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Fri Jan 22 14:06:57 2016 +0900

    Evas filters: Fix transform filter (crashes & blend)
    
    out was simply not initialized if the source and destination
    were the same. The COW flag is required here to separate input
    and output properly. Also, the source & destination pointers
    were badly calculated and could overflow.
    
    Instead of using memcpy this filter was supposed to use the
    blend functions. This patch also fixes that.
    
    In order to make this filter actually useful (think text reflection
    on a flat surface), more information needs to be passed to the Lua
    script, such as the text ascent, descent, etc...
---
 src/lib/evas/filters/evas_filter.c           |  12 +++-
 src/lib/evas/filters/evas_filter_transform.c | 101 +++++++++++++++++++--------
 2 files changed, 82 insertions(+), 31 deletions(-)

diff --git a/src/lib/evas/filters/evas_filter.c 
b/src/lib/evas/filters/evas_filter.c
index 01d8c7f..301b25a 100644
--- a/src/lib/evas/filters/evas_filter.c
+++ b/src/lib/evas/filters/evas_filter.c
@@ -1229,16 +1229,22 @@ evas_filter_command_transform_add(Evas_Filter_Context 
*ctx,
         return -1;
      }
 
-   if (in->alpha_only != out->alpha_only)
-     DBG("Incompatible buffer formats, will trigger implicit conversion.");
-
    cmd = _command_new(ctx, EVAS_FILTER_MODE_TRANSFORM, in, NULL, out);
    if (!cmd) return -1;
 
+   DRAW_COLOR_SET(255, 255, 255, 255);
    cmd->transform.flags = flags;
    cmd->draw.ox = ox;
    cmd->draw.oy = oy;
 
+   if (in->alpha_only == out->alpha_only)
+     {
+        DBG("Incompatible buffer formats, will trigger implicit conversion.");
+        cmd->draw.rop = EFL_GFX_RENDER_OP_COPY;
+     }
+   else
+     cmd->draw.rop = EFL_GFX_RENDER_OP_BLEND;
+
    out->dirty = EINA_TRUE;
 
    return cmd->id;
diff --git a/src/lib/evas/filters/evas_filter_transform.c 
b/src/lib/evas/filters/evas_filter_transform.c
index 5f262ee..704b8e8 100644
--- a/src/lib/evas/filters/evas_filter_transform.c
+++ b/src/lib/evas/filters/evas_filter_transform.c
@@ -1,31 +1,39 @@
 #include "evas_filter_private.h"
+#include "evas_blend_private.h"
+#include "draw.h"
 
-/* Apply geomeetrical transformations to a buffer.
- * This filter is a bit simplistic at the moment.
+/* Apply geometrical transformations to a buffer.
  *
- * It also assumes the destination is empty, as it does not use blend
- * operations. This should probably be fixed later on (use evas_map?).
+ * This filter is a very simplistic at the moment, future improvements require
+ * more options to the API.
  */
 
 static Eina_Bool
 _vflip_cpu(Evas_Filter_Command *cmd)
 {
    unsigned int src_len, src_stride, dst_len, dst_stride;
-   uint8_t *in, *out = NULL, *span = NULL;
+   uint8_t *in, *out = NULL;
    int w, h, sy, dy, oy, center, t, b, objh;
    Efl_Gfx_Colorspace cspace = cmd->output->alpha_only ? E_ALPHA : E_ARGB;
    int s0, s1, d0, d1;
    Eina_Bool ret = 0;
 
+   if (!cmd->draw.A && (cmd->draw.rop == EFL_GFX_RENDER_OP_BLEND))
+     return EINA_TRUE;
+
    w = cmd->input->w;
    h = cmd->input->h;
    in = _buffer_map_all(cmd->input->buffer, &src_len, E_READ, cspace, 
&src_stride);
-   if (cmd->input->buffer != cmd->output->buffer)
-     out = _buffer_map_all(cmd->output->buffer, &dst_len, E_WRITE, cspace, 
&dst_stride);
+   out = _buffer_map_all(cmd->output->buffer, &dst_len,
+                         E_WRITE | ECTOR_BUFFER_ACCESS_FLAG_COW,
+                         cspace, &dst_stride);
 
    EINA_SAFETY_ON_FALSE_GOTO(cmd->output->w == w, end);
    EINA_SAFETY_ON_FALSE_GOTO(cmd->output->h == h, end);
    EINA_SAFETY_ON_FALSE_GOTO(src_stride <= dst_stride, end);
+   EINA_SAFETY_ON_NULL_GOTO(in, end);
+   EINA_SAFETY_ON_NULL_GOTO(out, end);
+   EINA_SAFETY_ON_FALSE_GOTO(in != out, end);
 
    oy = cmd->draw.oy;
    t = cmd->ctx->padt;
@@ -33,46 +41,83 @@ _vflip_cpu(Evas_Filter_Command *cmd)
    objh = h - t - b;
    center = t + objh / 2 + oy;
 
-   s0 = t;
-   s1 = h - b - 1;
    if (oy >= 0)
      {
-        d0 = center + (objh / 2) + oy;
-        d1 = center - (objh / 2) - oy;
+        s1 = d0 = center + (objh / 2) + oy;
+        s0 = d1 = center - (objh / 2) - oy;
      }
    else
      {
-        d0 = center + (objh / 2) - oy;
-        d1 = center - (objh / 2) + oy;
+        s1 = d0 = center + (objh / 2) - oy;
+        s0 = d1 = center - (objh / 2) + oy;
      }
 
-   if (in == out)
+   /* avoid crashes */
+   d0 = CLAMP(0, d0, h - 1);
+   d1 = CLAMP(0, d1, h - 1);
+   s0 = CLAMP(0, s0, h - 1);
+   s1 = CLAMP(0, s1, h - 1);
+
+   if (cmd->input->buffer == cmd->output->buffer)
      {
-        span = alloca(src_stride);
-        if (!span) goto end;
-     }
+        /* flip a single buffer --> override its own contents */
+        for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
+          {
+             uint8_t* src = in + src_stride * sy;
+             uint8_t* dst = out + dst_stride * dy;
 
-   for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
+             memcpy(dst, src, src_stride);
+          }
+     }
+   else if (cspace == E_ALPHA)
      {
-        uint8_t* src = in + src_stride * sy;
-        uint8_t* dst = out + dst_stride * dy;
+        /* blend onto a target (alpha -> alpha) */
+        Alpha_Gfx_Func func = efl_draw_alpha_func_get(cmd->draw.rop, 
EINA_FALSE);
+        EINA_SAFETY_ON_NULL_GOTO(func, end);
 
-        if (in == out)
+        for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
           {
-             if (src == dst) break;
-             memcpy(span, dst, src_stride);
-             memcpy(dst, src, src_stride);
-             memcpy(src, span, src_stride);
-             if (sy >= center) break;
+             uint8_t* src = in + src_stride * sy;
+             uint8_t* dst = out + dst_stride * dy;
+
+             func(src, dst, w);
           }
+     }
+   else
+     {
+        /* blend onto a target (rgba -> rgba) */
+        uint32_t color = ARGB_JOIN(cmd->draw.A, cmd->draw.R, cmd->draw.G, 
cmd->draw.B);
+        RGBA_Gfx_Func func;
+
+        if (color == 0xFFFFFFFF)
+          func = evas_common_gfx_func_composite_pixel_span_get(1, 0, 1, 1, 
_gfx_to_evas_render_op(cmd->draw.rop));
         else
-          memcpy(dst, src, src_stride);
+          func = evas_common_gfx_func_composite_pixel_color_span_get(1, 0, 
color, 1, 1, _gfx_to_evas_render_op(cmd->draw.rop));
+        EINA_SAFETY_ON_NULL_GOTO(func, end);
+
+        for (sy = s0, dy = d0; (dy >= d1) && (sy <= s1); sy++, dy--)
+          {
+             uint32_t* src = (uint32_t *) (in + src_stride * sy);
+             uint32_t* dst = (uint32_t *) (out + dst_stride * dy);
+
+             func(src, NULL, color, dst, w);
+          }
      }
+
+   /* fill out outer areas */
+   if (cmd->draw.rop == EFL_GFX_RENDER_OP_COPY)
+     {
+        if (d1 > 0)
+          memset(out, 0, dst_stride * d1);
+        if (d0 < (h - 1))
+          memset(out + dst_stride * d0, 0, dst_stride * (h - d0 - 1));
+     }
+
    ret = EINA_TRUE;
 
 end:
    eo_do(cmd->input->buffer, ector_buffer_unmap(in, src_len));
-   if (in != out) eo_do(cmd->output->buffer, ector_buffer_unmap(out, dst_len));
+   eo_do(cmd->output->buffer, ector_buffer_unmap(out, dst_len));
    return ret;
 }
 

-- 


Reply via email to