From 2c341ded27a9f3540bcba77bc4e669d889311676 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Mon, 27 Nov 2023 17:03:15 +0100 Subject: [PATCH 01/15] Attribute for fill-opacity. --- lib/svg_f.ml | 6 ++++-- lib/svg_sigs.mli | 4 ++++ test/test_ppx.ml | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/svg_f.ml b/lib/svg_f.ml index 3a6a13ff5..9b250ee9c 100644 --- a/lib/svg_f.ml +++ b/lib/svg_f.ml @@ -368,7 +368,7 @@ struct let a_fy = user_attrib string_of_coord "fy" let a_offset x = - user_attrib C.string_of_offset "offset" x + user_attrib C.string_of_number_or_percentage "offset" x let a_patternUnits x = user_attrib C.string_of_big_variant "patternUnits" x @@ -539,6 +539,8 @@ struct let a_animation_fill x = user_attrib C.string_of_big_variant "fill" x + let a_fill_opacity = user_attrib C.string_of_number_or_percentage "fill-opacity" + let a_fill_rule = user_attrib C.string_of_fill_rule "fill-rule" let a_calcMode x = @@ -1104,7 +1106,7 @@ struct let string_of_numbers_semicolon = list ~sep:"; " string_of_number - let string_of_offset = function + let string_of_number_or_percentage = function | `Number x -> string_of_number x | `Percentage x -> string_of_percentage x diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index 94bf76ed7..c10ee1cea 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -488,6 +488,10 @@ module type T = sig val a_animation_fill : [< | `Freeze | `Remove ] wrap -> [> | `Fill_Animation ] attrib [@@reflect.attribute "fill" ["animate"]] + val a_fill_opacity : + [< `Number of number | `Percentage of percentage ] wrap -> + [> | `Fill_opacity ] attrib + val a_fill_rule : fill_rule wrap -> [> | `Fill_rule ] attrib val a_calcMode : diff --git a/test/test_ppx.ml b/test/test_ppx.ml index b521aada4..8861823fd 100644 --- a/test/test_ppx.ml +++ b/test/test_ppx.ml @@ -416,6 +416,10 @@ let svg = "svg", SvgTests.make Svg.[ [[%svg ""]], [animate ~a:[a_animation_fill `Freeze; a_animation_values ["1"; "2"]] []] ; + "fill_opacity, circle", + [[%svg ""]], + [rect ~a:[a_cx (50., None); a_cy (50., None); a_r (50., None); a_fill_opacity (`Number 0.5)] []] ; + "fill_rule type nonzero", [[%svg ""]], [path ~a:[a_fill_rule `Nonzero] []] ; From 7478b52efea09f873f22a87c44cc1c8872316d57 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Mon, 27 Nov 2023 17:14:40 +0100 Subject: [PATCH 02/15] Missing declaration in lib/svg_sigs.mli. --- lib/svg_sigs.mli | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index c10ee1cea..21d931172 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -1111,7 +1111,8 @@ module type Wrapped_functions = sig val string_of_numbers_semicolon : (float list, string) Xml.W.ft - val string_of_offset : ([< Svg_types.offset], string) Xml.W.ft + val string_of_number_or_percentage : + ([< `Number of number | `Percentage of percentage ], string) Xml.W.ft val string_of_orient : (Svg_types.Unit.angle option, string) Xml.W.ft From a496fd185f4f211396dc1aa2dd901d345ad5851c Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Wed, 29 Nov 2023 14:37:28 +0100 Subject: [PATCH 03/15] Reverting the merging of opacity with offset. Opacity now takes a number. --- lib/svg_f.ml | 15 ++++++++++----- lib/svg_sigs.mli | 9 ++++----- test/test_ppx.ml | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/svg_f.ml b/lib/svg_f.ml index 9b250ee9c..052a9f97f 100644 --- a/lib/svg_f.ml +++ b/lib/svg_f.ml @@ -368,7 +368,7 @@ struct let a_fy = user_attrib string_of_coord "fy" let a_offset x = - user_attrib C.string_of_number_or_percentage "offset" x + user_attrib C.string_of_offset "offset" x let a_patternUnits x = user_attrib C.string_of_big_variant "patternUnits" x @@ -539,7 +539,7 @@ struct let a_animation_fill x = user_attrib C.string_of_big_variant "fill" x - let a_fill_opacity = user_attrib C.string_of_number_or_percentage "fill-opacity" + let a_fill_opacity = user_attrib C.string_of_opacity "fill-opacity" let a_fill_rule = user_attrib C.string_of_fill_rule "fill-rule" @@ -713,9 +713,12 @@ struct let a_ontouchmove = Xml.touch_event_handler_attrib "ontouchmove" let a_ontouchcancel = Xml.touch_event_handler_attrib "ontouchcancel" + + let a_opacity = user_attrib C.string_of_opacity "opacity" + let a_stop_color = color_attrib "stop-color" - let a_stop_opacity = user_attrib C.string_of_number "stop-opacity" + let a_stop_opacity = user_attrib C.string_of_opacity "stop-opacity" let a_stroke = user_attrib C.string_of_paint "stroke" @@ -737,7 +740,7 @@ struct user_attrib C.string_of_length "stroke-dashoffset" let a_stroke_opacity = - user_attrib C.string_of_number "stroke-opacity" + user_attrib C.string_of_opacity "stroke-opacity" (* xlink namespace given a nickname since some attributes mandated by the svg standard such as xlink:href live in that namespace, and we @@ -1106,7 +1109,7 @@ struct let string_of_numbers_semicolon = list ~sep:"; " string_of_number - let string_of_number_or_percentage = function + let string_of_offset = function | `Number x -> string_of_number x | `Percentage x -> string_of_percentage x @@ -1116,6 +1119,8 @@ struct let string_of_paint = string_of_paint + let string_of_opacity = string_of_number + let string_of_fill_rule = string_of_fill_rule let string_of_strokedasharray = function diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index 21d931172..949ca3b07 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -488,9 +488,7 @@ module type T = sig val a_animation_fill : [< | `Freeze | `Remove ] wrap -> [> | `Fill_Animation ] attrib [@@reflect.attribute "fill" ["animate"]] - val a_fill_opacity : - [< `Number of number | `Percentage of percentage ] wrap -> - [> | `Fill_opacity ] attrib + val a_fill_opacity : number wrap -> [> | `Fill_opacity ] attrib val a_fill_rule : fill_rule wrap -> [> | `Fill_rule ] attrib @@ -637,6 +635,8 @@ module type T = sig | `Text_after_edge | `Text_before_edge | `Inherit ] wrap -> [> | `Dominant_Baseline ] attrib + val a_opacity : number wrap -> [> | `Opacity ] attrib + val a_stop_color : color wrap -> [> | `Stop_Color ] attrib val a_stop_opacity : number wrap -> [> | `Stop_Opacity ] attrib @@ -1111,8 +1111,7 @@ module type Wrapped_functions = sig val string_of_numbers_semicolon : (float list, string) Xml.W.ft - val string_of_number_or_percentage : - ([< `Number of number | `Percentage of percentage ], string) Xml.W.ft + val string_of_offset : ([< Svg_types.offset], string) Xml.W.ft val string_of_orient : (Svg_types.Unit.angle option, string) Xml.W.ft diff --git a/test/test_ppx.ml b/test/test_ppx.ml index 8861823fd..23401b064 100644 --- a/test/test_ppx.ml +++ b/test/test_ppx.ml @@ -418,7 +418,7 @@ let svg = "svg", SvgTests.make Svg.[ "fill_opacity, circle", [[%svg ""]], - [rect ~a:[a_cx (50., None); a_cy (50., None); a_r (50., None); a_fill_opacity (`Number 0.5)] []] ; + [rect ~a:[a_cx (50., None); a_cy (50., None); a_r (50., None); a_fill_opacity 0.5] []] ; "fill_rule type nonzero", [[%svg ""]], From 1efb435864623a0303e3ee9c4acb10630d393b6e Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Wed, 29 Nov 2023 14:43:11 +0100 Subject: [PATCH 04/15] Adding parser for fill-opacity. --- syntax/attribute_value.ml | 25 +++++++++++++++++++++++++ syntax/attribute_value.mli | 6 ++++++ 2 files changed, 31 insertions(+) diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 4630d6e11..0482eb17b 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -484,6 +484,31 @@ let paint ?separated_by:_ ?default:_ loc name s = `Icc ([%e iri], Some [%e paint_without_icc loc name remainder])] end [@metaloc loc] +let fill_opacity = + let bad_form name loc = + Common.error loc "Value of %s must be a number or percentage" name in + + let regexp = Re_str.regexp "\\([-+0-9eE.]+\\)\\(%\\)?" in + + fun ?separated_by:_ ?default:_ loc name s -> + if not @@ does_match regexp s then bad_form name loc; + + begin + let n = + match float_exp loc (Re_str.matched_group 1 s) with + | Some n -> n + | None -> bad_form name loc + in + + let v = + if group_matched 2 s then [%expr [%e n] /. 100.] + else [%expr [%e n]] in + + if v >= 0. && v <= 1. then Some v + else + Common.error loc "Value of %s must be between 0 and 1." name in + end [@metaloc loc] + let fill_rule ?separated_by:_ ?default:_ loc _name s = begin match s with | "nonzero" -> diff --git a/syntax/attribute_value.mli b/syntax/attribute_value.mli index 339afa6bd..6214b1385 100644 --- a/syntax/attribute_value.mli +++ b/syntax/attribute_value.mli @@ -198,6 +198,12 @@ val paint : parser {:{https://www.w3.org/TR/SVG/painting.html#SpecifyingPaint} Specifying paint}. *) +val fill_opacity : parser +(** Parses an SVG fill-opacity value, converting it into a number between 0. and 1. + + @see +*) + val fill_rule : parser (** Parses an SVG fill-rule value. From 74d4b5211fc5facbb2556d473a9feaab96db0125 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 14:33:42 +0100 Subject: [PATCH 05/15] Fixing some errors reported by the CI. --- lib/svg_sigs.mli | 2 ++ syntax/attribute_value.ml | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index 949ca3b07..ebd6dd1a2 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -1116,6 +1116,8 @@ module type Wrapped_functions = sig val string_of_orient : (Svg_types.Unit.angle option, string) Xml.W.ft val string_of_paint : ([< Svg_types.paint], string) Xml.W.ft + + val string_of_opacity : (float, string) Xml.W.ft val string_of_fill_rule : ([< Svg_types.fill_rule], string) Xml.W.ft diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 0482eb17b..43c815397 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -501,12 +501,12 @@ let fill_opacity = in let v = - if group_matched 2 s then [%expr [%e n] /. 100.] - else [%expr [%e n]] in + if group_matched 2 s then (n /. 100.) + else n in - if v >= 0. && v <= 1. then Some v + if v >= 0. && v <= 1. then Some [%expr [%e v]] else - Common.error loc "Value of %s must be between 0 and 1." name in + Common.error loc "Value of %s must be between 0 and 1." name end [@metaloc loc] let fill_rule ?separated_by:_ ?default:_ loc _name s = From 925474c2f61ee6129239e782d6e7e477dd45c6f3 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 15:04:45 +0100 Subject: [PATCH 06/15] Getting used to ppxlib. --- syntax/attribute_value.ml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 43c815397..52b6554cb 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -494,19 +494,20 @@ let fill_opacity = if not @@ does_match regexp s then bad_form name loc; begin - let n = - match float_exp loc (Re_str.matched_group 1 s) with - | Some n -> n - | None -> bad_form name loc - in - let v = - if group_matched 2 s then (n /. 100.) - else n in + try + let n = float_of_string (Re_str.matched_group 1 s) in + + let v = + if group_matched 2 s then (n /. 100.) + else n in + + if v >= 0. && v <= 1. then Some [%expr [%e v]] + else + Common.error loc "Value of %s must be between 0 and 1." name + + with Failure _ -> bad_form name loc - if v >= 0. && v <= 1. then Some [%expr [%e v]] - else - Common.error loc "Value of %s must be between 0 and 1." name end [@metaloc loc] let fill_rule ?separated_by:_ ?default:_ loc _name s = From 5e18fc55e82405b4af622391c99fa449c15e8fc8 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 15:15:49 +0100 Subject: [PATCH 07/15] Adding tests for fill-opacity. --- syntax/attribute_value.ml | 3 ++- test/test_jsx.re | 10 ++++++++++ test/test_ppx.ml | 10 +++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 52b6554cb..84d4c2d6c 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -502,7 +502,8 @@ let fill_opacity = if group_matched 2 s then (n /. 100.) else n in - if v >= 0. && v <= 1. then Some [%expr [%e v]] + if v >= 0. && v <= 1. then + Some [%expr [%e (Common.float loc @@ v)]] else Common.error loc "Value of %s must be between 0 and 1." name diff --git a/test/test_jsx.re b/test/test_jsx.re index 18a5d4a7c..37283c243 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -331,6 +331,16 @@ let svg = ( ), ], ), + ( + "fill_opacity float, circle", + [], + [circle(~a=[a_cx (1., None); a_cy (2., None); a_r (3., None); a_fill_opacity 0.5], [])], + ), + ( + "fill_opacity percentage, rect", + [], + [rect(~a=[a_cx (1., None); a_cy (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5], [])], + ), ( "fill_rule nonzero", [], diff --git a/test/test_ppx.ml b/test/test_ppx.ml index 23401b064..58251b95c 100644 --- a/test/test_ppx.ml +++ b/test/test_ppx.ml @@ -416,9 +416,13 @@ let svg = "svg", SvgTests.make Svg.[ [[%svg ""]], [animate ~a:[a_animation_fill `Freeze; a_animation_values ["1"; "2"]] []] ; - "fill_opacity, circle", - [[%svg ""]], - [rect ~a:[a_cx (50., None); a_cy (50., None); a_r (50., None); a_fill_opacity 0.5] []] ; + "fill_opacity float, circle", + [[%svg ""]], + [circle ~a:[a_cx (1., None); a_cy (2., None); a_r (3., None); a_fill_opacity 0.5] []] ; + + "fill_opacity percentage, rect", + [[%svg ""]], + [rect ~a:[a_cx (1., None); a_cy (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5] []] ; "fill_rule type nonzero", [[%svg ""]], From 7870dc46565003d2b7493a244477e4d4d5f9c943 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 15:32:43 +0100 Subject: [PATCH 08/15] Getting around the reflect construct. --- lib/svg_sigs.mli | 12 ++++++------ lib/svg_types.mli | 2 ++ syntax/attribute_value.ml | 2 +- syntax/attribute_value.mli | 6 ++++-- syntax/reflect/reflect.ml | 2 ++ test/test_jsx.re | 4 ++-- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index ebd6dd1a2..c288c0e9d 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -78,7 +78,7 @@ module type T = sig *) type 'a wrap = 'a Xml.W.t - (** [list_wrap] is a containre for list of elements. + (** [list_wrap] is a container for list of elements. In most cases, ['a list_wrap = 'a list]. For [R] modules (in eliom or js_of_ocaml), It will be {!ReactiveData.RList.t}. @@ -488,7 +488,7 @@ module type T = sig val a_animation_fill : [< | `Freeze | `Remove ] wrap -> [> | `Fill_Animation ] attrib [@@reflect.attribute "fill" ["animate"]] - val a_fill_opacity : number wrap -> [> | `Fill_opacity ] attrib + val a_fill_opacity : opacity wrap -> [> | `Fill_opacity ] attrib val a_fill_rule : fill_rule wrap -> [> | `Fill_rule ] attrib @@ -635,11 +635,11 @@ module type T = sig | `Text_after_edge | `Text_before_edge | `Inherit ] wrap -> [> | `Dominant_Baseline ] attrib - val a_opacity : number wrap -> [> | `Opacity ] attrib + val a_opacity : opacity wrap -> [> | `Opacity ] attrib val a_stop_color : color wrap -> [> | `Stop_Color ] attrib - val a_stop_opacity : number wrap -> [> | `Stop_Opacity ] attrib + val a_stop_opacity : opacity wrap -> [> | `Stop_Opacity ] attrib val a_stroke : paint wrap -> [> | `Stroke ] attrib @@ -658,7 +658,7 @@ module type T = sig val a_stroke_dashoffset : Unit.length wrap -> [> `Stroke_Dashoffset ] attrib - val a_stroke_opacity : float wrap -> [> `Stroke_Opacity ] attrib + val a_stroke_opacity : opacity wrap -> [> `Stroke_Opacity ] attrib (** {2 Events} @@ -1117,7 +1117,7 @@ module type Wrapped_functions = sig val string_of_paint : ([< Svg_types.paint], string) Xml.W.ft - val string_of_opacity : (float, string) Xml.W.ft + val string_of_opacity : (Svg_types.opacity, string) Xml.W.ft val string_of_fill_rule : ([< Svg_types.fill_rule], string) Xml.W.ft diff --git a/lib/svg_types.mli b/lib/svg_types.mli index a786da522..92ebc1f77 100644 --- a/lib/svg_types.mli +++ b/lib/svg_types.mli @@ -279,6 +279,8 @@ type strings = string list type color = string type icccolor = string +type opacity = float + type paint_whitout_icc = [ `None | `CurrentColor | `Color of (color * icccolor option) diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 84d4c2d6c..5f32acd57 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -484,7 +484,7 @@ let paint ?separated_by:_ ?default:_ loc name s = `Icc ([%e iri], Some [%e paint_without_icc loc name remainder])] end [@metaloc loc] -let fill_opacity = +let opacity = let bad_form name loc = Common.error loc "Value of %s must be a number or percentage" name in diff --git a/syntax/attribute_value.mli b/syntax/attribute_value.mli index 6214b1385..661822582 100644 --- a/syntax/attribute_value.mli +++ b/syntax/attribute_value.mli @@ -198,8 +198,10 @@ val paint : parser {:{https://www.w3.org/TR/SVG/painting.html#SpecifyingPaint} Specifying paint}. *) -val fill_opacity : parser -(** Parses an SVG fill-opacity value, converting it into a number between 0. and 1. +val opacity : parser +(** Parses an SVG fill-opacity value (either a percentage or a number), + converting it into a number between 0. and 1. + This parser is also used in other places expecting opacity. @see *) diff --git a/syntax/reflect/reflect.ml b/syntax/reflect/reflect.ml index dafd1975b..62a512e8e 100644 --- a/syntax/reflect/reflect.ml +++ b/syntax/reflect/reflect.ml @@ -154,6 +154,8 @@ let rec to_attribute_parser lang name ~loc = function | [[%type: iri]] | [[%type: color]] -> [%expr string] + | [[%type: opacity]] -> [%expr opacity] + | [[%type: nmtoken]; [%type: text wrap]] -> [%expr wrap string] | [[%type: string]; [%type: string wrap]] -> [%expr wrap string] | [[%type: string]; [%type: string list wrap]] -> [%expr wrap (spaces string)] diff --git a/test/test_jsx.re b/test/test_jsx.re index 37283c243..297292bac 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -333,12 +333,12 @@ let svg = ( ), ( "fill_opacity float, circle", - [], + [], [circle(~a=[a_cx (1., None); a_cy (2., None); a_r (3., None); a_fill_opacity 0.5], [])], ), ( "fill_opacity percentage, rect", - [], + [], [rect(~a=[a_cx (1., None); a_cy (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5], [])], ), ( From e71f853512302ea4dfe845f1d83ea9cc208295f9 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 15:47:43 +0100 Subject: [PATCH 09/15] Fixing the tests. --- test/test_jsx.re | 4 ++-- test/test_ppx.ml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_jsx.re b/test/test_jsx.re index 297292bac..2f1bca2e1 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -334,12 +334,12 @@ let svg = ( ( "fill_opacity float, circle", [], - [circle(~a=[a_cx (1., None); a_cy (2., None); a_r (3., None); a_fill_opacity 0.5], [])], + [circle(~a=[a_cx((1., None)), a_cy((2., None)), a_r((3., None)), a_fill_opacity(0.5)], [])], ), ( "fill_opacity percentage, rect", [], - [rect(~a=[a_cx (1., None); a_cy (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5], [])], + [rect(~a=[a_cx((1., None)), a_cy((2., None)), a_width((3., None)), a_height((4., None)), a_fill_opacity(0.5)], [])], ), ( "fill_rule nonzero", diff --git a/test/test_ppx.ml b/test/test_ppx.ml index 58251b95c..254fefdfd 100644 --- a/test/test_ppx.ml +++ b/test/test_ppx.ml @@ -422,7 +422,7 @@ let svg = "svg", SvgTests.make Svg.[ "fill_opacity percentage, rect", [[%svg ""]], - [rect ~a:[a_cx (1., None); a_cy (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5] []] ; + [rect ~a:[a_x (1., None); a_y (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5] []] ; "fill_rule type nonzero", [[%svg ""]], From 2394bf2246b1e36099e22bed1b48d19188ba938d Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 15:59:59 +0100 Subject: [PATCH 10/15] Doesn't the JSX parser accept single quotes? --- test/test_jsx.re | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_jsx.re b/test/test_jsx.re index 2f1bca2e1..6dae1de48 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -338,7 +338,7 @@ let svg = ( ), ( "fill_opacity percentage, rect", - [], + [], [rect(~a=[a_cx((1., None)), a_cy((2., None)), a_width((3., None)), a_height((4., None)), a_fill_opacity(0.5)], [])], ), ( From fc41690da5eb949599a2ed8f939121ce39fd0b9f Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Thu, 30 Nov 2023 17:09:47 +0100 Subject: [PATCH 11/15] Testing with additionnal double quotes. --- test/test_jsx.re | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_jsx.re b/test/test_jsx.re index 6dae1de48..50c52591a 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -333,13 +333,13 @@ let svg = ( ), ( "fill_opacity float, circle", - [], + [], [circle(~a=[a_cx((1., None)), a_cy((2., None)), a_r((3., None)), a_fill_opacity(0.5)], [])], ), ( "fill_opacity percentage, rect", - [], - [rect(~a=[a_cx((1., None)), a_cy((2., None)), a_width((3., None)), a_height((4., None)), a_fill_opacity(0.5)], [])], + [], + [rect(~a=[a_x((1., None)), a_y((2., None)), a_width((3., None)), a_height((4., None)), a_fill_opacity(0.5)], [])], ), ( "fill_rule nonzero", From ee1a34916b3388c35d027ff5e307a06b2efe9a4b Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Fri, 1 Dec 2023 14:53:44 +0100 Subject: [PATCH 12/15] More diverse tests. Adding opacity into the change log. --- CHANGES.md | 6 ++++++ test/test_jsx.re | 12 +++++++----- test/test_ppx.ml | 12 +++++++----- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index bb71b71c5..3bcd2b39f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,9 @@ +# NEXT + +* Add support for opacity attributes (`opacity`, `fill-opacity`, etc.). + (#325 by Martin @MBodin Bodin) + + # 4.6.0 * Update for OCaml 5.0 and drop support for OCaml 4.2.0 diff --git a/test/test_jsx.re b/test/test_jsx.re index 50c52591a..3bb4f91c3 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -332,14 +332,16 @@ let svg = ( ], ), ( - "fill_opacity float, circle", - [], - [circle(~a=[a_cx((1., None)), a_cy((2., None)), a_r((3., None)), a_fill_opacity(0.5)], [])], + "opacity, circle", + [], + [circle(~a=[a_cx((1., None)), a_cy((2., None)), a_r((3., None)), + a_fill(`Color (("green", None))), a_opacity(0.5)], [])], ), ( "fill_opacity percentage, rect", - [], - [rect(~a=[a_x((1., None)), a_y((2., None)), a_width((3., None)), a_height((4., None)), a_fill_opacity(0.5)], [])], + [], + [rect(~a=[a_x((1., None)), a_y((2., None)), a_width((3., None)), a_height((4., None)), + a_fill(`Color (("blue", None))), a_fill_opacity(0.5)], [])], ), ( "fill_rule nonzero", diff --git a/test/test_ppx.ml b/test/test_ppx.ml index 254fefdfd..1a9b3a18b 100644 --- a/test/test_ppx.ml +++ b/test/test_ppx.ml @@ -416,13 +416,15 @@ let svg = "svg", SvgTests.make Svg.[ [[%svg ""]], [animate ~a:[a_animation_fill `Freeze; a_animation_values ["1"; "2"]] []] ; - "fill_opacity float, circle", - [[%svg ""]], - [circle ~a:[a_cx (1., None); a_cy (2., None); a_r (3., None); a_fill_opacity 0.5] []] ; + "opacity, circle", + [[%svg ""]], + [circle ~a:[a_cx (1., None); a_cy (2., None); a_r (3., None); + a_fill (`Color ("green", None)); a_opacity 0.5] []] ; "fill_opacity percentage, rect", - [[%svg ""]], - [rect ~a:[a_x (1., None); a_y (2., None); a_width (3., None); a_height (4., None); a_fill_opacity 0.5] []] ; + [[%svg ""]], + [rect ~a:[a_x (1., None); a_y (2., None); a_width (3., None); a_height (4., None); + a_fill (`Color ("blue", None)); a_fill_opacity 0.5] []] ; "fill_rule type nonzero", [[%svg ""]], From 98f1b2e3365d041d95acebc9abf64ab2ca6149ce Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Fri, 1 Dec 2023 16:14:48 +0100 Subject: [PATCH 13/15] Naming alpha_value instead of opacity to be closer to the spec. --- lib/svg_f.ml | 10 +++++----- lib/svg_sigs.mli | 10 +++++----- lib/svg_types.mli | 4 +++- syntax/attribute_value.ml | 13 ++++--------- syntax/reflect/reflect.ml | 2 +- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/svg_f.ml b/lib/svg_f.ml index 052a9f97f..09bee606b 100644 --- a/lib/svg_f.ml +++ b/lib/svg_f.ml @@ -539,7 +539,7 @@ struct let a_animation_fill x = user_attrib C.string_of_big_variant "fill" x - let a_fill_opacity = user_attrib C.string_of_opacity "fill-opacity" + let a_fill_opacity = user_attrib C.string_of_alpha_value "fill-opacity" let a_fill_rule = user_attrib C.string_of_fill_rule "fill-rule" @@ -714,11 +714,11 @@ struct let a_ontouchcancel = Xml.touch_event_handler_attrib "ontouchcancel" - let a_opacity = user_attrib C.string_of_opacity "opacity" + let a_opacity = user_attrib C.string_of_alpha_value "opacity" let a_stop_color = color_attrib "stop-color" - let a_stop_opacity = user_attrib C.string_of_opacity "stop-opacity" + let a_stop_opacity = user_attrib C.string_of_alpha_value "stop-opacity" let a_stroke = user_attrib C.string_of_paint "stroke" @@ -740,7 +740,7 @@ struct user_attrib C.string_of_length "stroke-dashoffset" let a_stroke_opacity = - user_attrib C.string_of_opacity "stroke-opacity" + user_attrib C.string_of_alpha_value "stroke-opacity" (* xlink namespace given a nickname since some attributes mandated by the svg standard such as xlink:href live in that namespace, and we @@ -1119,7 +1119,7 @@ struct let string_of_paint = string_of_paint - let string_of_opacity = string_of_number + let string_of_alpha_value = string_of_number let string_of_fill_rule = string_of_fill_rule diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index c288c0e9d..99f49e93c 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -488,7 +488,7 @@ module type T = sig val a_animation_fill : [< | `Freeze | `Remove ] wrap -> [> | `Fill_Animation ] attrib [@@reflect.attribute "fill" ["animate"]] - val a_fill_opacity : opacity wrap -> [> | `Fill_opacity ] attrib + val a_fill_opacity : alpha_value wrap -> [> | `Fill_opacity ] attrib val a_fill_rule : fill_rule wrap -> [> | `Fill_rule ] attrib @@ -635,11 +635,11 @@ module type T = sig | `Text_after_edge | `Text_before_edge | `Inherit ] wrap -> [> | `Dominant_Baseline ] attrib - val a_opacity : opacity wrap -> [> | `Opacity ] attrib + val a_opacity : alpha_value wrap -> [> | `Opacity ] attrib val a_stop_color : color wrap -> [> | `Stop_Color ] attrib - val a_stop_opacity : opacity wrap -> [> | `Stop_Opacity ] attrib + val a_stop_opacity : alpha_value wrap -> [> | `Stop_Opacity ] attrib val a_stroke : paint wrap -> [> | `Stroke ] attrib @@ -658,7 +658,7 @@ module type T = sig val a_stroke_dashoffset : Unit.length wrap -> [> `Stroke_Dashoffset ] attrib - val a_stroke_opacity : opacity wrap -> [> `Stroke_Opacity ] attrib + val a_stroke_opacity : alpha_value wrap -> [> `Stroke_Opacity ] attrib (** {2 Events} @@ -1117,7 +1117,7 @@ module type Wrapped_functions = sig val string_of_paint : ([< Svg_types.paint], string) Xml.W.ft - val string_of_opacity : (Svg_types.opacity, string) Xml.W.ft + val string_of_opacity : (Svg_types.alpha_value, string) Xml.W.ft val string_of_fill_rule : ([< Svg_types.fill_rule], string) Xml.W.ft diff --git a/lib/svg_types.mli b/lib/svg_types.mli index 92ebc1f77..a8c8af1ed 100644 --- a/lib/svg_types.mli +++ b/lib/svg_types.mli @@ -279,7 +279,9 @@ type strings = string list type color = string type icccolor = string -type opacity = float +(* An alpha value can be either a number or a percentage. + We represent both as a number between 0 and 1. *) +type alpha_value = float type paint_whitout_icc = [ `None | `CurrentColor diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 5f32acd57..3c4325cd7 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -484,31 +484,26 @@ let paint ?separated_by:_ ?default:_ loc name s = `Icc ([%e iri], Some [%e paint_without_icc loc name remainder])] end [@metaloc loc] -let opacity = +let alpha_value = let bad_form name loc = Common.error loc "Value of %s must be a number or percentage" name in - let regexp = Re_str.regexp "\\([-+0-9eE.]+\\)\\(%\\)?" in fun ?separated_by:_ ?default:_ loc name s -> if not @@ does_match regexp s then bad_form name loc; - begin - try let n = float_of_string (Re_str.matched_group 1 s) in - let v = if group_matched 2 s then (n /. 100.) else n in - if v >= 0. && v <= 1. then Some [%expr [%e (Common.float loc @@ v)]] else - Common.error loc "Value of %s must be between 0 and 1." name - + let (min, max) = + if group_matched 2 s then ("0", "1") else ("0%", "100%") in + Common.error loc "Value of %s must be between %s and %s." name min max with Failure _ -> bad_form name loc - end [@metaloc loc] let fill_rule ?separated_by:_ ?default:_ loc _name s = diff --git a/syntax/reflect/reflect.ml b/syntax/reflect/reflect.ml index 62a512e8e..3a390463d 100644 --- a/syntax/reflect/reflect.ml +++ b/syntax/reflect/reflect.ml @@ -154,7 +154,7 @@ let rec to_attribute_parser lang name ~loc = function | [[%type: iri]] | [[%type: color]] -> [%expr string] - | [[%type: opacity]] -> [%expr opacity] + | [[%type: alpha_value]] -> [%expr alpha_value] | [[%type: nmtoken]; [%type: text wrap]] -> [%expr wrap string] | [[%type: string]; [%type: string wrap]] -> [%expr wrap string] From c1b619e8177021b5c096a9dbe581b50b16102f93 Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Fri, 1 Dec 2023 16:21:54 +0100 Subject: [PATCH 14/15] Fixing mistakes from the previous commit. --- lib/svg_sigs.mli | 2 +- syntax/attribute_value.mli | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/svg_sigs.mli b/lib/svg_sigs.mli index 99f49e93c..98f135892 100644 --- a/lib/svg_sigs.mli +++ b/lib/svg_sigs.mli @@ -1117,7 +1117,7 @@ module type Wrapped_functions = sig val string_of_paint : ([< Svg_types.paint], string) Xml.W.ft - val string_of_opacity : (Svg_types.alpha_value, string) Xml.W.ft + val string_of_alpha_value : (Svg_types.alpha_value, string) Xml.W.ft val string_of_fill_rule : ([< Svg_types.fill_rule], string) Xml.W.ft diff --git a/syntax/attribute_value.mli b/syntax/attribute_value.mli index 661822582..0986e3a6c 100644 --- a/syntax/attribute_value.mli +++ b/syntax/attribute_value.mli @@ -198,12 +198,12 @@ val paint : parser {:{https://www.w3.org/TR/SVG/painting.html#SpecifyingPaint} Specifying paint}. *) -val opacity : parser -(** Parses an SVG fill-opacity value (either a percentage or a number), +val alpha_value : parser +(** Parses an SVG alpha value (either a percentage or a number), converting it into a number between 0. and 1. - This parser is also used in other places expecting opacity. + This parser is used in various places expecting opacity values. - @see + @see *) val fill_rule : parser From a4cc943cca0203960bcadb0958d1efa468753ece Mon Sep 17 00:00:00 2001 From: Martin Bodin Date: Mon, 4 Dec 2023 10:26:14 +0100 Subject: [PATCH 15/15] Fixing wrong error message for alpha-value outside their range. --- syntax/attribute_value.ml | 5 +++-- test/test_jsx.re | 2 +- test/test_ppx.ml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/syntax/attribute_value.ml b/syntax/attribute_value.ml index 3c4325cd7..457b01e61 100644 --- a/syntax/attribute_value.ml +++ b/syntax/attribute_value.ml @@ -494,14 +494,15 @@ let alpha_value = begin try let n = float_of_string (Re_str.matched_group 1 s) in + let percent = group_matched 2 s in let v = - if group_matched 2 s then (n /. 100.) + if percent then (n /. 100.) else n in if v >= 0. && v <= 1. then Some [%expr [%e (Common.float loc @@ v)]] else let (min, max) = - if group_matched 2 s then ("0", "1") else ("0%", "100%") in + if percent then ("0%", "100%") else ("0", "1") in Common.error loc "Value of %s must be between %s and %s." name min max with Failure _ -> bad_form name loc end [@metaloc loc] diff --git a/test/test_jsx.re b/test/test_jsx.re index 3bb4f91c3..d7f50047d 100644 --- a/test/test_jsx.re +++ b/test/test_jsx.re @@ -333,7 +333,7 @@ let svg = ( ), ( "opacity, circle", - [], + [], [circle(~a=[a_cx((1., None)), a_cy((2., None)), a_r((3., None)), a_fill(`Color (("green", None))), a_opacity(0.5)], [])], ), diff --git a/test/test_ppx.ml b/test/test_ppx.ml index 1a9b3a18b..dd71af748 100644 --- a/test/test_ppx.ml +++ b/test/test_ppx.ml @@ -417,7 +417,7 @@ let svg = "svg", SvgTests.make Svg.[ [animate ~a:[a_animation_fill `Freeze; a_animation_values ["1"; "2"]] []] ; "opacity, circle", - [[%svg ""]], + [[%svg ""]], [circle ~a:[a_cx (1., None); a_cy (2., None); a_r (3., None); a_fill (`Color ("green", None)); a_opacity 0.5] []] ;