ector: refactored shape generation in software backend.
authorSubhransu Mohanty <sub.mohanty@samsung.com>
Mon, 17 Aug 2015 05:26:40 +0000 (14:26 +0900)
committerCedric BAIL <cedric@osg.samsung.com>
Wed, 19 Aug 2015 13:02:53 +0000 (15:02 +0200)
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/lib/ector/software/ector_renderer_software_shape.c

index 1c985d4..2ea12ee 100644 (file)
@@ -30,18 +30,38 @@ typedef struct _Outline
    int contours_alloc;
 }Outline;
 
+
+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->ft_outline.points = (SW_FT_Vector *) calloc(50, sizeof(SW_FT_Vector));
-   outline->ft_outline.tags = (char *) calloc(50, sizeof(char));
-
-   outline->ft_outline.contours = (short *) calloc(5, sizeof(short));
-
-   outline->points_alloc = 50;
-   outline->contours_alloc = 5;
+   outline->points_alloc = 0;
+   outline->contours_alloc = 0;
+   _grow_outline_contour(outline, 1);
+   _grow_outline_points(outline, 1);
    return outline;
 }
 
@@ -63,17 +83,14 @@ _outline_move_to(Outline *outline, double x, double y)
 {
    SW_FT_Outline *ft_outline = &outline->ft_outline;
 
-   if (ft_outline->n_contours == outline->contours_alloc)
-     {
-        outline->contours_alloc += 5;
-        ft_outline->contours = (short *) realloc(ft_outline->contours, outline->contours_alloc * sizeof(short));
-     }
+   _grow_outline_points(outline, 1);
    ft_outline->points[ft_outline->n_points].x = x;
    ft_outline->points[ft_outline->n_points].y = 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++;
      }
@@ -86,11 +103,7 @@ _outline_end(Outline *outline)
 {
    SW_FT_Outline *ft_outline = &outline->ft_outline;
 
-   if (ft_outline->n_contours == outline->contours_alloc)
-     {
-        outline->contours_alloc += 1;
-        ft_outline->contours = (short *) realloc(ft_outline->contours, outline->contours_alloc * sizeof(short));
-     }
+   _grow_outline_contour(outline, 1);
 
    if (ft_outline->n_points)
      {
@@ -104,12 +117,7 @@ static void  _outline_line_to(Outline *outline, double x, double y)
 {
    SW_FT_Outline *ft_outline = &outline->ft_outline;
 
-   if (ft_outline->n_points == outline->points_alloc)
-     {
-        outline->points_alloc += 50;
-        ft_outline->points = (SW_FT_Vector *) realloc(ft_outline->points, outline->points_alloc * sizeof(SW_FT_Vector));
-        ft_outline->tags = (char *) realloc(ft_outline->tags, outline->points_alloc * sizeof(char));
-     }
+   _grow_outline_points(outline, 1);
    ft_outline->points[ft_outline->n_points].x = x;
    ft_outline->points[ft_outline->n_points].y = y;
    ft_outline->tags[ft_outline->n_points] = SW_FT_CURVE_TAG_ON;
@@ -141,16 +149,12 @@ _outline_close_path(Outline *outline)
 }
 
 
-static void  _outline_cubic_to(Outline *outline, double cx1, double cy1, double cx2, double cy2, double x, double y)
+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;
 
-   if (ft_outline->n_points == outline->points_alloc)
-     {
-        outline->points_alloc += 50;
-        ft_outline->points = (SW_FT_Vector *) realloc(ft_outline->points, outline->points_alloc * sizeof(SW_FT_Vector));
-        ft_outline->tags = (char *) realloc(ft_outline->tags, outline->points_alloc * sizeof(char));
-     }
+   _grow_outline_points(outline, 3);
 
    ft_outline->points[ft_outline->n_points].x = cx1;
    ft_outline->points[ft_outline->n_points].y = cy1;
@@ -171,14 +175,17 @@ static void  _outline_cubic_to(Outline *outline, double cx1, double cy1, double
 static void _outline_transform(Outline *outline, Eina_Matrix3 *m)
 {
    int i;
+   double x, y;
    SW_FT_Outline *ft_outline = &outline->ft_outline;
 
    if (m)
      {
-        double x, y;
         for (i = 0; i < ft_outline->n_points; i++)
           {
-             eina_matrix3_point_transform(m, ft_outline->points[i].x, ft_outline->points[i].y, &x, &y);
+             eina_matrix3_point_transform(m,
+                                          ft_outline->points[i].x,
+                                          ft_outline->points[i].y,
+                                          &x, &y);
              ft_outline->points[i].x = (int)(x * 64);// to freetype 26.6 coordinate.
              ft_outline->points[i].y = (int)(y * 64);
           }
@@ -193,98 +200,145 @@ static void _outline_transform(Outline *outline, Eina_Matrix3 *m)
      }
 }
 
-
 static Eina_Bool
-_ector_renderer_software_shape_ector_renderer_generic_base_prepare(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+_generate_outline(const Efl_Gfx_Path_Command *cmds, const double *pts, Outline * outline)
 {
-   const Efl_Gfx_Path_Command *cmds = NULL;
-   const double *pts = NULL;
+   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:
 
-   // FIXME: shouldn't that be part of the shape generic implementation ?
-   if (pd->shape->fill)
-     eo_do(pd->shape->fill, ector_renderer_prepare());
-   if (pd->shape->stroke.fill)
-     eo_do(pd->shape->stroke.fill, ector_renderer_prepare());
-   if (pd->shape->stroke.marker)
-     eo_do(pd->shape->stroke.marker, ector_renderer_prepare());
+               _outline_move_to(outline, pts[0], pts[1]);
 
-   // shouldn't that be moved to the software base object
-   if (!pd->surface)
-     {
-        Eo *parent;
-        eo_do(obj, parent = eo_parent_get());
-        if (!parent) return EINA_FALSE;
-        pd->surface = eo_data_xref(parent, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
-        if (!pd->surface) return EINA_FALSE;
-     }
+               pts += 2;
+               break;
+            case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
 
-   eo_do(obj, efl_gfx_shape_path_get(&cmds, &pts));
-   if (!pd->shape_data && cmds)
-     {
-        Eina_Bool close_path = EINA_FALSE;
-        Outline * outline = _outline_create();
+               _outline_line_to(outline, pts[0], pts[1]);
 
-        for (; *cmds != EFL_GFX_PATH_COMMAND_TYPE_END; cmds++)
-          {
-             switch (*cmds)
-               {
-                case EFL_GFX_PATH_COMMAND_TYPE_MOVE_TO:
+               pts += 2;
+               break;
+            case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
 
-                   _outline_move_to(outline, pts[0], pts[1]);
+               // Be careful, we do have a different order than
+               // cairo, first is destination point, followed by
+               // the control point. The opposite of cairo.
+               _outline_cubic_to(outline,
+                                 pts[2], pts[3], pts[4], pts[5], // control points
+                                 pts[0], pts[1]); // destination point
+               pts += 6;
+               break;
 
-                   pts += 2;
-                   break;
-                case EFL_GFX_PATH_COMMAND_TYPE_LINE_TO:
+            case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
 
-                   _outline_line_to(outline, pts[0], pts[1]);
+               close_path = _outline_close_path(outline);
+               break;
 
-                   pts += 2;
-                   break;
-                case EFL_GFX_PATH_COMMAND_TYPE_CUBIC_TO:
+            case EFL_GFX_PATH_COMMAND_TYPE_LAST:
+            case EFL_GFX_PATH_COMMAND_TYPE_END:
+               break;
+          }
+     }
+   _outline_end(outline);
+   return close_path;
+}
 
-                   // Be careful, we do have a different order than
-                   // cairo, first is destination point, followed by
-                   // the control point. The opposite of cairo.
-                   _outline_cubic_to(outline,
-                                     pts[2], pts[3], pts[4], pts[5], // control points
-                                     pts[0], pts[1]); // destination point
-                   pts += 6;
-                   break;
+static Eina_Bool
+_generate_stroke_data(Ector_Renderer_Software_Shape_Data *pd)
+{
+   if (pd->outline_data) return EINA_FALSE;
 
-                case EFL_GFX_PATH_COMMAND_TYPE_CLOSE:
+   if (!pd->shape->stroke.fill &&
+       ((pd->shape->stroke.color.a == 0) ||
+        (pd->shape->stroke.width < 0.01)))
+     return EINA_FALSE;
 
-                   close_path = _outline_close_path(outline);
-                   break;
+   return EINA_TRUE;
+}
 
-                case EFL_GFX_PATH_COMMAND_TYPE_LAST:
-                case EFL_GFX_PATH_COMMAND_TYPE_END:
-                   break;
-               }
-          }
+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 void 
+_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+{
+   const Efl_Gfx_Path_Command *cmds = NULL;
+   const double *pts = NULL;
+   Eina_Bool close_path;
+   Outline *outline, *dash_outline;
 
-        _outline_end(outline);
+   eo_do(obj, efl_gfx_shape_path_get(&cmds, &pts));
+   if (cmds && (_generate_stroke_data(pd) || _generate_shape_data(pd)))
+     {
+        outline = _outline_create();
+        close_path = _generate_outline(cmds, pts, outline);
         _outline_transform(outline, pd->base->m);
 
-        // generate the shape data.
-        pd->shape_data = ector_software_rasterizer_generate_rle_data(pd->surface->software, &outline->ft_outline);
-        if (!pd->outline_data)
+        //shape data generation 
+        if (_generate_shape_data(pd))
+          pd->shape_data = ector_software_rasterizer_generate_rle_data(pd->surface->software,
+                                                                       &outline->ft_outline);
+
+        //stroke data generation
+        if ( _generate_stroke_data(pd))
           {
-             ector_software_rasterizer_stroke_set(pd->surface->software, (pd->shape->stroke.width * pd->shape->stroke.scale), pd->shape->stroke.cap,
+             ector_software_rasterizer_stroke_set(pd->surface->software,
+                                                  (pd->shape->stroke.width *
+                                                   pd->shape->stroke.scale),
+                                                  pd->shape->stroke.cap,
                                                   pd->shape->stroke.join);
-             pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->software, &outline->ft_outline, close_path);
+              pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->software,
+                                                                                    &outline->ft_outline,
+                                                                                    close_path);
           }
-
         _outline_destroy(outline);
      }
+}
+
+static Eina_Bool
+_ector_renderer_software_shape_ector_renderer_generic_base_prepare(Eo *obj,
+                                                                   Ector_Renderer_Software_Shape_Data *pd)
+{
+   // FIXME: shouldn't that be part of the shape generic implementation ?
+   if (pd->shape->fill)
+     eo_do(pd->shape->fill, ector_renderer_prepare());
+   if (pd->shape->stroke.fill)
+     eo_do(pd->shape->stroke.fill, ector_renderer_prepare());
+   if (pd->shape->stroke.marker)
+     eo_do(pd->shape->stroke.marker, ector_renderer_prepare());
 
+   // shouldn't that be moved to the software base object
+   if (!pd->surface)
+     {
+        Eo *parent;
+        eo_do(obj, parent = eo_parent_get());
+        if (!parent) return EINA_FALSE;
+        pd->surface = eo_data_xref(parent, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
+        if (!pd->surface) return EINA_FALSE;
+     }
    return EINA_TRUE;
 }
 
 static Eina_Bool
-_ector_renderer_software_shape_ector_renderer_generic_base_draw(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Shape_Data *pd, Ector_Rop op, Eina_Array *clips, unsigned int mul_col)
+_ector_renderer_software_shape_ector_renderer_generic_base_draw(Eo *obj,
+                                                                Ector_Renderer_Software_Shape_Data *pd,
+                                                                Ector_Rop op, Eina_Array *clips,
+                                                                unsigned int mul_col)
 {
    int x, y;
 
+   // do lazy creation of rle
+   _update_rle(obj, pd);
+
    // adjust the offset
    x = pd->surface->x + (int)pd->base->origin.x;
    y = pd->surface->y + (int)pd->base->origin.y;
@@ -296,30 +350,44 @@ _ector_renderer_software_shape_ector_renderer_generic_base_draw(Eo *obj EINA_UNU
    if (pd->shape->fill)
      {
         eo_do(pd->shape->fill, ector_renderer_software_base_fill());
-        ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->shape_data);
+        ector_software_rasterizer_draw_rle_data(pd->surface->software,
+                                                x, y, mul_col, op,
+                                                pd->shape_data);
      }
    else
      {
         if (pd->base->color.a > 0)
           {
-             ector_software_rasterizer_color_set(pd->surface->software, pd->base->color.r, pd->base->color.g, pd->base->color.b, pd->base->color.a);
-             ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->shape_data);
+             ector_software_rasterizer_color_set(pd->surface->software,
+                                                 pd->base->color.r,
+                                                 pd->base->color.g,
+                                                 pd->base->color.b,
+                                                 pd->base->color.a);
+             ector_software_rasterizer_draw_rle_data(pd->surface->software,
+                                                     x, y, mul_col, op,
+                                                     pd->shape_data);
           }
      }
 
    if (pd->shape->stroke.fill)
      {
         eo_do(pd->shape->stroke.fill, ector_renderer_software_base_fill());
-        ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->outline_data);
+        ector_software_rasterizer_draw_rle_data(pd->surface->software,
+                                                x, y, mul_col, op,
+                                                pd->outline_data);
      }
    else
      {
         if (pd->shape->stroke.color.a > 0)
           {
              ector_software_rasterizer_color_set(pd->surface->software,
-                                                 pd->shape->stroke.color.r, pd->shape->stroke.color.g,
-                                                 pd->shape->stroke.color.b, pd->shape->stroke.color.a);
-             ector_software_rasterizer_draw_rle_data(pd->surface->software, x, y, mul_col, op, pd->outline_data);
+                                                 pd->shape->stroke.color.r,
+                                                 pd->shape->stroke.color.g,
+                                                 pd->shape->stroke.color.b,
+                                                 pd->shape->stroke.color.a);
+             ector_software_rasterizer_draw_rle_data(pd->surface->software,
+                                                     x, y, mul_col, op,
+                                                     pd->outline_data);
           }
      }
 
@@ -327,7 +395,8 @@ _ector_renderer_software_shape_ector_renderer_generic_base_draw(Eo *obj EINA_UNU
 }
 
 static Eina_Bool
-_ector_renderer_software_shape_ector_renderer_software_base_fill(Eo *obj EINA_UNUSED, Ector_Renderer_Software_Shape_Data *pd EINA_UNUSED)
+_ector_renderer_software_shape_ector_renderer_software_base_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.
@@ -335,8 +404,10 @@ _ector_renderer_software_shape_ector_renderer_software_base_fill(Eo *obj EINA_UN
 }
 
 static void
-_ector_renderer_software_shape_efl_gfx_shape_path_set(Eo *obj, Ector_Renderer_Software_Shape_Data *pd,
-                                                      const Efl_Gfx_Path_Command *op, const double *points)
+_ector_renderer_software_shape_efl_gfx_shape_path_set(Eo *obj,
+                                                      Ector_Renderer_Software_Shape_Data *pd,
+                                                      const Efl_Gfx_Path_Command *op,
+                                                      const double *points)
 {
    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);
@@ -348,7 +419,8 @@ _ector_renderer_software_shape_efl_gfx_shape_path_set(Eo *obj, Ector_Renderer_So
 
 
 static Eina_Bool
-_ector_renderer_software_shape_path_changed(void *data, Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
+_ector_renderer_software_shape_path_changed(void *data, Eo *obj EINA_UNUSED,
+                                            const Eo_Event_Description *desc EINA_UNUSED,
                                             void *event_info EINA_UNUSED)
 {
    Ector_Renderer_Software_Shape_Data *pd = data;