evas ector: add software implmentation for masking feature. 19/194719/3
authorHermet Park <hermetpark@gmail.com>
Fri, 7 Dec 2018 05:11:09 +0000 (14:11 +0900)
committerHermet Park <hermetpark@gmail.com>
Fri, 7 Dec 2018 06:26:05 +0000 (15:26 +0900)
This implementation uses Ector_Buffer to generate mask image from vg container,
and pass it to Ector engine. Ector renderer could blend this image as a mask.
Yet only vg container works as a mask, we could extend shape to support masking as well.

Change-Id: I6faea19084b0399172b877eb56364601f2adf584

20 files changed:
src/lib/ector/ector_private.h
src/lib/ector/ector_renderer.c
src/lib/ector/ector_renderer.eo
src/lib/ector/software/ector_renderer_software_shape.c
src/lib/ector/software/ector_renderer_software_shape.eo
src/lib/ector/software/ector_software_buffer.c
src/lib/ector/software/ector_software_private.h
src/lib/ector/software/ector_software_rasterizer.c
src/lib/evas/canvas/efl_canvas_vg_container.c
src/lib/evas/canvas/efl_canvas_vg_container.eo
src/lib/evas/canvas/efl_canvas_vg_gradient_linear.c
src/lib/evas/canvas/efl_canvas_vg_gradient_radial.c
src/lib/evas/canvas/efl_canvas_vg_node.c
src/lib/evas/canvas/efl_canvas_vg_node.eo
src/lib/evas/canvas/efl_canvas_vg_object.c
src/lib/evas/canvas/efl_canvas_vg_shape.c
src/lib/evas/canvas/evas_vg_private.h
src/lib/evas/include/evas_private.h
src/modules/evas/engines/gl_generic/evas_engine.c
src/modules/evas/engines/software_generic/evas_engine.c

index 1f48366..8604768 100644 (file)
@@ -63,8 +63,6 @@ struct _Ector_Renderer_Data
       int r, g, b, a;
    } color;
 
-   Ector_Renderer *mask;
-
    Eina_Bool visibility : 1;
    Eina_Bool finalized : 1;
 };
index 1c2026e..186e323 100644 (file)
@@ -127,31 +127,6 @@ _ector_renderer_color_get(const Eo *obj EINA_UNUSED,
    if (a) *a = pd->color.a;
 }
 
-static void
-_ector_renderer_mask_set(Eo *obj EINA_UNUSED,
-                         Ector_Renderer_Data *pd,
-                         Ector_Renderer *mask)
-{
-   efl_replace(&pd->mask, mask);
-}
-
-static Ector_Renderer *
-_ector_renderer_mask_get(const Eo *obj EINA_UNUSED,
-                         Ector_Renderer_Data *pd)
-{
-   return pd->mask;
-}
-
-static Eina_Bool
-_ector_renderer_prepare(Eo *obj EINA_UNUSED,
-                        Ector_Renderer_Data *pd)
-{
-   if (pd->mask)
-     ector_renderer_prepare(pd->mask);
-
-   return EINA_TRUE;
-}
-
 static unsigned int
 _ector_renderer_crc_get(const Eo *obj EINA_UNUSED,
                         Ector_Renderer_Data *pd)
@@ -162,9 +137,16 @@ _ector_renderer_crc_get(const Eo *obj EINA_UNUSED,
    crc = eina_crc((void*) &pd->origin, sizeof(pd->origin), crc, EINA_FALSE);
 
    if (pd->m) crc = eina_crc((void*) pd->m, sizeof(Eina_Matrix3), crc, EINA_FALSE);
-   if (pd->mask) crc = _renderer_crc_get(pd->mask, crc);
 
    return crc;
 }
 
+static void
+_ector_renderer_mask_set(Eo *obj EINA_UNUSED,
+                         Ector_Renderer_Data *pd EINA_UNUSED,
+                         Ector_Buffer *mask EINA_UNUSED,
+                         int op EINA_UNUSED)
+{
+}
+
 #include "ector_renderer.eo.c"
index de669c0..844ec1a 100644 (file)
@@ -72,22 +72,21 @@ abstract Ector.Renderer (Efl.Object)
             a: int; [[The alpha component of the given color.]]
          }
       }
-      @property mask {
-         [[Rendering mask]]
-         set {
-         }
-         get {
-         }
-         values {
-            mask: Ector.Renderer; [[Rendering mask]]
-         }
-      }
       @property crc {
          [[Cyclic redundancy check]]
          get {
             return: uint; [[CRC value]]
          }
       }
+      @property mask {
+         [[Set Mask Image to this Renderer]]
+         set {
+         }
+         values {
+            mask: Ector.Buffer; [[Mask Image Buffer]]
+            op: int; [[Masking option]]
+         }
+      }
       draw @pure_virtual {
          [[Actual draw operation]]
          return: bool; [[$true on success, $false otherwise]]
@@ -97,7 +96,7 @@ abstract Ector.Renderer (Efl.Object)
             @in mul_col: uint; [[Premultiplied color]]
          }
       }
-      prepare {
+      prepare @pure_virtual {
          [[Prepare for rendering]]
          return: bool; [[$true on success, $false otherwise]]
       }
index be96c82..4ffad58 100644 (file)
@@ -36,6 +36,9 @@ struct _Ector_Renderer_Software_Shape_Data
    Shape_Rle_Data              *shape_data;
    Shape_Rle_Data              *outline_data;
 
+   Ector_Buffer                *mask;
+   int                          mask_op;
+
    Ector_Software_Shape_Task   *task;
 
    Eina_Bool                    done;
@@ -221,7 +224,7 @@ static void _outline_transform(Outline *outline, Eina_Matrix3 *m)
 static Eina_Bool
 _generate_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline)
 {
-   Eina_Bool close_path = EINA_FALSE; 
+   Eina_Bool close_path = EINA_FALSE;
    for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
      {
         switch (*cmds)
@@ -659,16 +662,18 @@ _ector_renderer_software_shape_ector_renderer_draw(Eo *obj,
    x = pd->surface->x + (int)pd->base->origin.x;
    y = pd->surface->y + (int)pd->base->origin.y;
 
-   // fill the span_data structure
    ector_software_rasterizer_clip_rect_set(pd->surface->rasterizer, clips);
    ector_software_rasterizer_transform_set(pd->surface->rasterizer, pd->base->m);
 
+   // fill the span_data structure
    if (pd->shape->fill)
      {
         ector_renderer_software_op_fill(pd->shape->fill);
         ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
                                                 x, y, mul_col, op,
-                                                pd->shape_data);
+                                                pd->shape_data,
+                                                pd->mask,
+                                                pd->mask_op);
      }
    else
      {
@@ -681,16 +686,22 @@ _ector_renderer_software_shape_ector_renderer_draw(Eo *obj,
                                                  pd->base->color.a);
              ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
                                                      x, y, mul_col, op,
-                                                     pd->shape_data);
+                                                     pd->shape_data,
+                                                     pd->mask,
+                                                     pd->mask_op);
           }
      }
 
+   if (!pd->outline_data) return EINA_TRUE;
+
    if (pd->shape->stroke.fill)
      {
         ector_renderer_software_op_fill(pd->shape->stroke.fill);
         ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
                                                 x, y, mul_col, op,
-                                                pd->outline_data);
+                                                pd->outline_data,
+                                                pd->mask,
+                                                pd->mask_op);
      }
    else
      {
@@ -703,7 +714,9 @@ _ector_renderer_software_shape_ector_renderer_draw(Eo *obj,
                                                  pd->public_shape->stroke.color.a);
              ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
                                                      x, y, mul_col, op,
-                                                     pd->outline_data);
+                                                     pd->outline_data,
+                                                     pd->mask,
+                                                     pd->mask_op);
           }
      }
 
@@ -830,4 +843,15 @@ _ector_renderer_software_shape_ector_renderer_crc_get(const Eo *obj,
    return crc;
 }
 
+static void
+_ector_renderer_software_shape_ector_renderer_mask_set(Eo *obj EINA_UNUSED,
+                                                       Ector_Renderer_Software_Shape_Data *pd,
+                                                       Ector_Buffer *mask,
+                                                       int op)
+{
+   //Use ref/unref.
+   pd->mask = mask;
+   pd->mask_op = op;
+}
+
 #include "ector_renderer_software_shape.eo.c"
index 97b15ca..abe8344 100644 (file)
@@ -6,6 +6,7 @@ class Ector.Renderer.Software.Shape (Ector.Renderer.Software, Ector.Renderer.Sha
       Ector.Renderer.prepare;
       Ector.Renderer.draw;
       Ector.Renderer.Software.op_fill;
+      Ector.Renderer.mask { set; }
       Ector.Renderer.crc { get; }
       Efl.Gfx.Path.path { set; }
       Efl.Object.constructor;
index e898128..e7d288e 100644 (file)
@@ -76,8 +76,8 @@ _ector_software_buffer_base_ector_buffer_pixels_set(Eo *obj, Ector_Software_Buff
 {
    unsigned pxs;
 
-   if (pd->generic->immutable)
-     fail("This buffer is immutable.");
+   //if (pd->generic->immutable)
+//     fail("This buffer is immutable.");
 
    if (pd->internal.maps)
      fail("Can not call pixels_set when the buffer is mapped.");
index 270a14d..e1a3fc2 100644 (file)
@@ -83,9 +83,11 @@ typedef struct _Span_Data
 
    int              offx, offy;
    Clip_Data        clip;
+   Ector_Software_Buffer_Base_Data    *mask;
+   int mask_op;
    Eina_Matrix3     inv;
    Span_Data_Type   type;
-   Eina_Bool        fast_matrix ;
+   Eina_Bool        fast_matrix;
    uint32_t         mul_col;
    Efl_Gfx_Render_Op        op;
    union {
@@ -129,7 +131,12 @@ void ector_software_rasterizer_clip_shape_set(Software_Rasterizer *rasterizer, S
 Shape_Rle_Data * ector_software_rasterizer_generate_rle_data(Ector_Software_Thread *thread, Software_Rasterizer *rasterizer, SW_FT_Outline *outline);
 Shape_Rle_Data * ector_software_rasterizer_generate_stroke_rle_data(Ector_Software_Thread *thread, Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath);
 
-void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer, int x, int y, uint32_t mul_col, Efl_Gfx_Render_Op op, Shape_Rle_Data* rle);
+void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer,
+                                             int x, int y, uint32_t mul_col,
+                                             Efl_Gfx_Render_Op op,
+                                             Shape_Rle_Data* rle,
+                                             Ector_Buffer *mask,
+                                             int mask_op);
 
 void ector_software_rasterizer_destroy_rle_data(Shape_Rle_Data *rle);
 
index 0671449..5838475 100644 (file)
 static void
 _blend_color_argb(int count, const SW_FT_Span *spans, void *user_data)
 {
-   RGBA_Comp_Func_Solid comp_func;
-   Span_Data *data = (Span_Data *)(user_data);
+   Span_Data *sd = user_data;
    uint32_t color, *buffer, *target;
-   const int pix_stride = data->raster_buffer->stride / 4;
+   const int pix_stride = sd->raster_buffer->stride / 4;
+
+   // multiply the color with mul_col if any
+   color = DRAW_MUL4_SYM(sd->color, sd->mul_col);
+   RGBA_Comp_Func_Solid comp_func = efl_draw_func_solid_span_get(sd->op, color);
+
+   // move to the offset location
+   buffer = sd->raster_buffer->pixels.u32 + ((pix_stride * sd->offy) + sd->offx);
+
+    while (count--)
+      {
+          target = buffer + ((pix_stride * spans->y) + spans->x);
+          comp_func(target, spans->len, color, spans->coverage);
+          ++spans;
+      }
+}
+
+static void
+_blend_color_argb_with_maskA(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   const int pix_stride = sd->raster_buffer->stride / 4;
+   Ector_Software_Buffer_Base_Data *mask = sd->mask;
+
+   // multiply the color with mul_col if any
+   uint32_t color = DRAW_MUL4_SYM(sd->color, sd->mul_col);
+   RGBA_Comp_Func_Solid comp_func = efl_draw_func_solid_span_get(sd->op, color);
+
+   // move to the offset location
+   uint32_t *buffer =
+         sd->raster_buffer->pixels.u32 + ((pix_stride * sd->offy) + sd->offx);
+   uint32_t *mbuffer = mask->pixels.u32;
+
+   //Temp buffer for intermediate processing
+   int tsize = sd->raster_buffer->generic->w;
+   uint32_t *tbuffer = alloca(sizeof(uint32_t) * tsize);
+
+   while (count--)
+     {
+        uint32_t *target = buffer + ((pix_stride * spans->y) + spans->x);
+        uint32_t *mtarget =
+              mbuffer + ((mask->generic->w * spans->y) + spans->x);
+        uint32_t *temp = tbuffer;
+        memset(temp, 0x00, sizeof(uint32_t) * spans->len);
+        comp_func(temp, spans->len, color, spans->coverage);
+
+        //masking
+        for (int i = 0; i < spans->len; i++)
+          {
+             *temp = draw_mul_256(((*mtarget)>>24), *temp);
+             int alpha = 255 - ((*temp) >> 24);
+             *target = *temp + draw_mul_256(alpha, *target);
+             ++temp;
+             ++mtarget;
+             ++target;
+          }
+        ++spans;
+     }
+}
+
+static void
+_blend_color_argb_with_maskInvA(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   const int pix_stride = sd->raster_buffer->stride / 4;
+   Ector_Software_Buffer_Base_Data *mask = sd->mask;
 
    // multiply the color with mul_col if any
-   color = DRAW_MUL4_SYM(data->color, data->mul_col);
-   comp_func = efl_draw_func_solid_span_get(data->op, color);
+   uint32_t color = DRAW_MUL4_SYM(sd->color, sd->mul_col);
+   RGBA_Comp_Func_Solid comp_func = efl_draw_func_solid_span_get(sd->op, color);
 
    // move to the offset location
-   buffer = data->raster_buffer->pixels.u32 + ((pix_stride * data->offy) + data->offx);
+   uint32_t *buffer =
+         sd->raster_buffer->pixels.u32 + ((pix_stride * sd->offy) + sd->offx);
+   uint32_t *mbuffer = mask->pixels.u32;
+
+   //Temp buffer for intermediate processing
+   int tsize = sd->raster_buffer->generic->w;
+   uint32_t *tbuffer = alloca(sizeof(uint32_t) * tsize);
 
    while (count--)
      {
-        target = buffer + ((pix_stride * spans->y) + spans->x);
-        comp_func(target, spans->len, color, spans->coverage);
+        uint32_t *target = buffer + ((pix_stride * spans->y) + spans->x);
+        uint32_t *mtarget =
+              mbuffer + ((mask->generic->w * spans->y) + spans->x);
+        uint32_t *temp = tbuffer;
+        memset(temp, 0x00, sizeof(uint32_t) * spans->len);
+        comp_func(temp, spans->len, color, spans->coverage);
+
+        //masking
+        for (int i = 0; i < spans->len; i++)
+          {
+             if (*mtarget)
+                *temp = draw_mul_256((255 - ((*mtarget)>>24)), *temp);
+             int alpha = 255 - ((*temp) >> 24);
+             *target = *temp + draw_mul_256(alpha, *target);
+             ++temp;
+             ++mtarget;
+             ++target;
+          }
         ++spans;
      }
 }
@@ -267,13 +353,24 @@ _span_fill_clipPath(int span_count, const SW_FT_Span *spans, void *user_data)
 static void
 _adjust_span_fill_methods(Span_Data *spdata)
 {
+   //Blending Function
    switch(spdata->type)
      {
         case None:
-          spdata->unclipped_blend = 0;
+          spdata->unclipped_blend = NULL;
           break;
         case Solid:
-          spdata->unclipped_blend = &_blend_color_argb;
+          {
+             if (spdata->mask)
+                {
+                   if (spdata->mask_op == 2)
+                     spdata->unclipped_blend = &_blend_color_argb_with_maskInvA;
+                   else
+                     spdata->unclipped_blend = &_blend_color_argb_with_maskA;
+                }
+             else
+                spdata->unclipped_blend = &_blend_color_argb;
+           }
           break;
         case LinearGradient:
         case RadialGradient:
@@ -531,17 +628,22 @@ void ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasteriz
    rasterizer->fill_data.type = RadialGradient;
 }
 
-void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer,
-                                             int x, int y, uint32_t mul_col,
-                                             Efl_Gfx_Render_Op op, Shape_Rle_Data* rle)
+void
+ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer,
+                                        int x, int y, uint32_t mul_col,
+                                        Efl_Gfx_Render_Op op, Shape_Rle_Data* rle,
+                                        Ector_Buffer *mask,
+                                        int mask_op)
 {
-   // check for NULL rle data
    if (!rle) return;
 
    rasterizer->fill_data.offx = x;
    rasterizer->fill_data.offy = y;
    rasterizer->fill_data.mul_col = mul_col;
    rasterizer->fill_data.op = op;
+   rasterizer->fill_data.mask =
+         mask ? efl_data_scope_get(mask, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN) : NULL;
+   rasterizer->fill_data.mask_op = mask_op;
 
    _setup_span_fill_matrix(rasterizer);
    _adjust_span_fill_methods(&rasterizer->fill_data);
index ccb8bfb..addbf0c 100644 (file)
@@ -22,17 +22,75 @@ _invalidate_cb(void *data EINA_UNUSED, const Efl_Event *event)
       efl_unref(child);
 }
 
+static Ector_Buffer *
+_prepare_mask(Evas_Object_Protected_Data *obj,     //vector object
+              Efl_Canvas_Vg_Node* mask_obj,
+              Ector_Surface *surface,
+              Eina_Matrix3 *ptransform,
+              Ector_Buffer *mask,
+              int mask_op)
+{
+   Efl_Canvas_Vg_Container_Data *pd = efl_data_scope_get(mask_obj, MY_CLASS);
+   Efl_Canvas_Vg_Node_Data *nd =
+         efl_data_scope_get(mask_obj, EFL_CANVAS_VG_NODE_CLASS);
+   if (nd->flags == EFL_GFX_CHANGE_FLAG_NONE) return pd->mask.buffer;
+
+   //1. Mask Size
+   Eina_Rect mbound;
+   mbound.x = 0;
+   mbound.y = 0;
+   mbound.w = obj->cur->geometry.w;
+   mbound.h = obj->cur->geometry.h;
+
+//   efl_gfx_path_bounds_get(mask, &mbound);
+
+   //2. Reusable ector buffer?
+   if (!pd->mask.buffer || (pd->mask.bound.w != mbound.w) ||
+         (pd->mask.bound.h != mbound.h))
+     {
+        if (pd->mask.pixels) free(pd->mask.pixels);
+        if (pd->mask.buffer) efl_unref(pd->mask.buffer);
+        pd->mask.pixels = calloc(sizeof(uint32_t), mbound.w * mbound.h);
+        pd->mask.buffer = ENFN->ector_buffer_new(ENC, obj->layer->evas->evas,
+                                                 mbound.w, mbound.h,
+                                                 EFL_GFX_COLORSPACE_ARGB8888,
+                                                 ECTOR_BUFFER_FLAG_DRAWABLE |
+                                                 ECTOR_BUFFER_FLAG_CPU_READABLE |
+                                                 ECTOR_BUFFER_FLAG_CPU_WRITABLE);
+        ector_buffer_pixels_set(pd->mask.buffer, pd->mask.pixels,
+                                mbound.w, mbound.h, 0,
+                                EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
+        pd->mask.bound.w = mbound.w;
+        pd->mask.bound.h = mbound.h;
+        pd->mask.vg_pd = obj;
+     }
+
+   pd->mask.bound.x = mbound.x;
+   pd->mask.bound.y = mbound.y;
+
+   if (!pd->mask.buffer) ERR("Mask Buffer is invalid");
+
+   pd->mask.dirty = EINA_TRUE;
+
+   //3. Prepare Drawing shapes...
+   _evas_vg_render_pre(obj, mask_obj, surface, ptransform, mask, mask_op);
+
+   return pd->mask.buffer;
+}
+
 static void
-_efl_canvas_vg_container_render_pre(Eo *obj EINA_UNUSED,
-                             Eina_Matrix3 *parent,
-                             Ector_Surface *s,
-                             void *data,
-                             Efl_Canvas_Vg_Node_Data *nd)
+_efl_canvas_vg_container_render_pre(Evas_Object_Protected_Data *vg_pd,
+                                    Efl_VG *obj EINA_UNUSED,
+                                    Efl_Canvas_Vg_Node_Data *nd,
+                                    Ector_Surface *surface,
+                                    Eina_Matrix3 *ptransform,
+                                    Ector_Buffer *mask,
+                                    int mask_op,
+                                    void *data)
 {
    Efl_Canvas_Vg_Container_Data *pd = data;
    Eina_List *l;
-   Eo *child;
-   Efl_Canvas_Vg_Node_Data *child_nd;
+   Efl_VG *child;
    Efl_Gfx_Change_Flag flag;
 
    if (nd->flags == EFL_GFX_CHANGE_FLAG_NONE) return;
@@ -40,20 +98,37 @@ _efl_canvas_vg_container_render_pre(Eo *obj EINA_UNUSED,
    flag = nd->flags;
    nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
 
-   EFL_CANVAS_VG_COMPUTE_MATRIX(current, parent, nd);
+   EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd);
+
+   //Container may have mask source.
+   if (pd->mask_src)
+     {
+        mask = _prepare_mask(vg_pd, pd->mask_src, surface, ptransform, mask,
+                             mask_op);
+        mask_op = pd->mask.option;
+     }
 
    EINA_LIST_FOREACH(pd->children, l, child)
      {
+        //Don't need to update mask nodes.
+        if (efl_isa(child, MY_CLASS))
+          {
+             Efl_Canvas_Vg_Container_Data *child_cd =
+                efl_data_scope_get(child, MY_CLASS);
+             if (child_cd->mask.target) continue;
+          }
+
         //Skip Gradients. they will be updated by Shape.
         if (efl_isa(child, EFL_CANVAS_VG_GRADIENT_CLASS))
           continue;
 
+        Efl_Canvas_Vg_Node_Data *child_nd =
+           efl_data_scope_get(child, EFL_CANVAS_VG_NODE_CLASS);
+
         if (flag & EFL_GFX_CHANGE_FLAG_MATRIX)
-          {
-             child_nd = efl_data_scope_get(child, EFL_CANVAS_VG_NODE_CLASS);
-             child_nd->flags |= EFL_GFX_CHANGE_FLAG_MATRIX;
-          }
-        _evas_vg_render_pre(child, s, current);
+          child_nd->flags |= EFL_GFX_CHANGE_FLAG_MATRIX;
+
+        _evas_vg_render_pre(vg_pd, child, surface, ctransform, mask, mask_op);
      }
 }
 
@@ -77,16 +152,23 @@ _efl_canvas_vg_container_efl_object_constructor(Eo *obj,
 
 static void
 _efl_canvas_vg_container_efl_object_destructor(Eo *obj,
-                                     Efl_Canvas_Vg_Container_Data *pd EINA_UNUSED)
+                                               Efl_Canvas_Vg_Container_Data *pd)
 {
-   efl_destructor(efl_super(obj, MY_CLASS));
+   //Destroy mask surface
+   if (pd->mask.buffer) efl_unref(pd->mask.buffer);
+   if (pd->mask.pixels) free(pd->mask.pixels);
+
+   efl_unref(pd->mask_src);
+   eina_list_free(pd->mask.target);
    eina_hash_free(pd->names);
+
+   efl_destructor(efl_super(obj, MY_CLASS));
 }
 
 static void
 _efl_canvas_vg_container_efl_gfx_path_bounds_get(const Eo *obj EINA_UNUSED,
-                                    Efl_Canvas_Vg_Container_Data *pd,
-                                    Eina_Rect *r)
+                                                 Efl_Canvas_Vg_Container_Data *pd,
+                                                 Eina_Rect *r)
 {
    Eina_Rect s;
    Eina_Bool first = EINA_TRUE;
@@ -162,12 +244,51 @@ _efl_canvas_vg_container_efl_gfx_path_interpolate(Eo *obj, Efl_Canvas_Vg_Contain
         if (!r) break;
      }
 
+   //Interpolates Mask
+   Efl_Canvas_Vg_Container_Data *fromd = efl_data_scope_get(from, MY_CLASS);
+   Efl_Canvas_Vg_Container_Data *tod = efl_data_scope_get(to, MY_CLASS);
+
+   if (fromd->mask_src && tod->mask_src && pd->mask_src)
+     {
+        if (!efl_gfx_path_interpolate(pd->mask_src,
+                                      fromd->mask_src, tod->mask_src, pos_map))
+          return EINA_FALSE;
+     }
+
    eina_iterator_free(from_it);
    eina_iterator_free(to_it);
 
    return r;
 }
 
+static void
+_efl_canvas_vg_container_efl_canvas_vg_node_mask_set(Eo *obj,
+                                                     Efl_Canvas_Vg_Container_Data *pd,
+                                                     Efl_Canvas_Vg_Node *mask,
+                                                     int op)
+{
+   if (pd->mask_src == mask) return;
+
+   EINA_SAFETY_ON_FALSE_RETURN(efl_isa(mask, MY_CLASS));
+
+   if (pd->mask_src)
+     {
+        Efl_Canvas_Vg_Container_Data *pd2 =
+              efl_data_scope_get(pd->mask_src, MY_CLASS);
+        pd2->mask.target = eina_list_remove(pd2->mask.target, obj);
+     }
+
+   if (mask)
+     {
+        Efl_Canvas_Vg_Container_Data *pd2 = efl_data_scope_get(mask, MY_CLASS);
+        pd2->mask.target = eina_list_append(pd2->mask.target, obj);
+     }
+
+   pd->mask.option = op;
+   efl_replace(&pd->mask_src, mask);
+   _efl_canvas_vg_node_changed(obj);
+}
+
 EOLIAN static Efl_VG *
 _efl_canvas_vg_container_efl_duplicate_duplicate(const Eo *obj,
                                              Efl_Canvas_Vg_Container_Data *pd)
@@ -180,6 +301,14 @@ _efl_canvas_vg_container_efl_duplicate_duplicate(const Eo *obj,
    efl_event_callback_add(container, EFL_EVENT_INVALIDATE, _invalidate_cb, NULL);
    efl_parent_set(container, efl_parent_get(obj));
 
+   //Copy Mask
+   if (pd->mask_src)
+     {
+        Eo * mask_src = efl_duplicate(pd->mask_src);
+        efl_parent_set(mask_src, container);
+        efl_canvas_vg_node_mask_set(container, mask_src, pd->mask.option);
+     }
+
    //Copy Children
    EINA_LIST_FOREACH(pd->children, l, child)
      {
index f89d584..4060441 100644 (file)
@@ -4,14 +4,14 @@ class Efl.Canvas.Vg.Container (Efl.Canvas.Vg.Node)
    legacy_prefix: evas_vg_container;
    methods {
       child_get {
-          [[Get child of container]]
+         [[Get child of container]]
          params {
             @in name: string; [[Child node name]]
          }
          return: Efl.Canvas.Vg.Node; [[Child object]]
       }
       children_get {
-          [[Get all children of container]]
+         [[Get all children of container]]
          return: iterator<Efl.Canvas.Vg.Node> @owned @warn_unused; [[Iterator to children]]
       }
    }
@@ -21,5 +21,6 @@ class Efl.Canvas.Vg.Container (Efl.Canvas.Vg.Node)
       Efl.Gfx.Path.bounds_get;
       Efl.Gfx.Path.interpolate;
       Efl.Duplicate.duplicate;
+      Efl.Canvas.Vg.Node.mask { set; }
    }
 }
index b8896f1..f56d6ff 100644 (file)
@@ -56,30 +56,33 @@ _efl_canvas_vg_gradient_linear_efl_gfx_gradient_linear_end_get(const Eo *obj EIN
 }
 
 static void
-_efl_canvas_vg_gradient_linear_render_pre(Eo *obj,
-                                   Eina_Matrix3 *parent,
-                                   Ector_Surface *s,
-                                   void *data,
-                                   Efl_Canvas_Vg_Node_Data *nd)
+_efl_canvas_vg_gradient_linear_render_pre(Evas_Object_Protected_Data *vg_pd EINA_UNUSED,
+                                          Efl_VG *obj,
+                                          Efl_Canvas_Vg_Node_Data *nd,
+                                          Ector_Surface *surface,
+                                          Eina_Matrix3 *ptransform,
+                                          Ector_Buffer *mask,
+                                          int mask_op,
+                                          void *data)
 {
    Efl_Canvas_Vg_Gradient_Linear_Data *pd = data;
    Efl_Canvas_Vg_Gradient_Data *gd;
 
-   if (nd->flags == EFL_GFX_CHANGE_FLAG_NONE) return ;
+   if (nd->flags == EFL_GFX_CHANGE_FLAG_NONE) return;
 
    nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
 
    gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
-   EFL_CANVAS_VG_COMPUTE_MATRIX(current, parent, nd);
+   EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd);
 
    if (!nd->renderer)
      {
         efl_domain_current_push(EFL_ID_DOMAIN_SHARED);
-        nd->renderer = ector_surface_renderer_factory_new(s, ECTOR_RENDERER_GRADIENT_LINEAR_MIXIN);
+        nd->renderer = ector_surface_renderer_factory_new(surface, ECTOR_RENDERER_GRADIENT_LINEAR_MIXIN);
         efl_domain_current_pop();
      }
 
-   ector_renderer_transformation_set(nd->renderer, current);
+   ector_renderer_transformation_set(nd->renderer, ctransform);
    ector_renderer_origin_set(nd->renderer, nd->x, nd->y);
    ector_renderer_color_set(nd->renderer, nd->r, nd->g, nd->b, nd->a);
    ector_renderer_visibility_set(nd->renderer, nd->visibility);
@@ -87,8 +90,8 @@ _efl_canvas_vg_gradient_linear_render_pre(Eo *obj,
    efl_gfx_gradient_spread_set(nd->renderer, gd->s);
    efl_gfx_gradient_linear_start_set(nd->renderer, pd->start.x, pd->start.y);
    efl_gfx_gradient_linear_end_set(nd->renderer, pd->end.x, pd->end.y);
-
    ector_renderer_prepare(nd->renderer);
+   ector_renderer_mask_set(nd->renderer, mask, mask_op);
 }
 
 static Eo *
index d452b51..9760c63 100644 (file)
@@ -72,11 +72,14 @@ _efl_canvas_vg_gradient_radial_efl_gfx_gradient_radial_focal_get(const Eo *obj E
 }
 
 static void
-_efl_canvas_vg_gradient_radial_render_pre(Eo *obj,
-                                    Eina_Matrix3 *parent,
-                                    Ector_Surface *s,
-                                    void *data,
-                                    Efl_Canvas_Vg_Node_Data *nd)
+_efl_canvas_vg_gradient_radial_render_pre(Evas_Object_Protected_Data *vg_pd EINA_UNUSED,
+                                          Efl_VG *obj,
+                                          Efl_Canvas_Vg_Node_Data *nd,
+                                          Ector_Surface *surface,
+                                          Eina_Matrix3 *ptransform,
+                                          Ector_Buffer *mask,
+                                          int mask_op,
+                                          void *data)
 {
    Efl_Canvas_Vg_Gradient_Radial_Data *pd = data;
    Efl_Canvas_Vg_Gradient_Data *gd;
@@ -86,16 +89,16 @@ _efl_canvas_vg_gradient_radial_render_pre(Eo *obj,
    nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
 
    gd = efl_data_scope_get(obj, EFL_CANVAS_VG_GRADIENT_CLASS);
-   EFL_CANVAS_VG_COMPUTE_MATRIX(current, parent, nd);
+   EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd);
 
    if (!nd->renderer)
      {
         efl_domain_current_push(EFL_ID_DOMAIN_SHARED);
-        nd->renderer = ector_surface_renderer_factory_new(s, ECTOR_RENDERER_GRADIENT_RADIAL_MIXIN);
+        nd->renderer = ector_surface_renderer_factory_new(surface, ECTOR_RENDERER_GRADIENT_RADIAL_MIXIN);
         efl_domain_current_pop();
      }
 
-   ector_renderer_transformation_set(nd->renderer, current);
+   ector_renderer_transformation_set(nd->renderer, ctransform);
    ector_renderer_origin_set(nd->renderer, nd->x, nd->y);
    ector_renderer_color_set(nd->renderer, nd->r, nd->g, nd->b, nd->a);
    ector_renderer_visibility_set(nd->renderer, nd->visibility);
@@ -104,8 +107,8 @@ _efl_canvas_vg_gradient_radial_render_pre(Eo *obj,
    efl_gfx_gradient_radial_center_set(nd->renderer, pd->center.x, pd->center.y);
    efl_gfx_gradient_radial_focal_set(nd->renderer, pd->focal.x, pd->focal.y);
    efl_gfx_gradient_radial_radius_set(nd->renderer, pd->radius);
-
    ector_renderer_prepare(nd->renderer);
+   ector_renderer_mask_set(nd->renderer, mask, mask_op);
 }
 
 static Eo *
index e7ef736..dc2c4a3 100644 (file)
@@ -66,6 +66,14 @@ _efl_canvas_vg_node_transformation_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_
 }
 
 static void
+_efl_canvas_vg_node_mask_set(Eo *obj EINA_UNUSED,
+                             Efl_Canvas_Vg_Node_Data *pd EINA_UNUSED,
+                             Efl_Canvas_Vg_Node *mask EINA_UNUSED,
+                             int op EINA_UNUSED)
+{
+}
+
+static void
 _efl_canvas_vg_node_origin_set(Eo *obj,
                         Efl_Canvas_Vg_Node_Data *pd,
                         double x, double y)
@@ -166,25 +174,6 @@ _efl_canvas_vg_node_efl_gfx_color_color_get(const Eo *obj EINA_UNUSED,
    if (a) *a = pd->a;
 }
 
-static void
-_efl_canvas_vg_node_mask_set(Eo *obj EINA_UNUSED,
-                       Efl_Canvas_Vg_Node_Data *pd,
-                       Efl_VG *r)
-{
-   Efl_VG *tmp = pd->mask;
-
-   pd->mask = efl_ref(r);
-   efl_unref(tmp);
-
-   _efl_canvas_vg_node_changed(obj);
-}
-
-static Efl_VG*
-_efl_canvas_vg_node_mask_get(const Eo *obj EINA_UNUSED, Efl_Canvas_Vg_Node_Data *pd)
-{
-   return pd->mask;
-}
-
 static Eina_Size2D
 _efl_canvas_vg_node_efl_gfx_entity_size_get(const Eo *obj, Efl_Canvas_Vg_Node_Data *pd EINA_UNUSED)
 {
@@ -711,14 +700,6 @@ _efl_canvas_vg_node_efl_gfx_path_interpolate(Eo *obj, Efl_Canvas_Vg_Node_Data *p
 
    pd->visibility = pos_map >= 0.5 ? tod->visibility : fromd->visibility;
 
-   //Interpolates Mask
-   if (fromd->mask && tod->mask && pd->mask)
-     {
-        if (!efl_gfx_path_interpolate(pd->mask,
-                                      fromd->mask, tod->mask, pos_map))
-          return EINA_FALSE;
-     }
-
    _efl_canvas_vg_node_changed(obj);
 
    return EINA_TRUE;
@@ -750,12 +731,6 @@ _efl_canvas_vg_node_efl_duplicate_duplicate(const Eo *obj, Efl_Canvas_Vg_Node_Da
         if (nd->m) memcpy(nd->m, pd->m, sizeof(Eina_Matrix3));
      }
 
-   if (pd->mask)
-     {
-        nd->mask = efl_duplicate(pd->mask);
-        efl_parent_set(nd->mask, node);
-     }
-
    nd->x = pd->x;
    nd->y = pd->y;
    nd->r = pd->r;
index 6b720c2..361fe74 100644 (file)
@@ -42,13 +42,12 @@ abstract Efl.Canvas.Vg.Node (Efl.Object, Efl.Gfx.Entity, Efl.Gfx.Color, Efl.Gfx.
          }
       }
       @property mask {
-         [[Vector graphics object mask]]
+         [[Set Mask Node to this renderer]]
          set {
          }
-         get {
-         }
          values {
-            m: Efl.Canvas.Vg.Node; [[Object mask]]
+            mask: Efl.Canvas.Vg.Node; [[Mask object]]
+            op: int; [[Masking Option. Reserved]]
          }
       }
    }
index 8eafff1..6b2e1a8 100644 (file)
@@ -484,37 +484,71 @@ _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, void *surface, Efl_VG *n,
+                void *engine, void *output, void *context, Efl_VG *node,
                 Eina_Array *clips, Eina_Bool do_async)
 {
-   if (efl_isa(n, EFL_CANVAS_VG_CONTAINER_CLASS))
+   if (efl_isa(node, EFL_CANVAS_VG_CONTAINER_CLASS))
      {
-        Efl_Canvas_Vg_Container_Data *vc;
+        Efl_Canvas_Vg_Container_Data *cd =
+           efl_data_scope_get(node, EFL_CANVAS_VG_CONTAINER_CLASS);
+
+        //Update Mask Image
+        if (cd->mask_src)
+          {
+             Efl_Canvas_Vg_Container_Data *cd2 =
+                efl_data_scope_get(cd->mask_src, EFL_CANVAS_VG_CONTAINER_CLASS);
+
+             if (cd2->mask.buffer && cd2->mask.dirty)
+               {
+                  Ector_Surface *ector = evas_ector_get(obj->layer->evas);
+                  if (!ector) return;
+
+                  ENFN->ector_end(engine, output, context, ector, EINA_FALSE);
+
+                  //Need a better approach.
+                  ector_buffer_pixels_set(ector, cd2->mask.pixels, cd2->mask.bound.w, cd2->mask.bound.h, 0,
+                                          EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
+                  ector_surface_reference_point_set(ector, -cd2->mask.bound.x, -cd2->mask.bound.y);
+
+                  //Draw Mask Image.
+                  Efl_VG *child;
+                  Eina_List *l;
+                  EINA_LIST_FOREACH(cd2->children, l, child)
+                     _evas_vg_render(obj, pd, engine, output, context, child,
+                                     clips, EINA_FALSE);
+
+                  cd2->mask.dirty = EINA_FALSE;
+#if 0
+                  FILE *fp = fopen("./test.raw", "w+");
+                  fwrite(cd2->mask.pixels, cd2->mask.bound.w * cd2->mask.bound.h, sizeof(uint32_t), fp);
+                  fclose(fp);
+                  ERR("size = %d x %d", cd2->mask.bound.w, cd2->mask.bound.h);
+#endif
+                  //Restore previous ector context
+                  ENFN->ector_begin(engine, output, context, ector, 0, 0, EINA_FALSE, do_async);
+               }
+          }
+
+        if (cd->mask.target) return;   //Don't draw mask itself.
+
         Efl_VG *child;
         Eina_List *l;
 
-        vc = efl_data_scope_get(n, EFL_CANVAS_VG_CONTAINER_CLASS);
-
-        EINA_LIST_FOREACH(vc->children, l, child)
-          _evas_vg_render(obj, pd,
-                          engine, output, context, surface, child,
-                          clips, do_async);
+        EINA_LIST_FOREACH(cd->children, l, child)
+          _evas_vg_render(obj, pd, engine, output, context, child, clips, do_async);
      }
    else
      {
-        Efl_Canvas_Vg_Node_Data *nd;
-        nd = efl_data_scope_get(n, EFL_CANVAS_VG_NODE_CLASS);
-        obj->layer->evas->engine.func->ector_renderer_draw(engine, output, context, surface, nd->renderer, clips, do_async);
-        if (do_async)
-          eina_array_push(&pd->cleanup, efl_ref(nd->renderer));
+        Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(node, EFL_CANVAS_VG_NODE_CLASS);
+        ENFN->ector_renderer_draw(engine, output, context, nd->renderer, clips, do_async);
+        if (do_async) eina_array_push(&pd->cleanup, efl_ref(nd->renderer));
      }
 }
 
 //renders a vg_tree to an offscreen buffer and push it to the cache.
 static void *
 _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
-                  void *engine, void *surface,
-                  Efl_VG *root, int w, int h, void *key,
+                  void *engine, Efl_VG *root, int w, int h, void *key,
                   void *buffer, Eina_Bool do_async, Eina_Bool cacheable)
 {
    Ector_Surface *ector;
@@ -535,29 +569,24 @@ _render_to_buffer(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd
         buffer_created = EINA_TRUE;
      }
 
-   _evas_vg_render_pre(root, ector, NULL);
+   _evas_vg_render_pre(obj, root, ector, NULL, NULL, 0);
 
    //initialize buffer
    context = evas_common_draw_context_new();
    evas_common_draw_context_set_render_op(context, _EVAS_RENDER_COPY);
    evas_common_draw_context_set_color(context, 255, 255, 255, 255);
-   obj->layer->evas->engine.func->ector_begin(engine, buffer,
-                                              context, surface,
-                                              ector,
-                                              0, 0,
-                                              do_async);
+
+   ENFN->ector_begin(engine, buffer, context, ector, 0, 0, EINA_TRUE, do_async);
+
    //draw on buffer
    _evas_vg_render(obj, pd,
                    engine, buffer,
-                   context, surface,
-                   root, NULL,
+                   context, root,
+                   NULL,
                    do_async);
 
-   obj->layer->evas->engine.func->image_dirty_region(engine, buffer, 0, 0, w, h);
-   obj->layer->evas->engine.func->ector_end(engine, buffer,
-                                            context, surface,
-                                            ector,do_async);
-
+   ENFN->image_dirty_region(engine, buffer, 0, 0, w, h);
+   ENFN->ector_end(engine, buffer, context, ector, do_async);
    evas_common_draw_context_free(context);
 
    //caching buffer only for first and last frames.
@@ -619,7 +648,7 @@ _cache_vg_entry_render(Evas_Object_Protected_Data *obj,
    void *buffer = obj->layer->evas->engine.func->ector_surface_cache_get(engine, root);
 
    if (!buffer)
-     buffer = _render_to_buffer(obj, pd, engine, surface, root, w, h, root, NULL,
+     buffer = _render_to_buffer(obj, pd, engine, root, w, h, root, NULL,
                                 do_async, cacheable);
    else
      //cache reference was increased when we get the cache.
@@ -656,20 +685,15 @@ _user_vg_entry_render(Evas_Object_Protected_Data *obj,
    if (!buffer)
      {
         // render to the buffer
-        buffer = _render_to_buffer(obj, pd,
-                                   engine, surface,
-                                   user_entry->root,
-                                   w, h,
-                                   user_entry,
-                                   buffer,
+        buffer = _render_to_buffer(obj, pd, engine, user_entry->root,
+                                   w, h, user_entry, buffer,
                                    do_async, cacheable);
      }
    else
      {
         // render to the buffer
         if (pd->changed)
-          buffer = _render_to_buffer(obj, pd,
-                                     engine, surface,
+          buffer = _render_to_buffer(obj, pd, engine,
                                      user_entry->root,
                                      w, h,
                                      user_entry,
@@ -763,7 +787,7 @@ _efl_canvas_vg_object_render_pre(Evas_Object *eo_obj,
    // FIXME: handle damage only on changed renderer.
    s = evas_ector_get(obj->layer->evas);
    if (pd->root && s)
-     _evas_vg_render_pre(pd->root, s, NULL);
+     _evas_vg_render_pre(obj, pd->root, s, NULL, NULL, 0);
 
    /* now figure what changed and add draw rects */
    /* if it just became visible or invisible */
index d55009a..106efec 100644 (file)
@@ -78,43 +78,45 @@ _efl_canvas_vg_shape_stroke_marker_get(const Eo *obj EINA_UNUSED,
 }
 
 static void
-_efl_canvas_vg_shape_render_pre(Eo *obj EINA_UNUSED,
-                         Eina_Matrix3 *parent,
-                         Ector_Surface *s,
-                         void *data,
-                         Efl_Canvas_Vg_Node_Data *nd)
+_efl_canvas_vg_shape_render_pre(Evas_Object_Protected_Data *vg_pd,
+                                Efl_VG *obj,
+                                Efl_Canvas_Vg_Node_Data *nd,
+                                Ector_Surface *surface,
+                                Eina_Matrix3 *ptransform,
+                                Ector_Buffer *mask,
+                                int mask_op,
+                                void *data)
 {
    Efl_Canvas_Vg_Shape_Data *pd = data;
-   Efl_Canvas_Vg_Node_Data *fill, *stroke_fill, *stroke_marker, *mask;
+   Efl_Canvas_Vg_Node_Data *fill, *stroke_fill, *stroke_marker;
 
    if (nd->flags == EFL_GFX_CHANGE_FLAG_NONE) return;
 
    nd->flags = EFL_GFX_CHANGE_FLAG_NONE;
 
-   EFL_CANVAS_VG_COMPUTE_MATRIX(current, parent, nd);
+   EFL_CANVAS_VG_COMPUTE_MATRIX(ctransform, ptransform, nd);
 
-   fill = _evas_vg_render_pre(pd->fill, s, current);
-   stroke_fill = _evas_vg_render_pre(pd->stroke.fill, s, current);
-   stroke_marker = _evas_vg_render_pre(pd->stroke.marker, s, current);
-   mask = _evas_vg_render_pre(nd->mask, s, current);
+   fill = _evas_vg_render_pre(vg_pd, pd->fill, surface, ctransform, mask, mask_op);
+   stroke_fill = _evas_vg_render_pre(vg_pd, pd->stroke.fill, surface, ctransform, mask, mask_op);
+   stroke_marker = _evas_vg_render_pre(vg_pd, pd->stroke.marker, surface, ctransform, mask, mask_op);
 
    if (!nd->renderer)
      {
         efl_domain_current_push(EFL_ID_DOMAIN_SHARED);
-        nd->renderer = ector_surface_renderer_factory_new(s, ECTOR_RENDERER_SHAPE_MIXIN);
+        nd->renderer = ector_surface_renderer_factory_new(surface, ECTOR_RENDERER_SHAPE_MIXIN);
         efl_domain_current_pop();
      }
-
-   ector_renderer_transformation_set(nd->renderer, current);
+   ector_renderer_transformation_set(nd->renderer, ctransform);
    ector_renderer_origin_set(nd->renderer, nd->x, nd->y);
    ector_renderer_color_set(nd->renderer, nd->r, nd->g, nd->b, nd->a);
    ector_renderer_visibility_set(nd->renderer, nd->visibility);
-   ector_renderer_mask_set(nd->renderer, mask ? mask->renderer : NULL);
    ector_renderer_shape_fill_set(nd->renderer, fill ? fill->renderer : NULL);
    ector_renderer_shape_stroke_fill_set(nd->renderer, stroke_fill ? stroke_fill->renderer : NULL);
    ector_renderer_shape_stroke_marker_set(nd->renderer, stroke_marker ? stroke_marker->renderer : NULL);
    efl_gfx_path_copy_from(nd->renderer, obj);
    ector_renderer_prepare(nd->renderer);
+   ector_renderer_mask_set(nd->renderer, mask, mask_op);
+
 }
 
 static Eo *
index 1068281..3899e74 100644 (file)
@@ -62,12 +62,13 @@ struct _Efl_Canvas_Vg_Node_Data
    Eina_Matrix3 *m;
    Efl_Canvas_Vg_Interpolation *intp;
 
-   Efl_Canvas_Vg_Node *mask;
    Ector_Renderer *renderer;
 
    Efl_VG *vg_obj;
 
-   void (*render_pre)(Eo *obj, Eina_Matrix3 *parent, Ector_Surface *s, void *data, Efl_Canvas_Vg_Node_Data *nd);
+   void (*render_pre)(Evas_Object_Protected_Data *vg_pd, Efl_VG *node,
+         Efl_Canvas_Vg_Node_Data *nd, Ector_Surface *surface,
+         Eina_Matrix3 *ptransform, Ector_Buffer *mask, int mask_op, void *data);
    void *data;
 
    double x, y;
@@ -79,11 +80,25 @@ struct _Efl_Canvas_Vg_Node_Data
    Eina_Bool parenting : 1;
 };
 
+typedef struct _Vg_Mask
+{
+   Evas_Object_Protected_Data *vg_pd;  //Vector Object (for accessing backend engine)
+   Ector_Buffer *buffer;               //Mask Ector Buffer
+   void *pixels;                       //Mask pixel buffer (actual data)
+   Eina_Rect bound;                    //Mask boundary
+   Eina_List *target;                  //Mask target
+   int option;                         //Mask option
+   Eina_Bool dirty : 1;                //Need to update mask image.
+} Vg_Mask;
+
 struct _Efl_Canvas_Vg_Container_Data
 {
    Eina_List *children;
-
    Eina_Hash *names;
+
+   //Masking feature.
+   Efl_Canvas_Vg_Node *mask_src;         //Mask Source
+   Vg_Mask mask;                         //Mask source data
 };
 
 struct _Efl_Canvas_Vg_Gradient_Data
@@ -120,13 +135,12 @@ Eina_Size2D                 evas_cache_vg_entry_default_size_get(const Vg_Cache_
 void                        efl_canvas_vg_node_root_set(Efl_VG *node, Efl_VG *vg_obj);
 
 static inline Efl_Canvas_Vg_Node_Data *
-_evas_vg_render_pre(Efl_VG *child, Ector_Surface *s, Eina_Matrix3 *m)
+_evas_vg_render_pre(Evas_Object_Protected_Data *vg_pd, Efl_VG *child, Ector_Surface *surface, Eina_Matrix3 *transform, Ector_Buffer *mask, int mask_op)
 {
    if (!child) return NULL;
-
-   Efl_Canvas_Vg_Node_Data *child_nd = efl_data_scope_get(child, EFL_CANVAS_VG_NODE_CLASS);
-   if (child_nd) child_nd->render_pre(child, m, s, child_nd->data, child_nd);
-   return child_nd;
+   Efl_Canvas_Vg_Node_Data *nd = efl_data_scope_get(child, EFL_CANVAS_VG_NODE_CLASS);
+   if (nd) nd->render_pre(vg_pd, child, nd, surface, transform, mask, mask_op, nd->data);
+   return nd;
 }
 
 static inline void
index 5cd8f49..802f1ad 100755 (executable)
@@ -1486,9 +1486,9 @@ struct _Evas_Func
    void  (*ector_destroy)                (void *engine, Ector_Surface *surface);
    Ector_Buffer *(*ector_buffer_wrap)    (void *engine, Evas *e, void *engine_image);
    Ector_Buffer *(*ector_buffer_new)     (void *engine, Evas *e, int width, int height, Efl_Gfx_Colorspace cspace, Ector_Buffer_Flag flags);
-   void  (*ector_begin)                  (void *engine, void *output, void *context, void *surface, Ector_Surface *ector, int x, int y, Eina_Bool do_async);
-   void  (*ector_renderer_draw)          (void *engine, void *output, void *context, void *surface, Ector_Renderer *r, Eina_Array *clips, Eina_Bool do_async);
-   void  (*ector_end)                    (void *engine, void *output, void *context, void *surface, Ector_Surface *ector, Eina_Bool do_async);
+   void  (*ector_begin)                  (void *engine, void *output, void *context, Ector_Surface *ector, int x, int y, Eina_Bool clear, Eina_Bool do_async);
+   void  (*ector_renderer_draw)          (void *engine, void *output, void *context, Ector_Renderer *r, Eina_Array *clips, Eina_Bool do_async);
+   void  (*ector_end)                    (void *engine, void *output, void *context, Ector_Surface *ector, Eina_Bool do_async);
 
    void *(*ector_surface_create)         (void *engine, int w, int h, int *error);
    void  (*ector_surface_destroy)        (void *engine, void *surface);
index c836bda..28f1f70 100755 (executable)
@@ -2,6 +2,7 @@
 #include "evas_gl_core_private.h"
 
 #include "software/Ector_Software.h"
+#include "../software_generic/evas_ector_software.h"
 #include "cairo/Ector_Cairo.h"
 #include "gl/Ector_GL.h"
 #include "evas_ector_gl.h"
@@ -2790,21 +2791,65 @@ static Ector_Buffer *
 eng_ector_buffer_new(void *engine, Evas *evas, int w, int h,
                      Efl_Gfx_Colorspace cspace, Ector_Buffer_Flag flags)
 {
-   return efl_add(EVAS_ECTOR_GL_BUFFER_CLASS, evas,
-                  evas_ector_gl_buffer_prepare(efl_added, engine, w, h, cspace, flags));
+   /* This condition is tricky, this buffer could be used for masking
+    * buffer by vector, Require to use software drawing.
+    */
+   if (flags != (ECTOR_BUFFER_FLAG_DRAWABLE | ECTOR_BUFFER_FLAG_CPU_READABLE | ECTOR_BUFFER_FLAG_CPU_WRITABLE))
+      {
+         return efl_add(EVAS_ECTOR_GL_BUFFER_CLASS, evas,
+                        evas_ector_gl_buffer_prepare(efl_added, engine, w, h, cspace, flags));
+      }
+   else
+     {
+        Ector_Buffer *buf;
+        Image_Entry *ie;
+        void *pixels;
+        int pxs;
+
+        if (cspace == EFL_GFX_COLORSPACE_ARGB8888)
+          pxs = 4;
+        else if (cspace == EFL_GFX_COLORSPACE_GRY8)
+          pxs = 1;
+        else
+          {
+             ERR("Unsupported colorspace: %d", (int) cspace);
+             return NULL;
+          }
+
+        // alloc buffer
+        ie = evas_cache_image_copied_data(evas_common_image_cache_get(), w, h,
+                                          NULL, EINA_TRUE, cspace);
+        if (!ie) return NULL;
+        pixels = ((RGBA_Image *) ie)->image.data;
+        memset(pixels, 0, w * h * pxs);
+
+        if (!efl_domain_current_push(EFL_ID_DOMAIN_SHARED))
+          {
+             evas_cache_image_drop(ie);
+             return NULL;
+          }
+
+        buf = efl_add_ref(EVAS_ECTOR_SOFTWARE_BUFFER_CLASS, NULL,
+                          evas_ector_buffer_engine_image_set(efl_added, engine, ie));
+        efl_domain_current_pop();
+
+        evas_cache_image_drop(ie);
+
+        return buf;
+     }
 }
 
 static void
-eng_ector_renderer_draw(void *engine EINA_UNUSED, void *output,
-                        void *context EINA_UNUSED, void *surface EINA_UNUSED,
-                        Ector_Renderer *renderer, Eina_Array *clips EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
+eng_ector_renderer_draw(void *engine EINA_UNUSED, void *surface,
+                        void *context EINA_UNUSED, Ector_Renderer *renderer,
+                        Eina_Array *clips EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
 {
-   if (use_cairo|| !use_gl)
+   if (use_cairo || !use_gl)
      {
         int w, h;
         Eina_Rectangle *r;
         Eina_Array *c = eina_array_new(4);
-        Evas_GL_Image *glimg = output;
+        Evas_GL_Image *glimg = surface;
 
         eng_image_size_get(engine, glimg, &w, &h);
         eina_array_push(c, eina_rectangle_new(0, 0, w, h));
@@ -2880,21 +2925,22 @@ eng_ector_surface_cache_drop(void *engine, void *key)
 }
 
 static void
-eng_ector_begin(void *engine, void *output,
-                void *context EINA_UNUSED, void *surface EINA_UNUSED,
-                Ector_Surface *ector, int x, int y, Eina_Bool do_async EINA_UNUSED)
+eng_ector_begin(void *engine, void *surface,
+                void *context EINA_UNUSED, Ector_Surface *ector,
+                int x, int y, Eina_Bool clear, Eina_Bool do_async EINA_UNUSED)
 {
    if (use_cairo|| !use_gl)
      {
         int w, h, stride;
-        Evas_GL_Image *glim = output;
+        Evas_GL_Image *glim = surface;
         DATA32 *pixels;
         int load_err;
 
         glim = eng_image_data_get(engine, glim, EINA_TRUE, &pixels, &load_err,NULL);
         eng_image_stride_get(engine, glim, &stride);
         eng_image_size_get(engine, glim, &w, &h);
-        memset(pixels, 0, stride * h);
+
+        if (clear) memset(pixels, 0, stride * h);
 
         // it just uses the software backend to draw for now
         ector_buffer_pixels_set(ector, pixels, w, h, stride, EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
@@ -2907,13 +2953,15 @@ eng_ector_begin(void *engine, void *output,
 }
 
 static void
-eng_ector_end(void *engine, void *output,
-              void *context EINA_UNUSED, void *surface EINA_UNUSED,
-              Ector_Surface *ector, Eina_Bool do_async EINA_UNUSED)
+eng_ector_end(void *engine,
+              void *surface,
+              void *context EINA_UNUSED,
+              Ector_Surface *ector,
+              Eina_Bool do_async EINA_UNUSED)
 {
    if (use_cairo || !use_gl)
      {
-        Evas_GL_Image *glim = output;
+        Evas_GL_Image *glim = surface;
         DATA32 *pixels;
         int load_err;
 
index 6dc3347..15264ef 100755 (executable)
@@ -411,6 +411,7 @@ struct _Evas_Thread_Command_Ector_Surface
    Ector_Surface *ector;
    void *pixels;
    int x, y;
+   Eina_Bool clear;
 };
 
 // declare here as it is re-used
@@ -4321,7 +4322,7 @@ eng_ector_buffer_wrap(void *data, Evas *e EINA_UNUSED, void *engine_image)
 }
 
 static Ector_Buffer *
-eng_ector_buffer_new(void *data EINA_UNUSED, Evas *evas, int width, int height,
+eng_ector_buffer_new(void *data, Evas *evas, int width, int height,
                      Efl_Gfx_Colorspace cspace, Ector_Buffer_Flag flags EINA_UNUSED)
 {
    Ector_Buffer *buf;
@@ -4377,8 +4378,8 @@ _draw_thread_ector_draw(void *data)
 
 static void
 eng_ector_renderer_draw(void *engine EINA_UNUSED, void *surface,
-                        void *context, void *remove EINA_UNUSED,
-                        Ector_Renderer *renderer, Eina_Array *clips, Eina_Bool do_async)
+                        void *context, Ector_Renderer *renderer,
+                        Eina_Array *clips, Eina_Bool do_async)
 {
    RGBA_Image *dst = surface;
    RGBA_Draw_Context *dc = context;
@@ -4484,7 +4485,7 @@ _draw_thread_ector_surface_set(void *data)
         x = ector_surface->x;
         y = ector_surface->y;
         // clear the surface before giving to ector
-        memset(pixels, 0, (w * h * 4));
+        if (ector_surface->clear) memset(pixels, 0, (w * h * 4));
      }
 
    ector_buffer_pixels_set(ector_surface->ector, pixels, w, h, 0, EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
@@ -4495,20 +4496,21 @@ _draw_thread_ector_surface_set(void *data)
 
 static void
 eng_ector_begin(void *engine EINA_UNUSED, void *surface,
-                void *context EINA_UNUSED, void *remove EINA_UNUSED,
-                Ector_Surface *ector, int x, int y, Eina_Bool do_async)
+                void *context EINA_UNUSED, Ector_Surface *ector,
+                int x, int y, Eina_Bool clear, Eina_Bool do_async)
 {
    if (do_async)
      {
         Evas_Thread_Command_Ector_Surface *nes;
 
         nes = eina_mempool_malloc(_mp_command_ector_surface, sizeof (Evas_Thread_Command_Ector_Surface));
-        if (!nes) return ;
+        if (!nes) return;
 
         nes->ector = ector;
         nes->pixels = surface;
         nes->x = x;
         nes->y = y;
+        nes->clear = clear;
 
         QCMD(_draw_thread_ector_surface_set, nes);
      }
@@ -4523,7 +4525,7 @@ eng_ector_begin(void *engine EINA_UNUSED, void *surface,
         w = sf->cache_entry.w;
         h = sf->cache_entry.h;
         // clear the surface before giving to ector
-        memset(pixels, 0, (w * h * 4));
+        if (clear) memset(pixels, 0, (w * h * 4));
 
         ector_buffer_pixels_set(ector, pixels, w, h, 0, EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
         ector_surface_reference_point_set(ector, x, y);
@@ -4531,9 +4533,11 @@ eng_ector_begin(void *engine EINA_UNUSED, void *surface,
 }
 
 static void
-eng_ector_end(void *engine EINA_UNUSED, void *surface EINA_UNUSED,
-              void *context EINA_UNUSED, void *remove EINA_UNUSED,
-              Ector_Surface *ector, Eina_Bool do_async)
+eng_ector_end(void *engine EINA_UNUSED,
+              void *surface EINA_UNUSED,
+              void *context EINA_UNUSED,
+              Ector_Surface *ector,
+              Eina_Bool do_async)
 {
    if (do_async)
      {