ector: Fix precomp layer rendering issue when it has alpha value

Summary:
When the precomp layer(parent layer) has alpha transparency and has more than 1 child layer
and they overlap each other if vg object just propagate the alpha to child layer
it will be applied twice in overlapped area.
Even if the child layer does not have alpha transparency, parent alpha is applied to each child.

Test Plan: N/A

Reviewers: Hermet, smohanty

Reviewed By: Hermet

Subscribers: cedric, #reviewers, kimcinoo, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D9072
This commit is contained in:
junsu choi 2019-06-20 16:07:05 +09:00 committed by Hermet Park
parent c27c469204
commit c7b1a40b5e
7 changed files with 97 additions and 7 deletions

View File

@ -21,5 +21,15 @@ mixin @beta Ector.Surface extends Ector.Buffer
@in type: const(Efl.Class); [[Efl class]] /* FIXME: Should probably be a more restricted type */
}
}
draw_image @pure_virtual {
[[ Draw image's buffer to surface buffer. ]]
params {
@in image: Ector.Buffer; [[Image buffer]]
@in x: int; [[Buffer position x]]
@in y: int; [[Buffer position y]]
@in alpha: int; [[Buffer alpha value]]
}
return: bool; [[True if drawing was successful]]
}
}
}

View File

@ -5,6 +5,7 @@
#include "sw_ft_raster.h"
#include "sw_ft_stroker.h"
#include "../ector_private.h"
#include "draw.h"
typedef struct _Ector_Software_Surface_Data Ector_Software_Surface_Data;
typedef struct _Ector_Software_Thread Ector_Software_Thread;

View File

@ -245,5 +245,31 @@ _ector_software_surface_ector_surface_reference_point_set(Eo *obj EINA_UNUSED,
pd->y = y;
}
static Eina_Bool
_ector_software_surface_ector_surface_draw_image(Eo *obj EINA_UNUSED,
Ector_Software_Surface_Data *pd,
Ector_Buffer *buffer, int x, int y, int alpha)
{
if (!buffer || !pd->rasterizer || !pd->rasterizer->fill_data.raster_buffer->pixels.u32)
return EINA_FALSE;
Ector_Software_Buffer_Base_Data *bd = efl_data_scope_get(buffer, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN);
const int pix_stride = pd->rasterizer->fill_data.raster_buffer->stride / 4;
uint32_t *src = bd->pixels.u32;
for (unsigned int local_y = 0; local_y < bd->generic->h; local_y++)
{
uint32_t *dst = pd->rasterizer->fill_data.raster_buffer->pixels.u32 + (x + ((local_y + y) * pix_stride));
for (unsigned int local_x = 0; local_x < bd->generic->w; local_x++)
{
*src = draw_mul_256(alpha, *src);
int inv_alpha = 255 - ((*src) >> 24);
*dst = *src + draw_mul_256(inv_alpha, *dst);
dst++;
src++;
}
}
return EINA_TRUE;
}
#include "ector_software_surface.eo.c"
#include "ector_renderer_software.eo.c"

View File

@ -6,6 +6,7 @@ class @beta Ector.Software.Surface extends Ector.Software.Buffer implements Ecto
implements {
Ector.Surface.renderer_factory_new;
Ector.Surface.reference_point { set; }
Ector.Surface.draw_image;
Efl.Object.destructor;
Efl.Object.constructor;
}

View File

@ -236,6 +236,9 @@ static void
_efl_canvas_vg_container_efl_object_destructor(Eo *obj,
Efl_Canvas_Vg_Container_Data *pd)
{
if (pd->blend_pixels) free(pd->blend_pixels);
if (pd->blend_buffer) efl_unref(pd->blend_buffer);
//Destroy mask surface
if (pd->mask.buffer) efl_unref(pd->mask.buffer);
if (pd->mask.pixels) free(pd->mask.pixels);

View File

@ -386,22 +386,66 @@ _efl_canvas_vg_object_efl_object_finalize(Eo *obj, Efl_Canvas_Vg_Object_Data *pd
static void
_evas_vg_render(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
void *engine, void *output, void *context, Efl_VG *node,
Eina_Array *clips, Eina_Bool do_async)
Eina_Array *clips, int w, int h, Ector_Surface *ector, Eina_Bool do_async)
{
if (!efl_gfx_entity_visible_get(node)) return;
if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS))
{
Efl_Canvas_Vg_Container_Data *cd =
efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
Efl_VG *child;
Eina_List *l;
Efl_Canvas_Vg_Container_Data *cd = efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
if (cd->mask.target) return; //Don't draw mask itself.
Efl_VG *child;
Eina_List *l;
int alpha = 255;
efl_gfx_color_get(node, NULL, NULL, NULL, &alpha);
EINA_LIST_FOREACH(cd->children, l, child)
_evas_vg_render(obj, pd, engine, output, context, child, clips, do_async);
if (alpha < 255)
{
// Reuse buffer
if (!cd->blend_pixels)
cd->blend_pixels = calloc(w * h, sizeof(uint32_t*));
else
memset(cd->blend_pixels, 0, sizeof(uint32_t) * (w * h));
if (!cd->blend_buffer)
{
cd->blend_buffer = ENFN->ector_buffer_new(ENC, obj->layer->evas->evas,
w, h,
EFL_GFX_COLORSPACE_ARGB8888,
ECTOR_BUFFER_FLAG_DRAWABLE |
ECTOR_BUFFER_FLAG_CPU_READABLE |
ECTOR_BUFFER_FLAG_CPU_WRITABLE);
ector_buffer_pixels_set(cd->blend_buffer, cd->blend_pixels,
w, h, 0,
EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
}
// Buffer change
ector_buffer_pixels_set(ector, cd->blend_pixels,
w, h, 0,
EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
ector_surface_reference_point_set(ector, 0,0);
// Draw child node to changed buffer
EINA_LIST_FOREACH(cd->children, l, child)
_evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async);
// Re-set original surface
ENFN->ector_begin(engine, output, context, ector, 0, 0, EINA_FALSE, do_async);
// Draw buffer to original surface.(Ector_Surface)
ector_surface_draw_image(ector, cd->blend_buffer, 0, 0, alpha);
}
else
{
if (cd->blend_pixels) free(cd->blend_pixels);
if (cd->blend_buffer) efl_unref(cd->blend_buffer);
EINA_LIST_FOREACH(cd->children, l, child)
_evas_vg_render(obj, pd, engine, output, context, child, clips, w, h, ector, do_async);
}
}
else
{
@ -451,6 +495,7 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd
engine, buffer,
context, root,
NULL,
w, h, ector,
do_async);
ENFN->image_dirty_region(engine, buffer, 0, 0, w, h);

View File

@ -94,6 +94,10 @@ struct _Efl_Canvas_Vg_Container_Data
//Masking feature.
Efl_Canvas_Vg_Node *mask_src; //Mask Source
Vg_Mask mask; //Mask source data
//Layer transparency feature. This buffer is only valid when the layer has transparency.
Ector_Buffer *blend_buffer;
void *blend_pixels;
};
struct _Efl_Canvas_Vg_Gradient_Data