diff options
author | Vitalii Vorobiov <vi.vorobiov@samsung.com> | 2017-02-17 17:00:01 +0200 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-11-07 11:54:09 +0900 |
commit | 405e56ac553db21f3e53d1702cc3db3863142811 (patch) | |
tree | c6ac76c18686aa95ce975234d8bb7946f4dc9e2a | |
parent | 6139aa78d5a48166a235087ecc49942b969b09af (diff) | |
download | efl-405e56ac553db21f3e53d1702cc3db3863142811.tar.gz |
svg_parse: parse linear gradient variables accroding to gradientUnits
There are difficult cases according to
https://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html
-rw-r--r-- | src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c | 137 | ||||
-rw-r--r-- | src/static_libs/vg_common/vg_common.h | 19 |
2 files changed, 146 insertions, 10 deletions
diff --git a/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c b/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c index 636b27fcb9..ff1b2d8e2d 100644 --- a/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c +++ b/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c @@ -42,6 +42,7 @@ typedef struct { int x, y, width, height; } global; struct { + Eina_Bool x1_percent, x2_percent, y1_percent, y2_percent; Eina_Bool fx_parsed; Eina_Bool fy_parsed; } gradient; @@ -126,6 +127,48 @@ _to_double(const char *str, SVG_Parser_Length_Type type) return parsed_value; } +/** + * Turn gradient variables into percentages + */ +static inline double +_gradient_to_double(const char *str, SVG_Parser_Length_Type type) +{ + char *end = NULL; + + double parsed_value = strtod(str, &end); + double max = 1; + + /* unique case, if that is percentage, just return it */ + if (strstr(str, "%")) + { + parsed_value = parsed_value / 100.0; + return parsed_value; + } + + if (type == SVG_PARSER_LENGTH_VERTICAL) + max = svg_parse.global.height; + else if (type == SVG_PARSER_LENGTH_HORIZONTAL) + max = svg_parse.global.width; + //TODO: what about radial? + + if (strstr(str, "cm")) + parsed_value = parsed_value * 35.43307; + else if (strstr(str, "mm")) + parsed_value = parsed_value * 3.543307; + else if (strstr(str, "pt")) + parsed_value = parsed_value * 1.25; + else if (strstr(str, "pc")) + parsed_value = parsed_value * 15; + else if (strstr(str, "in")) + parsed_value = parsed_value * 90; + //TODO: implement 'em', 'ex' attributes + + /* Transform into global percentage */ + parsed_value = parsed_value / max; + + return parsed_value; +} + static inline int _to_offset(const char *str) { @@ -1046,7 +1089,7 @@ _create_path_node(Svg_Node *parent, const char *buf, unsigned buflen) } #define CIRCLE_DEF(Name, Field, Type) \ - { #Name, sizeof (#Name), offsetof(Svg_Circle_Node, Field)} + { #Name, Type, sizeof (#Name), offsetof(Svg_Circle_Node, Field)} static const struct { const char *tag; @@ -1105,7 +1148,7 @@ _create_circle_node(Svg_Node *parent, const char *buf, unsigned buflen) } #define ELLIPSE_DEF(Name, Field, Type) \ - { #Name, Type, sizeof (#Name), offsetof(Svg_Ellipse_Node, Field)} + { #Name, Type, sizeof (#Name) + sizeof (Type), offsetof(Svg_Ellipse_Node, Field)} static const struct { const char *tag; @@ -1259,7 +1302,7 @@ _create_polyline_node(Svg_Node *parent, const char *buf, unsigned buflen) } #define RECT_DEF(Name, Field, Type) \ - { #Name, Type, sizeof (#Name), offsetof(Svg_Rect_Node, Field)} + { #Name, Type, sizeof (#Name) + sizeof(Type), offsetof(Svg_Rect_Node, Field)} static const struct { const char *tag; @@ -1325,7 +1368,7 @@ _create_rect_node(Svg_Node *parent, const char *buf, unsigned buflen) } #define LINE_DEF(Name, Field, Type) \ - { #Name, Type, sizeof (#Name), offsetof(Svg_Line_Node, Field)} + { #Name, Type, sizeof (#Name) + sizeof (Type), offsetof(Svg_Line_Node, Field)} static const struct { const char *tag; @@ -1779,37 +1822,96 @@ _attr_parse_stops(void *data, const char *key, const char *value) static void _handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value) { - linear->x1 = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL); + linear->x1 = _gradient_to_double(value, SVG_PARSER_LENGTH_HORIZONTAL); + if (strstr(value, "%")) + svg_parse.gradient.x1_percent = EINA_TRUE; } static void _handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value) { - linear->y1 = _to_double(value, SVG_PARSER_LENGTH_VERTICAL); + linear->y1 = _gradient_to_double(value, SVG_PARSER_LENGTH_VERTICAL); + if (strstr(value, "%")) + svg_parse.gradient.y1_percent = EINA_TRUE; } static void _handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value) { - linear->x2 = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL); + linear->x2 = _gradient_to_double(value, SVG_PARSER_LENGTH_HORIZONTAL); + /* checking if there are no percentage because x2 have default value + * already set in percentages (100%) */ + if (!strstr(value, "%")) + svg_parse.gradient.x2_percent = EINA_FALSE; } static void _handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value) { - linear->y2 = _to_double(value, SVG_PARSER_LENGTH_VERTICAL); + linear->y2 = _gradient_to_double(value, SVG_PARSER_LENGTH_VERTICAL); + if (strstr(value, "%")) + svg_parse.gradient.y2_percent = EINA_TRUE; +} + +static void +_recalc_linear_x1_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space) +{ + if (!svg_parse.gradient.x1_percent && !user_space) + { + /* Since previous percentage is not required (it was already percent) + * so oops and make it all back */ + linear->x1 = linear->x1 * svg_parse.global.width; + } + svg_parse.gradient.x1_percent = EINA_FALSE; +} + +static void +_recalc_linear_y1_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space) +{ + if (!svg_parse.gradient.y1_percent && !user_space) + { + /* Since previous percentage is not required (it was already percent) + * so oops and make it all back */ + linear->y1 = linear->y1 * svg_parse.global.height; + } + svg_parse.gradient.y1_percent = EINA_FALSE; +} + +static void +_recalc_linear_x2_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space) +{ + if (!svg_parse.gradient.x2_percent && !user_space) + { + /* Since previous percentage is not required (it was already percent) + * so oops and make it all back */ + linear->x2 = linear->x2 * svg_parse.global.width; + } + svg_parse.gradient.x2_percent = EINA_FALSE; } +static void +_recalc_linear_y2_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space) +{ + if (!svg_parse.gradient.y2_percent && !user_space) + { + /* Since previous percentage is not required (it was already percent) + * so oops and make it all back */ + linear->y2 = linear->y2 * svg_parse.global.height; + } + svg_parse.gradient.y2_percent = EINA_FALSE; +} typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value); +typedef void (*Linear_Method_Recalc)(Svg_Linear_Gradient *linear, Eina_Bool user_space); #define LINEAR_DEF(Name) \ - { #Name, sizeof (#Name), _handle_linear_##Name##_attr} + { #Name, sizeof (#Name), _handle_linear_##Name##_attr, _recalc_linear_##Name##_attr} static const struct { const char *tag; int sz; Linear_Method tag_handler;; + Linear_Method_Recalc tag_recalc;; } linear_tags[] = { LINEAR_DEF(x1), LINEAR_DEF(y1), @@ -1856,18 +1958,33 @@ static Svg_Style_Gradient * _create_linearGradient(const char *buf, unsigned buflen) { Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient)); + unsigned int i; grad->type = SVG_LINEAR_GRADIENT; grad->linear = calloc(1, sizeof(Svg_Linear_Gradient)); + /** + * Default value of x2 is 100% + */ + grad->linear->x2 = 1; + svg_parse.gradient.x2_percent = EINA_TRUE; eina_simple_xml_attributes_parse(buf, buflen, _attr_parse_linear_gradient_node, grad); - return grad; + for (i = 0; i < sizeof (linear_tags) / sizeof(linear_tags[0]); i++) + linear_tags[i].tag_recalc(grad->linear, grad->user_space); + + return grad; } #define GRADIENT_DEF(Name) \ { #Name, sizeof (#Name), _create_##Name } +/** + * For all Gradients lengths would be calculated into percentages related to + * canvas width and height. + * + * if user then recalculate actual pixels into percentages + */ static const struct { const char *tag; int sz; diff --git a/src/static_libs/vg_common/vg_common.h b/src/static_libs/vg_common/vg_common.h index 65c70a89a9..174cb2003e 100644 --- a/src/static_libs/vg_common/vg_common.h +++ b/src/static_libs/vg_common/vg_common.h @@ -176,6 +176,25 @@ struct _Svg_Radial_Gradient double r; }; +/** + * IMPORTANT! + * Talking about parsing gradient variables + * + * All variables (like x1,x2,y1,y2,fx,fy,rx,ry,r, etc) would be percentages + * and then all recalculations would be done after that if userSpaceOnUse + * is set or not (recalculation depends on that). + * + * If gradientUnits="userSpaceOnUse" (grad->user_space is set to true) + * > Gradient variables (x1,x2,r,fx etc) contains percentages of entire cavas + * > size. + * + * If gradientUnits="objectBoundingBox" (grad->user_space is set to false) + * > Gradient variables (x1,x2,r,fx etc) contain percentages of 'whatever' + * > figure. + * + * So later on, while using gradient, please be careful and + * check user_space to use and transform sizes correctly. + */ struct _Svg_Style_Gradient { Svg_Gradient_Type type; |