Support shorthand filter functions on SVG elements

This enables the full 'filter' property syntax on SVG elements.

Since SVG elements expect effects of zoom to be included in their local
transform, we have to take care to undo zoom from any Length parameters
when building the filter chain.

Bug: 109224
Change-Id: Ib7f6050f57cc2723d1396f05424da788df675188
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2595416
Reviewed-by: Xianzhu Wang <wangxianzhu@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#838451}
diff --git a/css/filter-effects/svg-filter-vs-clip-path.html b/css/filter-effects/svg-filter-vs-clip-path.html
new file mode 100644
index 0000000..0e17117
--- /dev/null
+++ b/css/filter-effects/svg-filter-vs-clip-path.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>Filter Effects: 'filter' and 'clip-path' on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#placement">
+<link rel="match" href="reference/green-100x100.html">
+<svg>
+  <clipPath id="c">
+    <rect width="100" height="100"/>
+  </clipPath>
+  <rect width="100" height="100" fill="red"
+	filter="blur(20px)" clip-path="url(#c)"/>
+  <rect width="100" height="100" fill="green"/>
+</svg>
diff --git a/css/filter-effects/svg-filter-vs-mask.html b/css/filter-effects/svg-filter-vs-mask.html
new file mode 100644
index 0000000..279db20
--- /dev/null
+++ b/css/filter-effects/svg-filter-vs-mask.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>Filter Effects: 'filter' and 'mask' on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#placement">
+<link rel="match" href="reference/green-100x100.html">
+<svg>
+  <mask id="m">
+    <rect width="100" height="100" fill="white"/>
+  </mask>
+  <rect width="100" height="100" fill="red"
+	filter="blur(20px)" mask="url(#m)"/>
+  <rect width="100" height="100" fill="green"/>
+</svg>
diff --git a/css/filter-effects/svg-multiple-filter-functions.html b/css/filter-effects/svg-multiple-filter-functions.html
new file mode 100644
index 0000000..d1b182a
--- /dev/null
+++ b/css/filter-effects/svg-multiple-filter-functions.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>Filter Effects: filter with multiple filter functions on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#filter-functions">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterElement">
+<link rel="match" href="reference/green-100x100.html">
+<svg>
+  <filter id="f_left" x="0" y="0" width="1" height="1"
+	  color-interpolation-filters="sRGB">
+    <feFlood flood-color="rgb(71.79%, 28.82%, 0%)" width="50"/>
+  </filter>
+  <filter id="f_right" x="0" y="0" width="1" height="1"
+	  color-interpolation-filters="sRGB">
+    <feFlood flood-color="rgb(71.79%, 28.82%, 0%)" x="50" width="50"/>
+    <feMerge>
+      <feMergeNode in="SourceGraphic"/>
+      <feMergeNode/>
+    </feMerge>
+  </filter>
+  <rect width="100" height="100" fill="red"
+	filter="url(#f_left) url(#f_right) hue-rotate(90deg)"/>
+</svg>
diff --git a/css/filter-effects/svg-mutation-drop-shadow-color.html b/css/filter-effects/svg-mutation-drop-shadow-color.html
new file mode 100644
index 0000000..fe8bf7e
--- /dev/null
+++ b/css/filter-effects/svg-mutation-drop-shadow-color.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>Filter Effects: changing color of drop-shadow() function on an SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="100" fill="green" filter="drop-shadow(50px 0 red)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("filter", "drop-shadow(50px 0 green)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-drop-shadow-offset.html b/css/filter-effects/svg-mutation-drop-shadow-offset.html
new file mode 100644
index 0000000..2d5a129
--- /dev/null
+++ b/css/filter-effects/svg-mutation-drop-shadow-offset.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>Filter Effects: changing offset of drop-shadow() function on an SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="100" fill="green" filter="drop-shadow(5px 0 green)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("filter", "drop-shadow(50px 0 green)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-function-to-url.html b/css/filter-effects/svg-mutation-function-to-url.html
new file mode 100644
index 0000000..61d657b
--- /dev/null
+++ b/css/filter-effects/svg-mutation-function-to-url.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>Filter Effects: switching from hue-rotate() to url() on an SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#filter-functions">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterElement">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <filter id="hue" color-interpolation-filters="sRGB">
+    <feColorMatrix type="hueRotate" values="90"/>
+  </filter>
+  <rect width="100" height="100" fill="rgb(71.79%, 28.82%, 0%)" filter="hue-rotate(330deg)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.querySelector("svg > rect");
+    rect.setAttribute("filter", "url(#hue)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-group-position-changed.html b/css/filter-effects/svg-mutation-group-position-changed.html
new file mode 100644
index 0000000..5a73f6e
--- /dev/null
+++ b/css/filter-effects/svg-mutation-group-position-changed.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Filter Effects: changing the position of an SVG group with filter</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <g filter="drop-shadow(-50px 0 green)">
+    <rect id="target" width="50" height="100" fill="green"/>
+  </g>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("x", "50");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-group-size-changed.html b/css/filter-effects/svg-mutation-group-size-changed.html
new file mode 100644
index 0000000..0486ec0
--- /dev/null
+++ b/css/filter-effects/svg-mutation-group-size-changed.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Filter Effects: changing the size of an SVG group with filter</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <g filter="drop-shadow(50px 0 green)">
+    <rect id="target" width="50" height="50" fill="green"/>
+  </g>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("height", "100");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-group-transform-changed.html b/css/filter-effects/svg-mutation-group-transform-changed.html
new file mode 100644
index 0000000..f0ff16e
--- /dev/null
+++ b/css/filter-effects/svg-mutation-group-transform-changed.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Filter Effects: changing the transform of an SVG group with filter</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <g id="target" filter="drop-shadow(-50px 0 green)">
+    <rect width="50" height="100" fill="green"/>
+  </g>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let group = document.getElementById("target");
+    group.setAttribute("transform", "translate(50, 0)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-object-position-changed.html b/css/filter-effects/svg-mutation-object-position-changed.html
new file mode 100644
index 0000000..76b75fc
--- /dev/null
+++ b/css/filter-effects/svg-mutation-object-position-changed.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Filter Effects: changing the position of an SVG element with filter</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="100" fill="green"
+	filter="drop-shadow(-50px 0 green)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("x", "50");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-object-size-changed.html b/css/filter-effects/svg-mutation-object-size-changed.html
new file mode 100644
index 0000000..2d55387
--- /dev/null
+++ b/css/filter-effects/svg-mutation-object-size-changed.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Filter Effects: changing the size of an SVG element with filter</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="50" fill="green"
+	filter="drop-shadow(50px 0 green)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("height", "100");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-object-transform-changed.html b/css/filter-effects/svg-mutation-object-transform-changed.html
new file mode 100644
index 0000000..75a82b1
--- /dev/null
+++ b/css/filter-effects/svg-mutation-object-transform-changed.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Filter Effects: changing the transform of an SVG element with filter</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="100" fill="green"
+	filter="drop-shadow(-50px 0 green)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("transform", "translate(50, 0)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-single-to-multiple-001.html b/css/filter-effects/svg-mutation-single-to-multiple-001.html
new file mode 100644
index 0000000..13da58c
--- /dev/null
+++ b/css/filter-effects/svg-mutation-single-to-multiple-001.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Filter Effects: extending the filter chain with an additional function on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-hue-rotate">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="100" fill="rgb(71.79%, 28.82%, 0%)"
+	filter="hue-rotate(90deg)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("filter", "hue-rotate(90deg) drop-shadow(50px 0 green)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-single-to-multiple-002.html b/css/filter-effects/svg-mutation-single-to-multiple-002.html
new file mode 100644
index 0000000..d7769a7
--- /dev/null
+++ b/css/filter-effects/svg-mutation-single-to-multiple-002.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>Filter Effects: extending the filter chain with an additional function on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#feColorMatrixElement">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <filter id="hue" color-interpolation-filters="sRGB">
+    <feColorMatrix type="hueRotate" values="90"/>
+  </filter>
+  <rect width="100" height="100" fill="red"/>
+  <rect id="target" width="50" height="100" fill="rgb(71.79%, 28.82%, 0%)"
+	filter="url(#hue)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.getElementById("target");
+    rect.setAttribute("filter", "url(#hue) drop-shadow(50px 0 green)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-mutation-url-to-function.html b/css/filter-effects/svg-mutation-url-to-function.html
new file mode 100644
index 0000000..fb08d84
--- /dev/null
+++ b/css/filter-effects/svg-mutation-url-to-function.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<title>Filter Effects: switching from url() to hue-rotate() on an SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#filter-functions">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterElement">
+<link rel="match" href="reference/green-100x100.html">
+<script src="/common/rendering-utils.js"></script>
+<script src="/common/reftest-wait.js"></script>
+<svg>
+  <filter id="hue" color-interpolation-filters="sRGB">
+    <feColorMatrix type="hueRotate" values="330"/>
+  </filter>
+  <rect width="100" height="100" fill="rgb(71.79%, 28.82%, 0%)" filter="url(#hue)"/>
+</svg>
+<script>
+  waitForAtLeastOneFrame().then(() => {
+    let rect = document.querySelector("svg > rect");
+    rect.setAttribute("filter", "hue-rotate(90deg)");
+    takeScreenshot();
+  });
+</script>
diff --git a/css/filter-effects/svg-shorthand-drop-shadow-001.html b/css/filter-effects/svg-shorthand-drop-shadow-001.html
new file mode 100644
index 0000000..0d05046
--- /dev/null
+++ b/css/filter-effects/svg-shorthand-drop-shadow-001.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Filter Effects: drop-shadow() function on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow">
+<link rel="match" href="reference/green-100x100.html">
+<svg>
+  <rect width="100" height="100" fill="red"/>
+  <rect width="50" height="100" fill="green" filter="drop-shadow(50px 0 green)"/>
+</svg>
diff --git a/css/filter-effects/svg-shorthand-hue-rotate-001.html b/css/filter-effects/svg-shorthand-hue-rotate-001.html
new file mode 100644
index 0000000..34f9b5c
--- /dev/null
+++ b/css/filter-effects/svg-shorthand-hue-rotate-001.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>Filter Effects: hue-rotate() function on SVG element</title>
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#FilterProperty">
+<link rel="help" href="https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-hue-rotate">
+<link rel="match" href="reference/green-100x100.html">
+<svg>
+  <rect width="100" height="100" fill="rgb(71.79%, 28.82%, 0%)" filter="hue-rotate(90deg)"/>
+</svg>
+