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