#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
--- /dev/null
+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]]
+ }
+ }
+}
--- /dev/null
+#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"
--- /dev/null
+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; }
+ }
+}
--- /dev/null
+#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"
--- /dev/null
+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; }
+ }
+}
--- /dev/null
+#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"
--- /dev/null
+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;
+ }
+}
--- /dev/null
+#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"
--- /dev/null
+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;
+ }
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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, ¤t_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, ¶ms);
+
+ // 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);
+}
--- /dev/null
+#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"
--- /dev/null
+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;
+ }
+}
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
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
#
#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"
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;
#include "region.h"
+#include <software/Ector_Software.h>
#include "evas_ector_software.h"
#include "draw.h"
#include "evas_filter_private.h"
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);
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;
/*
*****
**
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;
}
}
-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;
}
}
-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;
}
}
-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;
}
}
-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;
}
}
-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;
}
}
-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;
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");
(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)) ||
(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
{
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");
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;
}
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 *
}
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;
}
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();
+ }
}
//------------------------------------------------//
_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);
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);