summaryrefslogtreecommitdiffstats
path: root/layout/reftests/invalidation
diff options
context:
space:
mode:
Diffstat (limited to 'layout/reftests/invalidation')
-rw-r--r--layout/reftests/invalidation/1243409-1-ref.html11
-rw-r--r--layout/reftests/invalidation/1243409-1.html28
-rw-r--r--layout/reftests/invalidation/540247-1-ref.xhtml29
-rw-r--r--layout/reftests/invalidation/540247-1.xhtml33
-rw-r--r--layout/reftests/invalidation/543681-1-ref.html18
-rw-r--r--layout/reftests/invalidation/543681-1.html22
-rw-r--r--layout/reftests/invalidation/background-position-1-ref.html31
-rw-r--r--layout/reftests/invalidation/background-position-1.html41
-rw-r--r--layout/reftests/invalidation/background-position-2-ref.html20
-rw-r--r--layout/reftests/invalidation/background-position-2a.html32
-rw-r--r--layout/reftests/invalidation/background-position-2b.html36
-rw-r--r--layout/reftests/invalidation/background-position-2c.html36
-rw-r--r--layout/reftests/invalidation/background-position-2d.html43
-rw-r--r--layout/reftests/invalidation/background-position-2e.html43
-rw-r--r--layout/reftests/invalidation/background-position-2f.html36
-rw-r--r--layout/reftests/invalidation/border-radius-1-ref.html28
-rw-r--r--layout/reftests/invalidation/border-radius-1.html38
-rw-r--r--layout/reftests/invalidation/box-shadow-border-radius-ref.html19
-rw-r--r--layout/reftests/invalidation/box-shadow-border-radius.html27
-rw-r--r--layout/reftests/invalidation/clip-path-invalidation-1a.html40
-rw-r--r--layout/reftests/invalidation/clip-path-invalidation-1b.html47
-rw-r--r--layout/reftests/invalidation/clip-path-invalidation-1c.html42
-rw-r--r--layout/reftests/invalidation/clip-path-invalidation-1d.html50
-rw-r--r--layout/reftests/invalidation/clipped-animated-transform-1.html62
-rw-r--r--layout/reftests/invalidation/fast-scrolling.html113
-rw-r--r--layout/reftests/invalidation/filter-userspace-offset.svg156
-rw-r--r--layout/reftests/invalidation/fractional-transform-1.html36
-rw-r--r--layout/reftests/invalidation/fractional-transform-2.html32
-rw-r--r--layout/reftests/invalidation/fractional-transform-3.html32
-rw-r--r--layout/reftests/invalidation/image-scrolling-zoom-1-notref.html36
-rw-r--r--layout/reftests/invalidation/image-scrolling-zoom-1-ref.html36
-rw-r--r--layout/reftests/invalidation/image-scrolling-zoom-1.html51
-rw-r--r--layout/reftests/invalidation/image_rgrg-256x256-animated.gifbin0 -> 1748 bytes
-rw-r--r--layout/reftests/invalidation/image_rgrg-256x256.pngbin0 -> 131 bytes
-rw-r--r--layout/reftests/invalidation/inactive-layertree-visible-region-1.html60
-rw-r--r--layout/reftests/invalidation/inactive-layertree-visible-region-2.html62
-rw-r--r--layout/reftests/invalidation/jetstream-scroll-ref.html70
-rw-r--r--layout/reftests/invalidation/jetstream-scroll.html73
-rw-r--r--layout/reftests/invalidation/layer-splitting-1.html63
-rw-r--r--layout/reftests/invalidation/layer-splitting-2.html67
-rw-r--r--layout/reftests/invalidation/layer-splitting-3.html95
-rw-r--r--layout/reftests/invalidation/layer-splitting-4.html82
-rw-r--r--layout/reftests/invalidation/layer-splitting-5.html109
-rw-r--r--layout/reftests/invalidation/layer-splitting-6.html117
-rw-r--r--layout/reftests/invalidation/layer-splitting-7.html72
-rw-r--r--layout/reftests/invalidation/mask-invalidation-1-ref.html22
-rw-r--r--layout/reftests/invalidation/mask-invalidation-1a.html77
-rw-r--r--layout/reftests/invalidation/mask-invalidation-1b.html84
-rw-r--r--layout/reftests/invalidation/mask-invalidation-2-ref.html14
-rw-r--r--layout/reftests/invalidation/mask-invalidation-2a.html36
-rw-r--r--layout/reftests/invalidation/mask-invalidation-2b.html43
-rw-r--r--layout/reftests/invalidation/mask-invalidation-2c.html42
-rw-r--r--layout/reftests/invalidation/mask-invalidation-2d.html50
-rw-r--r--layout/reftests/invalidation/masklayer-1.html55
-rw-r--r--layout/reftests/invalidation/masklayer-2.html62
-rw-r--r--layout/reftests/invalidation/negative-w-component-ref.html73
-rw-r--r--layout/reftests/invalidation/negative-w-component.html86
-rw-r--r--layout/reftests/invalidation/nudge-to-integer-invalidation.html32
-rw-r--r--layout/reftests/invalidation/one-pixel-wide-background.pngbin0 -> 1059 bytes
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-1.html75
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-2.html67
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-3.html71
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-4.html70
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-5.html77
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-6.html78
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-7.html82
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-8-ref.html58
-rw-r--r--layout/reftests/invalidation/paintedlayer-recycling-8.html80
-rw-r--r--layout/reftests/invalidation/partially-scrolled-svg-group-ref.html51
-rw-r--r--layout/reftests/invalidation/partially-scrolled-svg-group.html57
-rw-r--r--layout/reftests/invalidation/reftest.list109
-rw-r--r--layout/reftests/invalidation/scroll-inactive-layers-2.html86
-rw-r--r--layout/reftests/invalidation/scroll-inactive-layers.html81
-rw-r--r--layout/reftests/invalidation/svg-paint-rect-changes-ref.html12
-rw-r--r--layout/reftests/invalidation/svg-paint-rect-changes.html22
-rw-r--r--layout/reftests/invalidation/table-repaint-a-ref.html13
-rw-r--r--layout/reftests/invalidation/table-repaint-a.html22
-rw-r--r--layout/reftests/invalidation/table-repaint-b-ref.html17
-rw-r--r--layout/reftests/invalidation/table-repaint-b.html29
-rw-r--r--layout/reftests/invalidation/table-repaint-border-collapse-ref.html21
-rw-r--r--layout/reftests/invalidation/table-repaint-border-collapse.html31
-rw-r--r--layout/reftests/invalidation/table-repaint-c-ref.html19
-rw-r--r--layout/reftests/invalidation/table-repaint-c.html30
-rw-r--r--layout/reftests/invalidation/table-repaint-d-ref.html14
-rw-r--r--layout/reftests/invalidation/table-repaint-d.html23
-rw-r--r--layout/reftests/invalidation/table-repaint-e-ref.html34
-rw-r--r--layout/reftests/invalidation/table-repaint-e.html42
-rw-r--r--layout/reftests/invalidation/table-repaint-non-border-collapse-ref.html20
-rw-r--r--layout/reftests/invalidation/table-repaint-non-border-collapse.html30
-rw-r--r--layout/reftests/invalidation/test-animated-image-layers-background.html16
-rw-r--r--layout/reftests/invalidation/test-animated-image-layers-ref.html8
-rw-r--r--layout/reftests/invalidation/test-animated-image-layers.html16
-rw-r--r--layout/reftests/invalidation/test-image-layers-multiple-displayitem.html21
-rw-r--r--layout/reftests/invalidation/test-image-layers-ref.html8
-rw-r--r--layout/reftests/invalidation/test-image-layers.html16
-rw-r--r--layout/reftests/invalidation/transform-floating-point-invalidation.html32
-rw-r--r--layout/reftests/invalidation/zero-opacity-animation.html15
-rw-r--r--layout/reftests/invalidation/zero-opacity-text.html15
98 files changed, 4418 insertions, 0 deletions
diff --git a/layout/reftests/invalidation/1243409-1-ref.html b/layout/reftests/invalidation/1243409-1-ref.html
new file mode 100644
index 0000000000..63b9c5b218
--- /dev/null
+++ b/layout/reftests/invalidation/1243409-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Testcase for bug 1243409</title>
+<html>
+<body>
+<svg>
+ <g transform="matrix(1, 0, 0, 1, 20, 10)">
+ <rect fill-opacity="1" height="10" width="20" fill="#000"></rect>
+ </g>
+</svg>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/1243409-1.html b/layout/reftests/invalidation/1243409-1.html
new file mode 100644
index 0000000000..cef841f506
--- /dev/null
+++ b/layout/reftests/invalidation/1243409-1.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Testcase for bug 1243409</title>
+<html class="reftest-wait">
+<body>
+<svg>
+ <g transform="matrix(1, 0, 0, 1, 0, 30)">
+ <rect fill-opacity="1" height="10" width="20" fill="#000"></rect>
+ </g>
+</svg>
+<script>
+var m = document.querySelector('svg > g').transform.baseVal[0].matrix;
+var times = 2;
+
+function doTest() {
+ if(!times--) {
+ document.documentElement.removeAttribute("class");
+ return;
+ }
+
+ m.e += 10;
+ m.f -= 10;
+ window.requestAnimationFrame(doTest);
+}
+
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/540247-1-ref.xhtml b/layout/reftests/invalidation/540247-1-ref.xhtml
new file mode 100644
index 0000000000..6754a091ab
--- /dev/null
+++ b/layout/reftests/invalidation/540247-1-ref.xhtml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<window id="Test for bug 540247" title="Testcase" class="reftest-wait"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script><![CDATA[
+document.addEventListener("MozReftestInvalidate", runtest, false);
+
+function runtest() {
+ document.getElementById('b').height = '100';
+
+ var scrollbox = document.getElementById('s');
+ scrollbox.scrollTo(0, 1000);
+
+ document.documentElement.className = "";
+}
+]]>
+</script>
+
+ <scrollbox id="s" height="200" style="overflow: scroll;">
+ <vbox>
+ <vbox height="150" width="200" style="background: red;" id="b"/>
+ <vbox height="150" width="200" style="background: green;"/>
+ <vbox height="150" width="200" style="background: blue;"/>
+ <label value="a"/>
+ </vbox>
+ </scrollbox>
+
+</window>
diff --git a/layout/reftests/invalidation/540247-1.xhtml b/layout/reftests/invalidation/540247-1.xhtml
new file mode 100644
index 0000000000..50fc80368d
--- /dev/null
+++ b/layout/reftests/invalidation/540247-1.xhtml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+
+<window id="Test for bug 540247" title="Testcase" class="reftest-wait"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<script><![CDATA[
+document.addEventListener("MozReftestInvalidate", runtest, false);
+
+function runtest() {
+ // Make sure that the effects of the scroll are painted to the screen before
+ // shrinking the size of the scrolled frame.
+ window.addEventListener("MozAfterPaint", finish, false);
+ var scrollbox = document.getElementById('s');
+ scrollbox.scrollTo(0, 1000);
+}
+
+function finish() {
+ document.getElementById('b').height = '100';
+ document.documentElement.className = "";
+}
+]]>
+</script>
+
+ <scrollbox id="s" height="200" style="overflow: scroll;">
+ <vbox>
+ <vbox height="150" width="200" style="background: red;" id="b"/>
+ <vbox height="150" width="200" style="background: green;"/>
+ <vbox height="150" width="200" style="background: blue;"/>
+ <label value="a"/>
+ </vbox>
+ </scrollbox>
+
+</window>
diff --git a/layout/reftests/invalidation/543681-1-ref.html b/layout/reftests/invalidation/543681-1-ref.html
new file mode 100644
index 0000000000..54b15abf6e
--- /dev/null
+++ b/layout/reftests/invalidation/543681-1-ref.html
@@ -0,0 +1,18 @@
+<html class="reftest-wait">
+<head>
+<script>
+document.addEventListener("MozReftestInvalidate", doTest);
+
+function doTest() {
+ window.location.href = "#two";
+ document.documentElement.className = "";
+}
+</script>
+</head>
+<body>
+<div style="height: 200px;">spacer</div>
+<div id="one" style="background: blue; width: 200px; height: 200px; display: none;">div one</div>
+<div id="two" style="background: red; width: 200px; height: 200px;">div two</div>
+<div style="height: 10000px;">spacer</div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/543681-1.html b/layout/reftests/invalidation/543681-1.html
new file mode 100644
index 0000000000..37aa856955
--- /dev/null
+++ b/layout/reftests/invalidation/543681-1.html
@@ -0,0 +1,22 @@
+<html class="reftest-wait">
+<head>
+<script>
+document.addEventListener("MozReftestInvalidate", doTest);
+
+function doTest() {
+ var one = document.getElementById("one");
+ var two = document.getElementById("two");
+ one.style.display = "none";
+ two.style.display = "";
+ window.location.href = "#two";
+ document.documentElement.className = "";
+}
+</script>
+</head>
+<body>
+<div style="height: 200px;">spacer</div>
+<div id="one" style="background: blue; width: 200px; height: 200px;">div one</div>
+<div id="two" style="background: red; width: 200px; height: 200px; display: none;">div two</div>
+<div style="height: 10000px;">spacer</div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/background-position-1-ref.html b/layout/reftests/invalidation/background-position-1-ref.html
new file mode 100644
index 0000000000..a5862f039e
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-1-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Changes to background-position should not cause things to repaint that don't intersect the background image.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ height: 512px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 300px 100px;
+}
+
+#not-intersecting-background {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ margin: 50px;
+ border: 1px solid lime;
+}
+
+</style>
+
+<div id="background">
+ <div id="not-intersecting-background"></div>
+</div>
diff --git a/layout/reftests/invalidation/background-position-1.html b/layout/reftests/invalidation/background-position-1.html
new file mode 100644
index 0000000000..c5d296b008
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-1.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should not cause things to repaint that don't intersect the background image.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ height: 512px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 300px 50px;
+}
+
+#not-intersecting-background {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ margin: 50px;
+ border: 1px solid lime;
+}
+
+</style>
+
+<div id="background">
+ <div id="not-intersecting-background" class="reftest-no-paint"></div>
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "300px 100px";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/background-position-2-ref.html b/layout/reftests/invalidation/background-position-2-ref.html
new file mode 100644
index 0000000000..f5b790a92a
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Reference for properly handled background-position changes.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-color: lime;
+}
+
+</style>
+
+<div id="background"></div>
diff --git a/layout/reftests/invalidation/background-position-2a.html b/layout/reftests/invalidation/background-position-2a.html
new file mode 100644
index 0000000000..ddf798f5fb
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2a.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should invalidate properly.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+}
+
+</style>
+
+<div id="background"></div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "-140px 0";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/background-position-2b.html b/layout/reftests/invalidation/background-position-2b.html
new file mode 100644
index 0000000000..332595055b
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2b.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should invalidate properly for input type=text.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+
+ border: 0;
+ border-radius: 0;
+ padding: 0;
+}
+
+</style>
+
+<input type="text" id="background">
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "-140px 0";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/background-position-2c.html b/layout/reftests/invalidation/background-position-2c.html
new file mode 100644
index 0000000000..69e6ac5884
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2c.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should invalidate properly for input type=button.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+
+ border: 0;
+ border-radius: 0;
+ padding: 0;
+}
+
+</style>
+
+<input type="button" id="background">
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "-140px 0";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/background-position-2d.html b/layout/reftests/invalidation/background-position-2d.html
new file mode 100644
index 0000000000..52d27c0f04
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2d.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should invalidate properly for table rows.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+
+ border: 0;
+ padding: 0;
+}
+
+table, tr, td {
+ width: 100px;
+ height: 100px;
+ border: 0;
+ padding: 0;
+ border-spacing: 0;
+}
+
+</style>
+
+<table><tr id="background"><td></td></table>
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "-140px 0";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/background-position-2e.html b/layout/reftests/invalidation/background-position-2e.html
new file mode 100644
index 0000000000..c9150da7a4
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2e.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should invalidate properly for table cells.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+
+ border: 0;
+ padding: 0;
+}
+
+table, tr, td {
+ width: 100px;
+ height: 100px;
+ border: 0;
+ padding: 0;
+ border-spacing: 0;
+}
+
+</style>
+
+<table><tr><td id="background"></td></table>
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "-140px 0";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/background-position-2f.html b/layout/reftests/invalidation/background-position-2f.html
new file mode 100644
index 0000000000..eb3797038c
--- /dev/null
+++ b/layout/reftests/invalidation/background-position-2f.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to background-position should invalidate properly for fieldsets.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 100px;
+ height: 100px;
+ background-image: url(image_rgrg-256x256.png);
+ background-repeat: no-repeat;
+ background-position: 0 0;
+
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+</style>
+
+<fieldset id="background"><legend></legend></fieldset>
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.backgroundPosition = "-140px 0";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/border-radius-1-ref.html b/layout/reftests/invalidation/border-radius-1-ref.html
new file mode 100644
index 0000000000..44132bfa86
--- /dev/null
+++ b/layout/reftests/invalidation/border-radius-1-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Changes to border-radius bounding rect should invalidate correctly.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 300px;
+ height: 200px;
+ border-radius: 100px;
+ overflow:hidden;
+}
+
+#inner {
+ width: 400px;
+ height: 400px;
+ background-color: red;
+}
+</style>
+
+<div id="background">
+ <div id="inner"></div>
+</div>
diff --git a/layout/reftests/invalidation/border-radius-1.html b/layout/reftests/invalidation/border-radius-1.html
new file mode 100644
index 0000000000..075864d7c2
--- /dev/null
+++ b/layout/reftests/invalidation/border-radius-1.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Changes to border-radius bounding rect should invalidate correctly.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#background {
+ width: 200px;
+ height: 200px;
+ border-radius: 100px;
+ overflow:hidden;
+}
+
+#inner {
+ width: 400px;
+ height: 400px;
+ background-color: red;
+}
+</style>
+
+<div id="background">
+ <div id="inner"></div>
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#background").style.width = "300px";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/box-shadow-border-radius-ref.html b/layout/reftests/invalidation/box-shadow-border-radius-ref.html
new file mode 100644
index 0000000000..fe4516d7c9
--- /dev/null
+++ b/layout/reftests/invalidation/box-shadow-border-radius-ref.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+<style>
+div#blurred {
+ box-shadow: 0 0 50px 0 #000;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ top: 30px;
+ left: 60px;
+
+ border-radius: 40px;
+}
+</style>
+</head>
+<body>
+<div id="blurred"></div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/box-shadow-border-radius.html b/layout/reftests/invalidation/box-shadow-border-radius.html
new file mode 100644
index 0000000000..8a6025863f
--- /dev/null
+++ b/layout/reftests/invalidation/box-shadow-border-radius.html
@@ -0,0 +1,27 @@
+<html class="reftest-wait">
+<head>
+<style>
+div#blurred {
+ box-shadow: 0 0 50px 0 #000;
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ top: 30px;
+ left: 30px;
+
+ border-radius: 40px;
+}
+</style>
+</head>
+<body>
+<div id="blurred"></div>
+<script>
+function doTest() {
+ var div = document.getElementById("blurred");
+ div.style.left = '60px';
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/clip-path-invalidation-1a.html b/layout/reftests/invalidation/clip-path-invalidation-1a.html
new file mode 100644
index 0000000000..0b03c1b59d
--- /dev/null
+++ b/layout/reftests/invalidation/clip-path-invalidation-1a.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: clipPath invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 10px;
+ height: 10px;
+ transform: scale(20);
+ transform-origin: top left;
+ }
+
+ div.clipped {
+ clip-path: url(#cp1);
+ }
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer clipped"></div>
+ <script type="text/javascript">
+ function changeTransform()
+ {
+ document.getElementById("d1").style.transform = "scale(10)";
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeTransform);
+ </script>
+ <svg height="0">
+ <clipPath id="cp1">
+ <rect x="10" y="10" width="5" height="5"/>
+ </clipPath>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/clip-path-invalidation-1b.html b/layout/reftests/invalidation/clip-path-invalidation-1b.html
new file mode 100644
index 0000000000..09789e5efd
--- /dev/null
+++ b/layout/reftests/invalidation/clip-path-invalidation-1b.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: clipPath invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 10px;
+ height: 10px;
+ transform: scale(20);
+ transform-origin: top left;
+ }
+
+ div.clipped {
+ clip-path: url(#cp1);
+ }
+
+ div.inner {
+ width: 5px;
+ height: 5px;
+ border: 1px solid transparent;
+ will-change: transform;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer clipped"><div class="inner"></div></div>
+ <script type="text/javascript">
+ function changeTransform()
+ {
+ document.getElementById("d1").style.transform = "scale(10)";
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeTransform);
+ </script>
+ <svg height="0">
+ <clipPath id="cp1">
+ <rect x="10" y="10" width="5" height="5"/>
+ </clipPath>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/clip-path-invalidation-1c.html b/layout/reftests/invalidation/clip-path-invalidation-1c.html
new file mode 100644
index 0000000000..9ba4db53fd
--- /dev/null
+++ b/layout/reftests/invalidation/clip-path-invalidation-1c.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: clipPath invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 200px;
+ height: 200px;
+ }
+
+ div.clipped {
+ clip-path: url(#cp1);
+ }
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer clipped"></div>
+ <script type="text/javascript">
+ function changeClipPath()
+ {
+ document.getElementById("r1").setAttribute("width", "50");
+ document.getElementById("r1").setAttribute("height", "50");
+ document.getElementById("r1").setAttribute("x", "100");
+ document.getElementById("r1").setAttribute("y", "100");
+
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeClipPath);
+ </script>
+ <svg height="0">
+ <clipPath id="cp1">
+ <rect id="r1" x="50" y="50" width="100" height="100"/>
+ </clipPath>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/clip-path-invalidation-1d.html b/layout/reftests/invalidation/clip-path-invalidation-1d.html
new file mode 100644
index 0000000000..6a46a47862
--- /dev/null
+++ b/layout/reftests/invalidation/clip-path-invalidation-1d.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: clipPath invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 200px;
+ height: 200px;
+ }
+
+ div.clipped {
+ clip-path: url(#cp1);
+ }
+
+ div.inner {
+ width: 5px;
+ height: 5px;
+ border: 1px solid transparent;
+ will-change: transform;
+ }
+
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer clipped"><div class="inner"></div></div>
+ <script type="text/javascript">
+ function changeClipPath()
+ {
+ document.getElementById("r1").setAttribute("width", "50");
+ document.getElementById("r1").setAttribute("height", "50");
+ document.getElementById("r1").setAttribute("x", "100");
+ document.getElementById("r1").setAttribute("y", "100");
+
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeClipPath);
+ </script>
+ <svg height="0">
+ <clipPath id="cp1">
+ <rect id="r1" x="50" y="50" width="100" height="100"/>
+ </clipPath>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/clipped-animated-transform-1.html b/layout/reftests/invalidation/clipped-animated-transform-1.html
new file mode 100644
index 0000000000..66b6fa2b7c
--- /dev/null
+++ b/layout/reftests/invalidation/clipped-animated-transform-1.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>The green box shouldn't be invalidated when the blue box starts to move.</title>
+
+<style>
+
+body {
+ margin: 0;
+}
+
+#clip {
+ border: 1px solid black;
+ margin: 50px;
+ overflow: hidden;
+ height: 200px;
+ width: 400px;
+ position: relative;
+}
+
+#animatedTransform {
+ border: 1px solid blue;
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ z-index: 1;
+ top: 50px;
+ left: 50px;
+ transition: transform ease-in-out 100s forwards;
+}
+
+#clip:hover > #animatedTransform,
+#animatedTransform.animate {
+ transform: translateX(200px);
+}
+
+#aboveTransform {
+ position: relative;
+ margin: 50px 100px;
+ border: 1px solid lime;
+ width: 80px;
+ height: 80px;
+ z-index: 2;
+}
+
+</style>
+
+<div id="clip">
+ <div id="animatedTransform"></div>
+</div>
+
+<div id="aboveTransform" class="reftest-no-paint"></div>
+
+<script>
+
+function doTest() {
+ document.getElementById("animatedTransform").className = "animate";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/fast-scrolling.html b/layout/reftests/invalidation/fast-scrolling.html
new file mode 100644
index 0000000000..c78456fad5
--- /dev/null
+++ b/layout/reftests/invalidation/fast-scrolling.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait" reftest-async-scroll>
+<meta charset="utf-8">
+<title>Bug 1164227 - Testcase for the invalid region simplification bug</title>
+
+<style>
+
+#scrollbox {
+ width: 400px;
+ height: 500px;
+ overflow: auto;
+ margin: 80px;
+ border: 1px solid black;
+}
+
+.contents {
+ height: 600px;
+ background: white;
+ padding: 20px;
+ position: relative;
+}
+
+.boxes > div {
+ box-sizing: border-box;
+ width: 10px;
+ height: 10px;
+ border: 1px solid black;
+ float: left;
+ margin-left: -2px;
+}
+
+.boxes > div:nth-child(odd) {
+ transform: translateY(500px);
+}
+
+.reftest-no-paint {
+ position: absolute;
+ top: 250px;
+ left: 30px;
+ width: 200px;
+ height: 50px;
+ border: 1px solid red;
+}
+</style>
+
+<div id="scrollbox"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="400"
+ reftest-displayport-h="500">
+
+ <div class="contents">
+
+ <div class="boxes">
+ <div style="margin-top: 0px"></div>
+ <div style="margin-top: 1px"></div>
+ <div style="margin-top: 2px"></div>
+ <div style="margin-top: 3px"></div>
+ <div style="margin-top: 4px"></div>
+ <div style="margin-top: 5px"></div>
+ <div style="margin-top: 6px"></div>
+ <div style="margin-top: 7px"></div>
+ <div style="margin-top: 8px"></div>
+ <div style="margin-top: 9px"></div>
+ <div style="margin-top: 10px"></div>
+ <div style="margin-top: 11px"></div>
+ <div style="margin-top: 12px"></div>
+ <div style="margin-top: 13px"></div>
+ <div style="margin-top: 14px"></div>
+ <div style="margin-top: 15px"></div>
+ <div style="margin-top: 16px"></div>
+ <div style="margin-top: 17px"></div>
+ <div style="margin-top: 18px"></div>
+ <div style="margin-top: 19px"></div>
+ <div style="margin-top: 20px"></div>
+ <div style="margin-top: 21px"></div>
+ <div style="margin-top: 22px"></div>
+ <div style="margin-top: 23px"></div>
+ <div style="margin-top: 24px"></div>
+ <div style="margin-top: 25px"></div>
+ <div style="margin-top: 26px"></div>
+ <div style="margin-top: 27px"></div>
+ <div style="margin-top: 28px"></div>
+ <div style="margin-top: 29px"></div>
+ <div style="margin-top: 30px"></div>
+ <div style="margin-top: 31px"></div>
+ <div style="margin-top: 32px"></div>
+ <div style="margin-top: 33px"></div>
+ <div style="margin-top: 34px"></div>
+ <div style="margin-top: 35px"></div>
+ <div style="margin-top: 36px"></div>
+ <div style="margin-top: 37px"></div>
+ <div style="margin-top: 38px"></div>
+ <div style="margin-top: 39px"></div>
+ </div>
+
+ <div class="reftest-no-paint"></div>
+
+ </div>
+
+</div>
+
+<script>
+
+var scrollbox = document.querySelector("#scrollbox");
+scrollbox.scrollTop = 100;
+
+window.addEventListener("MozReftestInvalidate", function (e) {
+ scrollbox.scrollTop = 0;
+ document.documentElement.removeAttribute("class");
+});
+
+</script>
diff --git a/layout/reftests/invalidation/filter-userspace-offset.svg b/layout/reftests/invalidation/filter-userspace-offset.svg
new file mode 100644
index 0000000000..2f0581b4d6
--- /dev/null
+++ b/layout/reftests/invalidation/filter-userspace-offset.svg
@@ -0,0 +1,156 @@
+<svg
+ width="500px" height="500px" viewBox="0 0 500 500"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
+ >
+ <title>Filters and offsets, user space origins, invalidation</title>
+ <defs>
+ <filter id="flood-boundingBox"
+ filterUnits="objectBoundingBox"
+ x="0%" y="0%" width="100%" height="100%"
+ color-interpolation-filters="sRGB">
+ <feFlood flood-color="lime"/>
+ </filter>
+ <filter id="matrix-boundingBox"
+ filterUnits="objectBoundingBox"
+ x="0%" y="0%" width="100%" height="100%"
+ color-interpolation-filters="sRGB">
+ <feColorMatrix type="matrix" values="0 1 0 0 0
+ 1 0 0 0 0
+ 0 0 1 0 0
+ 0 0 0 1 0"/>
+ </filter>
+ <filter id="matrix-fillPaint-boundingBox"
+ filterUnits="objectBoundingBox"
+ x="0%" y="0%" width="100%" height="100%"
+ color-interpolation-filters="sRGB">
+ <feColorMatrix type="matrix" values="0 1 0 0 0
+ 1 0 0 0 0
+ 0 0 1 0 0
+ 0 0 0 1 0" in="FillPaint"/>
+ </filter>
+ <filter id="flood-userSpace-atZero"
+ filterUnits="userSpaceOnUse"
+ x="0" y="0" width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <feFlood flood-color="lime"/>
+ </filter>
+ <filter id="matrix-userSpace-atZero"
+ filterUnits="userSpaceOnUse"
+ x="0" y="0" width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <feColorMatrix type="matrix" values="0 1 0 0 0
+ 1 0 0 0 0
+ 0 0 1 0 0
+ 0 0 0 1 0"/>
+ </filter>
+ <filter id="flood-userSpace-at100"
+ filterUnits="userSpaceOnUse"
+ x="100" y="100" width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <feFlood flood-color="lime"/>
+ </filter>
+ <filter id="matrix-userSpace-at100"
+ filterUnits="userSpaceOnUse"
+ x="100" y="100" width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <feColorMatrix type="matrix" values="0 1 0 0 0
+ 1 0 0 0 0
+ 0 0 1 0 0
+ 0 0 0 1 0"/>
+ </filter>
+ <filter id="matrix-fillPaint-userSpace-at100"
+ filterUnits="userSpaceOnUse"
+ x="100" y="100" width="100" height="100"
+ color-interpolation-filters="sRGB">
+ <feColorMatrix type="matrix" values="0 1 0 0 0
+ 1 0 0 0 0
+ 0 0 1 0 0
+ 0 0 0 1 0" in="FillPaint"/>
+ </filter>
+ <mask id="boundingBox" maskContentUnits="objectBoundingBox">
+ <rect x="0" y="0" width="1" height="1" fill="white"/>
+ </mask>
+ <mask id="userSpace-atZero" maskContentUnits="userSpaceOnUse">
+ <rect x="0" y="0" width="100" height="100" fill="white"/>
+ </mask>
+ <mask id="userSpace-at100" maskContentUnits="userSpaceOnUse">
+ <rect x="100" y="100" width="100" height="100" fill="white"/>
+ </mask>
+ <g id="usedRect">
+ <rect class="fillColor" width="100" height="100"/>
+ </g>
+ </defs>
+ <g transform="translate(40,40)">
+ <rect stroke-width="1" stroke="black" fill="none" x="99.5" y="99.5" width="101" height="101"/>
+
+ <rect x="0" y="100" width="100" height="100" class="fillColor offsetContainer" id="rect"/>
+ <use xlink:href="#usedRect" x="0" y="100" class="offsetContainer" id="use"/>
+ <svg x="0" y="100" width="100" height="100" class="offsetContainer" id="innerSVG">
+ <rect class="fillColor" width="100" height="100"/>
+ </svg>
+ <foreignObject x="0" y="100" width="100" height="100" class="offsetContainer" id="foreignObject">
+ <svg width="100" height="100">
+ <rect class="fillColor" width="100" height="100"/>
+ </svg>
+ </foreignObject>
+ </g>
+ <script><![CDATA[
+
+var options = {
+ offsetContainer: "rect",
+ filter: null,
+ mask: null,
+ updateOffsetOn: "reftestInvalidate" // | "initial" | "timeout"
+};
+
+location.search.substr(1).split("&").forEach(function (s) {
+ var pv = s.split("=");
+ options[pv[0]] = pv[1] || true;
+});
+
+var offsetContainer = document.getElementById(options.offsetContainer);
+
+function updateOffsetNow() {
+ offsetContainer.setAttribute("x", "100");
+}
+
+function updateOffsetOnReftestInvalidate() {
+ document.documentElement.setAttribute("class", "reftest-wait");
+ document.addEventListener("MozReftestInvalidate", function () {
+ updateOffsetNow();
+ document.documentElement.removeAttribute("class");
+ }, false);
+}
+
+function updateOffsetOnTimeout() {
+ setTimeout(updateOffsetNow, 500);
+}
+
+options.updateOffset = options.updateOffsetOn == "initial" ? updateOffsetNow :
+ (options.updateOffsetOn == "timeout" ? updateOffsetOnTimeout :
+ updateOffsetOnReftestInvalidate);
+
+var offsetContainers = Array.prototype.slice.call(document.getElementsByClassName("offsetContainer"), 0);
+for (var i = 0; i < offsetContainers.length; i++) {
+ if (offsetContainers[i] != offsetContainer) {
+ offsetContainers[i].parentNode.removeChild(offsetContainers[i]);
+ }
+}
+
+var fillColor = options.filter ? "red" : "lime";
+if (options.filter) {
+ offsetContainer.setAttribute("filter", "url(#" + options.filter + ")");
+}
+if (options.mask) {
+ offsetContainer.setAttribute("mask", "url(#" + options.mask + ")");
+}
+
+var fillColors = document.getElementsByClassName("fillColor");
+for (var j = 0; j < fillColors.length; j++) {
+ fillColors[j].setAttribute("fill", fillColor);
+}
+
+options.updateOffset();
+
+]]></script>
+</svg>
diff --git a/layout/reftests/invalidation/fractional-transform-1.html b/layout/reftests/invalidation/fractional-transform-1.html
new file mode 100644
index 0000000000..778621bcbc
--- /dev/null
+++ b/layout/reftests/invalidation/fractional-transform-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate either rect.</title>
+
+<style>
+body {
+ margin: 0;
+ height: 5000px;
+}
+</style>
+
+<body>
+
+<svg width="768" height="1000">
+
+ <g transform="translate(0 -2000.3234)">
+ <rect x="100" y="2300" height="50" width="50" fill="grey" class="reftest-no-paint"/>
+ </g>
+
+ <g transform="translate(0 -4000.6468)">
+ <rect x="200" y="4300" height="50" width="50" fill="grey" class="reftest-no-paint"/>
+ </g>
+
+</svg>
+
+<script>
+
+document.documentElement.scrollTop = 177;
+
+window.addEventListener("MozReftestInvalidate", function (e) {
+ document.documentElement.scrollTop = 30;
+ document.documentElement.removeAttribute("class");
+});
+
+</script>
diff --git a/layout/reftests/invalidation/fractional-transform-2.html b/layout/reftests/invalidation/fractional-transform-2.html
new file mode 100644
index 0000000000..9e47164ae3
--- /dev/null
+++ b/layout/reftests/invalidation/fractional-transform-2.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate the square.</title>
+
+<style>
+body {
+ margin: 0;
+ height: 5000px;
+}
+</style>
+
+<body>
+
+<svg width="768" height="1000">
+
+ <g transform="translate(0 112.152992)">
+ <rect x="100" y="650" height="50" width="50" fill="grey" class="reftest-no-paint"/>
+ </g>
+
+</svg>
+
+<script>
+
+document.documentElement.scrollTop = 709;
+
+window.addEventListener("MozReftestInvalidate", function (e) {
+ document.documentElement.scrollTop = 617;
+ document.documentElement.removeAttribute("class");
+});
+
+</script>
diff --git a/layout/reftests/invalidation/fractional-transform-3.html b/layout/reftests/invalidation/fractional-transform-3.html
new file mode 100644
index 0000000000..ebd89a66d6
--- /dev/null
+++ b/layout/reftests/invalidation/fractional-transform-3.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate the square.</title>
+
+<style>
+body {
+ margin: 0;
+ height: 5000px;
+}
+</style>
+
+<body>
+
+<svg width="768" height="1000">
+
+ <g transform="translate(0 0.999948799610138)">
+ <rect x="100" y="100" height="50" width="50" fill="grey" class="reftest-no-paint"/>
+ </g>
+
+</svg>
+
+<script>
+
+document.documentElement.scrollTop = 11;
+
+window.addEventListener("MozReftestInvalidate", function (e) {
+ document.documentElement.scrollTop = 51;
+ document.documentElement.removeAttribute("class");
+});
+
+</script>
diff --git a/layout/reftests/invalidation/image-scrolling-zoom-1-notref.html b/layout/reftests/invalidation/image-scrolling-zoom-1-notref.html
new file mode 100644
index 0000000000..524109ff96
--- /dev/null
+++ b/layout/reftests/invalidation/image-scrolling-zoom-1-notref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html reftest-zoom="0.3">
+<head>
+ <style type="text/css">
+ #container {
+ height: 100px;
+ overflow: auto;
+ }
+ #container-background {
+ background-color: white;
+ }
+ #container-background > div {
+ line-height: 20px;
+ }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <div id="container-background">
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/image-scrolling-zoom-1-ref.html b/layout/reftests/invalidation/image-scrolling-zoom-1-ref.html
new file mode 100644
index 0000000000..e989d0e863
--- /dev/null
+++ b/layout/reftests/invalidation/image-scrolling-zoom-1-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html reftest-zoom="0.3">
+<head>
+ <style type="text/css">
+ #container {
+ height: 100px;
+ overflow: auto;
+ }
+ #container-background {
+ background: url(one-pixel-wide-background.png);
+ }
+ #container-background > div {
+ line-height: 20px;
+ }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <div id="container-background">
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/image-scrolling-zoom-1.html b/layout/reftests/invalidation/image-scrolling-zoom-1.html
new file mode 100644
index 0000000000..33a82b31fb
--- /dev/null
+++ b/layout/reftests/invalidation/image-scrolling-zoom-1.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html class="reftest-wait" reftest-zoom="0.3">
+<head>
+ <style type="text/css">
+ #container {
+ height: 100px;
+ overflow: auto;
+ }
+ #container-background {
+ background: url(one-pixel-wide-background.png);
+ }
+ #container-background > div {
+ line-height: 20px;
+ }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <div id="container-background">
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ <div>Item</div>
+ </div>
+ </div>
+</body>
+<script>
+ var container = document.getElementById('container');
+
+ // Start scrolled all the way to the bottom.
+ container.scrollTop = container.scrollHeight;
+
+ // When we get MozReftestInvalidate, scroll to the top. This puts us at the
+ // same scroll position as the reference.
+ function doTest() {
+ container.scrollTop = 0;
+ document.documentElement.removeAttribute('class');
+ }
+
+ document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</html>
diff --git a/layout/reftests/invalidation/image_rgrg-256x256-animated.gif b/layout/reftests/invalidation/image_rgrg-256x256-animated.gif
new file mode 100644
index 0000000000..c03fad8bb0
--- /dev/null
+++ b/layout/reftests/invalidation/image_rgrg-256x256-animated.gif
Binary files differ
diff --git a/layout/reftests/invalidation/image_rgrg-256x256.png b/layout/reftests/invalidation/image_rgrg-256x256.png
new file mode 100644
index 0000000000..e6fba3daa5
--- /dev/null
+++ b/layout/reftests/invalidation/image_rgrg-256x256.png
Binary files differ
diff --git a/layout/reftests/invalidation/inactive-layertree-visible-region-1.html b/layout/reftests/invalidation/inactive-layertree-visible-region-1.html
new file mode 100644
index 0000000000..56af33d2bd
--- /dev/null
+++ b/layout/reftests/invalidation/inactive-layertree-visible-region-1.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Scrolling the horizontal bar away shouldn't invalidate the green rectangle</title>
+
+<style>
+
+.wrapper {
+ transform: translateY(1px);
+}
+
+.content {
+ box-sizing: border-box;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+}
+
+.first {
+ height: 20px;
+}
+
+.second {
+ margin-left: auto;
+ width: 20px;
+ height: 200px;
+}
+
+.reftest-no-paint {
+ margin: -150px 100px 0;
+ height: 100px;
+ border-color: lime;
+}
+
+body {
+ margin: 0;
+ padding: 50px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="wrapper">
+ <div class="first content"></div>
+ <div class="second content"></div>
+</div>
+
+<div class="reftest-no-paint content"></div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/inactive-layertree-visible-region-2.html b/layout/reftests/invalidation/inactive-layertree-visible-region-2.html
new file mode 100644
index 0000000000..980052db49
--- /dev/null
+++ b/layout/reftests/invalidation/inactive-layertree-visible-region-2.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Scrolling the horizontal bar away shouldn't invalidate the green rectangle</title>
+
+<style>
+
+.wrapper {
+ transform: translateY(1px);
+}
+
+.content {
+ box-sizing: border-box;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+}
+
+.first {
+ height: 20px;
+}
+
+.second {
+ margin-left: auto;
+ width: 20px;
+ height: 200px;
+}
+
+.reftest-no-paint {
+ margin: -150px 100px 0;
+ height: 100px;
+ border-color: lime;
+}
+
+body {
+ margin: 0;
+ padding: 50px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="wrapper">
+ <div class="wrapper">
+ <div class="first content"></div>
+ <div class="second content"></div>
+ </div>
+</div>
+
+<div class="reftest-no-paint content"></div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/jetstream-scroll-ref.html b/layout/reftests/invalidation/jetstream-scroll-ref.html
new file mode 100644
index 0000000000..780c77ef0c
--- /dev/null
+++ b/layout/reftests/invalidation/jetstream-scroll-ref.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class="reftest-wait" reftest-async-scroll><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover">
+<style>
+ figure {
+ position: relative;
+ width: 100vw;
+ left: 50%;
+ transform: translate(-50%);
+ }
+
+ figure img {
+ filter: url(#invertLightness)
+ }
+
+ main { scrollbar-width: none; width: 400px; height: 500px; overflow: auto; border: 1px solid black; }
+</style>
+
+</head>
+
+<body>
+
+ <svg xmlns="http://www.w3.org/2000/svg"> <style>svg{display:block;width:0;height:0}</style>
+ <filter id="invertLightness" x="0" y="0" style="color-interpolation-filters:sRGB">
+ <feColorMatrix type="matrix" in="SourceGraphic" result="red" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1">
+ </feColorMatrix>
+ <feColorMatrix type="matrix" in="SourceGraphic" result="green" values="0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1">
+ </feColorMatrix>
+ <feColorMatrix type="matrix" in="SourceGraphic" result="blue" values="0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1">
+ </feColorMatrix>
+ <feBlend in="red" in2="green" mode="lighten" result="maxyellow"></feBlend>
+ <feBlend in="maxyellow" in2="blue" mode="lighten" result="max"></feBlend>
+ <feBlend in="red" in2="green" mode="darken" result="minyellow"></feBlend>
+ <feBlend in="minyellow" in2="blue" mode="darken" result="min"></feBlend>
+ <feComponentTransfer result="adjustment" in="min">
+ <feFuncR type="linear" intercept="1" slope="-1"></feFuncR>
+ <feFuncG type="linear" intercept="1" slope="-1"></feFuncG>
+ <feFuncB type="linear" intercept="1" slope="-1"></feFuncB>
+ </feComponentTransfer>
+ <feComposite operator="arithmetic" in="SourceGraphic" in2="adjustment" k1="0" k2="1" k3="1" k4="-1" result="channelAdjustment"></feComposite>
+ <feComposite operator="arithmetic" in="channelAdjustment" in2="max" k1="0" k2="1" k3="-1" k4="1" result="finalColors">
+ </feComposite>
+ <feComposite operator="in" in="finalColors" in2="SourceAlpha"></feComposite>
+ </filter>
+ </svg>
+ <main id="content"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="400"
+ reftest-displayport-h="500">
+ <div>
+ <article>
+ <div>
+ <div style="height: 1000px"></div>
+ <figure>
+ <img id=telement src="data:image/webp;base64,UklGRugAAABXRUJQVlA4TNsAAAAvOEuOAQfQxhK3sf8BBW3bMOUPvzuO6H+G//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//qwEA" alt="JetStream 2 Scores. Bigger is Better.">
+ </figure>
+ </div>
+ </article>
+ </div>
+ </main>
+</body>
+<script>
+
+ document.getElementById("content").scrollTop = 1100;
+ document.documentElement.removeAttribute("class");
+</script>
+
+</html>
diff --git a/layout/reftests/invalidation/jetstream-scroll.html b/layout/reftests/invalidation/jetstream-scroll.html
new file mode 100644
index 0000000000..82ece014ad
--- /dev/null
+++ b/layout/reftests/invalidation/jetstream-scroll.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html class="reftest-wait" reftest-async-scroll><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes, viewport-fit=cover">
+<style>
+ figure {
+ position: relative;
+ width: 100vw;
+ left: 50%;
+ transform: translate(-50%);
+ }
+
+ figure img {
+ filter: url(#invertLightness)
+ }
+
+ main { scrollbar-width: none; width: 400px; height: 500px; overflow: auto; border: 1px solid black; }
+</style>
+
+</head>
+
+<body>
+
+ <svg xmlns="http://www.w3.org/2000/svg"> <style>svg{display:block;width:0;height:0}</style>
+ <filter id="invertLightness" x="0" y="0" style="color-interpolation-filters:sRGB">
+ <feColorMatrix type="matrix" in="SourceGraphic" result="red" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1">
+ </feColorMatrix>
+ <feColorMatrix type="matrix" in="SourceGraphic" result="green" values="0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1">
+ </feColorMatrix>
+ <feColorMatrix type="matrix" in="SourceGraphic" result="blue" values="0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1">
+ </feColorMatrix>
+ <feBlend in="red" in2="green" mode="lighten" result="maxyellow"></feBlend>
+ <feBlend in="maxyellow" in2="blue" mode="lighten" result="max"></feBlend>
+ <feBlend in="red" in2="green" mode="darken" result="minyellow"></feBlend>
+ <feBlend in="minyellow" in2="blue" mode="darken" result="min"></feBlend>
+ <feComponentTransfer result="adjustment" in="min">
+ <feFuncR type="linear" intercept="1" slope="-1"></feFuncR>
+ <feFuncG type="linear" intercept="1" slope="-1"></feFuncG>
+ <feFuncB type="linear" intercept="1" slope="-1"></feFuncB>
+ </feComponentTransfer>
+ <feComposite operator="arithmetic" in="SourceGraphic" in2="adjustment" k1="0" k2="1" k3="1" k4="-1" result="channelAdjustment"></feComposite>
+ <feComposite operator="arithmetic" in="channelAdjustment" in2="max" k1="0" k2="1" k3="-1" k4="1" result="finalColors">
+ </feComposite>
+ <feComposite operator="in" in="finalColors" in2="SourceAlpha"></feComposite>
+ </filter>
+ </svg>
+ <main id="content"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="400"
+ reftest-displayport-h="500">
+ <div>
+ <article>
+ <div>
+ <div style="height: 1000px"></div>
+ <figure>
+ <img id=telement src="data:image/webp;base64,UklGRugAAABXRUJQVlA4TNsAAAAvOEuOAQfQxhK3sf8BBW3bMOUPvzuO6H+G//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//+c9//vOf//znP//5z3/+85///Oc///nPf/7zn//85z//qwEA" alt="JetStream 2 Scores. Bigger is Better.">
+ </figure>
+ </div>
+ </article>
+ </div>
+ </main>
+</body>
+<script>
+
+ document.getElementById("content").scrollTop = 800;
+ document.addEventListener("MozReftestInvalidate", function() {
+ document.getElementById("content").scrollTop = 1100;
+ document.documentElement.removeAttribute("class");
+ });
+</script>
+
+</html>
diff --git a/layout/reftests/invalidation/layer-splitting-1.html b/layout/reftests/invalidation/layer-splitting-1.html
new file mode 100644
index 0000000000..1a979292e6
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-1.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Moving the transform under the absolutely-positioned layer should cause that to invalidate</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.absolute {
+ position: absolute;
+ z-index: 2;
+ top: 20px;
+ left: 240px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.transform {
+ will-change: transform;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="transform content" id="aboutToMoveUnderAbsolute">
+ <!--
+ This transform is active + prerendered, and will move under the
+ absolutely-positioned item.
+ -->
+</div>
+
+<div class="absolute reftest-no-paint content">
+ <!--
+ This absolutely-positioned element should get its own PaintedLayer above the
+ transform.
+
+ It shouldn't attempt to pull up an opaque background color from the page,
+ because the transform can move under it.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToMoveUnderAbsolute").style.transform = "translateX(100px)";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/layer-splitting-2.html b/layout/reftests/invalidation/layer-splitting-2.html
new file mode 100644
index 0000000000..878d514058
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-2.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate the fixed layer</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 20px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.distanceFromTop {
+ margin-top: 240px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+
+</style>
+
+<div class="distanceFromTop content">
+ <!--
+ This is just a non-uniform item that will be scrolled so that it's between
+ the page background and the fixed layer.
+ -->
+</div>
+
+<div class="fixed reftest-no-paint content">
+ <!--
+ This fixed layer gets its own PaintedLayer above the page.
+
+ It shouldn't attempt to pull up an opaque background color from the page,
+ because the page can move under it.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.documentElement.scrollTop = 0;
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/layer-splitting-3.html b/layout/reftests/invalidation/layer-splitting-3.html
new file mode 100644
index 0000000000..23c2004a94
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-3.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate the fixed items</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 20px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.distanceFromTop {
+ margin-top: 240px;
+}
+
+.clip {
+ width: 200px;
+ height: 200px;
+ overflow: hidden;
+}
+
+.transform {
+ position: relative;
+ will-change: transform;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+
+</style>
+
+<div class="fixed reftest-no-paint content">
+ <!--
+ This fixed layer gets its own PaintedLayer above the page.
+ -->
+</div>
+
+<div class="distanceFromTop clip">
+ <!--
+ This clip determines the potential pixels that can be affected by the
+ animated transform, *in relation to the scrolled page*. If the page
+ is scrolled, the clip moves relative to the fixed items, so the fixed
+ items need to anticipate the transform getting between them.
+ -->
+
+ <div class="transform content">
+ <!--
+ This is an animated transform item. It can move freely but will be
+ clipped by the .clip element.
+ -->
+ </div>
+
+</div>
+
+<div class="fixed reftest-no-paint content">
+ <!--
+ This fixed layer is above the animated transform, in z-order. The
+ transform is clipped in such a way that initially, the clip doesn't
+ intersect the fixed items, but once the page is scrolled, it does.
+ So this fixed item must not share a layer with the lower fixed item.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.documentElement.scrollTop = 0;
+document.addEventListener("MozReftestInvalidate", doTest);
+// setTimeout(doTest, 500);
+
+</script>
diff --git a/layout/reftests/invalidation/layer-splitting-4.html b/layout/reftests/invalidation/layer-splitting-4.html
new file mode 100644
index 0000000000..53af2eb90b
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-4.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>The two items in the scroll box should share a layer, despite all the other stuff that's going on around them</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid blue;
+ background: white;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+.opacity {
+ opacity: 0.9;
+ width: 200px;
+ height: 200px;
+ background-color: yellow;
+ will-change: opacity;
+}
+
+.overlap {
+ margin-top: -100px;
+}
+
+.scrollable {
+ position: absolute;
+ top: 20px;
+ left: 240px;
+ width: 400px;
+ height: 400px;
+ border: 1px solid black;
+ overflow: auto;
+}
+
+.scrollarea {
+ height: 800px;
+ padding: 40px;
+}
+
+.low-z, .mid-z, .high-z {
+ position: relative;
+}
+
+.low-z { z-index: 1; }
+.mid-z { z-index: 2; }
+.high-z { z-index: 3; }
+
+</style>
+
+<div class="content" reftest-assigned-layer="page-background"></div>
+<div class="overlap opacity"></div>
+<div class="overlap mid-z content" reftest-assigned-layer="on-top-of-opacity">
+ <!--
+ This item cannot merge into the page background layer because there's an
+ active container layer for the opacity in between.
+ -->
+</div>
+
+<div class="scrollable">
+ <div class="scrollarea">
+ <div class="low-z content" reftest-assigned-layer="scrolled-content"></div>
+ <div class="high-z overlap content" reftest-assigned-layer="scrolled-content"></div>
+ </div>
+</div>
+<script>
+
+var scrollable = document.querySelector(".scrollable");
+
+// Make .scrollable start out with active scrolling.
+scrollable.scrollTop = 0;
+scrollable.scrollTop = 20;
+
+</script>
diff --git a/layout/reftests/invalidation/layer-splitting-5.html b/layout/reftests/invalidation/layer-splitting-5.html
new file mode 100644
index 0000000000..a7f47b4679
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-5.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Things overlapping active scrollboxes should be in a layer on top of the scrolled contents.</title>
+
+<style>
+
+div {
+ height: 50px;
+ border: 1px solid;
+ box-model: border-box;
+}
+
+.first, .second {
+ border-color: blue;
+ margin: 50px 0;
+}
+
+.overlap {
+ border-color: #088;
+ margin-left: 100px;
+ width: 80px;
+ margin-bottom: -30px;
+ position: relative;
+}
+
+.scrollable {
+ height: auto;
+ overflow: auto;
+}
+
+.scrollarea {
+ width: 5000px;
+ border: none;
+ padding: 10px 0 20px;
+ height: auto;
+}
+
+.scrolled {
+ margin-left: 220px;
+ width: 100px;
+ height: 100px;
+ border-color: red;
+}
+
+body {
+ margin: 0;
+ padding: 0 100px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="first" reftest-assigned-layer="page-background">
+ <!--
+ This is just a regular box, it should end up in the page background layer.
+ -->
+</div>
+
+<div class="overlap reftest-no-paint">
+ <!--
+ This item intersects with the scrollable box and is positioned above
+ .scrolled, in z-order, so it should be split into its own layer as soon
+ as the scrollbox gets active scrolling. The splitting should not wait for
+ .scrolled to move under .overlap.
+ -->
+</div>
+
+<div class="scrollable">
+ <div class="scrollarea">
+ <div class="scrolled reftest-opaque-layer">
+ <!--
+ This will move under .overlap by .scrollable being scrolled. This
+ action should not invalidate .overlap.
+
+ Furthermore, since the background of .scrollable is uniform and opaque,
+ .scrolled should be able to pull up that background color and become
+ opaque itself.
+ -->
+ </div>
+ </div>
+</div>
+
+<div class="second" reftest-assigned-layer="page-background">
+ <!--
+ This should share a layer with .first and the page background.
+ -->
+</div>
+
+<script>
+
+var scrollable = document.querySelector(".scrollable");
+
+function doTest() {
+ scrollable.scrollLeft = 100;
+ document.documentElement.removeAttribute("class");
+}
+
+// Make .scrollable start out with active scrolling.
+scrollable.scrollLeft = 0;
+scrollable.scrollLeft = 20;
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
+
diff --git a/layout/reftests/invalidation/layer-splitting-6.html b/layout/reftests/invalidation/layer-splitting-6.html
new file mode 100644
index 0000000000..42da3ec61d
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-6.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Things overlapping active scrollboxes should be in a layer on top of the scrolled contents, and that layer shouldn't pull up a background color through the scrollbox.</title>
+<!--
+ This test is the same as layer-splitting-5.html, but without the scrollbox
+ border. The lack of a border here makes it attractive for .overlap to pull
+ a background color from the page background (because there's no scrollbox
+ border in the way), but it shouldn't do that because .scrolled can move
+ under it.
+-->
+
+<style>
+
+div {
+ height: 50px;
+ border: 1px solid;
+ box-model: border-box;
+}
+
+.first, .second {
+ border-color: blue;
+ margin: 50px 0;
+}
+
+.overlap {
+ border-color: #088;
+ margin-left: 100px;
+ width: 80px;
+ margin-bottom: -30px;
+ position: relative;
+}
+
+.scrollable {
+ height: auto;
+ overflow: auto;
+ border: none;
+}
+
+.scrollarea {
+ width: 5000px;
+ border: none;
+ padding: 10px 0 20px;
+ height: auto;
+}
+
+.scrolled {
+ margin-left: 220px;
+ width: 100px;
+ height: 100px;
+ border-color: red;
+}
+
+body {
+ margin: 0;
+ padding: 0 100px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="first" reftest-assigned-layer="page-background">
+ <!--
+ This is just a regular box, it should end up in the page background layer.
+ -->
+</div>
+
+<div class="overlap reftest-no-paint">
+ <!--
+ This item intersects with the scrollable box and is positioned above
+ .scrolled, in z-order, so it should be split into its own layer as soon
+ as the scrollbox gets active scrolling. The splitting should not wait for
+ .scrolled to move under .overlap.
+ -->
+</div>
+
+<div class="scrollable">
+ <div class="scrollarea">
+ <div class="scrolled reftest-opaque-layer">
+ <!--
+ This will move under .overlap by .scrollable being scrolled. This
+ action should not invalidate .overlap.
+
+ Furthermore, since the background of .scrollable is uniform and opaque,
+ .scrolled should be able to pull up that background color and become
+ opaque itself.
+ -->
+ </div>
+ </div>
+</div>
+
+<div class="second" reftest-assigned-layer="page-background">
+ <!--
+ This should share a layer with .first and the page background.
+ -->
+</div>
+
+<script>
+
+var scrollable = document.querySelector(".scrollable");
+
+function doTest() {
+ scrollable.scrollLeft = 100;
+ document.documentElement.removeAttribute("class");
+}
+
+// Make .scrollable start out with active scrolling.
+scrollable.scrollLeft = 0;
+scrollable.scrollLeft = 20;
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
+
diff --git a/layout/reftests/invalidation/layer-splitting-7.html b/layout/reftests/invalidation/layer-splitting-7.html
new file mode 100644
index 0000000000..b4e72d523b
--- /dev/null
+++ b/layout/reftests/invalidation/layer-splitting-7.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate the relatively-positioned layer</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 20px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.distanceFromTop {
+ margin-top: 240px;
+}
+
+.relative {
+ position: relative;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+
+</style>
+
+<div class="fixed reftest-no-paint content">
+ <!--
+ This fixed layer gets its own PaintedLayer above the page.
+
+ It shouldn't attempt to pull up an opaque background color from the page,
+ because the page can move under it.
+ -->
+</div>
+
+<div class="distanceFromTop relative reftest-no-paint content">
+ <!--
+ This item is above .fixed in z-order, but it starts out not intersecting
+ .fixed. It should still get its own layer from the start, because it can
+ get scrolled on top of .fixed.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.documentElement.scrollTop = 0;
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/mask-invalidation-1-ref.html b/layout/reftests/invalidation/mask-invalidation-1-ref.html
new file mode 100644
index 0000000000..e2ebf07edb
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-1-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask repainting.</title>
+ <style type="text/css">
+ div {
+ background-color: purple;
+ position: absolute;
+ margin: 1px 2px 3px 4px;
+ border: solid purple;
+ width: 44px;
+ height: 9px;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="outer" style="top: 15px; left: 15px;"></div>
+ <div class="outer" style="top: 15px; left: 115px;"></div>
+ <div class="outer" style="top: 15px; left: 215px;"></div>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-1a.html b/layout/reftests/invalidation/mask-invalidation-1a.html
new file mode 100644
index 0000000000..594cbbca8f
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-1a.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ background-color: purple;
+ position: absolute;
+ margin: 1px 2px 3px 4px;
+ border: solid purple;
+ width: 40px;
+ height: 20px;
+ }
+
+ div.mask {
+ mask-size: 100% 100%;
+ mask-origin: border-box;
+ mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="100%" height="50%" fill="blue" fill-opacity="1"/><rect x="0" y="50%" width="100%" height="50%" fill="blue" fill-opacity="0"/></svg>');
+ }
+
+ #d1 {
+ top: 10px;
+ left: 10px;
+ mask-clip: padding-box;
+ border-width: 10px;
+ padding: 0px;
+ }
+
+ #d2 {
+ top: 10px;
+ left: 110px;
+ mask-clip: padding-box;
+ border-width: 0px;
+ padding: 10px;
+ }
+
+ #d3 {
+ top: 15px;
+ left: 215px;
+ mask-clip: content-box;
+ border-width: 10px;
+ padding: 0px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer mask"></div>
+ <div id="d2" class="outer mask"></div>
+ <div id="d3" class="outer mask"></div>
+ <script type="text/javascript">
+ function invalidateMaskedElements()
+ {
+ // Shrink border area, thicken padding area. Keep ths size of this
+ // division unchanged.
+ document.getElementById("d1").style.borderWidth = "5px";
+ document.getElementById("d1").style.padding = "5px";
+
+ // Shrink padding area, thicken border area. Keep ths size of this
+ // division unchanged.
+ document.getElementById("d2").style.borderWidth = "5px";
+ document.getElementById("d2").style.padding = "5px";
+
+ // Shrink border area, thicken content area. Keep ths size of this
+ // division unchanged.
+ document.getElementById("d3").style.width = "50px";
+ document.getElementById("d3").style.height = "30px";
+ document.getElementById("d3").style.borderWidth = "0px";
+
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ invalidateMaskedElements);
+ </script>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-1b.html b/layout/reftests/invalidation/mask-invalidation-1b.html
new file mode 100644
index 0000000000..cfc39c4f0f
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-1b.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ background-color: purple;
+ position: absolute;
+ margin: 1px 2px 3px 4px;
+ border: solid purple;
+ width: 40px;
+ height: 20px;
+ }
+
+ div.inner {
+ width: 10px;
+ height: 10px;
+ border: 1px solid transparent;
+ will-change: transform;
+ }
+
+ div.mask {
+ mask-size: 100% 100%;
+ mask-origin: border-box;
+ mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="100%" height="50%" fill="blue" fill-opacity="1"/><rect x="0" y="50%" width="100%" height="50%" fill="blue" fill-opacity="0"/></svg>');
+ }
+
+ #d1 {
+ top: 10px;
+ left: 10px;
+ mask-clip: padding-box;
+ border-width: 10px;
+ padding: 0px;
+ }
+
+ #d2 {
+ top: 10px;
+ left: 110px;
+ mask-clip: padding-box;
+ border-width: 0px;
+ padding: 10px;
+ }
+
+ #d3 {
+ top: 15px;
+ left: 215px;
+ mask-clip: content-box;
+ border-width: 10px;
+ padding: 0px;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer mask"><div class="inner"></div></div>
+ <div id="d2" class="outer mask"><div class="inner"></div></div>
+ <div id="d3" class="outer mask"><div class="inner"></div></div>
+ <script type="text/javascript">
+ function invalidateMaskedElements()
+ {
+ // Shrink border area, thicken padding area. Keep ths size of this
+ // division unchanged.
+ document.getElementById("d1").style.borderWidth = "5px";
+ document.getElementById("d1").style.padding = "5px";
+
+ // Shrink padding area, thicken border area. Keep ths size of this
+ // division unchanged.
+ document.getElementById("d2").style.borderWidth = "5px";
+ document.getElementById("d2").style.padding = "5px";
+
+ // Shrink border area, thicken content area. Keep ths size of this
+ // division unchanged.
+ document.getElementById("d3").style.width = "50px";
+ document.getElementById("d3").style.height = "30px";
+ document.getElementById("d3").style.borderWidth = "0px";
+
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ invalidateMaskedElements);
+ </script>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-2-ref.html b/layout/reftests/invalidation/mask-invalidation-2-ref.html
new file mode 100644
index 0000000000..e16c871e66
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-2-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask repainting.</title>
+ <link rel="author" title="CJ Ku" href="mailto:cku@mozilla.com">
+ <link rel="author" title="Mozilla" href="https://www.mozilla.org">
+ </head>
+ <body>
+ <svg width="200" height="200">
+ <rect x="100" y="100" width="50" height="50" style="stroke:none; fill: purple;"/>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-2a.html b/layout/reftests/invalidation/mask-invalidation-2a.html
new file mode 100644
index 0000000000..61e9b0bfc2
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-2a.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 10px;
+ height: 10px;
+ transform: scale(20);
+ transform-origin: top left;
+ }
+
+ div.mask {
+ mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><rect x="10" y="10" width="5" height="5" fill="black"/></svg>');
+ }
+
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer mask"></div>
+ <script type="text/javascript">
+ function changeTransform()
+ {
+ document.getElementById("d1").style.transform = "scale(10)";
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeTransform);
+ </script>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-2b.html b/layout/reftests/invalidation/mask-invalidation-2b.html
new file mode 100644
index 0000000000..42ef779f1d
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-2b.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 10px;
+ height: 10px;
+ transform: scale(20);
+ transform-origin: top left;
+ }
+
+ div.mask {
+ mask-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 10 10"><rect x="10" y="10" width="5" height="5" fill="black"/></svg>');
+ }
+
+ div.inner {
+ width: 5px;
+ height: 5px;
+ border: 1px solid transparent;
+ will-change: transform;
+ }
+
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer mask"><div class="inner"></div></div>
+ <script type="text/javascript">
+ function changeTransform()
+ {
+ document.getElementById("d1").style.transform = "scale(10)";
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeTransform);
+ </script>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-2c.html b/layout/reftests/invalidation/mask-invalidation-2c.html
new file mode 100644
index 0000000000..a27c60b4d2
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-2c.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 200px;
+ height: 200px;
+ }
+
+ div.mask {
+ mask-image: url(#m1);
+ }
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer mask"></div>
+ <script type="text/javascript">
+ function changeMask()
+ {
+ document.getElementById("r1").setAttribute("width", "50");
+ document.getElementById("r1").setAttribute("height", "50");
+ document.getElementById("r1").setAttribute("x", "100");
+ document.getElementById("r1").setAttribute("y", "100");
+
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeMask);
+ </script>
+ <svg height="0">
+ <mask id="m1" x="0" y="0" width="1" height="1">
+ <rect id="r1" x="50" y="50" width="100" height="100" style="stroke:none; fill: #ffffff;"/>
+ </mask>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/mask-invalidation-2d.html b/layout/reftests/invalidation/mask-invalidation-2d.html
new file mode 100644
index 0000000000..5fa5d96270
--- /dev/null
+++ b/layout/reftests/invalidation/mask-invalidation-2d.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Masking: mask invalidation.</title>
+ <style type="text/css">
+ div.outer {
+ position: absolute;
+ background-color: purple;
+ border: solid purple;
+ width: 200px;
+ height: 200px;
+ }
+
+ div.mask {
+ mask-image: url(#m1);
+ }
+
+ div.inner {
+ width: 5px;
+ height: 5px;
+ border: 1px solid transparent;
+ will-change: transform;
+ }
+
+ </style>
+ </head>
+ <body>
+ <div id="d1" class="outer mask"><div class="inner"></div></div>
+ <script type="text/javascript">
+ function changeMask()
+ {
+ document.getElementById("r1").setAttribute("width", "50");
+ document.getElementById("r1").setAttribute("height", "50");
+ document.getElementById("r1").setAttribute("x", "100");
+ document.getElementById("r1").setAttribute("y", "100");
+
+ document.documentElement.removeAttribute("class");
+ }
+
+ document.addEventListener("MozReftestInvalidate",
+ changeMask);
+ </script>
+ <svg height="0">
+ <mask id="m1" x="0" y="0" width="1" height="1">
+ <rect id="r1" x="50" y="50" width="100" height="100" style="stroke:none; fill: #ffffff;"/>
+ </mask>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/invalidation/masklayer-1.html b/layout/reftests/invalidation/masklayer-1.html
new file mode 100644
index 0000000000..137bb0ba39
--- /dev/null
+++ b/layout/reftests/invalidation/masklayer-1.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Moving a layer in a box with a rounded clip shouldn't invalidate.</title>
+
+<style>
+
+#outer {
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 300px;
+ height: 200px;
+ background-color: #DDD;
+ overflow: hidden;
+ border-radius: 10px;
+}
+
+#animatedLeft {
+ position: absolute;
+ top: 50px;
+ left: 40px;
+ box-model: border-box;
+ border: 1px solid lime;
+ width: 100px;
+ height: 100px;
+}
+
+</style>
+
+<body>
+
+<div id="outer">
+ <div id="animatedLeft" class="reftest-no-paint"></div>
+</div>
+
+<script>
+
+var animatedLeft = document.getElementById("animatedLeft");
+
+function doTest() {
+ animatedLeft.style.left = "100px";
+ document.documentElement.removeAttribute("class");
+}
+
+// Layerize #animatedLeft
+animatedLeft.offsetLeft;
+animatedLeft.style.left = "60px";
+animatedLeft.offsetLeft;
+animatedLeft.style.left = "40px";
+animatedLeft.offsetLeft;
+
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/masklayer-2.html b/layout/reftests/invalidation/masklayer-2.html
new file mode 100644
index 0000000000..c6befa2001
--- /dev/null
+++ b/layout/reftests/invalidation/masklayer-2.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en" reftest-async-scroll>
+<meta charset="utf-8">
+<title>Moving a layer in a box with a rounded clip shouldn't invalidate.</title>
+
+<style>
+
+#scrollbox {
+ position: absolute;
+ top: 50px;
+ left: 50px;
+ width: 300px;
+ height: 200px;
+ background-color: #DDD;
+ overflow: auto;
+ border-radius: 10px;
+}
+
+#scrollable {
+ width: 600px;
+}
+
+#scrolledLayer {
+ margin-top: 50px;
+ margin-left: 100px;
+ box-model: border-box;
+ border: 1px solid lime;
+ width: 100px;
+ height: 100px;
+}
+
+</style>
+
+<body>
+
+<div id="scrollbox" reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="300"
+ reftest-displayport-h="200">
+ <div id="scrollable">
+ <div id="scrolledLayer" class="reftest-no-paint"></div>
+ </div>
+</div>
+
+<script>
+
+var scrollbox = document.getElementById("scrollbox");
+
+function doTest() {
+ scrollbox.scrollLeft = 0;
+ document.documentElement.removeAttribute("class");
+}
+
+// Make #scrollbox have active scrolling
+scrollbox.scrollLeft = 60;
+scrollbox.offsetLeft;
+scrollbox.scrollLeft = 40;
+scrollbox.offsetLeft;
+
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/negative-w-component-ref.html b/layout/reftests/invalidation/negative-w-component-ref.html
new file mode 100644
index 0000000000..f8d845d17e
--- /dev/null
+++ b/layout/reftests/invalidation/negative-w-component-ref.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Change a layer's transform making negative w component.</title>
+
+<style>
+
+body {
+ background-color: white;
+ overflow: hidden;
+}
+
+#outer {
+ perspective: 500px;
+ perspective-origin: 350px 250px;
+ width: 700px;
+ height: 500px;
+ display: block;
+ top: 10px;
+ left: 10px;
+ position: absolute;
+ overflow: visible;
+}
+
+#container1 {
+ transform-style: preserve-3d;
+ transform: translateX(-50px) translateZ(350px) rotateY(-90deg);
+}
+
+#container2 {
+ transform-style: preserve-3d;
+ transform: translateY(-200px) translateX(50px) translateZ(350px) rotateY(90deg);
+}
+
+#scale {
+ transform-style: preserve-3d;
+}
+
+.negw {
+ transform: translateZ(1px);
+}
+
+.posw {
+ transform: translateZ(-500px);;
+}
+
+#dummy {
+ transform-style: preserve-3d;
+ transform: translateY(150px);
+}
+
+#square1, #square2 {
+ background-color: red;
+ width: 700px;
+ height: 200px;
+}
+
+</style>
+
+<body>
+
+<div id="outer">
+ <div id="scale" class="posw">
+ <div id="dummy">
+ <div id="container1">
+ <div id="square1"></div>
+ </div>
+ <div id="container2">
+ <div id="square2"></div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/layout/reftests/invalidation/negative-w-component.html b/layout/reftests/invalidation/negative-w-component.html
new file mode 100644
index 0000000000..4e27fd5edb
--- /dev/null
+++ b/layout/reftests/invalidation/negative-w-component.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Change a layer's transform making negative w component.</title>
+
+<style>
+
+body {
+ background-color: white;
+ overflow: hidden;
+}
+
+#outer {
+ perspective: 500px;
+ perspective-origin: 350px 250px;
+ width: 700px;
+ height: 500px;
+ display: block;
+ top: 10px;
+ left: 10px;
+ position: absolute;
+ overflow: visible;
+}
+
+#container1 {
+ transform-style: preserve-3d;
+ transform: translateX(-50px) translateZ(350px) rotateY(-90deg);
+}
+
+#container2 {
+ transform-style: preserve-3d;
+ transform: translateY(-200px) translateX(50px) translateZ(350px) rotateY(90deg);
+}
+
+#scale {
+ transform-style: preserve-3d;
+}
+
+.negw {
+ transform: translateZ(1px);
+}
+
+.posw {
+ transform: translateZ(-500px);;
+}
+
+#dummy {
+ transform-style: preserve-3d;
+ transform: translateY(150px);
+}
+
+#square1, #square2 {
+ background-color: red;
+ width: 700px;
+ height: 200px;
+}
+
+</style>
+
+<body>
+
+<div id="outer">
+ <div id="scale" class="negw">
+ <div id="dummy">
+ <div id="container1">
+ <div id="square1"></div>
+ </div>
+ <div id="container2">
+ <div id="square2"></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<script>
+
+var scale = document.getElementById("scale");
+
+function doTest() {
+ scale.className = "posw";
+ document.documentElement.removeAttribute("class");
+}
+
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/nudge-to-integer-invalidation.html b/layout/reftests/invalidation/nudge-to-integer-invalidation.html
new file mode 100644
index 0000000000..0b8d8db1b1
--- /dev/null
+++ b/layout/reftests/invalidation/nudge-to-integer-invalidation.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Different epsilons in NudeToInteger and FuzzyEqual cause invalidations</title>
+
+<body>
+
+<svg viewBox="0 0 700 3000" width="700px" height="3000px">
+ <g transform="translate(0, -220.999756)">
+ <rect x="100" y="400" height="50" width="50" fill="grey" class="reftest-no-paint"/>
+ </g>
+</svg>
+
+<script>
+
+var scrollPositions = [0, 50];
+if (location.search.includes("reverse")) {
+ scrollPositions.reverse();
+}
+document.documentElement.scrollTop = scrollPositions[0];
+
+function doTest() {
+ document.documentElement.scrollTop = scrollPositions[1];
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/one-pixel-wide-background.png b/layout/reftests/invalidation/one-pixel-wide-background.png
new file mode 100644
index 0000000000..09f59e39ac
--- /dev/null
+++ b/layout/reftests/invalidation/one-pixel-wide-background.png
Binary files differ
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-1.html b/layout/reftests/invalidation/paintedlayer-recycling-1.html
new file mode 100644
index 0000000000..5f0b211e10
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-1.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Switching the transform to animate shouldn't invalidate the fixed layer</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ background-color: white;
+ top: 20px;
+ left: 240px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.transform {
+ transform: translateY(0.1px);
+}
+
+.aboveTransform {
+ margin-top: 20px;
+ border-color: blue;
+ position: relative;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="transform content" id="aboutToAnimate">
+ <!--
+ This transform starts out inactive and is going to turn active + prerendered.
+ -->
+</div>
+
+<div class="aboveTransform content">
+ <!--
+ This content is on top of .transform in z-order but starts out in the
+ same layer as .transform (and the canvas background). Once the transform
+ turns active, this needs its own PaintedLayer because the prerendered
+ transform might asynchronously move underneath it.
+ -->
+</div>
+
+<div class="fixed reftest-no-paint content">
+ <!--
+ This fixed layer gets its own PaintedLayer above the rest.
+ When .aboveTransform requires its own PaintedLayer, it should not cause
+ .fixed to change layers.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToAnimate").style.willChange = "transform";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-2.html b/layout/reftests/invalidation/paintedlayer-recycling-2.html
new file mode 100644
index 0000000000..bcec2aef84
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-2.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Starting to scroll the nested scrollbox shouldn't invalidate the fixed layer</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 240px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.scrollable {
+ overflow: auto;
+ padding: 10px;
+}
+
+.scrolled {
+ border: 1px solid gray;
+ height: 400px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="scrollable content" id="aboutToScroll">
+ <!--
+ This scrollbox starts out without active scrolling and is going to become
+ actively scrolled.
+ -->
+ <div class="scrolled"></div>
+</div>
+
+<div class="fixed reftest-no-paint content">
+ <!--
+ This fixed layer gets its own PaintedLayer above the rest.
+ When the contents of .scrollable require their own PaintedLayer, that
+ should not cause .fixed to change layers.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToScroll").scrollTop = 50 - document.querySelector("#aboutToScroll").scrollTop;
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-3.html b/layout/reftests/invalidation/paintedlayer-recycling-3.html
new file mode 100644
index 0000000000..271997b492
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-3.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Adding a new display item to the bottom of an existing PaintedLayer shouldn't cause the other items in that layer to change layers</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 140px;
+}
+
+.onTopOfFixed {
+ position: absolute;
+ top: 120px;
+ left: 260px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+#aboutToBecomeVisible {
+ left: 20px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force .onTopOfFixed into a PaintedLayer above
+ the page background.
+ -->
+</div>
+
+<div class="onTopOfFixed content" id="aboutToBecomeVisible" style="visibility: hidden">
+ <!--
+ This item starts out invisible but should end up in the same layer as the other
+ .onTopOfFixed item, once it's visible.
+ -->
+</div>
+
+<div class="onTopOfFixed reftest-no-paint content">
+ <!--
+ This item shouldn't repaint when the other .onTopOfFixed item becomes visible.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToBecomeVisible").style.visibility = "visible";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-4.html b/layout/reftests/invalidation/paintedlayer-recycling-4.html
new file mode 100644
index 0000000000..d69cd35cbd
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-4.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Removing an existing display item from the bottom of an existing PaintedLayer shouldn't cause the other items in that layer to change layers</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 140px;
+}
+
+.onTopOfFixed {
+ position: absolute;
+ top: 120px;
+ left: 260px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+#aboutToBecomeHidden {
+ left: 20px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force .onTopOfFixed into a PaintedLayer above
+ the page background.
+ -->
+</div>
+
+<div class="onTopOfFixed content" id="aboutToBecomeHidden" style="visibility: visible">
+ <!--
+ This item starts out visible, in the same layer as the other .onTopOfFixed item.
+ -->
+</div>
+
+<div class="onTopOfFixed reftest-no-paint content">
+ <!--
+ This item shouldn't repaint when the other .onTopOfFixed item becomes invisible.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToBecomeHidden").style.visibility = "hidden";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-5.html b/layout/reftests/invalidation/paintedlayer-recycling-5.html
new file mode 100644
index 0000000000..8a8529e2ff
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-5.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Removing an existing display item that has its own PaintedLayer shouldn't cause invalidations in other PaintedLayers on top of it</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 140px;
+}
+
+.onTopOfFixed {
+ position: absolute;
+ top: 120px;
+ left: 260px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+#aboutToBecomeHidden {
+ left: 20px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force .onTopOfFixed into PaintedLayers above
+ the page background.
+ -->
+</div>
+
+<div class="onTopOfFixed content" id="aboutToBecomeHidden" style="visibility: visible">
+ <!--
+ This item starts out visible, and has its own PaintedLayer.
+ -->
+</div>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force the next .onTopOfFixed into its own
+ PaintedLayer.
+ -->
+</div>
+
+<div class="onTopOfFixed reftest-no-paint content">
+ <!--
+ This item shouldn't repaint when the other .onTopOfFixed item is hidden.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToBecomeHidden").style.visibility = "hidden";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-6.html b/layout/reftests/invalidation/paintedlayer-recycling-6.html
new file mode 100644
index 0000000000..1e54cfc8c1
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-6.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Adding a new display item that has its own PaintedLayer shouldn't cause invalidations in other PaintedLayers on top of it</title>
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 140px;
+}
+
+.onTopOfFixed {
+ position: absolute;
+ top: 120px;
+ left: 260px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+#aboutToBecomeVisible {
+ left: 20px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force .onTopOfFixed into PaintedLayers above
+ the page background.
+ -->
+</div>
+
+<div class="onTopOfFixed content" id="aboutToBecomeVisible" style="visibility: hidden">
+ <!--
+ This item starts out hidden, and will get its own PaintedLayer when it
+ becomes visible.
+ -->
+</div>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force the next .onTopOfFixed into its own
+ PaintedLayer.
+ -->
+</div>
+
+<div class="onTopOfFixed reftest-no-paint content">
+ <!--
+ This item shouldn't repaint when the other .onTopOfFixed item becomes visible.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToBecomeVisible").style.visibility = "visible";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-7.html b/layout/reftests/invalidation/paintedlayer-recycling-7.html
new file mode 100644
index 0000000000..0e23c37a2d
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-7.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>When a PaintedLayer is split up into two, the lower items should stay in their layer and the higher items should get a new one.</title>
+<!-- The motivation for this is that we don't ever want to assign a new layer to the canvas background just because an item is split from it. -->
+
+
+<style>
+
+.content {
+ box-sizing: border-box;
+ width: 200px;
+ height: 200px;
+ border: 1px solid black;
+}
+
+.fixed {
+ position: fixed;
+ top: 20px;
+ left: 140px;
+}
+
+.onTopOfFixed {
+ position: absolute;
+ top: 120px;
+ left: 260px;
+}
+
+.reftest-no-paint {
+ border-color: lime;
+}
+
+.onTopOfFixed.reftest-no-paint {
+ left: 20px;
+}
+
+body {
+ margin: 0;
+ padding: 20px;
+ height: 3000px;
+}
+
+</style>
+
+<div class="fixed content">
+ <!--
+ This layer is just there to force .onTopOfFixed into PaintedLayers above
+ the page background.
+ -->
+</div>
+
+<div class="onTopOfFixed reftest-no-paint content">
+ <!--
+ This item should start out sharing a PaintedLayer with the other
+ .onTopOfFixed item.
+ -->
+</div>
+
+<div class="fixed content" id="aboutToBecomeVisible" style="visibility: hidden">
+ <!--
+ This layer starts out hidden. When it becomes visible, it forces the two
+ .onTopOfFixed items into separate layers.
+ -->
+</div>
+
+<div class="onTopOfFixed content">
+ <!--
+ This item should start out sharing a PaintedLayer with the other
+ .onTopOfFixed item, but when the two items get split up, it should be this
+ one that changes layers, not the other one.
+ -->
+</div>
+
+<script>
+
+function doTest() {
+ document.querySelector("#aboutToBecomeVisible").style.visibility = "visible";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-8-ref.html b/layout/reftests/invalidation/paintedlayer-recycling-8-ref.html
new file mode 100644
index 0000000000..6023ddefba
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-8-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>PaintedLayer recycling should use the right translation</title>
+<style>
+body {
+ overflow: hidden;
+ background-color: grey;
+}
+
+.fixed {
+ position: fixed;
+ width: 800px;
+ height: 800px;
+}
+
+.container {
+ position: relative;
+ top: 50px;
+ left: 50px;
+ width: 400px;
+ height: 400px;
+ z-index: 1;
+ pointer-events: none;
+ transform: scale(1.0);
+}
+
+.not-transformed {
+ background-color: lightblue;
+ width: 200px;
+ height: 200px;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ z-index: 1;
+}
+
+.transformed {
+ position: relative;
+ top: 50px;
+ left: 50px;
+ width: 200px;
+ height: 200px;
+ background: red;
+ transform: scale(1.5);
+}
+</style>
+</head>
+<body>
+ <div class="fixed">
+ <div class="container">
+ <div class="not-transformed"></div>
+ <div class="transformed"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/paintedlayer-recycling-8.html b/layout/reftests/invalidation/paintedlayer-recycling-8.html
new file mode 100644
index 0000000000..b72371b795
--- /dev/null
+++ b/layout/reftests/invalidation/paintedlayer-recycling-8.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+<title>PaintedLayer recycling should use the right translation</title>
+<style>
+body {
+ overflow: hidden;
+ background-color: grey;
+}
+
+.fixed {
+ position: fixed;
+ width: 800px;
+ height: 800px;
+}
+
+.container {
+ position: relative;
+ top: 50px;
+ left: 50px;
+ width: 400px;
+ height: 400px;
+ z-index: 1;
+ pointer-events: none;
+}
+
+.not-transformed {
+ background-color: blue;
+ width: 200px;
+ height: 200px;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ z-index: 1;
+}
+
+.transformed {
+ position: relative;
+ top: 50px;
+ left: 50px;
+ width: 200px;
+ height: 200px;
+ background: red;
+ transform: scale(1.5);
+}
+</style>
+</head>
+<body>
+ <div class="fixed">
+ <div class="container">
+ <div class="not-transformed"></div>
+ <div class="transformed"></div>
+ </div>
+ </div>
+</body>
+<script type="text/javascript">
+function end() {
+ document.documentElement.removeAttribute("class");
+}
+
+function runAfterNextPaint(cb) {
+ requestAnimationFrame(() => requestAnimationFrame(cb))
+}
+
+function change() {
+ document.querySelector(".not-transformed").style["background-color"] = "lightblue";
+ runAfterNextPaint(end);
+}
+
+function doTest() {
+ document.querySelector(".container").style.transform = "scale(1.0)";
+ runAfterNextPaint(change);
+}
+
+document.addEventListener("MozReftestInvalidate", doTest);
+
+//setTimeout(doTest, 5000);
+</script>
+</html>
diff --git a/layout/reftests/invalidation/partially-scrolled-svg-group-ref.html b/layout/reftests/invalidation/partially-scrolled-svg-group-ref.html
new file mode 100644
index 0000000000..901be4ef76
--- /dev/null
+++ b/layout/reftests/invalidation/partially-scrolled-svg-group-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html lang="en"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<body>
+ <div>
+ <h4 style="height: 600px">All the lines at the bottom should show up when this is scrolled down.</h4>
+ <div id="ember801" class="graph-data ember-view">
+ <div style="position: relative;">
+ <div style="position: relative; width: 920px; height: 500px;" dir="ltr">
+ <div style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;" aria-label="A chart.">
+ <svg width="920" height="500" style="" aria-label="A chart.">
+ <defs id="defs">
+ <clipPath id="_ABSTRACT_RENDERER_ID_2">
+ <rect x="85" y="50" width="708" height="400"></rect>
+ </clipPath></defs>
+ <rect x="0" y="0" width="920" height="500" stroke="none" stroke-width="0" fill="#ffffff"></rect>
+ <g></g>
+ <g>
+ <rect x="85" y="50" width="708" height="400" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect>
+ <g clip-path="url(#_ABSTRACT_RENDERER_ID_2)">
+ <g>
+ <rect y="50" width="1" height="400" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="399" y="50" width="1" height="400" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="449" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="349" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="250" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="150" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="50" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ </g>
+ </g>
+ </g>
+ </svg>
+ </div>
+ </div>
+ <div aria-hidden="true" style="position: absolute; top: 510px; left: 930px; white-space: nowrap; font-family: Arial; font-size: 14px; display: none;">0.2.42</div>
+ <div></div>
+ </div>
+ </div>
+ </div>
+
+<script>
+document.documentElement.scrollTop = 200;
+
+</script>
+
+ </body>
+ </html> \ No newline at end of file
diff --git a/layout/reftests/invalidation/partially-scrolled-svg-group.html b/layout/reftests/invalidation/partially-scrolled-svg-group.html
new file mode 100644
index 0000000000..d7c08582af
--- /dev/null
+++ b/layout/reftests/invalidation/partially-scrolled-svg-group.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<body>
+ <div>
+ <h4 style="height: 600px">All the lines at the bottom should show up when this is scrolled down.</h4>
+ <div id="ember801" class="graph-data ember-view">
+ <div style="position: relative;">
+ <div style="position: relative; width: 920px; height: 500px;" dir="ltr">
+ <div style="position: absolute; left: 0px; top: 0px; width: 100%; height: 100%;" aria-label="A chart.">
+ <svg width="920" height="500" style="" aria-label="A chart.">
+ <defs id="defs">
+ <clipPath id="_ABSTRACT_RENDERER_ID_2">
+ <rect x="85" y="50" width="708" height="400"></rect>
+ </clipPath></defs>
+ <rect x="0" y="0" width="920" height="500" stroke="none" stroke-width="0" fill="#ffffff"></rect>
+ <g></g>
+ <g>
+ <rect x="85" y="50" width="708" height="400" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect>
+ <g clip-path="url(#_ABSTRACT_RENDERER_ID_2)">
+ <g>
+ <rect y="50" width="1" height="400" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="399" y="50" width="1" height="400" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="449" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="349" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="250" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="150" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ <rect x="85" y="50" width="708" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect>
+ </g>
+ </g>
+ </g>
+ </svg>
+ </div>
+ </div>
+ <div aria-hidden="true" style="position: absolute; top: 510px; left: 930px; white-space: nowrap; font-family: Arial; font-size: 14px; display: none;">0.2.42</div>
+ <div></div>
+ </div>
+ </div>
+ </div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 200;
+ document.documentElement.removeAttribute("class");
+}
+
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
+
+ </body>
+ </html> \ No newline at end of file
diff --git a/layout/reftests/invalidation/reftest.list b/layout/reftests/invalidation/reftest.list
new file mode 100644
index 0000000000..27b228fa2b
--- /dev/null
+++ b/layout/reftests/invalidation/reftest.list
@@ -0,0 +1,109 @@
+== table-repaint-a.html table-repaint-a-ref.html
+== table-repaint-b.html table-repaint-b-ref.html
+== table-repaint-border-collapse.html table-repaint-border-collapse-ref.html
+== table-repaint-c.html table-repaint-c-ref.html
+== table-repaint-d.html table-repaint-d-ref.html
+== table-repaint-e.html table-repaint-e-ref.html
+== table-repaint-non-border-collapse.html table-repaint-non-border-collapse-ref.html
+== chrome://reftest/content/invalidation/540247-1.xhtml chrome://reftest/content/invalidation/540247-1-ref.xhtml
+== 543681-1.html 543681-1-ref.html
+== 1243409-1.html 1243409-1-ref.html
+skip == test-image-layers.html test-image-layers-ref.html # Bug 1067360
+skip == test-image-layers-multiple-displayitem.html test-image-layers-ref.html # Bug 1067360
+skip-if(gtkWidget) == test-animated-image-layers.html test-animated-image-layers-ref.html
+skip-if(gtkWidget) == test-animated-image-layers-background.html test-animated-image-layers-ref.html
+== box-shadow-border-radius.html box-shadow-border-radius-ref.html
+== filter-userspace-offset.svg?offsetContainer=rect filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&filter=flood-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use&filter=flood-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=flood-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=flood-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use&filter=matrix-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=matrix-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=matrix-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&filter=flood-userSpace-at100 filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use&filter=flood-userSpace-atZero filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=flood-userSpace-atZero filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=flood-userSpace-at100 filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-userSpace-at100 filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use&filter=matrix-userSpace-atZero filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG&filter=matrix-userSpace-atZero filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject&filter=matrix-userSpace-at100 filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&mask=boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use&mask=boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG&mask=boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject&mask=boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&mask=userSpace-at100 filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=use&mask=userSpace-atZero filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=innerSVG&mask=userSpace-atZero filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=foreignObject&mask=userSpace-at100 filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-boundingBox filter-userspace-offset.svg
+== filter-userspace-offset.svg?offsetContainer=rect&filter=matrix-fillPaint-userSpace-at100 filter-userspace-offset.svg
+
+!= scroll-inactive-layers.html about:blank
+!= scroll-inactive-layers-2.html about:blank
+random-if(useDrawSnapshot) != inactive-layertree-visible-region-1.html about:blank
+!= inactive-layertree-visible-region-2.html about:blank
+!= transform-floating-point-invalidation.html about:blank
+!= transform-floating-point-invalidation.html?reverse about:blank
+!= nudge-to-integer-invalidation.html about:blank
+!= nudge-to-integer-invalidation.html?reverse about:blank
+!= clipped-animated-transform-1.html about:blank
+!= paintedlayer-recycling-1.html about:blank
+!= paintedlayer-recycling-2.html about:blank
+pref(layers.single-tile.enabled,false) != paintedlayer-recycling-3.html about:blank
+!= paintedlayer-recycling-4.html about:blank
+!= paintedlayer-recycling-5.html about:blank
+!= paintedlayer-recycling-6.html about:blank
+!= paintedlayer-recycling-7.html about:blank
+!= masklayer-1.html about:blank
+!= masklayer-2.html about:blank
+!= layer-splitting-1.html about:blank
+!= layer-splitting-2.html about:blank
+!= layer-splitting-3.html about:blank
+!= layer-splitting-4.html about:blank
+!= layer-splitting-5.html about:blank
+!= layer-splitting-6.html about:blank
+!= layer-splitting-7.html about:blank
+fuzzy(0-16,0-3230) == image-scrolling-zoom-1.html image-scrolling-zoom-1-ref.html
+!= image-scrolling-zoom-1-ref.html image-scrolling-zoom-1-notref.html
+pref(layers.single-tile.enabled,false) != fast-scrolling.html about:blank
+== background-position-1.html background-position-1-ref.html
+== background-position-2a.html background-position-2-ref.html
+== background-position-2b.html background-position-2-ref.html
+== background-position-2c.html background-position-2-ref.html
+== background-position-2d.html background-position-2-ref.html
+== background-position-2e.html background-position-2-ref.html
+== background-position-2f.html background-position-2-ref.html
+== zero-opacity-animation.html about:blank
+== zero-opacity-text.html about:blank
+== negative-w-component.html negative-w-component-ref.html
+
+== mask-invalidation-1a.html mask-invalidation-1-ref.html
+== mask-invalidation-1b.html mask-invalidation-1-ref.html
+
+== mask-invalidation-2a.html mask-invalidation-2-ref.html
+== mask-invalidation-2b.html mask-invalidation-2-ref.html
+== mask-invalidation-2c.html mask-invalidation-2-ref.html
+== mask-invalidation-2d.html mask-invalidation-2-ref.html
+
+== clip-path-invalidation-1a.html mask-invalidation-2-ref.html
+== clip-path-invalidation-1b.html mask-invalidation-2-ref.html
+== clip-path-invalidation-1c.html mask-invalidation-2-ref.html
+== clip-path-invalidation-1d.html mask-invalidation-2-ref.html
+
+!= fractional-transform-1.html about:blank
+skip-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)) != fractional-transform-2.html about:blank
+!= fractional-transform-3.html about:blank
+
+== partially-scrolled-svg-group.html partially-scrolled-svg-group-ref.html
+
+== paintedlayer-recycling-8.html paintedlayer-recycling-8-ref.html
+pref(image.downscale-during-decode.enabled,true) == jetstream-scroll.html jetstream-scroll-ref.html
+
+fuzzy(0-2,0-2) == svg-paint-rect-changes.html svg-paint-rect-changes-ref.html
+== border-radius-1.html border-radius-1-ref.html
diff --git a/layout/reftests/invalidation/scroll-inactive-layers-2.html b/layout/reftests/invalidation/scroll-inactive-layers-2.html
new file mode 100644
index 0000000000..70606bad63
--- /dev/null
+++ b/layout/reftests/invalidation/scroll-inactive-layers-2.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<title>Scrolling over inactive layers shouldn't repaint their contents even if both the top and the bottom edge of the inactive layers are offscreen</title>
+
+<style>
+
+html, body {
+ margin: 0;
+ padding: 0;
+}
+
+.outer {
+ border: 1px solid black;
+ width: 100px;
+ height: 2000px;
+ margin-right: 20px;
+ padding-top: 200px;
+ float: left;
+}
+
+.opacity {
+ opacity: 0.5;
+}
+
+.transform {
+ transform: translateX(1px);
+}
+
+.filter {
+ filter: url(#filter);
+}
+
+.mask {
+ mask: url(#mask);
+}
+
+.reftest-no-paint {
+ height: 50px;
+ border: 1px solid lime;
+}
+
+</style>
+
+<svg height="0">
+ <defs>
+ <filter id="filter" filterUnits="objectBoundingBox"
+ x="0%" y="0%" width="100%" height="100%"
+ color-interpolation-filters="sRGB">
+ <feMerge><feMergeNode/><feMerge>
+ </filter>
+ <mask id="mask" maskContentUnits="objectBoundingBox">
+ <rect x="0" y="0" width="1" height="1" fill="white"/>
+ </mask>
+ </defs>
+</svg>
+
+<div class="outer opacity">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer transform">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer filter">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer mask">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.documentElement.scrollTop = 50;
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/scroll-inactive-layers.html b/layout/reftests/invalidation/scroll-inactive-layers.html
new file mode 100644
index 0000000000..94d7c05196
--- /dev/null
+++ b/layout/reftests/invalidation/scroll-inactive-layers.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<title>Scrolling over inactive layers shouldn't repaint their contents</title>
+
+<style>
+
+.outer {
+ border: 1px solid black;
+ width: 100px;
+ height: 2000px;
+ margin-top: 200px;
+ margin-right: 20px;
+ padding-top: 100px;
+ float: left;
+}
+
+.opacity {
+ opacity: 0.5;
+}
+
+.transform {
+ transform: translateX(1px);
+}
+
+.filter {
+ filter: url(#filter);
+}
+
+.mask {
+ mask: url(#mask);
+}
+
+.reftest-no-paint {
+ height: 50px;
+ border: 1px solid lime;
+}
+
+</style>
+
+<svg height="0">
+ <defs>
+ <filter id="filter" filterUnits="objectBoundingBox"
+ x="0%" y="0%" width="100%" height="100%"
+ color-interpolation-filters="sRGB">
+ <feMerge><feMergeNode/><feMerge>
+ </filter>
+ <mask id="mask" maskContentUnits="objectBoundingBox">
+ <rect x="0" y="0" width="1" height="1" fill="white"/>
+ </mask>
+ </defs>
+</svg>
+
+<div class="outer opacity">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer transform">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer filter">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<div class="outer mask">
+ <div class="reftest-no-paint"></div>
+</div>
+
+<script>
+
+function doTest() {
+ document.documentElement.scrollTop = 100;
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/svg-paint-rect-changes-ref.html b/layout/reftests/invalidation/svg-paint-rect-changes-ref.html
new file mode 100644
index 0000000000..58192c0fa2
--- /dev/null
+++ b/layout/reftests/invalidation/svg-paint-rect-changes-ref.html
@@ -0,0 +1,12 @@
+<html>
+ <div id=out style="overflow: hidden; height:30px">
+ <div style="transform: rotate(2deg)">
+ <div style="overflow: hidden; width: 40px;">
+ <svg>
+ <rect x=0 y=0 width=100 height=100></rect>
+ <rect fill=red id=c x=10 y=10 width=20 height=20></rect>
+ </svg>
+ </div>
+ </div>
+ </div>
+</html>
diff --git a/layout/reftests/invalidation/svg-paint-rect-changes.html b/layout/reftests/invalidation/svg-paint-rect-changes.html
new file mode 100644
index 0000000000..6cd08b58b7
--- /dev/null
+++ b/layout/reftests/invalidation/svg-paint-rect-changes.html
@@ -0,0 +1,22 @@
+<html class="reftest-wait">
+ <script>
+ function doTest() {
+ document.getElementById("out").style.height = 30 + "px";
+ document.getElementById("c").setAttribute("width", 20);
+ document.documentElement.removeAttribute("class");
+ }
+ document.addEventListener("MozReftestInvalidate", doTest);
+ </script>
+ <div id=out style="overflow: hidden; height:40px">
+ <!-- avoid letting the clip leak into the svg by separating it with
+ a transform -->
+ <div style="transform: rotate(2deg)">
+ <div style="overflow: hidden; width: 40px;">
+ <svg>
+ <rect x=0 y=0 width=100 height=100></rect>
+ <rect fill=red id=c x=10 y=10 width=1 height=20></rect>
+ </svg>
+ </div>
+ </div>
+ </div>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-a-ref.html b/layout/reftests/invalidation/table-repaint-a-ref.html
new file mode 100644
index 0000000000..a7957c34fe
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-a-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>table-repaint-a-ref</title>
+</head>
+<body>
+<table>
+ <tr>
+ <td bgcolor="lime"></td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-a.html b/layout/reftests/invalidation/table-repaint-a.html
new file mode 100644
index 0000000000..362aa2b482
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-a.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <title>table-repaint-a</title>
+</head>
+<body>
+<table>
+ <tr>
+ <td bgcolor="black"></td>
+ <td bgcolor="lime"></td>
+ </tr>
+</table>
+<script>
+function foo() {
+ var x=document.getElementsByTagName('td')[0];
+ x.style.display = 'none';
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", foo);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-b-ref.html b/layout/reftests/invalidation/table-repaint-b-ref.html
new file mode 100644
index 0000000000..1581e0458e
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-b-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<title>table-repaint-b-ref</title>
+<body>
+<table>
+<tr>
+ <td>aaa</td><td><span style="position: relative"><div style="height: 0px"><div style="height: 300px; width: 10px; background: green"></div></div>bbb</td>
+</tr>
+<tr>
+ <td>
+ longer text: above this, first cell should say 'aaa' while second says 'bbb'. There should be only one green rectangle.
+ </td>
+</tr>
+</table>
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-b.html b/layout/reftests/invalidation/table-repaint-b.html
new file mode 100644
index 0000000000..ed70855f40
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-b.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait"><head>
+<title>table-repaint-b-ref</title>
+<body>
+<table id="x">
+<tr>
+ <td>aaa</td>
+ <td>
+ <span style="position: relative">
+ <div style="height: 0px">
+ <div style="height: 300px; width: 10px; background: green"></div>
+ </div>bbb
+ </td>
+</tr>
+</table>
+<script>
+ function foo() {
+ var t = document.getElementById("x");
+ var r = document.createElement("tr");
+ var c = document.createElement("td");
+ c.appendChild(document.createTextNode("longer text: above this, first cell should say 'aaa' while second says 'bbb'. There should be only one green rectangle."));
+ r.appendChild(c);
+ t.tBodies[0].appendChild(r);
+ document.documentElement.removeAttribute("class");
+ }
+document.addEventListener("MozReftestInvalidate", foo);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-border-collapse-ref.html b/layout/reftests/invalidation/table-repaint-border-collapse-ref.html
new file mode 100644
index 0000000000..a02341e8c6
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-border-collapse-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>table-repaint-border-collapse-ref</title>
+ <style>
+ table, td, th {
+ border-collapse: collapse;
+ border: 1px solid black;
+ }
+ </style>
+</head>
+<body>
+<table>
+ <tr>
+ <td style="border: 5px solid black">xxx</td>
+ <td>YYY</td>
+ <td>zzz</td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-border-collapse.html b/layout/reftests/invalidation/table-repaint-border-collapse.html
new file mode 100644
index 0000000000..aa9eccd609
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-border-collapse.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <title>table-repaint-border-collapse</title>
+ <style>
+ table, td, th {
+ border-collapse: collapse;
+ border: 1px solid black;
+ }
+ </style>
+</head>
+<body>
+<table>
+ <tr>
+ <td>xxx</td>
+ <td>yyy</td>
+ <td>zzz</td>
+ </tr>
+</table>
+<script>
+ function foo() {
+ let x=document.getElementsByTagName('td')[0];
+ x.style.border = "5px solid black";
+ let y=document.getElementsByTagName('td')[1];
+ y.innerHTML = "YYY";
+ document.documentElement.removeAttribute("class");
+ }
+ document.addEventListener("MozReftestInvalidate", foo);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-c-ref.html b/layout/reftests/invalidation/table-repaint-c-ref.html
new file mode 100644
index 0000000000..1e9393b958
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-c-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<title>table-repaint-c-ref</title>
+<style>
+td {
+width: 50px;
+height: 50px;
+}
+</style>
+</head>
+<body>
+<table >
+<tbody>
+<tr>
+<td bgcolor="lime"></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-c.html b/layout/reftests/invalidation/table-repaint-c.html
new file mode 100644
index 0000000000..11489b6169
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-c.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait"><head>
+<title>table-repaint-c</title>
+<style>
+td {
+width: 50px;
+height: 50px;
+}
+</style>
+</head>
+<body>
+<table>
+ <col id="foo">
+ <tbody>
+ <tr>
+ <td bgcolor="black"></td>
+ <td bgcolor="lime"></td>
+ </tr>
+ </tbody>
+</table>
+<script>
+function foo() {
+var x=document.getElementById("foo");
+x.style.visibility = 'collapse';
+document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", foo);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-d-ref.html b/layout/reftests/invalidation/table-repaint-d-ref.html
new file mode 100644
index 0000000000..917c73427d
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-d-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<title>table-repaint-d-ref</title>
+<body>
+<table>
+<tr>
+ <td>aaa</td><td>bbb</td>
+</tr>
+<tr>
+ <td>longer text: above this, first cell should say 'aaa' while second says 'bbb'.</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-d.html b/layout/reftests/invalidation/table-repaint-d.html
new file mode 100644
index 0000000000..ed6832cb10
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-d.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class="reftest-wait"><head>
+<title>table-repaint-d</title>
+<body>
+<table id="x">
+<tr>
+ <td>aaa</td><td>bbb</td>
+</tr>
+</table>
+<script>
+ function foo() {
+ var t = document.getElementById("x");
+ var r = document.createElement("tr");
+ var c = document.createElement("td");
+ c.appendChild(document.createTextNode("longer text: above this, first cell should say 'aaa' while second says 'bbb'."));
+ r.appendChild(c);
+ t.tBodies[0].appendChild(r);
+ document.documentElement.removeAttribute("class");
+ }
+document.addEventListener("MozReftestInvalidate", foo);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-e-ref.html b/layout/reftests/invalidation/table-repaint-e-ref.html
new file mode 100644
index 0000000000..27f949b19e
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-e-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>table-repaint-e</title>
+<style>
+table {
+ border-collapse: collapse;
+}
+tr {
+ border: 1px solid transparent;
+}
+</style>
+</head>
+<body>
+<table
+ <tr>
+ <td>
+ <div>one</div>
+ </td>
+ <td>
+ <div>two</div>
+ </td>
+ </tr
+ <tr>
+ <td>
+ <div>three</div>
+ </td>
+ <td>
+ <div>four</div>
+ </td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-e.html b/layout/reftests/invalidation/table-repaint-e.html
new file mode 100644
index 0000000000..69cbb31d19
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-e.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<title>table-repaint-e</title>
+<style>
+table {
+ border-collapse: collapse;
+}
+tr {
+ border: 1px solid transparent;
+}
+</style>
+</head>
+<body>
+<table
+ <tr>
+ <td>
+ <div>one</div>
+ </td>
+ <td id="x" style="border: 1px solid black">
+ <div>two</div>
+ </td>
+ </tr
+ <tr>
+ <td>
+ <div>three</div>
+ </td>
+ <td>
+ <div>four</div>
+ </td>
+ </tr>
+</table>
+<script>
+ function doTest() {
+ var t = document.getElementById("x");
+ t.style.border = "initial";
+ document.documentElement.removeAttribute("class");
+ }
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-non-border-collapse-ref.html b/layout/reftests/invalidation/table-repaint-non-border-collapse-ref.html
new file mode 100644
index 0000000000..0ece7d81db
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-non-border-collapse-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>table-repaint-non-border-collapse-ref</title>
+ <style>
+ table, td, th {
+ border: 1px solid black;
+ }
+ </style>
+</head>
+<body>
+<table>
+ <tr>
+ <td style="border: 5px solid black">xxx</td>
+ <td>YYY</td>
+ <td>zzz</td>
+ </tr>
+</table>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/table-repaint-non-border-collapse.html b/layout/reftests/invalidation/table-repaint-non-border-collapse.html
new file mode 100644
index 0000000000..ce4c64fec8
--- /dev/null
+++ b/layout/reftests/invalidation/table-repaint-non-border-collapse.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <title>table-repaint-non-border-collapse</title>
+ <style>
+ table, td, th {
+ border: 1px solid black;
+ }
+ </style>
+</head>
+<body>
+<table>
+ <tr>
+ <td>xxx</td>
+ <td>yyy</td>
+ <td>zzz</td>
+ </tr>
+</table>
+<script>
+ function foo() {
+ let x=document.getElementsByTagName('td')[0];
+ x.style.border = "5px solid black";
+ let y=document.getElementsByTagName('td')[1];
+ y.innerHTML = "YYY";
+ document.documentElement.removeAttribute("class");
+ }
+ document.addEventListener("MozReftestInvalidate", foo);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/test-animated-image-layers-background.html b/layout/reftests/invalidation/test-animated-image-layers-background.html
new file mode 100644
index 0000000000..ca51a27bfb
--- /dev/null
+++ b/layout/reftests/invalidation/test-animated-image-layers-background.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<div>
+<div id="image" style="width: 256px; height: 256px; background-image: url('image_rgrg-256x256-animated.gif');" class="reftest-no-paint"></div>
+</div>
+<script type="application/javascript">
+
+function doTest() {
+ document.body.style.background = "black";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/test-animated-image-layers-ref.html b/layout/reftests/invalidation/test-animated-image-layers-ref.html
new file mode 100644
index 0000000000..d8bfb86556
--- /dev/null
+++ b/layout/reftests/invalidation/test-animated-image-layers-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<body style="background:black">
+<div>
+<img id="image" src="./image_rgrg-256x256.png"></img>
+</div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/test-animated-image-layers.html b/layout/reftests/invalidation/test-animated-image-layers.html
new file mode 100644
index 0000000000..153e84ec8b
--- /dev/null
+++ b/layout/reftests/invalidation/test-animated-image-layers.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<div>
+<img id="image" class="reftest-no-paint" src="./image_rgrg-256x256-animated.gif"></img>
+</div>
+<script type="application/javascript">
+
+function doTest() {
+ document.body.style.background = "black";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/test-image-layers-multiple-displayitem.html b/layout/reftests/invalidation/test-image-layers-multiple-displayitem.html
new file mode 100644
index 0000000000..7aeaaf038e
--- /dev/null
+++ b/layout/reftests/invalidation/test-image-layers-multiple-displayitem.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<style>
+img {
+ background-color: green;
+}
+</style>
+<div>
+<img id="image" class="reftest-no-paint" src="./image_rgrg-256x256.png" style="-moz-transform: perspective(1px)"></img>
+</div>
+<script type="application/javascript">
+
+function doTest() {
+ document.body.style.background = "black";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/test-image-layers-ref.html b/layout/reftests/invalidation/test-image-layers-ref.html
new file mode 100644
index 0000000000..fce127b737
--- /dev/null
+++ b/layout/reftests/invalidation/test-image-layers-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<body style="background:black">
+<div>
+<img id="image" src="./image_rgrg-256x256.png" style="-moz-transform: perspective(1px)"></img>
+</div>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/test-image-layers.html b/layout/reftests/invalidation/test-image-layers.html
new file mode 100644
index 0000000000..0f8faf6c70
--- /dev/null
+++ b/layout/reftests/invalidation/test-image-layers.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<div>
+<img id="image" class="reftest-no-paint" src="./image_rgrg-256x256.png" style="-moz-transform: perspective(1px)"></img>
+</div>
+<script type="application/javascript">
+
+function doTest() {
+ document.body.style.background = "black";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/transform-floating-point-invalidation.html b/layout/reftests/invalidation/transform-floating-point-invalidation.html
new file mode 100644
index 0000000000..5c0f468dfd
--- /dev/null
+++ b/layout/reftests/invalidation/transform-floating-point-invalidation.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait"
+ reftest-displayport-x="0"
+ reftest-displayport-y="0"
+ reftest-displayport-w="800"
+ reftest-displayport-h="1000">
+<meta charset="utf-8">
+<title>Scrolling shouldn't invalidate the rect</title>
+
+<body>
+
+<svg width="824" height="1375" viewBox="0 0 660 1100">
+ <rect x="100" y="600" width="120" height="120" fill="#EEE"
+ transform="matrix(0,0.969665,-2.0321494,0,1828.58132,65.718239)"
+ class="reftest-no-paint"/>
+</svg>
+
+<script>
+
+var scrollPositions = [81, 82];
+if (location.search.includes("reverse")) {
+ scrollPositions.reverse();
+}
+document.documentElement.scrollTop = scrollPositions[0];
+
+function doTest() {
+ document.documentElement.scrollTop = scrollPositions[1];
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+
+</script>
diff --git a/layout/reftests/invalidation/zero-opacity-animation.html b/layout/reftests/invalidation/zero-opacity-animation.html
new file mode 100644
index 0000000000..5aba74795f
--- /dev/null
+++ b/layout/reftests/invalidation/zero-opacity-animation.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<div style="opacity:0">
+ <div id="d" class="reftest-no-paint" style="height:50px; border:2px solid black"></div>
+</div>
+<script type="application/javascript">
+function doTest() {
+ d.style.border = "2px solid green";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>
diff --git a/layout/reftests/invalidation/zero-opacity-text.html b/layout/reftests/invalidation/zero-opacity-text.html
new file mode 100644
index 0000000000..9009470e61
--- /dev/null
+++ b/layout/reftests/invalidation/zero-opacity-text.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body>
+<div style="opacity:0">
+ <div id="d" class="reftest-no-paint" style="height:50px;">abc</div>
+</div>
+<script type="application/javascript">
+function doTest() {
+ d.textContent = "def";
+ document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</body>
+</html>