Invalidate when PendingLayer effect node changes.

This is needed because, when the result of DecompositeEffect changes, it
can change the effect node on the PendingLayer without changing the
effect node on any of the paint chunks.

Both added tests fail reliably without this change and pass with it.

Fixed: 1330438
Change-Id: I1fd5a92dbf582d888dac04751c915c1049f7e659
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3692324
Reviewed-by: Philip Rogers <pdr@chromium.org>
Commit-Queue: David Baron <dbaron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1012030}
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc b/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc
index a5d6501..fd6126c 100644
--- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.cc
@@ -177,6 +177,7 @@
     RasterInvalidationFunction function,
     const PaintChunkSubset& new_chunks,
     bool layer_offset_or_state_changed,
+    bool layer_effect_changed,
     Vector<PaintChunkInfo>& new_chunks_info) {
   ChunkToLayerMapper mapper(layer_state_, layer_offset_);
   Vector<bool> old_chunks_matched;
@@ -227,8 +228,14 @@
       auto& new_chunk_info = new_chunks_info.emplace_back(*this, mapper, it);
 
       if (reason == PaintInvalidationReason::kNone) {
-        reason = ChunkPropertiesChanged(new_chunk, old_chunk, new_chunk_info,
-                                        old_chunk_info, layer_state_);
+        if (layer_effect_changed) {
+          // Because of DecompositeEffect, the layer's effect may have changed
+          // even if the chunk's didn't.
+          reason = PaintInvalidationReason::kPaintProperty;
+        } else {
+          reason = ChunkPropertiesChanged(new_chunk, old_chunk, new_chunk_info,
+                                          old_chunk_info, layer_state_);
+        }
       }
 
       if (IsFullPaintInvalidationReason(reason)) {
@@ -331,6 +338,7 @@
 
   bool layer_offset_or_state_changed =
       layer_offset_ != layer_offset || layer_state_ != layer_state;
+  bool layer_effect_changed = &layer_state_.Effect() != &layer_state.Effect();
   bool layer_bounds_was_empty = layer_bounds_.IsEmpty();
   layer_offset_ = layer_offset;
   layer_bounds_ = layer_bounds;
@@ -359,7 +367,8 @@
     }
   } else {
     GenerateRasterInvalidations(raster_invalidation_function, new_chunks,
-                                layer_offset_or_state_changed, new_chunks_info);
+                                layer_offset_or_state_changed,
+                                layer_effect_changed, new_chunks_info);
   }
 
   old_paint_chunks_info_ = std::move(new_chunks_info);
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h b/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h
index cf369e8..92de1b9 100644
--- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h
+++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidator.h
@@ -107,6 +107,7 @@
   void GenerateRasterInvalidations(RasterInvalidationFunction,
                                    const PaintChunkSubset&,
                                    bool layer_offset_or_state_changed,
+                                   bool layer_effect_changed,
                                    Vector<PaintChunkInfo>& new_chunks_info);
 
   ALWAYS_INLINE const PaintChunk& GetOldChunk(wtf_size_t index) const;
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 523f97f..420d6b5 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -40,6 +40,7 @@
               "external/wpt/animation-worklet",
               "external/wpt/css/css-animations",
               "external/wpt/css/css-backgrounds",
+              "external/wpt/css/css-color/animation",
               "external/wpt/css/css-scroll-snap",
               "external/wpt/css/css-transforms/animation",
               "external/wpt/css/css-transforms/individual-transform/animation",
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-001-ref.html
new file mode 100644
index 0000000..ca55dc6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-001-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<title>CSS Test Reference (Color): ending of opacity animation</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="https://www.google.com/">
+
+<style>
+#test {
+  position: sticky;
+  top: 0;
+  height: 50px;
+  background: blue;
+  opacity: 0.2;
+}
+
+.tall {
+  height: 5000px;
+}
+</style>
+
+<div id="test">
+</div>
+<div class="tall">
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-001.html b/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-001.html
new file mode 100644
index 0000000..1fb36cd3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-001.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<title>CSS Test (Color): ending of opacity animation</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="https://www.google.com/">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1330438">
+<link rel="help" href="https://www.w3.org/TR/css-color-3/#transparency">
+<link rel="match" href="opacity-animation-ending-correctly-001-ref.html">
+
+<style>
+#test {
+  position: sticky;
+  top: 0;
+  height: 50px;
+  background: blue;
+  transition: opacity 50ms step-start;
+}
+
+#test.fade {
+  opacity: 0.2;
+}
+
+.tall {
+  height: 5000px;
+}
+</style>
+
+<div id="test">
+</div>
+<div class="tall">
+</div>
+
+<script>
+function flushStyleLayoutAndPrePaint() {
+  document.elementFromPoint(10, 10);
+}
+
+document.getElementById("test").addEventListener("transitionend", function(e) {
+  document.documentElement.classList.remove("reftest-wait");
+});
+requestAnimationFrame(function() {
+  flushStyleLayoutAndPrePaint();
+  requestAnimationFrame(function() {
+    document.getElementById("test").classList.add("fade");
+    flushStyleLayoutAndPrePaint();
+  });
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-002.html b/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-002.html
new file mode 100644
index 0000000..7ba097f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-color/animation/opacity-animation-ending-correctly-002.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<title>CSS Test (Color): ending of opacity animation</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="https://www.google.com/">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1330438">
+<link rel="help" href="https://www.w3.org/TR/css-color-3/#transparency">
+<link rel="match" href="opacity-animation-ending-correctly-001-ref.html">
+
+<style>
+#test {
+  position: sticky;
+  top: 0;
+  height: 50px;
+  background: blue;
+  transform: translate(0);
+  filter: grayscale(0%);
+  transition: opacity 50ms step-start;
+}
+
+#test.fade {
+  opacity: 0.2;
+}
+
+.tall {
+  height: 5000px;
+}
+</style>
+
+<div id="test">
+</div>
+<div class="tall">
+</div>
+
+<script>
+function flushStyleLayoutAndPrePaint() {
+  document.elementFromPoint(10, 10);
+}
+
+document.getElementById("test").addEventListener("transitionend", function(e) {
+  document.documentElement.classList.remove("reftest-wait");
+});
+requestAnimationFrame(function() {
+  flushStyleLayoutAndPrePaint();
+  requestAnimationFrame(function() {
+    document.getElementById("test").classList.add("fade");
+    flushStyleLayoutAndPrePaint();
+  });
+});
+</script>