efl/gfx: fix svg path parsing logic.
authorSubhransu Mohanty <sub.mohanty@samsung.com>
Fri, 28 Aug 2015 01:12:44 +0000 (10:12 +0900)
committerCedric BAIL <cedric@osg.samsung.com>
Tue, 20 Oct 2015 22:22:31 +0000 (15:22 -0700)
1. according to svg path specification, path string may or may not contain ',' as the separator
with current parsing logic we were expecting a ',' after each segment.
2. relative cubic bezier parsing was wrong as we were not adding the current value to all 4 points.
3. refactored the parse_pair, parse_six and parse_quad to use same helper function
path1: "M7.279,2h35.442C45.637,2,48,4.359,48,7.271v35.455C48,45.639,45.637,48,42.723,48H7.279C4.362,47.997,2,45.639,2,42.727V7.271C2,4.359,4.362,2,7.279,2z"
path2: "M-2.073-7h36.147C36.796-7,39-4.793,39-2.073v36.146C39,36.796,36.796,39,34.074,39H-2.073C-4.793,39-7,36.796-7,34.072V-2.073C-7-4.793-4.793-7-2.073-7z"

Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
src/lib/efl/interfaces/efl_gfx_shape.c

index b054ca7..6b5d05d 100644 (file)
@@ -873,11 +873,11 @@ _efl_gfx_path_append_vertical_to(Eo *obj, Efl_Gfx_Shape_Data *pd,
 }
 
 static char *
-_strcomma(const char *content)
+_skipcomma(const char *content)
 {
    while (*content && isspace(*content)) content++;
-   if (*content != ',') return NULL;
-   return (char*) content + 1;
+   if (*content == ',') return (char*) content + 1;
+   return (char*) content;
 }
 
 static inline Eina_Bool
@@ -889,21 +889,30 @@ _next_isnumber(const char *content)
    return content != tmp;
 }
 
+static inline Eina_Bool
+_parse_number(char **content, double *number)
+{
+   char *end = NULL;
+   *number = strtod(*content, &end);
+   // if the start of string is not number 
+   if ((*content) == end) return EINA_FALSE;
+   //skip comma if any
+   *content = _skipcomma(end);
+   return EINA_TRUE;
+}
+
 static Eina_Bool
 _efl_gfx_path_parse_pair(const char *content, char **end, double *x, double *y)
 {
-   /* "x,y" */
-   char *end1 = NULL;
-   char *end2 = NULL;
+   char *str = (char *) content;
 
-   *x = strtod(content, &end1);
-   end1 = _strcomma(end1);
-   if (!end1) return EINA_FALSE;
-   *y = strtod(end1, &end2);
-   if (end1 == end2) return EINA_FALSE;
-
-   *end = end2;
-   return EINA_TRUE;
+   if (_parse_number(&str, x))
+     if (_parse_number(&str, y))
+       {
+          *end = str;
+          return EINA_TRUE;
+       }
+   return EINA_FALSE;
 }
 
 static Eina_Bool
@@ -979,31 +988,18 @@ _efl_gfx_path_parse_six(const char *content, char **end,
                         double *ctrl_x0, double *ctrl_y0,
                         double *ctrl_x1, double *ctrl_y1)
 {
-   /* "x,y ctrl_x0,ctrl_y0 ctrl_x1,ctrl_y1" */
-   char *end1 = NULL;
-   char *end2 = NULL;
-
-   *ctrl_x0 = strtod(content, &end1);
-   end1 = _strcomma(end1);
-   if (!end1) return EINA_FALSE;
-   *ctrl_y0 = strtod(end1, &end2);
-   if (end1 == end2) return EINA_FALSE;
-
-   *ctrl_x1 = strtod(end2, &end2);
-   end2 = _strcomma(end2);
-   if (!end2) return EINA_FALSE;
-   *ctrl_y1 = strtod(end2, &end1);
-   if (end1 == end2) return EINA_FALSE;
-
-   *x = strtod(end1, &end2);
-   end2 = _strcomma(end2);
-   if (!end2) return EINA_FALSE;
-   *y = strtod(end2, &end1);
-   if (end1 == end2) return EINA_FALSE;
-
-   *end = end1;
-
-   return EINA_TRUE;
+   char *str = (char *) content;
+   if (_parse_number(&str, ctrl_x0))
+     if (_parse_number(&str, ctrl_y0))
+       if (_parse_number(&str, ctrl_x1))
+         if (_parse_number(&str, ctrl_y1))
+           if (_parse_number(&str, x))
+             if (_parse_number(&str, y))
+               {
+                  *end = str;
+                  return EINA_TRUE;
+               }
+   return EINA_FALSE;
 }
 
 static Eina_Bool
@@ -1030,8 +1026,11 @@ _efl_gfx_path_parse_six_to(const char *content, char **end,
           {
              x += *current_x;
              y += *current_y;
+             ctrl_x0 += *current_x;
+             ctrl_y0 += *current_y;
+             ctrl_x1 += *current_x;
+             ctrl_y1 += *current_y;
           }
-
         func(obj, pd, x, y, ctrl_x0, ctrl_y0, ctrl_x1, ctrl_y1);
         content = *end;
 
@@ -1048,25 +1047,17 @@ _efl_gfx_path_parse_quad(const char *content, char **end,
                          double *x, double *y,
                          double *ctrl_x0, double *ctrl_y0)
 {
-   /* "x,y ctrl_x0,ctrl_y0" */
-   char *end1 = NULL;
-   char *end2 = NULL;
-
-   *ctrl_x0 = strtod(content, &end1);
-   end1 = _strcomma(end1);
-   if (!end1) return EINA_FALSE;
-   *ctrl_y0 = strtod(end1, &end2);
-   if (end1 == end2) return EINA_FALSE;
-
-   *x = strtod(end2, &end1);
-   end1 = _strcomma(end2);
-   if (!end1) return EINA_FALSE;
-   *y = strtod(end1, &end2);
-   if (end1 == end2) return EINA_FALSE;
-
-   *end = end2;
-
-   return EINA_TRUE;
+   char *str = (char *) content;
+
+   if (_parse_number(&str, ctrl_x0))
+     if (_parse_number(&str, ctrl_y0))
+       if (_parse_number(&str, x))
+         if (_parse_number(&str, y))
+           {
+              *end = str;
+              return EINA_TRUE;
+           }
+   return EINA_FALSE;
 }
 
 static Eina_Bool
@@ -1113,34 +1104,32 @@ _efl_gfx_path_parse_arc(const char *content, char **end,
                         double *radius,
                         Eina_Bool *large_arc, Eina_Bool *sweep)
 {
-   /* "rx,ry r large-arc-flag,sweep-flag x,y" */
+   char *str = (char *) content;
    char *end1 = NULL;
    char *end2 = NULL;
 
-   *rx = strtod(content, &end1);
-   end1 = _strcomma(end1);
-   if (!end1) return EINA_FALSE;
-   *ry = strtod(end1, &end2);
-   if (end1 == end2) return EINA_FALSE;
-
-   *radius = strtod(end2, &end1);
-   if (end1 == end2) return EINA_FALSE;
-
-   *large_arc = strtol(end1, &end2, 10) ? EINA_TRUE : EINA_FALSE;
-   end1 = _strcomma(end2);
-   if (!end1) return EINA_FALSE;
-   *sweep = strtol(end1, &end2, 10) ? EINA_TRUE : EINA_FALSE;
-   if (end1 == end2) return EINA_FALSE;
-
-   *x = strtod(end2, &end1);
-   end1 = _strcomma(end2);
-   if (!end1) return EINA_FALSE;
-   *y = strtod(end1, &end2);
-   if (end1 == end2) return EINA_FALSE;
-
-   *end = end2;
-
-   return EINA_TRUE;
+   if (_parse_number(&str, rx))
+     if (_parse_number(&str, ry))
+       if (_parse_number(&str, radius))
+         {
+            // large_arc
+            *large_arc = strtol(str, &end1, 10) ? EINA_TRUE : EINA_FALSE;
+            if (!end1 || (str == end1)) return EINA_FALSE;
+            end1 = _skipcomma(end1);
+
+            // sweeo
+            *sweep = strtol(end2, &end1, 10) ? EINA_TRUE : EINA_FALSE;
+            if (!end1 || (end1 == end2)) return EINA_FALSE;
+            str = _skipcomma(end1);
+
+            if (_parse_number(&str, x))
+              if (_parse_number(&str, y))
+                {
+                   *end = str;
+                   return EINA_TRUE;
+                }
+         }
+   return EINA_FALSE;
 }
 
 static Eina_Bool
@@ -1367,7 +1356,7 @@ _efl_gfx_shape_append_svg_path(Eo *obj, Efl_Gfx_Shape_Data *pd,
                 return ;
               break;
            default:
-              return ;
+              return;
           }
      }
 }