Revert "ector - code clean up." 91/259091/1 accepted/tizen/unified/20210602.122542 submit/tizen/20210601.080645 submit/tizen/20210601.084003
authorChun <jykeon@samsung.com>
Tue, 1 Jun 2021 05:00:13 +0000 (05:00 +0000)
committerChun <jykeon@samsung.com>
Tue, 1 Jun 2021 05:00:13 +0000 (05:00 +0000)
This reverts commit 8aae7d5e11124e37c1cc43454ead4dc91a1a6ceb.

Change-Id: I1029adbf5952a24c27be20f0e4e5c4c70d0c8dfc

19 files changed:
src/lib/ector/software/Ector_Software.h
src/lib/ector/software/ector_renderer_software.eo [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_gradient_linear.c [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_gradient_linear.eo [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_gradient_radial.c [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_gradient_radial.eo [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_image.c [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_image.eo [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_shape.c [new file with mode: 0644]
src/lib/ector/software/ector_renderer_software_shape.eo [new file with mode: 0644]
src/lib/ector/software/ector_software_gradient.c [new file with mode: 0644]
src/lib/ector/software/ector_software_gradient.h [new file with mode: 0644]
src/lib/ector/software/ector_software_gradient_sse3.c [new file with mode: 0644]
src/lib/ector/software/ector_software_rasterizer.c [new file with mode: 0644]
src/lib/ector/software/ector_software_surface.c [new file with mode: 0644]
src/lib/ector/software/ector_software_surface.eo [new file with mode: 0644]
src/lib/ector/software/meson.build
src/modules/evas/engines/gl_generic/evas_engine.c
src/modules/evas/engines/software_generic/evas_engine.c

index 4098c1e..85529e6 100644 (file)
 
 #ifdef EFL_BETA_API_SUPPORT
 
+#include "software/ector_software_surface.eo.h"
 #include "software/ector_software_buffer.eo.h"
 #include "software/ector_software_buffer_base.eo.h"
+#include "software/ector_renderer_software.eo.h"
+#include "software/ector_renderer_software_shape.eo.h"
+#include "software/ector_renderer_software_image.eo.h"
+#include "software/ector_renderer_software_gradient_linear.eo.h"
+#include "software/ector_renderer_software_gradient_radial.eo.h"
 
 #endif
 
diff --git a/src/lib/ector/software/ector_renderer_software.eo b/src/lib/ector/software/ector_renderer_software.eo
new file mode 100644 (file)
index 0000000..00e1040
--- /dev/null
@@ -0,0 +1,11 @@
+abstract @beta Ector.Renderer.Software extends Ector.Renderer
+{
+   [[Ector software renderer class]]
+   data: null;
+   methods {
+      op_fill @pure_virtual {
+          [[Renderer fill operation]]
+         return: bool; [[$true on success, $false otherwise]]
+      }
+   }
+}
diff --git a/src/lib/ector/software/ector_renderer_software_gradient_linear.c b/src/lib/ector/software/ector_renderer_software_gradient_linear.c
new file mode 100644 (file)
index 0000000..0e5bc93
--- /dev/null
@@ -0,0 +1,119 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Eina.h>
+#include <Ector.h>
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+#include "ector_software_gradient.h"
+
+static Eina_Bool
+_ector_renderer_software_gradient_linear_ector_renderer_prepare(Eo *obj,
+                                                                Ector_Renderer_Software_Gradient_Data *pd)
+{
+   pd->ctable_status = CTABLE_NOT_READY;
+
+   if (!pd->surface)
+     {
+        Ector_Renderer_Data *base = efl_data_scope_get(obj, ECTOR_RENDERER_CLASS);
+        pd->surface = efl_data_xref(base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
+     }
+   ector_software_gradient_color_update(pd);
+
+   pd->linear.x1 = pd->gld->start.x;
+   pd->linear.y1 = pd->gld->start.y;
+
+   pd->linear.x2 = pd->gld->end.x;
+   pd->linear.y2 = pd->gld->end.y;
+
+   pd->linear.dx = pd->linear.x2 - pd->linear.x1;
+   pd->linear.dy = pd->linear.y2 - pd->linear.y1;
+   pd->linear.l = pd->linear.dx * pd->linear.dx + pd->linear.dy * pd->linear.dy;
+   pd->linear.off = 0;
+
+   if (!EINA_DBL_EQ(pd->linear.l, 0.0))
+     {
+        pd->linear.dx /= pd->linear.l;
+        pd->linear.dy /= pd->linear.l;
+        pd->linear.off = -pd->linear.dx * pd->linear.x1 - pd->linear.dy * pd->linear.y1;
+     }
+
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ector_renderer_software_gradient_linear_ector_renderer_draw(Eo *obj EINA_UNUSED,
+                                                             Ector_Renderer_Software_Gradient_Data *pd EINA_UNUSED,
+                                                             Efl_Gfx_Render_Op op EINA_UNUSED, Eina_Array *clips EINA_UNUSED,
+                                                             unsigned int mul_col EINA_UNUSED)
+{
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_ector_renderer_software_gradient_linear_ector_renderer_software_op_fill(Eo *obj EINA_UNUSED,
+                                                                         Ector_Renderer_Software_Gradient_Data *pd)
+{
+   ector_software_rasterizer_linear_gradient_set(pd->surface->rasterizer, pd);
+   ector_software_gradient_color_update(pd);
+
+   return EINA_TRUE;
+}
+
+static Eo *
+_ector_renderer_software_gradient_linear_efl_object_constructor(Eo *obj,
+                                                                Ector_Renderer_Software_Gradient_Data *pd)
+{
+   obj = efl_constructor(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS));
+   if (!obj) return NULL;
+
+   pd->gd  = efl_data_xref(obj, ECTOR_RENDERER_GRADIENT_MIXIN, obj);
+   pd->gld = efl_data_xref(obj, ECTOR_RENDERER_GRADIENT_LINEAR_MIXIN, obj);
+   pd->ctable_status = CTABLE_NOT_READY;
+
+   return obj;
+}
+
+static void
+_ector_renderer_software_gradient_linear_efl_object_destructor(Eo *obj,
+                                                            Ector_Renderer_Software_Gradient_Data *pd)
+{
+   Ector_Renderer_Data *base;
+
+   destroy_color_table(pd);
+
+   base = efl_data_scope_get(obj, ECTOR_RENDERER_CLASS);
+   efl_data_xunref(base->surface, pd->surface, obj);
+
+   efl_data_xunref(obj, pd->gd, obj);
+   efl_data_xunref(obj, pd->gld, obj);
+
+   efl_destructor(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS));
+}
+
+void
+_ector_renderer_software_gradient_linear_efl_gfx_gradient_stop_set(Eo *obj, Ector_Renderer_Software_Gradient_Data *pd EINA_UNUSED,
+                                                                   const Efl_Gfx_Gradient_Stop *colors, unsigned int length)
+{
+   efl_gfx_gradient_stop_set(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS), colors, length);
+}
+
+static unsigned int
+_ector_renderer_software_gradient_linear_ector_renderer_crc_get(const Eo *obj, Ector_Renderer_Software_Gradient_Data *pd)
+{
+   unsigned int crc;
+
+   crc = ector_renderer_crc_get(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS));
+
+   crc = eina_crc((void*) pd->gd->s, sizeof (Efl_Gfx_Gradient_Spread), crc, EINA_FALSE);
+   if (pd->gd->colors_count)
+     crc = eina_crc((void*) pd->gd->colors, sizeof (Efl_Gfx_Gradient_Stop) * pd->gd->colors_count, crc, EINA_FALSE);
+   crc = eina_crc((void*) pd->gld, sizeof (Ector_Renderer_Gradient_Linear_Data), crc, EINA_FALSE);
+
+   return crc;
+}
+
+#include "ector_renderer_software_gradient_linear.eo.c"
diff --git a/src/lib/ector/software/ector_renderer_software_gradient_linear.eo b/src/lib/ector/software/ector_renderer_software_gradient_linear.eo
new file mode 100644 (file)
index 0000000..5f4f539
--- /dev/null
@@ -0,0 +1,15 @@
+class @beta Ector.Renderer.Software.Gradient.Linear extends Ector.Renderer.Software implements Ector.Renderer.Gradient, Ector.Renderer.Gradient.Linear
+{
+   [[Ector software renderer gradient linear class]]
+   c_prefix: ector_renderer_software_gradient_linear;
+   data: Ector_Renderer_Software_Gradient_Data;
+   implements {
+      Ector.Renderer.prepare;
+      Ector.Renderer.draw;
+      Ector.Renderer.crc { get; }
+      Ector.Renderer.Software.op_fill;
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Gfx.Gradient.stop { set; }
+   }
+}
diff --git a/src/lib/ector/software/ector_renderer_software_gradient_radial.c b/src/lib/ector/software/ector_renderer_software_gradient_radial.c
new file mode 100644 (file)
index 0000000..6f6c877
--- /dev/null
@@ -0,0 +1,129 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Eina.h>
+#include <Ector.h>
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+#include "ector_software_gradient.h"
+
+static Eina_Bool
+_ector_renderer_software_gradient_radial_ector_renderer_prepare(Eo *obj, Ector_Renderer_Software_Gradient_Data *pd)
+{
+   pd->ctable_status = CTABLE_NOT_READY;
+
+   if (!pd->surface)
+     {
+        Ector_Renderer_Data *base = efl_data_scope_get(obj, ECTOR_RENDERER_CLASS);
+        pd->surface = efl_data_xref(base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
+     }
+
+   ector_software_gradient_color_update(pd);
+
+   pd->radial.cx = pd->grd->radial.x;
+   pd->radial.cy = pd->grd->radial.y;
+   pd->radial.cradius = pd->grd->radius;
+
+   if (EINA_DBL_EQ(pd->grd->focal.x, 0.0))
+     pd->radial.fx = pd->grd->radial.x;
+   else
+     pd->radial.fx = pd->grd->focal.x;
+
+   if (EINA_DBL_EQ(pd->grd->focal.y, 0.0))
+     pd->radial.fy = pd->grd->radial.y;
+   else
+     pd->radial.fy = pd->grd->focal.y;
+
+   pd->radial.fradius = 0;
+
+   pd->radial.dx = pd->radial.cx - pd->radial.fx;
+   pd->radial.dy = pd->radial.cy - pd->radial.fy;
+
+   pd->radial.dr = pd->radial.cradius - pd->radial.fradius;
+   pd->radial.sqrfr = pd->radial.fradius * pd->radial.fradius;
+
+   pd->radial.a = pd->radial.dr * pd->radial.dr -
+     pd->radial.dx * pd->radial.dx -
+     pd->radial.dy * pd->radial.dy;
+   pd->radial.inv2a = 1 / (2 * pd->radial.a);
+
+   pd->radial.extended = (pd->radial.fradius >= 0.00001f) || pd->radial.a >= 0.00001f;
+
+   return EINA_FALSE;
+}
+
+// Clearly duplicated and should be in a common place...
+static Eina_Bool
+_ector_renderer_software_gradient_radial_ector_renderer_draw(Eo *obj EINA_UNUSED,
+                                                             Ector_Renderer_Software_Gradient_Data *pd EINA_UNUSED,
+                                                             Efl_Gfx_Render_Op op EINA_UNUSED, Eina_Array *clips EINA_UNUSED,
+                                                             unsigned int mul_col EINA_UNUSED)
+{
+   return EINA_TRUE;
+}
+
+// Clearly duplicated and should be in a common place...
+static Eina_Bool
+_ector_renderer_software_gradient_radial_ector_renderer_software_op_fill(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Gradient_Data *pd)
+{
+   ector_software_rasterizer_radial_gradient_set(pd->surface->rasterizer, pd);
+   ector_software_gradient_color_update(pd);
+
+   return EINA_TRUE;
+}
+
+Eo *
+_ector_renderer_software_gradient_radial_efl_object_constructor(Eo *obj,
+                                                                Ector_Renderer_Software_Gradient_Data *pd)
+{
+   obj = efl_constructor(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS));
+   pd->gd  = efl_data_xref(obj, ECTOR_RENDERER_GRADIENT_MIXIN, obj);
+   pd->gld = efl_data_xref(obj, ECTOR_RENDERER_GRADIENT_RADIAL_MIXIN, obj);
+   pd->ctable_status = CTABLE_NOT_READY;
+
+   return obj;
+}
+
+void
+_ector_renderer_software_gradient_radial_efl_object_destructor(Eo *obj,
+                                                            Ector_Renderer_Software_Gradient_Data *pd)
+{
+   Ector_Renderer_Data *base;
+
+   destroy_color_table(pd);
+
+   base = efl_data_scope_get(obj, ECTOR_RENDERER_CLASS);
+   efl_data_xunref(base->surface, pd->surface, obj);
+
+   efl_data_xunref(obj, pd->gd, obj);
+   efl_data_xunref(obj, pd->gld, obj);
+
+   efl_destructor(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS));
+}
+
+void
+_ector_renderer_software_gradient_radial_efl_gfx_gradient_stop_set(Eo *obj, Ector_Renderer_Software_Gradient_Data *pd EINA_UNUSED,
+                                                                   const Efl_Gfx_Gradient_Stop *colors, unsigned int length)
+{
+   efl_gfx_gradient_stop_set(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS), colors, length);
+}
+
+static unsigned int
+_ector_renderer_software_gradient_radial_ector_renderer_crc_get(const Eo *obj, Ector_Renderer_Software_Gradient_Data *pd)
+{
+   unsigned int crc;
+
+   crc = ector_renderer_crc_get(efl_super(obj, ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS));
+
+   crc = eina_crc((void*) pd->gd->s, sizeof (Efl_Gfx_Gradient_Spread), crc, EINA_FALSE);
+   if (pd->gd->colors_count)
+     crc = eina_crc((void*) pd->gd->colors, sizeof (Efl_Gfx_Gradient_Stop) * pd->gd->colors_count, crc, EINA_FALSE);
+   crc = eina_crc((void*) pd->gld, sizeof (Ector_Renderer_Gradient_Radial_Data), crc, EINA_FALSE);
+
+   return crc;
+}
+
+#include "ector_renderer_software_gradient_radial.eo.c"
diff --git a/src/lib/ector/software/ector_renderer_software_gradient_radial.eo b/src/lib/ector/software/ector_renderer_software_gradient_radial.eo
new file mode 100644 (file)
index 0000000..b0a36d3
--- /dev/null
@@ -0,0 +1,15 @@
+class @beta Ector.Renderer.Software.Gradient.Radial extends Ector.Renderer.Software implements Ector.Renderer.Gradient, Ector.Renderer.Gradient.Radial
+{
+   [[Ector software renderer gradient radial]]
+   c_prefix: ector_renderer_software_gradient_radial;
+   data: Ector_Renderer_Software_Gradient_Data;
+   implements {
+      Ector.Renderer.prepare;
+      Ector.Renderer.draw;
+      Ector.Renderer.crc { get; }
+      Ector.Renderer.Software.op_fill;
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Gfx.Gradient.stop { set; }
+   }
+}
diff --git a/src/lib/ector/software/ector_renderer_software_image.c b/src/lib/ector/software/ector_renderer_software_image.c
new file mode 100644 (file)
index 0000000..d7807ed
--- /dev/null
@@ -0,0 +1,198 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <math.h>
+#include <float.h>
+
+#include <Eina.h>
+#include <Ector.h>
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+
+#define MY_CLASS ECTOR_RENDERER_SOFTWARE_IMAGE_CLASS
+
+typedef struct _Ector_Renderer_Software_Image_Data Ector_Renderer_Software_Image_Data;
+
+struct _Ector_Renderer_Software_Image_Data
+{
+   Ector_Software_Surface_Data *surface;
+   Ector_Renderer_Image_Data   *image;
+   Ector_Renderer_Data         *base;
+   Ector_Buffer                *comp;
+   Efl_Gfx_Vg_Composite_Method comp_method;
+   int                          opacity;
+   Eina_Matrix3                 inv_m;
+   struct {
+      int x1, y1, x2, y2;
+   } boundary;
+};
+
+static Eina_Bool
+_ector_renderer_software_image_ector_renderer_prepare(Eo *obj,
+                                                      Ector_Renderer_Software_Image_Data *pd)
+{
+   if (!pd->surface)
+     pd->surface = efl_data_xref(pd->base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
+
+   if (!pd->image->buffer || !pd->surface->rasterizer->fill_data.raster_buffer)
+     return EINA_FALSE;
+
+   Eina_Matrix3 m;
+   double m11, m12, m21, m22, m31, m32;
+   int x = pd->surface->x + (int)pd->base->origin.x;
+   int y = pd->surface->y + (int)pd->base->origin.y;
+   int image_w, image_h;
+   ector_buffer_size_get(pd->image->buffer, &image_w, &image_h);
+
+   double px[4] = {x, x + image_w, x, x + image_w};
+   double py[4] = {y, y, y + image_h, y + image_h};
+
+   //Only use alpha color
+   pd->opacity = pd->base->color.a;
+   /*ector_software_rasterizer_color_set(pd->surface->rasterizer,
+     pd->base->color.r,
+     pd->base->color.g,
+     pd->base->color.b,
+     pd->base->color.a);*/
+
+   if (!pd->base->m)
+     {
+        eina_matrix3_identity(&m);
+        eina_matrix3_scale(&m, (double)pd->surface->rasterizer->fill_data.raster_buffer->generic->w / (double)image_w,
+                           (double)pd->surface->rasterizer->fill_data.raster_buffer->generic->h / (double)image_h);
+     }
+   else
+     eina_matrix3_copy(&m, pd->base->m);
+   eina_matrix3_values_get(&m, &m11, &m12, NULL,
+                           &m21, &m22, NULL,
+                           &m31, &m32, NULL);
+   //Calc draw boundbox
+   pd->boundary.x1 = MAX(pd->surface->rasterizer->fill_data.raster_buffer->generic->w , (unsigned int)image_w);
+   pd->boundary.y1 = MAX(pd->surface->rasterizer->fill_data.raster_buffer->generic->h , (unsigned int)image_h);
+   pd->boundary.x2 = 0; pd->boundary.y2 = 0;
+   for (int i = 0; i < 4; i++)
+     {
+        pd->boundary.x1 = MIN(pd->boundary.x1, (int)(((px[i] * m11) + (py[i] * m21) + m31) + 0.5));
+        pd->boundary.y1 = MIN(pd->boundary.y1, (int)(((px[i] * m12) + (py[i] * m22) + m32) + 0.5));
+
+        pd->boundary.x2 = MAX(pd->boundary.x2, (int)(((px[i] * m11) + (py[i] * m21) + m31) + 0.5));
+        pd->boundary.y2 = MAX(pd->boundary.y2, (int)(((px[i] * m12) + (py[i] * m22) + m32) + 0.5));
+     }
+
+   eina_matrix3_inverse(&m, &pd->inv_m);
+
+   return EINA_TRUE;
+}
+
+//FIXME: We need to implement that apply op, clips and mul_col.
+static Eina_Bool
+_ector_renderer_software_image_ector_renderer_draw(Eo *obj EINA_UNUSED,
+                                                   Ector_Renderer_Software_Image_Data *pd,
+                                                   Efl_Gfx_Render_Op op EINA_UNUSED, Eina_Array *clips EINA_UNUSED,
+                                                   unsigned int mul_col EINA_UNUSED)
+{
+   if (!pd->image->buffer || !pd->surface->rasterizer->fill_data.raster_buffer->pixels.u32)
+          return EINA_FALSE;
+
+   if (pd->opacity == 0)
+      return EINA_TRUE;
+
+   const int pix_stride = pd->surface->rasterizer->fill_data.raster_buffer->stride / 4;
+   Ector_Software_Buffer_Base_Data *comp = pd->comp ? efl_data_scope_get(pd->comp, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN) : NULL;
+   Ector_Software_Buffer_Base_Data *bpd = efl_data_scope_get(pd->image->buffer, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN);
+   double im11, im12, im21, im22, im31, im32;
+   uint32_t *dst_buf, *src_buf;
+   int image_w, image_h;
+
+   int dst_buf_width = MIN(pd->boundary.x2, (int)pd->surface->rasterizer->fill_data.raster_buffer->generic->w);
+   int dst_buf_height = MIN(pd->boundary.y2, (int)pd->surface->rasterizer->fill_data.raster_buffer->generic->h);
+
+   ector_buffer_size_get(pd->image->buffer, &image_w, &image_h);
+
+   dst_buf = pd->surface->rasterizer->fill_data.raster_buffer->pixels.u32;
+   src_buf = bpd->pixels.u32;
+
+   eina_matrix3_values_get(&pd->inv_m, &im11, &im12, NULL,
+                                       &im21, &im22, NULL,
+                                       &im31, &im32, NULL);
+
+   //Draw
+   for (int local_y = pd->boundary.y1; local_y < dst_buf_height; local_y++)
+     {
+        for (int local_x = pd->boundary.x1; local_x <  dst_buf_width; local_x++)
+          {
+             uint32_t *dst = dst_buf + ((int)local_x + ((int)local_y * pix_stride));
+             int rx, ry;
+             rx = (int)(((double)local_x * im11) + ((double)local_y * im21) + im31 + 0.5);
+             ry = (int)(((double)local_x * im12) + ((double)local_y * im22) + im32 + 0.5);
+             if (rx < 0 || rx >= image_w || ry < 0 || ry >= image_h)
+               continue;
+             uint32_t *src = src_buf + (rx + (ry * image_w));  //FIXME: use to stride
+             uint32_t temp = 0x0;
+             if (comp)
+               {
+                  uint32_t *m = comp->pixels.u32 + ((int)local_x + ((int)local_y * comp->generic->w));
+                  //FIXME : This comping can work only matte case.
+                  //        We need consider to inverse matte case.
+                  temp = draw_mul_256((((*m)>>24) * pd->opacity)>>8, *src);
+               }
+             else
+               {
+                  temp = draw_mul_256(pd->opacity, *src);
+               }
+             int inv_alpha = 255 - ((temp) >> 24);
+             *dst = temp + draw_mul_256(inv_alpha, *dst);
+          }
+     }
+
+   return EINA_TRUE;
+}
+
+static Eo *
+_ector_renderer_software_image_efl_object_constructor(Eo *obj, Ector_Renderer_Software_Image_Data *pd)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   if (!obj) return NULL;
+
+   pd->image = efl_data_xref(obj, ECTOR_RENDERER_IMAGE_MIXIN, obj);
+   pd->base = efl_data_xref(obj, ECTOR_RENDERER_CLASS, obj);
+
+   return obj;
+}
+
+static void
+_ector_renderer_software_image_efl_object_destructor(Eo *obj, Ector_Renderer_Software_Image_Data *pd)
+{
+   efl_data_xunref(pd->base->surface, pd->surface, obj);
+   efl_data_xunref(obj, pd->base, obj);
+   efl_data_xunref(obj, pd->image, obj);
+
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+unsigned int
+_ector_renderer_software_image_ector_renderer_crc_get(const Eo *obj,
+                                                      Ector_Renderer_Software_Image_Data *pd)
+{
+   unsigned int crc;
+
+   crc = ector_renderer_crc_get(efl_super(obj, MY_CLASS));
+
+   crc = eina_crc((void*) pd->image, sizeof (Ector_Renderer_Image_Data), crc, EINA_FALSE);
+   return crc;
+}
+
+static void
+_ector_renderer_software_image_ector_renderer_comp_method_set(Eo *obj EINA_UNUSED,
+                                                              Ector_Renderer_Software_Image_Data *pd,
+                                                              Ector_Buffer *comp,
+                                                              Efl_Gfx_Vg_Composite_Method method)
+{
+   pd->comp = comp;
+   pd->comp_method = method;
+}
+
+#include "ector_renderer_software_image.eo.c"
diff --git a/src/lib/ector/software/ector_renderer_software_image.eo b/src/lib/ector/software/ector_renderer_software_image.eo
new file mode 100644 (file)
index 0000000..4771702
--- /dev/null
@@ -0,0 +1,13 @@
+class @beta Ector.Renderer.Software.Image extends Ector.Renderer.Software implements Ector.Renderer.Image
+{
+   [[Ector software renderer image class]]
+   c_prefix: ector_renderer_software_image;
+   implements {
+      Ector.Renderer.prepare;
+      Ector.Renderer.draw;
+      Ector.Renderer.comp_method { set; }
+      Ector.Renderer.crc { get; }
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+   }
+}
diff --git a/src/lib/ector/software/ector_renderer_software_shape.c b/src/lib/ector/software/ector_renderer_software_shape.c
new file mode 100644 (file)
index 0000000..658a82e
--- /dev/null
@@ -0,0 +1,831 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <math.h>
+#include <float.h>
+
+#include <Eina.h>
+#include <Ector.h>
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+
+#define MY_CLASS ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS
+
+typedef struct _Ector_Renderer_Software_Shape_Data Ector_Renderer_Software_Shape_Data;
+typedef struct _Ector_Software_Shape_Task Ector_Software_Shape_Task;
+
+struct _Ector_Software_Shape_Task
+{
+   Ector_Renderer_Software_Shape_Data *pd;
+
+   const Efl_Gfx_Path_Command *cmds;
+   const double *pts;
+
+   Efl_Gfx_Fill_Rule fill_rule;
+};
+
+struct _Ector_Renderer_Software_Shape_Data
+{
+   Efl_Gfx_Shape_Public        *public_shape;
+
+   Ector_Software_Surface_Data *surface;
+   Ector_Renderer_Shape_Data   *shape;
+   Ector_Renderer_Data         *base;
+
+   Shape_Rle_Data              *shape_data;
+   Shape_Rle_Data              *outline_data;
+
+   Ector_Buffer                *comp;
+   Efl_Gfx_Vg_Composite_Method comp_method;
+
+   Ector_Software_Shape_Task   *task;
+};
+
+typedef struct _Outline
+{
+   SW_FT_Outline ft_outline;
+   int points_alloc;
+   int contours_alloc;
+} Outline;
+
+
+#define TO_FT_COORD(x) ((x) * 64) // to freetype 26.6 coordinate.
+
+static inline void
+_grow_outline_contour(Outline *outline, int num)
+{
+   if ( outline->ft_outline.n_contours + num > outline->contours_alloc)
+     {
+        outline->contours_alloc += 5;
+        outline->ft_outline.contours = (short *) realloc(outline->ft_outline.contours,
+                                                         outline->contours_alloc * sizeof(short));
+     }
+}
+
+static inline void
+_grow_outline_points(Outline *outline, int num)
+{
+   if ( outline->ft_outline.n_points + num > outline->points_alloc)
+     {
+        outline->points_alloc += 50;
+        outline->ft_outline.points = (SW_FT_Vector *) realloc(outline->ft_outline.points,
+                                                              outline->points_alloc * sizeof(SW_FT_Vector));
+        outline->ft_outline.tags = (char *) realloc(outline->ft_outline.tags,
+                                                    outline->points_alloc * sizeof(char));
+     }
+}
+static Outline *
+_outline_create()
+{
+   Outline *outline = (Outline *) calloc(1, sizeof(Outline));
+   outline->points_alloc = 0;
+   outline->contours_alloc = 0;
+   _grow_outline_contour(outline, 1);
+   _grow_outline_points(outline, 1);
+   return outline;
+}
+
+static
+void _outline_destroy(Outline *outline)
+{
+   if (outline)
+     {
+        free(outline->ft_outline.points);
+        free(outline->ft_outline.tags);
+        free(outline->ft_outline.contours);
+        free(outline);
+     }
+}
+
+static void
+_outline_move_to(Outline *outline, double x, double y)
+{
+   SW_FT_Outline *ft_outline = &outline->ft_outline;
+
+   _grow_outline_points(outline, 1);
+   ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
+   ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
+   ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
+
+   if (ft_outline->n_points)
+     {
+        _grow_outline_contour(outline, 1);
+        ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1;
+        ft_outline->n_contours++;
+     }
+
+   ft_outline->n_points++;
+}
+
+static void
+_outline_end(Outline *outline)
+{
+   SW_FT_Outline *ft_outline = &outline->ft_outline;
+
+   _grow_outline_contour(outline, 1);
+
+   if (ft_outline->n_points)
+     {
+        ft_outline->contours[ft_outline->n_contours] = ft_outline->n_points - 1;
+        ft_outline->n_contours++;
+     }
+}
+
+
+static void  _outline_line_to(Outline *outline, double x, double y)
+{
+   SW_FT_Outline *ft_outline = &outline->ft_outline;
+
+   _grow_outline_points(outline, 1);
+   ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
+   ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
+   ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
+   ft_outline->n_points++;
+}
+
+
+static Eina_Bool
+_outline_close_path(Outline *outline)
+{
+   SW_FT_Outline *ft_outline = &outline->ft_outline;
+   int index ;
+
+   if (ft_outline->n_contours)
+     {
+        index = ft_outline->contours[ft_outline->n_contours - 1] + 1;
+     }
+   else
+     {
+        // First path
+        index = 0;
+     }
+
+   // Make sure there is at least one point in the current path
+   if (ft_outline->n_points == index) return EINA_FALSE;
+
+   // Close the path
+   _grow_outline_points(outline, 1);
+   ft_outline->points[ft_outline->n_points].x = ft_outline->points[index].x;
+   ft_outline->points[ft_outline->n_points].y = ft_outline->points[index].y;
+   ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
+   ft_outline->n_points++;
+
+   return EINA_TRUE;
+}
+
+
+static void _outline_cubic_to(Outline *outline, double cx1, double cy1,
+                              double cx2, double cy2, double x, double y)
+{
+   SW_FT_Outline *ft_outline = &outline->ft_outline;
+
+   _grow_outline_points(outline, 3);
+
+   ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(cx1);
+   ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(cy1);
+   ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC;
+   ft_outline->n_points++;
+
+   ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(cx2);
+   ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(cy2);
+   ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_CUBIC;
+   ft_outline->n_points++;
+
+   ft_outline->points[ft_outline->n_points].x = TO_FT_COORD(x);
+   ft_outline->points[ft_outline->n_points].y = TO_FT_COORD(y);
+   ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
+   ft_outline->n_points++;
+}
+
+static void _outline_transform(Outline *outline, Eina_Matrix3 *m)
+{
+   int i;
+   double x, y;
+   SW_FT_Outline *ft_outline = &outline->ft_outline;
+
+   if (m && (eina_matrix3_type_get(m) != EINA_MATRIX_TYPE_IDENTITY))
+     {
+        for (i = 0; i < ft_outline->n_points; i++)
+          {
+             eina_matrix3_point_transform(m,
+                                          ft_outline->points[i].x/64.0,/* convert back to normal coord.*/
+                                          ft_outline->points[i].y/64.0,/* convert back to normal coord.*/
+                                          &x, &y);
+
+             ft_outline->points[i].x = TO_FT_COORD(x);
+             ft_outline->points[i].y = TO_FT_COORD(y);
+          }
+     }
+}
+
+static Eina_Bool
+_generate_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline)
+{
+   Eina_Bool close_path = EINA_FALSE;
+   for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
+     {
+        switch (*cmds)
+          {
+            case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
+
+               _outline_move_to(outline, pts[0], pts[1]);
+
+               pts += 2;
+               break;
+            case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
+
+               _outline_line_to(outline, pts[0], pts[1]);
+
+               pts += 2;
+               break;
+            case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
+
+               _outline_cubic_to(outline,
+                                 pts[0], pts[1], pts[2], pts[3], // control points
+                                 pts[4], pts[5]); // destination point
+               pts += 6;
+               break;
+
+            case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
+
+               close_path = _outline_close_path(outline);
+               break;
+
+            case EFL_GFX_PATH_COMMAND_TYPE_LAST:
+            case EFL_GFX_PATH_COMMAND_TYPE_END:
+               break;
+          }
+     }
+   _outline_end(outline);
+   return close_path;
+}
+
+typedef struct _Line
+{
+   double x1;
+   double y1;
+   double x2;
+   double y2;
+}Line;
+
+static void
+_line_value_set(Line *l, double x1, double y1, double x2, double y2)
+{
+   l->x1 = x1;
+   l->y1 = y1;
+   l->x2 = x2;
+   l->y2 = y2;
+}
+
+// approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
+// With alpha = 1, beta = 3/8, giving results with the largest error less
+// than 7% compared to the exact value.
+static double
+_line_length(Line *l)
+{
+   double x = l->x2 - l->x1;
+   double y = l->y2 - l->y1;
+   x = x < 0 ? -x : x;
+   y = y < 0 ? -y : y;
+   return (x > y ? x + 0.375 * y : y + 0.375 * x);
+}
+
+static void
+_line_split_at_length(Line *l, double length, Line *left, Line *right)
+{
+   double len = _line_length(l);
+   double dx = ((l->x2 - l->x1)/len) *length;
+   double dy = ((l->y2 - l->y1)/len) *length;
+
+   left->x1 = l->x1;
+   left->y1 = l->y1;
+   left->x2 = left->x1 + dx;
+   left->y2 = left->y1 + dy;
+
+   right->x1 = left->x2;
+   right->y1 = left->y2;
+   right->x2 = l->x2;
+   right->y2 = l->y2;
+}
+
+typedef struct _Dash_Stroker
+{
+   Efl_Gfx_Dash *dash;
+   int           dash_len;
+   Outline      *outline;
+   int cur_dash_index;
+   double cur_dash_length;
+   Eina_Bool cur_op_gap;
+   double start_x, start_y;
+   double cur_x, cur_y;
+}Dash_Stroker;
+
+static void
+_dasher_line_to(Dash_Stroker *dasher, double x, double y)
+{
+   Line l, left, right;
+   double line_len = 0.0;
+   _line_value_set(&l, dasher->cur_x, dasher->cur_y, x, y);
+   line_len = _line_length(&l);
+   if (line_len < dasher->cur_dash_length)
+     {
+        dasher->cur_dash_length -= line_len;
+        if (!dasher->cur_op_gap)
+          {
+             _outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
+             _outline_line_to(dasher->outline, x, y);
+          }
+     }
+   else
+     {
+        while (line_len > dasher->cur_dash_length)
+          {
+             line_len -= dasher->cur_dash_length;
+             _line_split_at_length(&l, dasher->cur_dash_length, &left, &right);
+             if (!dasher->cur_op_gap)
+               {
+                  _outline_move_to(dasher->outline, left.x1, left.y1);
+                  _outline_line_to(dasher->outline, left.x2, left.y2);
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
+               }
+             else
+               {
+                  dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
+               }
+             dasher->cur_op_gap = !dasher->cur_op_gap;
+             l = right;
+             dasher->cur_x = l.x1;
+             dasher->cur_y = l.y1;
+          }
+        // remainder
+        dasher->cur_dash_length -= line_len;
+        if (!dasher->cur_op_gap)
+          {
+             _outline_move_to(dasher->outline, l.x1, l.y1);
+             _outline_line_to(dasher->outline, l.x2, l.y2);
+          }
+        if (dasher->cur_dash_length < 1.0)
+          {
+             // move to next dash
+             if (!dasher->cur_op_gap)
+               {
+                  dasher->cur_op_gap = EINA_TRUE;
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
+               }
+             else
+               {
+                  dasher->cur_op_gap = EINA_FALSE;
+                  dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
+               }
+          }
+     }
+   dasher->cur_x = x;
+   dasher->cur_y = y;
+}
+
+static void
+_dasher_cubic_to(Dash_Stroker *dasher, double cx1 , double cy1, double cx2, double cy2, double x, double y)
+{
+   Eina_Bezier b, left, right;
+   double bez_len = 0.0;
+   eina_bezier_values_set(&b, dasher->cur_x, dasher->cur_y, cx1, cy1, cx2, cy2, x, y);
+   bez_len = eina_bezier_length_get(&b);
+   if (bez_len < dasher->cur_dash_length)
+     {
+        dasher->cur_dash_length -= bez_len;
+        if (!dasher->cur_op_gap)
+          {
+             _outline_move_to(dasher->outline, dasher->cur_x, dasher->cur_y);
+             _outline_cubic_to(dasher->outline, cx1, cy1, cx2, cy2, x, y);
+          }
+     }
+   else
+     {
+        while (bez_len > dasher->cur_dash_length)
+          {
+             bez_len -= dasher->cur_dash_length;
+             eina_bezier_split_at_length(&b, dasher->cur_dash_length, &left, &right);
+             if (!dasher->cur_op_gap)
+               {
+                  _outline_move_to(dasher->outline, left.start.x, left.start.y);
+                  _outline_cubic_to(dasher->outline, left.ctrl_start.x, left.ctrl_start.y, left.ctrl_end.x, left.ctrl_end.y, left.end.x, left.end.y);
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
+               }
+             else
+               {
+                  dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
+               }
+             dasher->cur_op_gap = !dasher->cur_op_gap;
+             b = right;
+             dasher->cur_x = b.start.x;
+             dasher->cur_y = b.start.y;
+          }
+         // remainder
+        dasher->cur_dash_length -= bez_len;
+        if (!dasher->cur_op_gap)
+          {
+             _outline_move_to(dasher->outline, b.start.x, b.start.y);
+             _outline_cubic_to(dasher->outline, b.ctrl_start.x, b.ctrl_start.y, b.ctrl_end.x, b.ctrl_end.y, b.end.x, b.end.y);
+          }
+        if (dasher->cur_dash_length < 1.0)
+          {
+             // move to next dash
+             if (!dasher->cur_op_gap)
+               {
+                  dasher->cur_op_gap = EINA_TRUE;
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].gap;
+               }
+             else
+               {
+                  dasher->cur_op_gap = EINA_FALSE;
+                  dasher->cur_dash_index = (dasher->cur_dash_index +1) % dasher->dash_len ;
+                  dasher->cur_dash_length = dasher->dash[dasher->cur_dash_index].length;
+               }
+          }
+      }
+   dasher->cur_x = x;
+   dasher->cur_y = y;
+}
+
+static Eina_Bool
+_generate_dashed_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline, Efl_Gfx_Dash *dash, int dash_len)
+{
+   Dash_Stroker dasher;
+   dasher.dash = dash;
+   dasher.dash_len = dash_len;
+   dasher.outline = outline;
+   dasher.cur_dash_length = 0.0;
+   dasher.cur_dash_index = 0;
+   dasher.cur_op_gap = EINA_FALSE;
+   dasher.start_x = 0.0;
+   dasher.start_y = 0.0;
+   dasher.cur_x = 0.0;
+   dasher.cur_y = 0.0;
+
+   for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
+     {
+        switch (*cmds)
+          {
+            case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
+              {
+                 // reset the dash
+                 dasher.cur_dash_index = 0;
+                 dasher.cur_dash_length = dasher.dash[0].length;
+                 dasher.cur_op_gap = EINA_FALSE;
+                 dasher.start_x = pts[0];
+                 dasher.start_y = pts[1];
+                 dasher.cur_x = pts[0];
+                 dasher.cur_y = pts[1];
+                 pts += 2;
+              }
+               break;
+            case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
+               _dasher_line_to(&dasher, pts[0], pts[1]);
+               pts += 2;
+               break;
+            case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
+               _dasher_cubic_to(&dasher, pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
+               pts += 6;
+               break;
+
+            case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
+               _dasher_line_to(&dasher, dasher.start_x, dasher.start_y);
+               break;
+
+            case EFL_GFX_PATH_COMMAND_TYPE_LAST:
+            case EFL_GFX_PATH_COMMAND_TYPE_END:
+               break;
+          }
+     }
+   _outline_end(outline);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_generate_stroke_data(Ector_Renderer_Software_Shape_Data *pd)
+{
+   if (pd->outline_data) return EINA_FALSE;
+
+   if (!pd->shape->stroke.fill &&
+       ((pd->public_shape->stroke.color.a == 0) ||
+        (pd->public_shape->stroke.width < 0.01)))
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_generate_shape_data(Ector_Renderer_Software_Shape_Data *pd)
+{
+   if (pd->shape_data) return EINA_FALSE;
+
+   if (!pd->shape->fill && (pd->base->color.a == 0)) return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Ector_Software_Shape_Task *
+_need_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+{
+   if (pd->task) return pd->task;
+
+   if (!pd->base->visibility || (!_generate_stroke_data(pd) &&
+       !_generate_shape_data(pd)))
+     return NULL;
+
+   const Efl_Gfx_Path_Command *cmds;
+   const double *pts;
+   efl_gfx_path_get(obj, &cmds, &pts);
+   if (!cmds) return NULL;
+
+   Ector_Software_Shape_Task *task = malloc(sizeof(Ector_Software_Shape_Task));
+   if (!task) return NULL;
+
+   task->pd = pd;
+   task->cmds = cmds;
+   task->pts = pts;
+   task->fill_rule = efl_gfx_shape_fill_rule_get(obj);
+
+   pd->task = task;
+
+   return task;
+}
+
+static void
+_done_rle(void *data)
+{
+   Ector_Software_Shape_Task *task = data;
+   if (!task) return;
+   if (task->pd) task->pd->task = NULL;
+   free(task);
+}
+
+static void
+_update_rle(void *data, Ector_Software_Thread *thread)
+{
+   Ector_Software_Shape_Task *task = data;
+   Eina_Bool close_path;
+   Outline *outline, *dash_outline;
+
+   outline = _outline_create();
+   close_path = _generate_outline(task->cmds, task->pts, outline);
+   if (task->fill_rule == EFL_GFX_FILL_RULE_ODD_EVEN)
+     outline->ft_outline.flags = SW_FT_OUTLINE_EVEN_ODD_FILL;
+   else
+     outline->ft_outline.flags = SW_FT_OUTLINE_NONE; // default is winding fill
+
+   _outline_transform(outline, task->pd->base->m);
+
+   //shape data generation
+   if (_generate_shape_data(task->pd))
+     task->pd->shape_data = ector_software_rasterizer_generate_rle_data(thread,
+                                                                        task->pd->surface->rasterizer,
+                                                                        &outline->ft_outline);
+
+   //stroke data generation
+   if (_generate_stroke_data(task->pd))
+     {
+        ector_software_rasterizer_stroke_set(thread, task->pd->surface->rasterizer,
+                                             (task->pd->public_shape->stroke.width *
+                                              task->pd->public_shape->stroke.scale),
+                                             task->pd->public_shape->stroke.cap,
+                                             task->pd->public_shape->stroke.join,
+                                             task->pd->base->m,
+                                             task->pd->public_shape->stroke.miterlimit);
+
+        if (task->pd->public_shape->stroke.dash)
+          {
+             dash_outline = _outline_create();
+             close_path = _generate_dashed_outline(task->cmds, task->pts, dash_outline,
+                                                   task->pd->public_shape->stroke.dash,
+                                                   task->pd->public_shape->stroke.dash_length);
+             _outline_transform(dash_outline, task->pd->base->m);
+             task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
+                                                                                         task->pd->surface->rasterizer,
+                                                                                         &dash_outline->ft_outline,
+                                                                                         close_path);
+             _outline_destroy(dash_outline);
+          }
+        else
+          {
+             task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
+                                                                                         task->pd->surface->rasterizer,
+                                                                                         &outline->ft_outline,
+                                                                                         close_path);
+          }
+     }
+   _outline_destroy(outline);
+}
+
+static Eina_Bool
+_ector_renderer_software_shape_ector_renderer_prepare(Eo *obj,
+                                                      Ector_Renderer_Software_Shape_Data *pd)
+{
+   // FIXME: shouldn't this be moved to the software base object?
+   if (!pd->surface)
+     pd->surface = efl_data_xref(pd->base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
+
+   // Asynchronously lazy build of the RLE data for this shape
+   if (!pd->task)
+     {
+        Ector_Software_Shape_Task *task = _need_update_rle(obj, pd);
+        if (task) ector_software_schedule(_update_rle, _done_rle, task);
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_ector_renderer_software_shape_ector_renderer_draw(Eo *obj EINA_UNUSED,
+                                                   Ector_Renderer_Software_Shape_Data *pd,
+                                                   Efl_Gfx_Render_Op op, Eina_Array *clips,
+                                                   unsigned int mul_col)
+{
+   int x, y;
+
+   // check if RLE data are ready
+   Ector_Software_Shape_Task *task = pd->task;
+   if (task) ector_software_wait(_update_rle, _done_rle, task);
+
+   // adjust the offset
+   x = (int)pd->base->origin.x - pd->surface->x;
+   y = (int)pd->base->origin.y - pd->surface->y;
+
+   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->comp,
+                                                pd->comp_method);
+     }
+   else
+     {
+        if (pd->base->color.a > 0)
+          {
+             ector_software_rasterizer_color_set(pd->surface->rasterizer,
+                                                 pd->base->color.r,
+                                                 pd->base->color.g,
+                                                 pd->base->color.b,
+                                                 pd->base->color.a);
+             ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
+                                                     x, y, mul_col, op,
+                                                     pd->shape_data,
+                                                     pd->comp,
+                                                     pd->comp_method);
+          }
+     }
+
+   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->comp,
+                                                pd->comp_method);
+     }
+   else
+     {
+        if (pd->public_shape->stroke.color.a > 0)
+          {
+             ector_software_rasterizer_color_set(pd->surface->rasterizer,
+                                                 pd->public_shape->stroke.color.r,
+                                                 pd->public_shape->stroke.color.g,
+                                                 pd->public_shape->stroke.color.b,
+                                                 pd->public_shape->stroke.color.a);
+             ector_software_rasterizer_draw_rle_data(pd->surface->rasterizer,
+                                                     x, y, mul_col, op,
+                                                     pd->outline_data,
+                                                     pd->comp,
+                                                     pd->comp_method);
+          }
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_ector_renderer_software_shape_ector_renderer_software_op_fill(Eo *obj EINA_UNUSED,
+                                                                 Ector_Renderer_Software_Shape_Data *pd EINA_UNUSED)
+{
+   // FIXME: let's find out how to fill a shape with a shape later.
+   // I need to read SVG specification and see how to map that with software.
+   return EINA_FALSE;
+}
+
+EOLIAN static void
+_ector_renderer_software_shape_efl_gfx_path_commit(Eo *obj EINA_UNUSED,
+                                                   Ector_Renderer_Software_Shape_Data *pd)
+{
+   if (pd->shape_data)
+     {
+        ector_software_rasterizer_destroy_rle_data(pd->shape_data);
+        pd->shape_data = NULL;
+     }
+   if (pd->outline_data)
+     {
+        ector_software_rasterizer_destroy_rle_data(pd->outline_data);
+        pd->outline_data = NULL;
+     }
+}
+
+static Eo *
+_ector_renderer_software_shape_efl_object_constructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   if (!obj) return NULL;
+
+   pd->public_shape = efl_data_xref(obj, EFL_GFX_SHAPE_MIXIN, obj);
+   pd->shape = efl_data_xref(obj, ECTOR_RENDERER_SHAPE_MIXIN, obj);
+   pd->base = efl_data_xref(obj, ECTOR_RENDERER_CLASS, obj);
+
+   return obj;
+}
+
+static void
+_ector_renderer_software_shape_efl_object_destructor(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+{
+   // FIXME: As base class, destructor can't call destructor of mixin class.
+   // Call explicit API to free shape data.
+   if (pd->task)
+     ector_software_wait(_update_rle, _done_rle, pd->task);
+
+   efl_gfx_path_reset(obj);
+
+   if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data);
+   if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data);
+
+   efl_data_xunref(pd->base->surface, pd->surface, obj);
+   efl_data_xunref(obj, pd->base, obj);
+   efl_data_xunref(obj, pd->shape, obj);
+   efl_data_xunref(obj, pd->public_shape, obj);
+
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+unsigned int
+_ector_renderer_software_shape_ector_renderer_crc_get(const Eo *obj,
+                                                      Ector_Renderer_Software_Shape_Data *pd)
+{
+   unsigned int crc;
+
+   crc = ector_renderer_crc_get(efl_super(obj, MY_CLASS));
+
+   crc = eina_crc((void*) &pd->shape->stroke.marker,
+                  sizeof (pd->shape->stroke.marker),
+                  crc, EINA_FALSE);
+   crc = eina_crc((void*) &pd->public_shape->stroke.scale,
+                  sizeof (pd->public_shape->stroke.scale) * 3,
+                  crc, EINA_FALSE); // scale, width, centered
+   crc = eina_crc((void*) &pd->public_shape->stroke.color,
+                  sizeof (pd->public_shape->stroke.color),
+                  crc, EINA_FALSE);
+   crc = eina_crc((void*) &pd->public_shape->stroke.cap,
+                  sizeof (pd->public_shape->stroke.cap),
+                  crc, EINA_FALSE);
+   crc = eina_crc((void*) &pd->public_shape->stroke.join,
+                  sizeof (pd->public_shape->stroke.join),
+                  crc, EINA_FALSE);
+
+   if (pd->shape->fill)
+     crc = _renderer_crc_get(pd->shape->fill, crc);
+   if (pd->shape->stroke.fill)
+     crc = _renderer_crc_get(pd->shape->stroke.fill, crc);
+   if (pd->shape->stroke.marker)
+     crc = _renderer_crc_get(pd->shape->stroke.marker, crc);
+   if (pd->public_shape->stroke.dash_length)
+     {
+        crc = eina_crc((void*) pd->public_shape->stroke.dash,
+                       sizeof (Efl_Gfx_Dash) * pd->public_shape->stroke.dash_length,
+                       crc, EINA_FALSE);
+     }
+
+   return crc;
+}
+
+static void
+_ector_renderer_software_shape_ector_renderer_comp_method_set(Eo *obj EINA_UNUSED,
+                                                              Ector_Renderer_Software_Shape_Data *pd,
+                                                              Ector_Buffer *comp,
+                                                              Efl_Gfx_Vg_Composite_Method method)
+{
+   //Use ref/unref.
+   pd->comp = comp;
+   pd->comp_method = method;
+}
+
+#include "ector_renderer_software_shape.eo.c"
diff --git a/src/lib/ector/software/ector_renderer_software_shape.eo b/src/lib/ector/software/ector_renderer_software_shape.eo
new file mode 100644 (file)
index 0000000..83b87c0
--- /dev/null
@@ -0,0 +1,15 @@
+class @beta Ector.Renderer.Software.Shape extends Ector.Renderer.Software implements Ector.Renderer.Shape
+{
+   [[Ector software renderer shape class]]
+   c_prefix: ector_renderer_software_shape;
+   implements {
+      Ector.Renderer.prepare;
+      Ector.Renderer.draw;
+      Ector.Renderer.Software.op_fill;
+      Ector.Renderer.comp_method { set; }
+      Ector.Renderer.crc { get; }
+      Efl.Gfx.Path.commit;
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+   }
+}
diff --git a/src/lib/ector/software/ector_software_gradient.c b/src/lib/ector/software/ector_software_gradient.c
new file mode 100644 (file)
index 0000000..be20635
--- /dev/null
@@ -0,0 +1,214 @@
+#include "ector_software_gradient.h"
+
+#ifdef BUILD_SSE3
+void _radial_helper_sse3(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data, float det, float delta_det, float delta_delta_det, float b, float delta_b);
+void _linear_helper_sse3(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data, int t, int inc);
+#endif
+
+#define GRADIENT_STOPTABLE_SIZE 1024
+#define FIXPT_BITS 8
+#define FIXPT_SIZE (1<<FIXPT_BITS)
+
+typedef void (*Ector_Radial_Helper_Func)(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data,
+                                          float det, float delta_det, float delta_delta_det, float b, float delta_b);
+typedef void (*Ector_Linear_Helper_Func)(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data,
+                                          int t_fixed, int inc_fixed);
+
+static Ector_Radial_Helper_Func _ector_radial_helper;
+static Ector_Linear_Helper_Func _ector_linear_helper;
+
+static void
+_update_color_table(void *data, Ector_Software_Thread *t EINA_UNUSED)
+{
+   Ector_Renderer_Software_Gradient_Data *gdata = data;
+   gdata->alpha = efl_draw_generate_gradient_color_table(gdata->gd->colors, gdata->gd->colors_count,
+                                                         gdata->color_table, GRADIENT_STOPTABLE_SIZE);
+}
+
+static void
+_done_color_table(void *data)
+{
+   Ector_Renderer_Software_Gradient_Data *gdata = data;
+   gdata->ctable_status = CTABLE_READY_DONE;
+}
+
+void
+ector_software_gradient_color_update(Ector_Renderer_Software_Gradient_Data *gdata)
+{
+   if (gdata->ctable_status == CTABLE_READY_DONE) return;
+
+   //OPTIMIZE: This color can be updated only when gradient properties are changed.
+
+   //Alloc only one time.
+   if (!gdata->color_table)
+     gdata->color_table = malloc(GRADIENT_STOPTABLE_SIZE * 4);
+
+   if (gdata->ctable_status == CTABLE_NOT_READY)
+     {
+        gdata->ctable_status = CTABLE_PROCESSING;
+        ector_software_schedule(_update_color_table, _done_color_table, gdata);
+     }
+   else if (gdata->ctable_status == CTABLE_PROCESSING)
+        ector_software_wait(_update_color_table, _done_color_table, gdata);
+}
+
+void
+destroy_color_table(Ector_Renderer_Software_Gradient_Data *gdata)
+{
+   if (gdata->color_table)
+     {
+        free(gdata->color_table);
+        gdata->color_table = NULL;
+     }
+}
+
+static void
+_linear_helper_generic(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data,
+                       int t_fixed, int inc_fixed)
+{
+   int i;
+
+   for (i = 0 ; i < length ; i++)
+     {
+        *buffer++ = _gradient_pixel_fixed(g_data, t_fixed);
+        t_fixed += inc_fixed;
+     }
+}
+
+void
+fetch_linear_gradient(uint32_t *buffer, Span_Data *data, int y, int x, int length)
+{
+   Ector_Renderer_Software_Gradient_Data *g_data = data->gradient;
+   float t, inc, rx=0, ry=0;
+   uint32_t *end;
+   int t_fixed, inc_fixed;
+
+   if (EINA_DBL_EQ(g_data->linear.l, 0.0))
+     {
+        t = inc = 0;
+     }
+   else
+     {
+        rx = data->inv.xy * (y + (float)0.5) + data->inv.xz + data->inv.xx * (x + (float)0.5);
+        ry = data->inv.yy * (y + (float)0.5) + data->inv.yz + data->inv.yx * (x + (float)0.5);
+        t = g_data->linear.dx*rx + g_data->linear.dy*ry + g_data->linear.off;
+        inc = g_data->linear.dx * data->inv.xx + g_data->linear.dx * data->inv.yx;
+
+        t *= (GRADIENT_STOPTABLE_SIZE - 1);
+        inc *= (GRADIENT_STOPTABLE_SIZE - 1);
+     }
+
+    end = buffer + length;
+    if (inc > (float)(-1e-5) && inc < (float)(1e-5))
+      {
+         draw_memset32(buffer, _gradient_pixel_fixed(g_data, (int)(t * FIXPT_SIZE)), length);
+      }
+    else
+      {
+         const int vmax = INT_MAX >> (FIXPT_BITS + 1);
+         const int vmin = -vmax;
+         float v = t + (inc *length);
+
+         if ((v < (float)vmax) && (v > (float)(vmin)))
+           {
+              // we can use fixed point math
+              t_fixed = (int)(t * FIXPT_SIZE);
+              inc_fixed = (int)(inc * FIXPT_SIZE);
+              _ector_linear_helper(buffer, length, g_data, t_fixed, inc_fixed);
+           }
+         else
+           {
+              // we have to fall back to float math
+              while (buffer < end)
+                {
+                   *buffer++ = _gradient_pixel(g_data, t/GRADIENT_STOPTABLE_SIZE);
+                   t += inc;
+                }
+           }
+      }
+}
+
+static void
+_radial_helper_generic(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data, float det,
+                       float delta_det, float delta_delta_det, float b, float delta_b)
+{
+   int i;
+
+   for (i = 0 ; i < length ; i++)
+     {
+        *buffer++ = _gradient_pixel(g_data, sqrt(det) - b);
+        det += delta_det;
+        delta_det += delta_delta_det;
+        b += delta_b;
+     }
+}
+
+
+void
+fetch_radial_gradient(uint32_t *buffer, Span_Data *data, int y, int x, int length)
+{
+   Ector_Renderer_Software_Gradient_Data *g_data = data->gradient;
+   float rx, ry, inv_a, delta_rx, delta_ry, b, delta_b, b_delta_b, delta_b_delta_b,
+         bb, delta_bb, rxrxryry, delta_rxrxryry, rx_plus_ry, delta_rx_plus_ry, det,
+         delta_det, delta_delta_det;
+
+   // avoid division by zero
+   if (fabsf(g_data->radial.a) <= 0.00001f)
+     {
+        draw_memset32(buffer, 0, length);
+        return;
+     }
+
+   rx = data->inv.xy * (y + (float)0.5) + data->inv.xz + data->inv.xx * (x + (float)0.5);
+   ry = data->inv.yy * (y + (float)0.5) + data->inv.yz + data->inv.yx * (x + (float)0.5);
+
+   rx -= g_data->radial.fx;
+   ry -= g_data->radial.fy;
+
+   inv_a = 1 / (float)(2 * g_data->radial.a);
+
+   delta_rx = data->inv.xx;
+   delta_ry = data->inv.yx;
+
+   b = 2*(g_data->radial.dr*g_data->radial.fradius + rx * g_data->radial.dx + ry * g_data->radial.dy);
+   delta_b = 2*(delta_rx * g_data->radial.dx + delta_ry * g_data->radial.dy);
+   b_delta_b = 2 * b * delta_b;
+   delta_b_delta_b = 2 * delta_b * delta_b;
+
+   bb = b * b;
+   delta_bb = delta_b * delta_b;
+   b *= inv_a;
+   delta_b *= inv_a;
+
+   rxrxryry = rx * rx + ry * ry;
+   delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
+   rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
+   delta_rx_plus_ry = 2 * delta_rxrxryry;
+
+   inv_a *= inv_a;
+
+   det = (bb - 4 * g_data->radial.a * (g_data->radial.sqrfr - rxrxryry)) * inv_a;
+   delta_det = (b_delta_b + delta_bb + 4 * g_data->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
+   delta_delta_det = (delta_b_delta_b + 4 * g_data->radial.a * delta_rx_plus_ry) * inv_a;
+
+   _ector_radial_helper(buffer, length, g_data, det, delta_det, delta_delta_det, b, delta_b);
+}
+
+int
+ector_software_gradient_init(void)
+{
+   static int i = 0;
+   if (!(i++))
+     {
+        _ector_radial_helper = _radial_helper_generic;
+        _ector_linear_helper = _linear_helper_generic;
+#ifdef BUILD_SSE3
+        if (eina_cpu_features_get() & EINA_CPU_SSE3)
+          {
+             _ector_radial_helper = _radial_helper_sse3;
+             _ector_linear_helper = _linear_helper_sse3;
+          }
+#endif
+     }
+   return i;
+}
diff --git a/src/lib/ector/software/ector_software_gradient.h b/src/lib/ector/software/ector_software_gradient.h
new file mode 100644 (file)
index 0000000..38731de
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef ECTOR_SOFTWARE_GRADIENT_H
+# define ECTOR_SOFTWARE_GRADIENT_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <math.h>
+
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+#include "draw.h"
+
+#define GRADIENT_STOPTABLE_SIZE 1024
+#define FIXPT_BITS 8
+#define FIXPT_SIZE (1<<FIXPT_BITS)
+
+#define CTABLE_NOT_READY 0
+#define CTABLE_PROCESSING 1
+#define CTABLE_READY_DONE 2
+
+static inline int
+_gradient_clamp(const Ector_Renderer_Software_Gradient_Data *data, int ipos)
+{
+   int limit;
+
+   if (data->gd->s == EFL_GFX_GRADIENT_SPREAD_REPEAT)
+     {
+        ipos = ipos % GRADIENT_STOPTABLE_SIZE;
+        ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
+     }
+   else if (data->gd->s == EFL_GFX_GRADIENT_SPREAD_REFLECT)
+     {
+        limit = GRADIENT_STOPTABLE_SIZE * 2;
+        ipos = ipos % limit;
+        ipos = ipos < 0 ? limit + ipos : ipos;
+        ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos;
+     }
+   else
+     {
+        if (ipos < 0) ipos = 0;
+        else if (ipos >= GRADIENT_STOPTABLE_SIZE)
+          ipos = GRADIENT_STOPTABLE_SIZE-1;
+     }
+   return ipos;
+}
+
+static inline uint32_t
+_gradient_pixel_fixed(const Ector_Renderer_Software_Gradient_Data *data, int fixed_pos)
+{
+   int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
+
+   return data->color_table[_gradient_clamp(data, ipos)];
+}
+
+static inline uint32_t
+_gradient_pixel(const Ector_Renderer_Software_Gradient_Data *data, float pos)
+{
+   int ipos = (int)(pos * (GRADIENT_STOPTABLE_SIZE - 1) + (float)(0.5));
+
+   return data->color_table[_gradient_clamp(data, ipos)];
+}
+
+#endif
diff --git a/src/lib/ector/software/ector_software_gradient_sse3.c b/src/lib/ector/software/ector_software_gradient_sse3.c
new file mode 100644 (file)
index 0000000..883bdbf
--- /dev/null
@@ -0,0 +1,214 @@
+#include "ector_software_gradient.h"
+
+#ifdef BUILD_SSE3
+#include <immintrin.h>
+
+#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
+typedef union { __m128i v; int i[4];}  vec4_i;
+typedef union { __m128 v; float f[4];} vec4_f;
+
+#define FETCH_CLAMP_INIT_F \
+  __m128 v_min = _mm_set1_ps(0.0f); \
+  __m128 v_max = _mm_set1_ps((float)(GRADIENT_STOPTABLE_SIZE-1)); \
+  __m128 v_halff = _mm_set1_ps(0.5f); \
+  __m128i v_repeat_mask = _mm_set1_epi32(~((uint32_t)(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT)); \
+  __m128i v_reflect_mask = _mm_set1_epi32(~((uint32_t)(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1))); \
+  __m128i v_reflect_limit = _mm_set1_epi32(2 * GRADIENT_STOPTABLE_SIZE - 1);
+
+#define FETCH_CLAMP_REPEAT_F \
+  vec4_i index_vec; \
+  index_vec.v = _mm_and_si128(v_repeat_mask, _mm_cvttps_epi32(v_index));
+
+#define FETCH_CLAMP_REFLECT_F \
+  vec4_i index_vec; \
+  __m128i v_index_i = _mm_and_si128(v_reflect_mask, _mm_cvttps_epi32(v_index)); \
+  __m128i v_index_i_inv = _mm_sub_epi32(v_reflect_limit, v_index_i); \
+  index_vec.v = _mm_min_epi16(v_index_i, v_index_i_inv);
+
+#define FETCH_CLAMP_PAD_F \
+  vec4_i index_vec; \
+  index_vec.v = _mm_cvttps_epi32(_mm_min_ps(v_max, _mm_max_ps(v_min, v_index)));
+
+#define FETCH_EPILOGUE_CPY \
+  *buffer++ = g_data->color_table[index_vec.i[0]]; \
+  *buffer++ = g_data->color_table[index_vec.i[1]]; \
+  *buffer++ = g_data->color_table[index_vec.i[2]]; \
+  *buffer++ = g_data->color_table[index_vec.i[3]]; \
+}
+
+static void
+loop_break(unsigned int *buffer, int length, int *lprealign, int *lby4 , int *lremaining)
+{
+   int l1=0, l2=0, l3=0;
+
+   while ((uintptr_t)buffer & 0xF)
+     buffer++ , l1++;
+
+   if(length <= l1)
+     {
+        l1 = length;
+     }
+   else
+     {
+        l3 = (length - l1) % 4;
+        l2 = length - l1 - l3 ;
+     }
+
+   *lprealign = l1;
+   *lby4 = l2;
+   *lremaining = l3;
+}
+
+void
+_radial_helper_sse3(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data,
+                    float det, float delta_det, float delta_delta_det, float b, float delta_b)
+{
+   int lprealign, lby4, lremaining, i;
+   vec4_f det_vec;
+   vec4_f delta_det4_vec;
+   vec4_f b_vec;
+   __m128 v_delta_delta_det16;
+   __m128 v_delta_delta_det6;
+   __m128 v_delta_b4;
+
+   loop_break(buffer, length, &lprealign, &lby4, &lremaining);
+
+   // prealign loop
+   for (i = 0 ; i < lprealign ; i++)
+     {
+        *buffer++ = _gradient_pixel(g_data, sqrt(det) - b);
+        det += delta_det;
+        delta_det += delta_delta_det;
+        b += delta_b;
+     }
+
+   // lby4 16byte align loop
+   for (i = 0; i < 4; ++i)
+     {
+        det_vec.f[i] = det;
+        delta_det4_vec.f[i] = 4 * delta_det;
+        b_vec.f[i] = b;
+
+        det += delta_det;
+        delta_det += delta_delta_det;
+        b += delta_b;
+     }
+
+   v_delta_delta_det16 = _mm_set1_ps(16 * delta_delta_det);
+   v_delta_delta_det6 = _mm_set1_ps(6 * delta_delta_det);
+   v_delta_b4 = _mm_set1_ps(4 * delta_b);
+
+#define FETCH_RADIAL_PROLOGUE                                           \
+   for (i = 0 ; i < lby4 ; i+=4) {                                      \
+      __m128 v_index_local = _mm_sub_ps(_mm_sqrt_ps(det_vec.v), b_vec.v); \
+      __m128 v_index = _mm_add_ps(_mm_mul_ps(v_index_local, v_max), v_halff); \
+      det_vec.v = _mm_add_ps(_mm_add_ps(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \
+      delta_det4_vec.v = _mm_add_ps(delta_det4_vec.v, v_delta_delta_det16); \
+      b_vec.v = _mm_add_ps(b_vec.v, v_delta_b4);
+
+#define FETCH_RADIAL_LOOP(FETCH_CLAMP) \
+   FETCH_RADIAL_PROLOGUE;              \
+   FETCH_CLAMP;                        \
+   FETCH_EPILOGUE_CPY;
+
+   FETCH_CLAMP_INIT_F;
+   switch (g_data->gd->s)
+     {
+      case EFL_GFX_GRADIENT_SPREAD_REPEAT:
+         FETCH_RADIAL_LOOP(FETCH_CLAMP_REPEAT_F);
+         break;
+      case EFL_GFX_GRADIENT_SPREAD_REFLECT:
+         FETCH_RADIAL_LOOP( FETCH_CLAMP_REFLECT_F);
+         break;
+      default:
+         FETCH_RADIAL_LOOP(FETCH_CLAMP_PAD_F);
+         break;
+     }
+
+   // remaining loop
+   for (i = 0 ; i < lremaining ; i++)
+     *buffer++ = _gradient_pixel(g_data, sqrt(det_vec.f[i]) - b_vec.f[i]);
+}
+
+void
+_linear_helper_sse3(uint32_t *buffer, int length, Ector_Renderer_Software_Gradient_Data *g_data, int t, int inc)
+{
+   int lprealign, lby4, lremaining, i;
+   vec4_i t_vec;
+   __m128i v_inc;
+   __m128i v_fxtpt_size;
+   __m128i v_min;
+   __m128i v_max;
+   __m128i v_repeat_mask;
+   __m128i v_reflect_mask;
+   __m128i v_reflect_limit;
+
+   loop_break(buffer, length, &lprealign, &lby4, &lremaining);
+
+   // prealign loop
+   for (i = 0 ; i < lprealign ; i++)
+     {
+        *buffer++ = _gradient_pixel_fixed(g_data, t);
+        t += inc;
+     }
+
+   // lby4 16byte align loop
+   for (i = 0; i < 4; ++i)
+     {
+        t_vec.i[i] = t;
+        t += inc;
+     }
+
+   v_inc = _mm_set1_epi32(4 * inc);
+   v_fxtpt_size = _mm_set1_epi32(FIXPT_SIZE * 0.5);
+
+   v_min = _mm_set1_epi32(0);
+   v_max = _mm_set1_epi32((GRADIENT_STOPTABLE_SIZE - 1));
+
+   v_repeat_mask = _mm_set1_epi32(~((uint32_t)(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT));
+   v_reflect_mask = _mm_set1_epi32(~((uint32_t)(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT + 1)));
+
+   v_reflect_limit = _mm_set1_epi32(2 * GRADIENT_STOPTABLE_SIZE - 1);
+
+#define FETCH_LINEAR_LOOP_PROLOGUE                                      \
+   for (i = 0 ; i < lby4 ; i+=4) {                                      \
+      vec4_i index_vec;                                                 \
+      __m128i v_index;                                                  \
+      v_index =  _mm_srai_epi32(_mm_add_epi32(t_vec.v, v_fxtpt_size), FIXPT_BITS); \
+      t_vec.v = _mm_add_epi32(t_vec.v, v_inc);
+
+#define FETCH_LINEAR_LOOP_CLAMP_REPEAT                  \
+   index_vec.v = _mm_and_si128(v_repeat_mask, v_index);
+
+#define FETCH_LINEAR_LOOP_CLAMP_REFLECT                                 \
+   __m128i v_index_i = _mm_and_si128(v_reflect_mask, v_index);          \
+   __m128i v_index_i_inv = _mm_sub_epi32(v_reflect_limit, v_index_i);   \
+   index_vec.v = _mm_min_epi16(v_index_i, v_index_i_inv);
+
+#define FETCH_LINEAR_LOOP_CLAMP_PAD                                     \
+   index_vec.v = _mm_min_epi16(v_max, _mm_max_epi16(v_min, v_index));
+
+#define FETCH_LINEAR_LOOP(FETCH_LINEAR_LOOP_CLAMP)      \
+   FETCH_LINEAR_LOOP_PROLOGUE;                          \
+   FETCH_LINEAR_LOOP_CLAMP;                             \
+   FETCH_EPILOGUE_CPY;
+
+   switch (g_data->gd->s)
+     {
+      case EFL_GFX_GRADIENT_SPREAD_REPEAT:
+         FETCH_LINEAR_LOOP(FETCH_LINEAR_LOOP_CLAMP_REPEAT);
+         break;
+      case EFL_GFX_GRADIENT_SPREAD_REFLECT:
+         FETCH_LINEAR_LOOP(FETCH_LINEAR_LOOP_CLAMP_REFLECT);
+         break;
+      default:
+         FETCH_LINEAR_LOOP(FETCH_LINEAR_LOOP_CLAMP_PAD);
+         break;
+     }
+
+   // remaining loop
+   for (i = 0 ; i < lremaining ; i++)
+     *buffer++ = _gradient_pixel_fixed(g_data, t_vec.i[i]);
+}
+
+#endif
diff --git a/src/lib/ector/software/ector_software_rasterizer.c b/src/lib/ector/software/ector_software_rasterizer.c
new file mode 100644 (file)
index 0000000..bbaba48
--- /dev/null
@@ -0,0 +1,946 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Eina.h>
+#include <Ector.h>
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+
+#include "draw.h"
+
+static void
+_blend_argb(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   uint32_t color, *buffer, *target;
+   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
+_comp_matte_alpha(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 *comp = sd->comp;
+   if (!comp || !comp->pixels.u32) return;
+   const int comp_stride = comp->stride / 4;
+
+   // 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 = comp->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 + ((comp_stride * spans->y) + spans->x);
+        uint32_t *temp = tbuffer;
+        memset(temp, 0x00, sizeof(uint32_t) * spans->len);
+        comp_func(temp, spans->len, color, spans->coverage);
+
+        //composite
+        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
+_comp_matte_alpha_inv(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 *comp = sd->comp;
+   if (!comp || !comp->pixels.u32) return;
+   const int comp_stride = comp->stride / 4;
+
+   // 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 = comp->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 + ((comp_stride * spans->y) + spans->x);
+        uint32_t *temp = tbuffer;
+        memset(temp, 0x00, sizeof(uint32_t) * spans->len);
+        comp_func(temp, spans->len, color, spans->coverage);
+
+        //composite
+        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;
+     }
+}
+
+static void
+_comp_mask_add(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   Ector_Software_Buffer_Base_Data *comp = sd->comp;
+   if (!comp || !comp->pixels.u32) return;
+   const int comp_stride = comp->stride / 4;
+
+   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);
+   uint32_t *mbuffer = comp->pixels.u32;
+
+   int tsize = sd->raster_buffer->generic->w;
+   uint32_t *ttarget = alloca(sizeof(uint32_t) * tsize);
+
+   while (count--)
+     {
+        uint32_t *mtarget = mbuffer + ((comp_stride * spans->y) + spans->x);
+        memset(ttarget, 0x00, sizeof(uint32_t) * spans->len);
+        comp_func(ttarget, spans->len, color, spans->coverage);
+        for (int i = 0; i < spans->len; i++)
+          mtarget[i] = draw_mul_256(0xFF - (ttarget[i]>>24), mtarget[i]) + ttarget[i];
+        ++spans;
+     }
+}
+
+static void
+_comp_mask_sub(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   Ector_Software_Buffer_Base_Data *comp = sd->comp;
+   if (!comp || !comp->pixels.u32) return;
+   const int comp_stride = comp->stride / 4;
+
+   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);
+   uint32_t *mbuffer = comp->pixels.u32;
+
+   int tsize = sd->raster_buffer->generic->w;
+   uint32_t *ttarget = alloca(sizeof(uint32_t) * tsize);
+
+   while (count--)
+     {
+        uint32_t *mtarget = mbuffer + ((comp_stride * spans->y) + spans->x);
+        memset(ttarget, 0x00, sizeof(uint32_t) * spans->len);
+        comp_func(ttarget, spans->len, color, spans->coverage);
+        for (int i = 0; i < spans->len; i++)
+          mtarget[i] = draw_mul_256(0xFF - (ttarget[i]>>24), mtarget[i]);
+        ++spans;
+     }
+}
+
+
+static void
+_comp_mask_ins(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   Ector_Software_Buffer_Base_Data *comp = sd->comp;
+   if (!comp || !comp->pixels.u32) return;
+   const int comp_stride = comp->stride / 4;
+
+   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);
+   uint32_t *mbuffer = comp->pixels.u32;
+
+   int tsize = sd->raster_buffer->generic->w;
+   uint32_t *ttarget = alloca(sizeof(uint32_t) * tsize);
+
+   for(unsigned int y = 0; y < comp->generic->h; y++)
+     {
+        for(unsigned int x = 0; x < comp->generic->w; x++)
+          {
+             if (x == (unsigned int)spans->x && x + spans->len <= comp->generic->w &&
+                 y == (unsigned int)spans->y && count > 0)
+               {
+                  memset(ttarget, 0x00, sizeof(uint32_t) * spans->len);
+                  uint32_t *mtarget = mbuffer + ((comp_stride * spans->y) + spans->x);
+                  comp_func(ttarget, spans->len, color, spans->coverage);
+                  for (int c = 0; c < spans->len; c++)
+                    mtarget[c] = draw_mul_256(ttarget[c]>>24, mtarget[c]);
+                  x += spans->len - 1;
+                  ++spans;
+                  --count;
+               }
+             else
+               {
+                  mbuffer[x + (comp_stride * y)] = (0x00FFFFFF & mbuffer[x + (comp_stride * y)]);
+               }
+          }
+     }
+}
+
+
+static void
+_comp_mask_diff(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = user_data;
+   Ector_Software_Buffer_Base_Data *comp = sd->comp;
+   if (!comp || !comp->pixels.u32) return;
+   const int comp_stride = comp->stride / 4;
+
+   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);
+   uint32_t *mbuffer = comp->pixels.u32;
+
+   int tsize = sd->raster_buffer->generic->w;
+   uint32_t *ttarget = alloca(sizeof(uint32_t) * tsize);
+
+   while (count--)
+     {
+        memset(ttarget, 0x00, sizeof(uint32_t) * spans->len);
+        uint32_t *mtarget = mbuffer + ((comp_stride * spans->y) + spans->x);
+        comp_func(ttarget, spans->len, color, spans->coverage);
+        for (int i = 0; i < spans->len; i++)
+          mtarget[i] = draw_mul_256(0xFF - (mtarget[i]>>24), ttarget[i]) + draw_mul_256(0xFF - (ttarget[i]>>24), mtarget[i]);
+        ++spans;
+     }
+}
+
+#define BLEND_GRADIENT_BUFFER_SIZE 2048
+
+typedef void (*src_fetch) (unsigned int *buffer, Span_Data *data, int y, int x, int length);
+
+static void
+_blend_gradient(int count, const SW_FT_Span *spans, void *user_data)
+{
+   RGBA_Comp_Func comp_func;
+   Span_Data *sd = (Span_Data *)(user_data);
+   src_fetch fetchfunc = NULL;
+   unsigned int buffer[BLEND_GRADIENT_BUFFER_SIZE], *target, *destbuffer;
+   int length, l;
+   const int pix_stride = sd->raster_buffer->stride / 4;
+
+   // FIXME: Get the proper composition function using ,color, ECTOR_OP etc.
+   if (sd->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
+   if (sd->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
+
+   if (!fetchfunc || !sd->raster_buffer->pixels.u32) return;
+
+   comp_func = efl_draw_func_span_get(sd->op, sd->mul_col, sd->gradient->alpha);
+
+   // move to the offset location
+   destbuffer = sd->raster_buffer->pixels.u32 + ((pix_stride * sd->offy) + sd->offx);
+
+   while (count--)
+     {
+        target = destbuffer + ((pix_stride * spans->y) + spans->x);
+        length = spans->len;
+        while (length)
+          {
+             l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
+             //FIXME: span->x must have adding an offset as much as subtracted length...
+             fetchfunc(buffer, sd, spans->y, spans->x, l);
+             comp_func(target, buffer, l, sd->mul_col, spans->coverage);
+             target += l;
+             length -= l;
+          }
+        ++spans;
+     }
+}
+
+static void
+_blend_gradient_alpha(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = (Span_Data *)(user_data);
+   src_fetch fetchfunc = NULL;
+   uint32_t *buffer;
+   const int pix_stride = sd->raster_buffer->stride / 4;
+   uint32_t gbuffer[BLEND_GRADIENT_BUFFER_SIZE];  //gradient buffer
+
+   // FIXME: Get the proper composition function using ,color, ECTOR_OP etc.
+   if (sd->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
+   if (sd->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
+
+   if (!fetchfunc) return;
+
+   Ector_Software_Buffer_Base_Data *comp = sd->comp;
+   uint32_t *mbuffer = comp->pixels.u32;
+   const int comp_stride = comp->stride / 4;
+
+   // move to the offset location
+   buffer = sd->raster_buffer->pixels.u32 + ((pix_stride * sd->offy) + sd->offx);
+
+   while (count--)
+     {
+        uint32_t *target = buffer + ((pix_stride * spans->y) + spans->x);
+        uint32_t *mtarget = mbuffer + ((comp_stride * spans->y) + spans->x);
+        int length = spans->len;
+
+        while (length)
+          {
+             int l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
+             //FIXME: span->x must have adding an offset as much as subtracted length...
+             fetchfunc(gbuffer, sd, spans->y, spans->x, l);
+             uint32_t *temp = gbuffer;
+
+             for (int i = 0; i < l; i++)
+               {
+                  *temp = draw_mul_256(((*mtarget)>>24), *temp);
+                  int alpha = 255 - ((*temp) >> 24);
+                  *target = *temp + draw_mul_256(alpha, *target);
+                  ++temp;
+                  ++mtarget;
+                  ++target;
+               }
+             length -= l;
+          }
+        ++spans;
+     }
+}
+
+static void
+_blend_gradient_alpha_inv(int count, const SW_FT_Span *spans, void *user_data)
+{
+   Span_Data *sd = (Span_Data *)(user_data);
+   src_fetch fetchfunc = NULL;
+   uint32_t *buffer;
+   const int pix_stride = sd->raster_buffer->stride / 4;
+   uint32_t gbuffer[BLEND_GRADIENT_BUFFER_SIZE];  //gradient buffer
+
+   // FIXME: Get the proper composition function using ,color, ECTOR_OP etc.
+   if (sd->type == LinearGradient) fetchfunc = &fetch_linear_gradient;
+   if (sd->type == RadialGradient) fetchfunc = &fetch_radial_gradient;
+
+   if (!fetchfunc) return;
+
+   Ector_Software_Buffer_Base_Data *comp = sd->comp;
+   uint32_t *mbuffer = comp->pixels.u32;
+   const int comp_stride = comp->stride / 4;
+
+   // move to the offset location
+   buffer = sd->raster_buffer->pixels.u32 + ((pix_stride * sd->offy) + sd->offx);
+
+   while (count--)
+     {
+        uint32_t *target = buffer + ((pix_stride * spans->y) + spans->x);
+        uint32_t *mtarget = mbuffer + ((comp_stride * spans->y) + spans->x);
+        int length = spans->len;
+
+        while (length)
+          {
+             int l = MIN(length, BLEND_GRADIENT_BUFFER_SIZE);
+             //FIXME: span->x must have adding an offset as much as subtracted length...
+             fetchfunc(gbuffer, sd, spans->y, spans->x, l);
+             uint32_t *temp = gbuffer;
+
+             for (int i = 0; i < l; 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;
+               }
+             length -= l;
+          }
+        ++spans;
+     }
+}
+/*!
+    \internal
+    spans must be sorted on y
+*/
+static const
+SW_FT_Span *_intersect_spans_rect(const Eina_Rectangle *clip,
+                                  const SW_FT_Span *spans,
+                                  const SW_FT_Span *end,
+                                  SW_FT_Span **out_spans,
+                                  int available)
+{
+   SW_FT_Span *out = *out_spans;
+   short minx, miny, maxx, maxy;
+   minx = clip->x;
+   miny = clip->y;
+   maxx = minx + clip->w - 1;
+   maxy = miny + clip->h - 1;
+
+   while (available && spans < end )
+     {
+        if (spans->y > maxy)
+          {
+             spans = end;// update spans so that we can breakout
+             break;
+          }
+        if (spans->y < miny
+            || spans->x > maxx
+            || spans->x + spans->len <= minx)
+          {
+             ++spans;
+             continue;
+          }
+        if (spans->x < minx)
+          {
+             out->len = MIN(spans->len - (minx - spans->x), maxx - minx + 1);
+             out->x = minx;
+          }
+        else
+          {
+             out->x = spans->x;
+             out->len = MIN(spans->len, (maxx - spans->x + 1));
+          }
+        if (out->len != 0)
+          {
+             out->y = spans->y;
+             out->coverage = spans->coverage;
+             ++out;
+          }
+        ++spans;
+        --available;
+     }
+
+   *out_spans = out;
+   return spans;
+}
+
+static inline int
+_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; }
+
+static const
+SW_FT_Span *_intersect_spans_region(const Shape_Rle_Data *clip,
+                                    int *currentClip,
+                                    const SW_FT_Span *spans,
+                                    const SW_FT_Span *end,
+                                    SW_FT_Span **out_spans,
+                                    int available)
+{
+   SW_FT_Span *out = *out_spans;
+   int sx1, sx2, cx1, cx2, x, len;
+
+   const SW_FT_Span *clipSpans = clip->spans + *currentClip;
+   const SW_FT_Span *clipEnd = clip->spans + clip->size;
+
+   while (available && spans < end )
+     {
+        if (clipSpans >= clipEnd)
+          {
+             spans = end;
+             break;
+          }
+        if (clipSpans->y > spans->y)
+          {
+             ++spans;
+             continue;
+          }
+        if (spans->y != clipSpans->y)
+          {
+             ++clipSpans;
+             continue;
+          }
+        //assert(spans->y == clipSpans->y);
+        sx1 = spans->x;
+        sx2 = sx1 + spans->len;
+        cx1 = clipSpans->x;
+        cx2 = cx1 + clipSpans->len;
+
+        if (cx1 < sx1 && cx2 < sx1)
+          {
+             ++clipSpans;
+             continue;
+          }
+        else if (sx1 < cx1 && sx2 < cx1)
+          {
+             ++spans;
+             continue;
+          }
+        x = MAX(sx1, cx1);
+        len = MIN(sx2, cx2) - x;
+        if (len)
+          {
+             out->x = MAX(sx1, cx1);
+             out->len = MIN(sx2, cx2) - out->x;
+             out->y = spans->y;
+             out->coverage = _div_255(spans->coverage * clipSpans->coverage);
+             ++out;
+             --available;
+          }
+        if (sx2 < cx2)
+          {
+             ++spans;
+          }
+        else
+          {
+             ++clipSpans;
+          }
+     }
+
+   *out_spans = out;
+   *currentClip = clipSpans - clip->spans;
+   return spans;
+}
+
+static void
+_span_fill_clipRect(int span_count, const SW_FT_Span *spans, void *user_data)
+{
+   const int NSPANS = 256;
+   int clip_count, i;
+   Span_Data *fill_data = (Span_Data *) user_data;
+   Clip_Data clip = fill_data->clip;
+   SW_FT_Span *clipped;
+   Eina_Rectangle *rect;
+   Eina_Rectangle tmp_rect;
+   SW_FT_Span *cspans = NULL;
+   Eina_Bool intersect = EINA_FALSE;
+
+   //Note: Uses same span_count sized heap memory in intersect mask case.
+   if (fill_data->comp_method == EFL_GFX_VG_COMPOSITE_METHOD_MASK_INTERSECT)
+     {
+        intersect = EINA_TRUE;
+        cspans = malloc(sizeof(SW_FT_Span) * (span_count));
+        if (!cspans)
+          {
+             ERR("OOM: Failed malloc()");
+             return ;
+          }
+     }
+   else
+     {
+        cspans = alloca(sizeof(SW_FT_Span) * (NSPANS));
+     }
+
+   clip_count = eina_array_count(clip.clips);
+
+   for (i = 0; i < clip_count; i++)
+     {
+        rect = (Eina_Rectangle *)eina_array_data_get(clip.clips, i);
+
+        // invert transform the offset
+        tmp_rect.x = rect->x - fill_data->offx;
+        tmp_rect.y = rect->y - fill_data->offy;
+        tmp_rect.w = rect->w;
+        tmp_rect.h = rect->h;
+        const SW_FT_Span *end = spans + span_count;
+
+        while (spans < end)
+          {
+             clipped = cspans;
+             spans = _intersect_spans_rect(&tmp_rect, spans, end, &clipped, intersect ? span_count : NSPANS);
+             if (clipped - cspans)
+               fill_data->unclipped_blend(clipped - cspans, cspans, fill_data);
+          }
+     }
+   if (intersect && cspans) free(cspans);
+}
+
+static void
+_span_fill_clipPath(int span_count, const SW_FT_Span *spans, void *user_data)
+{
+   const int NSPANS = 256;
+   int current_clip = 0;
+   Span_Data *fill_data = (Span_Data *) user_data;
+   Clip_Data clip = fill_data->clip;
+   SW_FT_Span *clipped;
+   SW_FT_Span *cspans = NULL;
+   Eina_Bool intersect = EINA_FALSE;
+
+   //Note: Uses same span_count sized heap memory in intersect mask case.
+   if (fill_data->comp_method == EFL_GFX_VG_COMPOSITE_METHOD_MASK_INTERSECT)
+     {
+        intersect = EINA_TRUE;
+        cspans = malloc(sizeof(SW_FT_Span) * (span_count));
+        if (!cspans)
+          {
+             ERR("OOM: Failed malloc()");
+             return ;
+          }
+     }
+   else
+     {
+        cspans = alloca(sizeof(SW_FT_Span) * (NSPANS));
+     }
+
+   // FIXME: Take clip path offset into account.
+   const SW_FT_Span *end = spans + span_count;
+   while (spans < end)
+     {
+        clipped = cspans;
+        spans = _intersect_spans_region(clip.path, &current_clip, spans, end, &clipped, intersect ? span_count : NSPANS);
+        if (clipped - cspans)
+          fill_data->unclipped_blend(clipped - cspans, cspans, fill_data);
+     }
+   if (intersect && cspans) free(cspans);
+}
+
+static void
+_adjust_span_fill_methods(Span_Data *spdata)
+{
+   //Blending Function
+   if (spdata->comp)
+     {
+        switch (spdata->comp_method)
+          {
+           default:
+           case EFL_GFX_VG_COMPOSITE_METHOD_MATTE_ALPHA:
+              if (spdata->type == Solid)
+                spdata->unclipped_blend = &_comp_matte_alpha;
+              else if (spdata->type == LinearGradient || spdata->type == RadialGradient)
+                spdata->unclipped_blend = &_blend_gradient_alpha;
+              else //None
+                spdata->unclipped_blend = NULL;
+              break;
+           case EFL_GFX_VG_COMPOSITE_METHOD_MATTE_ALPHA_INVERSE:
+              if (spdata->type == Solid)
+                spdata->unclipped_blend = &_comp_matte_alpha_inv;
+              else if (spdata->type == LinearGradient || spdata->type == RadialGradient)
+                spdata->unclipped_blend = &_blend_gradient_alpha_inv;
+              else //None
+                spdata->unclipped_blend = NULL;
+              break;
+           case EFL_GFX_VG_COMPOSITE_METHOD_MASK_ADD:
+              spdata->unclipped_blend = &_comp_mask_add;
+              break;
+           case EFL_GFX_VG_COMPOSITE_METHOD_MASK_SUBSTRACT:
+              spdata->unclipped_blend = &_comp_mask_sub;
+              break;
+           case EFL_GFX_VG_COMPOSITE_METHOD_MASK_INTERSECT:
+              spdata->unclipped_blend = &_comp_mask_ins;
+              break;
+           case EFL_GFX_VG_COMPOSITE_METHOD_MASK_DIFFERENCE:
+              spdata->unclipped_blend = &_comp_mask_diff;
+              break;
+          }
+     }
+   else
+     {
+        if (spdata->type == Solid)
+          spdata->unclipped_blend = &_blend_argb;
+        else if (spdata->type == LinearGradient || spdata->type == RadialGradient)
+          spdata->unclipped_blend = &_blend_gradient;
+        else //None
+          spdata->unclipped_blend = NULL;
+     }
+
+   // Clipping Function
+   if (spdata->clip.enabled)
+     {
+        if (spdata->clip.type == 0)
+          spdata->blend = &_span_fill_clipRect;
+        else
+          spdata->blend = &_span_fill_clipPath;
+     }
+   else
+     spdata->blend = spdata->unclipped_blend;
+}
+
+void ector_software_thread_init(Ector_Software_Thread *thread)
+{
+   // initialize the rasterizer and stroker
+   sw_ft_grays_raster.raster_new(&thread->raster);
+
+   SW_FT_Stroker_New(&thread->stroker);
+   SW_FT_Stroker_Set(thread->stroker, 1 << 6,
+                     SW_FT_STROKER_LINECAP_BUTT, SW_FT_STROKER_LINEJOIN_MITER_FIXED, 0x4<<16);
+}
+
+void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
+{
+   //initialize the span data.
+   rasterizer->fill_data.clip.enabled = EINA_FALSE;
+   rasterizer->fill_data.unclipped_blend = 0;
+   rasterizer->fill_data.blend = 0;
+   efl_draw_init();
+   ector_software_gradient_init();
+}
+
+void ector_software_thread_shutdown(Ector_Software_Thread *thread)
+{
+   sw_ft_grays_raster.raster_done(thread->raster);
+   SW_FT_Stroker_Done(thread->stroker);
+}
+
+void ector_software_rasterizer_stroke_set(Ector_Software_Thread *thread,
+                                          Software_Rasterizer *rasterizer EINA_UNUSED, double width,
+                                          Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style,
+                                          Eina_Matrix3 *m, double miterlimit)
+{
+   SW_FT_Stroker_LineCap cap;
+   SW_FT_Stroker_LineJoin join;
+   int stroke_width;
+   double scale_factor = 1.0;
+
+   // convert to freetype co-ordinate
+   SW_FT_Fixed miter_limit = miterlimit * (1<<16);
+
+   if (m)
+     {
+        // get the minimum scale factor from matrix
+        scale_factor =  m->xx < m->yy ? m->xx : m->yy;
+     }
+   width = width * scale_factor;
+   width = width/2.0; // as free type uses it as the radius of the
+                      // pen not the diameter.
+   // convert to freetype co-ordinate
+   stroke_width = (int)(width * 64);
+
+   switch (cap_style)
+     {
+        case EFL_GFX_CAP_SQUARE:
+          cap = SW_FT_STROKER_LINECAP_SQUARE;
+          break;
+        case EFL_GFX_CAP_ROUND:
+          cap = SW_FT_STROKER_LINECAP_ROUND;
+          break;
+        default:
+          cap = SW_FT_STROKER_LINECAP_BUTT;
+          break;
+     }
+
+   switch (join_style)
+     {
+        case EFL_GFX_JOIN_BEVEL:
+          join = SW_FT_STROKER_LINEJOIN_BEVEL;
+          break;
+        case EFL_GFX_JOIN_ROUND:
+          join = SW_FT_STROKER_LINEJOIN_ROUND;
+          break;
+        default:
+          join = SW_FT_STROKER_LINEJOIN_MITER_FIXED;
+          break;
+     }
+   SW_FT_Stroker_Set(thread->stroker, stroke_width, cap, join, miter_limit);
+}
+
+static void
+_rle_generation_cb( int count, const SW_FT_Span*  spans,void *user)
+{
+   Shape_Rle_Data *rle = (Shape_Rle_Data *) user;
+   int newsize = rle->size + count;
+
+   // allocate enough memory for new spans
+   // alloc is required to prevent free and reallocation
+   // when the rle needs to be regenerated because of attribute change.
+   if (rle->alloc < newsize)
+     {
+        rle->spans = (SW_FT_Span *) realloc(rle->spans, newsize * sizeof(SW_FT_Span));
+        rle->alloc = newsize;
+     }
+
+   // copy the new spans to the allocated memory
+   SW_FT_Span *lastspan = (rle->spans + rle->size);
+   memcpy(lastspan,spans, count * sizeof(SW_FT_Span));
+
+   // update the size
+   rle->size = newsize;
+}
+
+Shape_Rle_Data *
+ector_software_rasterizer_generate_rle_data(Ector_Software_Thread *thread,
+                                            Software_Rasterizer *rasterizer EINA_UNUSED,
+                                            SW_FT_Outline *outline)
+{
+   int i, rle_size;
+   int l = 0, t = 0, r = 0, b = 0;
+   Shape_Rle_Data *rle_data = (Shape_Rle_Data *) calloc(1, sizeof(Shape_Rle_Data));
+   SW_FT_Raster_Params params;
+   SW_FT_Span* span;
+
+   params.flags = SW_FT_RASTER_FLAG_DIRECT | SW_FT_RASTER_FLAG_AA ;
+   params.gray_spans = &_rle_generation_cb;
+   params.user = rle_data;
+   params.source = outline;
+
+   sw_ft_grays_raster.raster_render(thread->raster, &params);
+
+   // update RLE bounding box.
+   span = rle_data->spans;
+   rle_size = rle_data->size;
+   if (rle_size)
+     {
+        t = span[0].y;
+        b = span[rle_size-1].y;
+        for (i = 0; i < rle_size; i++)
+          {
+             if (span[i].x < l) l = span[i].x;
+             if (span[i].x + span[i].len > r) r = span[i].x + span[i].len;
+          }
+        rle_data->bbox.x = l;
+        rle_data->bbox.y = t;
+        rle_data->bbox.w = r - l;
+        rle_data->bbox.h = b - t + 1;
+     }
+   return rle_data;
+}
+
+Shape_Rle_Data *
+ector_software_rasterizer_generate_stroke_rle_data(Ector_Software_Thread *thread,
+                                                   Software_Rasterizer *rasterizer,
+                                                   SW_FT_Outline *outline,
+                                                   Eina_Bool closePath)
+{
+   uint32_t points,contors;
+   Shape_Rle_Data *rle_data;
+   SW_FT_Outline strokeOutline = { 0, 0, NULL, NULL, NULL, 0 };
+
+   SW_FT_Stroker_ParseOutline(thread->stroker, outline, !closePath);
+   SW_FT_Stroker_GetCounts(thread->stroker,&points, &contors);
+
+   strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
+   strokeOutline.tags = (char *) calloc(points, sizeof(char));
+   strokeOutline.contours = (short *) calloc(contors, sizeof(short));
+
+   SW_FT_Stroker_Export(thread->stroker, &strokeOutline);
+
+   rle_data = ector_software_rasterizer_generate_rle_data(thread, rasterizer, &strokeOutline);
+
+   // cleanup the outline data.
+   free(strokeOutline.points);
+   free(strokeOutline.tags);
+   free(strokeOutline.contours);
+
+   return rle_data;
+}
+
+void
+ector_software_rasterizer_destroy_rle_data(Shape_Rle_Data *rle)
+{
+   if (rle)
+     {
+        if (rle->spans)
+          free(rle->spans);
+        free(rle);
+     }
+}
+
+static
+void _setup_span_fill_matrix(Software_Rasterizer *rasterizer)
+{
+   if (rasterizer->transform)
+     eina_matrix3_inverse(rasterizer->transform, &rasterizer->fill_data.inv);
+   else
+     eina_matrix3_identity(&rasterizer->fill_data.inv);
+}
+
+void
+ector_software_rasterizer_transform_set(Software_Rasterizer *rasterizer, Eina_Matrix3 *t)
+{
+   rasterizer->transform = t;
+}
+
+void
+ector_software_rasterizer_clip_rect_set(Software_Rasterizer *rasterizer, Eina_Array *clips)
+{
+   if (clips)
+     {
+        rasterizer->fill_data.clip.clips = clips;
+        rasterizer->fill_data.clip.type = 0;
+        rasterizer->fill_data.clip.enabled = EINA_TRUE;
+     }
+   else
+     {
+        rasterizer->fill_data.clip.clips = NULL;
+        rasterizer->fill_data.clip.type = 0;
+        rasterizer->fill_data.clip.enabled = EINA_FALSE;
+     }
+}
+
+void
+ector_software_rasterizer_clip_shape_set(Software_Rasterizer *rasterizer, Shape_Rle_Data *clip)
+{
+   if (clip)
+     {
+        rasterizer->fill_data.clip.path = clip;
+        rasterizer->fill_data.clip.type = 1;
+        rasterizer->fill_data.clip.enabled = EINA_TRUE;
+     }
+   else
+     {
+        rasterizer->fill_data.clip.path = NULL;
+        rasterizer->fill_data.clip.type = 0;
+        rasterizer->fill_data.clip.enabled = EINA_FALSE;
+     }
+}
+
+void
+ector_software_rasterizer_color_set(Software_Rasterizer *rasterizer, int r, int g, int b, int a)
+{
+   rasterizer->fill_data.color = DRAW_ARGB_JOIN(a, r, g, b);
+   rasterizer->fill_data.type = Solid;
+}
+
+void ector_software_rasterizer_linear_gradient_set(Software_Rasterizer *rasterizer,
+                                                   Ector_Renderer_Software_Gradient_Data *linear)
+{
+   rasterizer->fill_data.gradient = linear;
+   rasterizer->fill_data.type = LinearGradient;
+}
+
+void
+ector_software_rasterizer_radial_gradient_set(Software_Rasterizer *rasterizer,
+                                              Ector_Renderer_Software_Gradient_Data *radial)
+{
+   rasterizer->fill_data.gradient = radial;
+   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,
+                                        Ector_Buffer *comp,
+                                        Efl_Gfx_Vg_Composite_Method comp_method)
+{
+   if (!rle) return;
+   if (!rasterizer->fill_data.raster_buffer->pixels.u32) 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.comp =
+         comp ? efl_data_scope_get(comp, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN) : NULL;
+   rasterizer->fill_data.comp_method = comp_method;
+
+   _setup_span_fill_matrix(rasterizer);
+   _adjust_span_fill_methods(&rasterizer->fill_data);
+
+   if (rasterizer->fill_data.blend)
+     rasterizer->fill_data.blend(rle->size, rle->spans, &rasterizer->fill_data);
+}
diff --git a/src/lib/ector/software/ector_software_surface.c b/src/lib/ector/software/ector_software_surface.c
new file mode 100644 (file)
index 0000000..ba64445
--- /dev/null
@@ -0,0 +1,288 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <Ector.h>
+#include <software/Ector_Software.h>
+
+#include "ector_private.h"
+#include "ector_software_private.h"
+
+#define MY_CLASS ECTOR_SOFTWARE_SURFACE_CLASS
+
+typedef struct _Ector_Software_Task Ector_Software_Task;
+
+struct _Ector_Software_Task
+{
+   Eina_Thread_Queue_Msg member;
+
+   Ector_Thread_Worker_Cb cb;
+   Eina_Free_Cb done;
+   void *data;
+};
+
+static int _count_init = 0;
+static unsigned int current = 0;
+static unsigned int cpu_core = 0;
+static Ector_Software_Thread *ths = NULL;
+static Eina_Thread_Queue *render_queue = NULL;
+static Ector_Software_Thread render_thread;
+
+static void *
+_prepare_process(void *data, Eina_Thread t)
+{
+   Ector_Software_Thread *th = data;
+
+   eina_thread_name_set(t, "Ector Preparing Thread");
+   do
+     {
+        Ector_Software_Task *task, todo;
+        void *ref;
+
+        task = eina_thread_queue_wait(th->queue, &ref);
+
+        if (!task) break ;
+        todo.cb = task->cb;
+        todo.data = task->data;
+        todo.done = task->done;
+
+        eina_thread_queue_wait_done(th->queue, ref);
+
+        if (!todo.cb) break ;
+
+        todo.cb(todo.data, th);
+
+        task = eina_thread_queue_send(render_queue, sizeof (Ector_Software_Task), &ref);
+        task->cb = todo.cb;
+        task->data = todo.data;
+        task->done = todo.done;
+        eina_thread_queue_send_done(render_queue, ref);
+     }
+   while (1);
+
+   return th;
+}
+
+
+static void
+_ector_software_init(void)
+{
+   int cpu, i;
+
+   ++_count_init;
+   if (_count_init != 1) return;
+
+   cpu = eina_cpu_count() - 1;
+   if (cpu < 1)
+     {
+        render_thread.queue = NULL;
+        ector_software_thread_init(&render_thread);
+        return ;
+     }
+   cpu = cpu > 8 ? 8 : cpu;
+   cpu_core = cpu;
+
+   render_queue = eina_thread_queue_new();
+
+   ths = malloc(sizeof(Ector_Software_Thread) * cpu);
+   for (i = 0; i < cpu; i++)
+     {
+        Ector_Software_Thread *t;
+
+        t = &ths[i];
+        t->queue = eina_thread_queue_new();
+        ector_software_thread_init(t);
+        if (!eina_thread_create(&t->thread, EINA_THREAD_NORMAL, -1,
+                                _prepare_process, t))
+          {
+             eina_thread_queue_free(t->queue);
+             t->queue = NULL;
+          }
+     }
+}
+
+static void
+_ector_software_shutdown(void)
+{
+   Ector_Software_Thread *t;
+   unsigned int i;
+
+   --_count_init;
+   if (_count_init != 0) return;
+
+   if (!ths)
+     {
+        ector_software_thread_shutdown(&render_thread);
+        return ;
+     }
+
+   for (i = 0; i < cpu_core; i++)
+     {
+        Ector_Software_Task *task;
+        void *ref;
+
+        t = &ths[i];
+
+        task = eina_thread_queue_send(t->queue, sizeof (Ector_Software_Task), &ref);
+        task->cb = NULL;
+        task->data = NULL;
+        eina_thread_queue_send_done(t->queue, ref);
+
+        eina_thread_join(t->thread);
+        eina_thread_queue_free(t->queue);
+        ector_software_thread_shutdown(t);
+     }
+
+   eina_thread_queue_free(render_queue);
+   render_queue = NULL;
+
+   free(ths);
+   ths = NULL;
+}
+
+void
+ector_software_schedule(Ector_Thread_Worker_Cb cb, Eina_Free_Cb done, void *data)
+{
+   Ector_Software_Thread *t;
+   Ector_Software_Task *task;
+   void *ref;
+
+   // Not enough CPU, doing it inline in the rendering thread
+   if (!ths) return ;
+
+   t = &ths[current];
+   current = (current + 1) % cpu_core;
+
+   task = eina_thread_queue_send(t->queue, sizeof (Ector_Software_Task), &ref);
+   task->cb = cb;
+   task->done = done;
+   task->data = data;
+   eina_thread_queue_send_done(t->queue, ref);
+}
+
+// Do not call this function if the done function has already called
+void
+ector_software_wait(Ector_Thread_Worker_Cb cb, Eina_Free_Cb done, void *data)
+{
+   Ector_Software_Task *task, covering;
+
+   // First handle case with just inlined prepare code call inside the rendering thread
+   if (!ths)
+     {
+        render_thread.thread = eina_thread_self();
+        cb(data, &render_thread);
+        done(data);
+
+        return ;
+     }
+
+   // We don't know which task is going to be done first, so
+   // we iterate until we find ourself back and trigger all
+   // the done call along the way.
+   do
+     {
+        void *ref;
+
+        task = eina_thread_queue_wait(render_queue, &ref);
+        if (!task) break;
+        covering.cb = task->cb;
+        covering.done = task->done;
+        covering.data = task->data;
+        eina_thread_queue_wait_done(render_queue, ref);
+
+        covering.done(covering.data);
+     }
+   while (covering.cb != cb ||
+          covering.done != done ||
+          covering.data != data);
+}
+
+static Ector_Renderer *
+_ector_software_surface_ector_surface_renderer_factory_new(Eo *obj,
+                                                           Ector_Software_Surface_Data *pd EINA_UNUSED,
+                                                           const Efl_Class *type)
+{
+   if (type == ECTOR_RENDERER_SHAPE_MIXIN)
+     return efl_add_ref(ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS, NULL, ector_renderer_surface_set(efl_added, obj));
+   else if (type == ECTOR_RENDERER_IMAGE_MIXIN)
+     return efl_add_ref(ECTOR_RENDERER_SOFTWARE_IMAGE_CLASS, NULL, ector_renderer_surface_set(efl_added, obj));
+   else if (type == ECTOR_RENDERER_GRADIENT_LINEAR_MIXIN)
+     return efl_add_ref(ECTOR_RENDERER_SOFTWARE_GRADIENT_LINEAR_CLASS, NULL, ector_renderer_surface_set(efl_added, obj));
+   else if (type == ECTOR_RENDERER_GRADIENT_RADIAL_MIXIN)
+     return efl_add_ref(ECTOR_RENDERER_SOFTWARE_GRADIENT_RADIAL_CLASS, NULL, ector_renderer_surface_set(efl_added, obj));
+
+   ERR("Couldn't find class for type: %s", efl_class_name_get(type));
+   return NULL;
+}
+
+static Eo *
+_ector_software_surface_efl_object_constructor(Eo *obj, Ector_Software_Surface_Data *pd)
+{
+   _ector_software_init();
+
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   pd->rasterizer = (Software_Rasterizer *) calloc(1, sizeof(Software_Rasterizer));
+   ector_software_rasterizer_init(pd->rasterizer);
+   pd->rasterizer->fill_data.raster_buffer = efl_data_ref(obj, ECTOR_SOFTWARE_BUFFER_BASE_MIXIN);
+   return obj;
+}
+
+static void
+_ector_software_surface_efl_object_destructor(Eo *obj, Ector_Software_Surface_Data *pd)
+{
+   efl_data_unref(obj, pd->rasterizer->fill_data.raster_buffer);
+   free(pd->rasterizer);
+   pd->rasterizer = NULL;
+   efl_destructor(efl_super(obj, ECTOR_SOFTWARE_SURFACE_CLASS));
+
+   _ector_software_shutdown();
+}
+
+static void
+_ector_software_surface_ector_surface_reference_point_get(const Eo *obj EINA_UNUSED,
+                                                          Ector_Software_Surface_Data *pd,
+                                                          int* x, int* y)
+{
+   if (x) *x = pd->x;
+   if (y) *y = pd->y;
+}
+
+static void
+_ector_software_surface_ector_surface_reference_point_set(Eo *obj EINA_UNUSED,
+                                                          Ector_Software_Surface_Data *pd,
+                                                          int x, int y)
+{
+   pd->x = x;
+   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;
+   if (!src) return EINA_FALSE;
+
+   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"
diff --git a/src/lib/ector/software/ector_software_surface.eo b/src/lib/ector/software/ector_software_surface.eo
new file mode 100644 (file)
index 0000000..5836951
--- /dev/null
@@ -0,0 +1,13 @@
+class @beta Ector.Software.Surface extends Ector.Software.Buffer implements Ector.Surface
+{
+   [[Ector surface software class]]
+   c_prefix: ector_software_surface;
+   methods {}
+   implements {
+      Ector.Surface.renderer_factory_new;
+      Ector.Surface.reference_point { set; get; }
+      Ector.Surface.draw_image;
+      Efl.Object.destructor;
+      Efl.Object.constructor;
+   }
+}
index 5345adc..75d2171 100644 (file)
@@ -1,12 +1,25 @@
 
 ector_src += files([
+  'ector_renderer_software_gradient_linear.c',
+  'ector_renderer_software_gradient_radial.c',
+  'ector_renderer_software_shape.c',
+  'ector_renderer_software_image.c',
+  'ector_software_gradient.c',
+  'ector_software_rasterizer.c',
+  'ector_software_surface.c',
   'ector_software_buffer.c',
 ])
 
 
 pub_eo_files = [
+  'ector_software_surface.eo',
   'ector_software_buffer.eo',
   'ector_software_buffer_base.eo',
+  'ector_renderer_software.eo',
+  'ector_renderer_software_shape.eo',
+  'ector_renderer_software_image.eo',
+  'ector_renderer_software_gradient_radial.eo',
+  'ector_renderer_software_gradient_linear.eo',
 ]
 
 foreach eo_file : pub_eo_files
@@ -24,6 +37,17 @@ foreach eo_file : pub_eo_files
 endforeach
 
 
+if cpu_sse3 == true
+  ector_opt = static_library('ector_opt',
+    sources: pub_eo_file_target + [ 'ector_software_gradient_sse3.c' ],
+    dependencies: ector_pub_deps + [triangulator, freetype, draw, m] + ector_deps,
+    include_directories: config_dir + [ include_directories('..') ],
+    c_args: native_arch_opt_c_args,
+  )
+  ector_opt_lib += [ ector_opt ]
+endif
+
+
 #
 # Only enable that again when the namespace problems are fixed. ref T8648
 #
index 28c1b54..bdd1869 100755 (executable)
@@ -1,6 +1,7 @@
 #include "evas_common_private.h"
 #include "evas_gl_core_private.h"
 
+#include "software/Ector_Software.h"
 #include "gl/Ector_GL.h"
 #include "evas_ector_gl.h"
 #include "filters/gl_engine_filter.h"
@@ -2746,6 +2747,8 @@ eng_ector_create(void *engine EINA_UNUSED)
         ector = efl_add_ref(ECTOR_GL_SURFACE_CLASS, NULL);
         use_gl = EINA_TRUE;
      }
+   else
+     ector = efl_add_ref(ECTOR_SOFTWARE_SURFACE_CLASS, NULL);
 
    efl_domain_current_pop();
    return ector;
index f97ed9c..8d27410 100755 (executable)
@@ -4,6 +4,7 @@
 
 #include "region.h"
 
+#include <software/Ector_Software.h>
 #include "evas_ector_software.h"
 #include "draw.h"
 #include "evas_filter_private.h"
@@ -408,6 +409,12 @@ struct _Evas_Thread_Command_Ector
    Eina_Bool free_it;
 };
 
+struct _Evas_Thread_Command_Ector_Surface
+{
+   Ector_Surface *ector;
+   void *pixels;
+   int x, y;
+};
 
 // declare here as it is re-used
 static void *eng_image_map_surface_new(void *data, int w, int h, int alpha);
@@ -419,6 +426,8 @@ Eina_Mempool *_mp_command_image = NULL;
 Eina_Mempool *_mp_command_font = NULL;
 Eina_Mempool *_mp_command_map = NULL;
 Eina_Mempool *_mp_command_multi_font = NULL;
+Eina_Mempool *_mp_command_ector = NULL;
+Eina_Mempool *_mp_command_ector_surface = NULL;
 /*
  *****
  **
@@ -1929,8 +1938,8 @@ eng_image_surface_noscale_new(void *engdata, int w, int h, int alpha)
    return eng_image_map_surface_new(engdata, w, h, alpha);
 }
 
-static void
-_image_flip_horizontal(DATA32 *pixels_out, const DATA32 *pixels_in,
+EAPI void
+_evas_image_flip_horizontal(DATA32 *pixels_out, const DATA32 *pixels_in,
                        int iw, int ih)
 {
    const unsigned int *pi1, *pi2;
@@ -1953,8 +1962,8 @@ _image_flip_horizontal(DATA32 *pixels_out, const DATA32 *pixels_in,
      }
 }
 
-static void
-_image_flip_vertical(DATA32 *pixels_out, const DATA32 *pixels_in,
+EAPI void
+_evas_image_flip_vertical(DATA32 *pixels_out, const DATA32 *pixels_in,
                      int iw, int ih)
 {
    const unsigned int *pi1, *pi2;
@@ -1977,8 +1986,8 @@ _image_flip_vertical(DATA32 *pixels_out, const DATA32 *pixels_in,
      }
 }
 
-static void
-_image_rotate_180(DATA32 *pixels_out, const DATA32 *pixels_in,
+EAPI void
+_evas_image_rotate_180(DATA32 *pixels_out, const DATA32 *pixels_in,
                   int iw, int ih)
 {
    const unsigned int *pi1, *pi2;
@@ -1999,8 +2008,8 @@ _image_rotate_180(DATA32 *pixels_out, const DATA32 *pixels_in,
      }
 }
 
-static void
-_image_rotate_90(DATA32 *pixels_out, const DATA32 *pixels_in, int iw, int ih)
+EAPI void
+_evas_image_rotate_90(DATA32 *pixels_out, const DATA32 *pixels_in, int iw, int ih)
 {
    int x, y, xx, yy, xx2, yy2;
 
@@ -2030,8 +2039,8 @@ _image_rotate_90(DATA32 *pixels_out, const DATA32 *pixels_in, int iw, int ih)
      }
 }
 
-static void
-_image_rotate_270(DATA32 *pixels_out, const DATA32 *pixels_in, int iw, int ih)
+EAPI void
+_evas_image_rotate_270(DATA32 *pixels_out, const DATA32 *pixels_in, int iw, int ih)
 {
    int x, y, xx, yy, xx2, yy2;
 
@@ -2061,8 +2070,8 @@ _image_rotate_270(DATA32 *pixels_out, const DATA32 *pixels_in, int iw, int ih)
      }
 }
 
-static void
-_image_flip_transpose(DATA32 *pixels_out, const DATA32 *pixels_in,
+EAPI void
+_evas_image_flip_transpose(DATA32 *pixels_out, const DATA32 *pixels_in,
                       int iw, int ih)
 {
    int x, y;
@@ -2084,8 +2093,8 @@ _image_flip_transpose(DATA32 *pixels_out, const DATA32 *pixels_in,
      }
 }
 
-static void
-_image_flip_transverse(DATA32 *pixels_out, const DATA32 *pixels_in,
+EAPI void
+_evas_image_flip_transverse(DATA32 *pixels_out, const DATA32 *pixels_in,
                        int iw, int ih)
 {
    int x, y;
@@ -2172,13 +2181,13 @@ eng_image_orient_set(void *data EINA_UNUSED, void *image, Evas_Image_Orient orie
               ERR("You shouldn't get this message, wrong orient value");
               goto on_error;
            case EVAS_IMAGE_ORIENT_90:
-              _image_rotate_90(pixels_out, pixels_in, im->w, im->h);
+              _evas_image_rotate_90(pixels_out, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_ORIENT_180:
-              _image_rotate_180(pixels_out, pixels_in, im->w, im->h);
+             _evas_image_rotate_180(pixels_out, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_ORIENT_270:
-              _image_rotate_270(pixels_out, pixels_in, im->w, im->h);
+             _evas_image_rotate_270(pixels_out, pixels_in, im->w, im->h);
               break;
            default:
               ERR("Wrong orient value");
@@ -2191,7 +2200,7 @@ eng_image_orient_set(void *data EINA_UNUSED, void *image, Evas_Image_Orient orie
              (orient == EVAS_IMAGE_ORIENT_NONE)))
      {
         // flip horizontally to get the new orientation
-        _image_flip_horizontal(pixels_out, pixels_in, im->w, im->h);
+       _evas_image_flip_horizontal(pixels_out, pixels_in, im->w, im->h);
      }
    else if (((im->orient == EVAS_IMAGE_ORIENT_NONE) &&
              (orient == EVAS_IMAGE_FLIP_VERTICAL)) ||
@@ -2199,7 +2208,7 @@ eng_image_orient_set(void *data EINA_UNUSED, void *image, Evas_Image_Orient orie
              (orient == EVAS_IMAGE_ORIENT_NONE)))
      {
         // flip vertically to get the new orientation
-        _image_flip_vertical(pixels_out, pixels_in, im->w, im->h);
+       _evas_image_flip_vertical(pixels_out, pixels_in, im->w, im->h);
      }
    else
      {
@@ -2218,25 +2227,25 @@ eng_image_orient_set(void *data EINA_UNUSED, void *image, Evas_Image_Orient orie
               memcpy(pixels_tmp, pixels_in, sizeof (unsigned int) * w * h);
               break;
            case EVAS_IMAGE_ORIENT_90:
-              _image_rotate_270(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_rotate_270(pixels_tmp, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_ORIENT_180:
-              _image_rotate_180(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_rotate_180(pixels_tmp, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_ORIENT_270:
-              _image_rotate_90(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_rotate_90(pixels_tmp, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_FLIP_HORIZONTAL:
-              _image_flip_horizontal(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_flip_horizontal(pixels_tmp, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_FLIP_VERTICAL:
-              _image_flip_vertical(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_flip_vertical(pixels_tmp, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_FLIP_TRANSPOSE:
-              _image_flip_transpose(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_flip_transpose(pixels_tmp, pixels_in, im->w, im->h);
               break;
            case EVAS_IMAGE_FLIP_TRANSVERSE:
-              _image_flip_transverse(pixels_tmp, pixels_in, im->w, im->h);
+             _evas_image_flip_transverse(pixels_tmp, pixels_in, im->w, im->h);
               break;
            default:
               ERR("Wrong orient value");
@@ -2252,25 +2261,25 @@ eng_image_orient_set(void *data EINA_UNUSED, void *image, Evas_Image_Orient orie
               memcpy(pixels_out, pixels_tmp, sizeof (unsigned int) * w * h);
               break;
            case EVAS_IMAGE_ORIENT_90:
-              _image_rotate_90(pixels_out, pixels_tmp, tw, th);
+             _evas_image_rotate_90(pixels_out, pixels_tmp, tw, th);
               break;
            case EVAS_IMAGE_ORIENT_180:
-              _image_rotate_180(pixels_out, pixels_tmp, tw, th);
+             _evas_image_rotate_180(pixels_out, pixels_tmp, tw, th);
               break;
            case EVAS_IMAGE_ORIENT_270:
-              _image_rotate_270(pixels_out, pixels_tmp, tw, th);
+             _evas_image_rotate_270(pixels_out, pixels_tmp, tw, th);
               break;
            case EVAS_IMAGE_FLIP_HORIZONTAL:
-              _image_flip_horizontal(pixels_out, pixels_tmp, tw, th);
+             _evas_image_flip_horizontal(pixels_out, pixels_tmp, tw, th);
               break;
            case EVAS_IMAGE_FLIP_VERTICAL:
-              _image_flip_vertical(pixels_out, pixels_tmp, tw, th);
+             _evas_image_flip_vertical(pixels_out, pixels_tmp, tw, th);
               break;
            case EVAS_IMAGE_FLIP_TRANSPOSE:
-              _image_flip_transpose(pixels_out, pixels_tmp, tw, th);
+             _evas_image_flip_transpose(pixels_out, pixels_tmp, tw, th);
               break;
            case EVAS_IMAGE_FLIP_TRANSVERSE:
-              _image_flip_transverse(pixels_out, pixels_tmp, tw, th);
+             _evas_image_flip_transverse(pixels_out, pixels_tmp, tw, th);
               break;
           }
 
@@ -4374,39 +4383,63 @@ eng_output_idle_flush(void *engine EINA_UNUSED, void *data)
 static Ector_Surface *
 eng_ector_create(void *engine EINA_UNUSED)
 {
-   return NULL;
+   Ector_Surface *ector;
+
+   efl_domain_current_push(EFL_ID_DOMAIN_SHARED);
+   ector = efl_add_ref(ECTOR_SOFTWARE_SURFACE_CLASS, NULL);
+   efl_domain_current_pop();
+   return ector;
 }
 
 static void*
-eng_ector_surface_create(void *engine EINA_UNUSED, int width EINA_UNUSED, int height EINA_UNUSED, int *error EINA_UNUSED)
+eng_ector_surface_create(void *engine, int width, int height, int *error)
 {
-   return NULL;
+   void *surface;
+
+   *error = EINA_FALSE;
+
+   surface = eng_image_new_from_copied_data(engine, width, height, NULL, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
+   if (!surface) *error = EINA_TRUE;
+
+   return surface;
 }
 
 static void
-eng_ector_surface_destroy(void *engine EINA_UNUSED, void *surface EINA_UNUSED)
+eng_ector_surface_destroy(void *engine, void *surface)
 {
+   if (!surface) return;
+   eng_image_free(engine, surface);
 }
 
 static void
-eng_ector_surface_cache_set(void *engine EINA_UNUSED, void *key EINA_UNUSED, void *surface EINA_UNUSED)
+eng_ector_surface_cache_set(void *engine, void *key , void *surface)
 {
+   Render_Engine_Software_Generic *e = engine;
+
+   generic_cache_data_set(e->surface_cache, key, surface);
+
 }
 
 static void *
-eng_ector_surface_cache_get(void *engine EINA_UNUSED, void *key EINA_UNUSED)
+eng_ector_surface_cache_get(void *engine, void *key)
 {
-   return NULL;
+   Render_Engine_Software_Generic *e = engine;
+
+   return generic_cache_data_get(e->surface_cache, key);
 }
 
 static void
-eng_ector_surface_cache_drop(void *engine EINA_UNUSED, void *key EINA_UNUSED)
+eng_ector_surface_cache_drop(void *engine, void *key)
 {
+   Render_Engine_Software_Generic *e = engine;
+
+   generic_cache_data_drop(e->surface_cache, key);
 }
 
 static void
-eng_ector_destroy(void *data EINA_UNUSED, Ector_Surface *ector EINA_UNUSED)
+eng_ector_destroy(void *data EINA_UNUSED, Ector_Surface *ector)
 {
+   if (ector) efl_unref(ector);
 }
 
 static Ector_Buffer *
@@ -4462,17 +4495,186 @@ eng_ector_buffer_new(void *data, Evas *evas, int width, int height,
 }
 
 static void
-eng_ector_renderer_draw(void *engine EINA_UNUSED, void *surface EINA_UNUSED,
-                        void *context EINA_UNUSED, Ector_Renderer *renderer EINA_UNUSED,
-                        Eina_Array *clips EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
+_draw_thread_ector_cleanup(Evas_Thread_Command_Ector *ector)
+{
+   Eina_Rectangle *r;
+
+   while ((r = eina_array_pop(ector->clips)))
+     eina_rectangle_free(r);
+   eina_array_free(ector->clips);
+
+   if (ector->free_it)
+     eina_mempool_free(_mp_command_ector, ector);
+}
+
+static void
+_draw_thread_ector_draw(void *data)
+{
+   Evas_Thread_Command_Ector *ector = data;
+
+   ector_renderer_draw(ector->r, ector->render_op, ector->clips, ector->mul_col);
+
+   _draw_thread_ector_cleanup(ector);
+}
+
+static void
+eng_ector_renderer_draw(void *engine EINA_UNUSED, void *surface,
+                        void *context, Ector_Renderer *renderer,
+                        Eina_Array *clips, Eina_Bool do_async)
+{
+   RGBA_Image *dst = surface;
+   RGBA_Draw_Context *dc = context;
+   Evas_Thread_Command_Ector ector;
+   Eina_Array *c;
+   Eina_Rectangle *r;
+   Eina_Rectangle clip;
+   Eina_Array_Iterator it;
+   unsigned int i;
+
+   if (dc->clip.use)
+     {
+        clip.x = dc->clip.x;
+        clip.y = dc->clip.y;
+        clip.w = dc->clip.w;
+        clip.h = dc->clip.h;
+        // clip the clip rect to surface boundary.
+        RECTS_CLIP_TO_RECT(clip.x, clip.y, clip.w, clip.h, 0, 0, dst->cache_entry.w, dst->cache_entry.h);
+        if ((clip.w < 1) || (clip.h < 1)) return;
+     }
+   else
+     {
+        clip.x = 0;
+        clip.y = 0;
+        clip.w = dst->cache_entry.w;
+        clip.h = dst->cache_entry.h;
+     }
+
+   c = eina_array_new(8);
+   if (clips)
+     {
+        EINA_ARRAY_ITER_NEXT(clips, i, r, it)
+          {
+             Eina_Rectangle *rc;
+
+             rc = eina_rectangle_new(r->x, r->y, r->w, r->h);
+             if (!rc) continue;
+
+             if (eina_rectangle_intersection(rc, &clip))
+               eina_array_push(c, rc);
+             else
+               eina_rectangle_free(rc);
+          }
+
+        if (eina_array_count(c) == 0 &&
+            eina_array_count(clips) > 0)
+          {
+             eina_array_free(c);
+             return;
+          }
+     }
+
+   if (eina_array_count(c) == 0)
+     eina_array_push(c, eina_rectangle_new(clip.x, clip.y, clip.w, clip.h));
+
+   ector.r = renderer; // This has already been refcounted by Evas_Object_VG
+   ector.clips = c;
+   ector.render_op = EFL_GFX_RENDER_OP_BLEND;
+   ector.mul_col = 0xffffffff;
+   ector.free_it = EINA_FALSE;
+
+   if (do_async)
+     {
+        Evas_Thread_Command_Ector *ne;
+
+        ne = eina_mempool_malloc(_mp_command_ector, sizeof (Evas_Thread_Command_Ector));
+        if (!ne)
+          {
+             _draw_thread_ector_cleanup(&ector);
+             return;
+          }
+
+        memcpy(ne, &ector, sizeof (Evas_Thread_Command_Ector));
+        ne->free_it = EINA_TRUE;
+
+        QCMD(_draw_thread_ector_draw, ne);
+     }
+   else
+     {
+        _draw_thread_ector_draw(&ector);
+     }
+}
+
+static void
+_draw_thread_ector_surface_set(void *data)
 {
+   Evas_Thread_Command_Ector_Surface *ector_surface = data;
+   RGBA_Image *surface = ector_surface->pixels;
+   void *pixels = NULL;
+   unsigned int w = 0;
+   unsigned int h = 0;
+   unsigned int x = 0;
+   unsigned int y = 0;
+
+   // flush the cpu pipeline before ector drawing.
+   evas_common_cpu_end_opt();
+
+   if (surface)
+     {
+        pixels = evas_cache_image_pixels(&surface->cache_entry);
+        if (pixels)
+          {
+             w = surface->cache_entry.w;
+             h = surface->cache_entry.h;
+             x = ector_surface->x;
+             y = ector_surface->y;
+             // clear the surface before giving to ector
+             memset(pixels, 0, (w * h * 4));
+          }
+     }
+
+   ector_buffer_pixels_set(ector_surface->ector, pixels, w, h, 0, EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
+   ector_surface_reference_point_set(ector_surface->ector, x, y);
+
+   eina_mempool_free(_mp_command_ector_surface, ector_surface);
 }
 
 static Eina_Bool
-eng_ector_begin(void *engine EINA_UNUSED, void *surface EINA_UNUSED,
-                void *context EINA_UNUSED, Ector_Surface *ector EINA_UNUSED,
-                int x EINA_UNUSED, int y EINA_UNUSED, Eina_Bool do_async EINA_UNUSED)
+eng_ector_begin(void *engine EINA_UNUSED, void *surface,
+                void *context EINA_UNUSED, Ector_Surface *ector,
+                int x, int y, 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 EINA_FALSE;
+
+        nes->ector = ector;
+        nes->pixels = surface;
+        nes->x = x;
+        nes->y = y;
+
+        QCMD(_draw_thread_ector_surface_set, nes);
+     }
+   else
+     {
+        RGBA_Image *sf = surface;
+        void *pixels = NULL;
+        unsigned int w = 0;
+        unsigned int h = 0;
+
+        pixels = evas_cache_image_pixels(&sf->cache_entry);
+        if (!pixels) return EINA_FALSE;
+
+        w = sf->cache_entry.w;
+        h = sf->cache_entry.h;
+        // clear the surface before giving to ector
+        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);
+     }
    return EINA_TRUE;
 }
 
@@ -4480,9 +4682,26 @@ static void
 eng_ector_end(void *engine EINA_UNUSED,
               void *surface EINA_UNUSED,
               void *context EINA_UNUSED,
-              Ector_Surface *ector EINA_UNUSED,
-              Eina_Bool do_async EINA_UNUSED)
+              Ector_Surface *ector,
+              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 ;
+
+        nes->ector = ector;
+        nes->pixels = NULL;
+
+        QCMD(_draw_thread_ector_surface_set, nes);
+     }
+   else
+     {
+        ector_buffer_pixels_set(ector, NULL, 0, 0, 0, EFL_GFX_COLORSPACE_ARGB8888, EINA_TRUE);
+        evas_common_cpu_end_opt();
+     }
 }
 
 //------------------------------------------------//
@@ -5856,10 +6075,17 @@ module_open(Evas_Module *em)
    _mp_command_multi_font =
      eina_mempool_add("chained_mempool", "Evas_Thread_Command_Multi_Font",
                       NULL, sizeof(Evas_Thread_Command_Multi_Font), 128);
+   _mp_command_ector =
+     eina_mempool_add("chained_mempool", "Evas_Thread_Command_Ector",
+                      NULL, sizeof(Evas_Thread_Command_Ector), 128);
+   _mp_command_ector_surface =
+     eina_mempool_add("chained_mempool", "Evas_Thread_Command_Ector_Surface",
+                      NULL, sizeof(Evas_Thread_Command_Ector_Surface), 128);
 
    ector_init();
 // do on demand when first evas_gl_api_get is called...
 //   init_gl();
+   ector_glsym_set(dlsym, RTLD_DEFAULT);
    evas_common_pipe_init();
 
    em->functions = (void *)(&func);
@@ -5877,6 +6103,7 @@ module_close(Evas_Module *em EINA_UNUSED)
    eina_mempool_del(_mp_command_image);
    eina_mempool_del(_mp_command_font);
    eina_mempool_del(_mp_command_map);
+   eina_mempool_del(_mp_command_ector);
    if (_evas_soft_gen_log_dom >= 0)
      {
         eina_log_domain_unregister(_evas_soft_gen_log_dom);