Fix BGPT backdrop-filter with opacity<1 parent

Previous to this CL, a layer with opacity<1 that contained a single compositing
child with backdrop-filter would not be properly rendered, due to an
optimization that removed the render surface for the opacity<1 layer. That
would cause the backdrop-filter to filter elements higher up the tree than it
should, due to the lack of isolation imposed by the opacity<1 layer. With this
CL, this situation is properly detected and a render surface is assigned to the
opacity<1 layer.

As part of this CL, backdrop-filter was moved from the Filter node to the
Effect node. This is required, because a single element with both opacity
and backdrop-filter need to be contained in the same node, so that the
render surface created for the backdrop filter also sees the opacity.

Bug: 497522, 836885
Change-Id: Ie6ad38231ddfda02fae8d574ca8f30d075c673e5
Reviewed-on: https://chromium-review.googlesource.com/c/1399467
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#629835}
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 25bafa2..3b0833daf 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -820,7 +820,12 @@
   }
 
   // If the layer uses a CSS filter.
-  if (!Filters(layer).IsEmpty() || !BackdropFilters(layer).IsEmpty()) {
+  if (!Filters(layer).IsEmpty()) {
+    return true;
+  }
+
+  // If the layer uses a CSS backdrop-filter.
+  if (!BackdropFilters(layer).IsEmpty()) {
     return true;
   }
 
diff --git a/third_party/blink/renderer/core/paint/object_paint_properties.h b/third_party/blink/renderer/core/paint/object_paint_properties.h
index 168fff1..c1a1f74 100644
--- a/third_party/blink/renderer/core/paint/object_paint_properties.h
+++ b/third_party/blink/renderer/core/paint/object_paint_properties.h
@@ -142,8 +142,8 @@
   // follows:
   // [ effect ]
   // |     Isolated group to apply various CSS effects, including opacity,
-  // |     mix-blend-mode, and for isolation if a mask needs to be applied or
-  // |     backdrop-dependent children are present.
+  // |     mix-blend-mode, backdrop-filter, and for isolation if a mask needs
+  // |     to be applied or backdrop-dependent children are present.
   // +-[ filter ]
   // |     Isolated group for CSS filter.
   // +-[ vertical/horizontal scrollbar effect ]
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index a197d63e..47822f3 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -3262,6 +3262,7 @@
   const auto& style = GetLayoutObject().StyleRef();
   if (style.BackdropFilter().IsEmpty()) {
     operations.Clear();
+    *backdrop_filter_bounds = gfx::RRectF();
     return;
   }
   FloatRect reference_box = BackdropFilterReferenceBox();
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index e0b3d16..3158aa38 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -801,6 +801,9 @@
   if (blend_mode != SkBlendMode::kSrcOver)
     return true;
 
+  if (!style.BackdropFilter().IsEmpty())
+    return true;
+
   if (style.Opacity() != 1.0f || style.HasWillChangeOpacityHint())
     return true;
 
@@ -928,6 +931,25 @@
         state.blend_mode = WebCoreCompositeToSkiaComposite(
             kCompositeSourceOver, style.GetBlendMode());
       }
+      if (object_.IsBoxModelObject()) {
+        if (auto* layer = ToLayoutBoxModelObject(object_).Layer()) {
+          // Try to use the cached effect for backdrop-filter.
+          if (properties_->Effect()) {
+            state.backdrop_filter = properties_->Effect()->BackdropFilter();
+            state.backdrop_filter_bounds =
+                properties_->Effect()->BackdropFilterBounds();
+          }
+          // With BGPT disabled, UpdateFilterReferenceBox gets called from
+          // CompositedLayerMapping::UpdateGraphicsLayerGeometry, but only
+          // for composited layers.
+          if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+              layer->GetCompositingState() != kPaintsIntoOwnBacking) {
+            layer->UpdateFilterReferenceBox();
+          }
+          layer->UpdateCompositorFilterOperationsForBackdropFilter(
+              state.backdrop_filter, &state.backdrop_filter_bounds);
+        }
+      }
       if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() ||
           RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
         // We may begin to composite our subtree prior to an animation starts,
@@ -1025,8 +1047,7 @@
     return false;
 
   // TODO(trchen): SVG caches filters in SVGResources. Implement it.
-  if (object.StyleRef().HasFilter() || object.HasReflection() ||
-      object.HasBackdropFilter())
+  if (object.StyleRef().HasFilter() || object.HasReflection())
     return true;
 
   // TODO(flackr): Check for nodes for each KeyframeModel target
@@ -1056,9 +1077,6 @@
         // Try to use the cached filter.
         if (properties_->Filter()) {
           state.filter = properties_->Filter()->Filter();
-          state.backdrop_filter = properties_->Filter()->BackdropFilter();
-          state.backdrop_filter_bounds =
-              properties_->Filter()->BackdropFilterBounds();
         }
 
         // With BGPT disabled, UpdateFilterReferenceBox gets called from
@@ -1069,8 +1087,6 @@
           layer->UpdateFilterReferenceBox();
         }
         layer->UpdateCompositorFilterOperationsForFilter(state.filter);
-        layer->UpdateCompositorFilterOperationsForBackdropFilter(
-            state.backdrop_filter, &state.backdrop_filter_bounds);
         layer->ClearFilterOnEffectNodeDirty();
       }
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index 392ca60..b59a2d9 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -970,13 +970,17 @@
   HashSet<int> pending_render_surfaces;
   auto& effect_tree = host.property_trees()->effect_tree;
   for (const auto& layer : layers) {
+    bool found_backdrop_filter = false;
     for (auto* effect = effect_tree.Node(layer->effect_tree_index());
-         !effect->has_render_surface;
+         !effect->has_render_surface || !effect->backdrop_filters.IsEmpty();
          effect = effect_tree.Node(effect->parent_id)) {
+      found_backdrop_filter |= !effect->backdrop_filters.IsEmpty();
       if (effect->opacity != 1.f &&
-          !pending_render_surfaces.insert(effect->id).is_new_entry) {
-        // The opacity-only effect is seen the second time, which means that it
-        // has more than one compositing child and needs a render surface.
+          (!pending_render_surfaces.insert(effect->id).is_new_entry ||
+           found_backdrop_filter)) {
+        // The opacity-only effect is seen a second time, which means that it
+        // has more than one compositing child and needs a render surface. Or
+        // the opacity effect has a backdrop-filter child.
         effect->has_render_surface = true;
         break;
       }
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index c5ea197..f5a6823 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -3346,6 +3346,32 @@
                  kHasRenderSurface);
 }
 
+TEST_P(PaintArtifactCompositorTest, OpacityRenderSurfacesWithBackdropChildren) {
+  // Opacity effect with a single compositing backdrop-filter child. Normally
+  // the opacity effect would not get a render surface. However, because
+  // backdrop-filter needs to only filter up to the backdrop root, it always
+  // gets a render surface.
+  auto e = CreateOpacityEffect(e0(), 0.4f);
+  auto a = CreateOpacityEffect(*e, 0.5f);
+  CompositorFilterOperations blur_filter;
+  blur_filter.AppendBlurFilter(5);
+  auto bd = CreateBackdropFilterEffect(
+      *a, blur_filter, FloatPoint(),
+      CompositingReason::kActiveBackdropFilterAnimation);
+
+  TestPaintArtifact artifact;
+  FloatRect r(150, 150, 100, 100);
+  artifact.Chunk(t0(), c0(), *a).RectDrawing(r, Color::kWhite);
+  artifact.Chunk(t0(), c0(), *bd).RectDrawing(r, Color::kWhite);
+  Update(artifact.Build());
+  ASSERT_EQ(2u, ContentLayerCount());
+
+  EXPECT_OPACITY(ContentLayerAt(0)->effect_tree_index(), 0.5,
+                 kHasRenderSurface);
+  EXPECT_OPACITY(ContentLayerAt(1)->effect_tree_index(), 1.0,
+                 kHasRenderSurface);
+}
+
 TEST_P(PaintArtifactCompositorTest, OpacityIndirectlyAffectingTwoLayers) {
   auto opacity = CreateOpacityEffect(e0(), 0.5f);
   auto child_composited_effect = CreateOpacityEffect(
diff --git a/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h b/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h
index 12a40b2..9ad4051 100644
--- a/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h
+++ b/third_party/blink/renderer/platform/testing/paint_property_test_helpers.h
@@ -72,6 +72,33 @@
                             compositing_reasons);
 }
 
+inline scoped_refptr<EffectPaintPropertyNode> CreateBackdropFilterEffect(
+    const EffectPaintPropertyNode& parent,
+    const TransformPaintPropertyNode& local_transform_space,
+    const ClipPaintPropertyNode* output_clip,
+    CompositorFilterOperations backdrop_filter,
+    const FloatPoint& filters_origin = FloatPoint(),
+    CompositingReasons compositing_reasons = CompositingReason::kNone) {
+  EffectPaintPropertyNode::State state;
+  state.local_transform_space = &local_transform_space;
+  state.output_clip = output_clip;
+  state.backdrop_filter = std::move(backdrop_filter);
+  state.filters_origin = filters_origin;
+  state.direct_compositing_reasons = compositing_reasons;
+  return EffectPaintPropertyNode::Create(parent, std::move(state));
+}
+
+inline scoped_refptr<EffectPaintPropertyNode> CreateBackdropFilterEffect(
+    const EffectPaintPropertyNode& parent,
+    CompositorFilterOperations backdrop_filter,
+    const FloatPoint& paint_offset = FloatPoint(),
+    CompositingReasons compositing_reasons = CompositingReason::kNone) {
+  return CreateBackdropFilterEffect(
+      parent, parent.Unalias().LocalTransformSpace(),
+      parent.Unalias().OutputClip(), backdrop_filter, paint_offset,
+      compositing_reasons);
+}
+
 inline scoped_refptr<ClipPaintPropertyNode> CreateClip(
     const ClipPaintPropertyNode& parent,
     const TransformPaintPropertyNode& local_transform_space,
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
index d6e3678..d0d1a1e 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -425,11 +425,15 @@
 crbug.com/923429 compositing/layer-creation/fixed-position-out-of-view-with-backdrop-filter.html [ Failure ]
 crbug.com/923429 compositing/overflow/scroll-parent-absolute-with-backdrop-filter.html [ Failure ]
 crbug.com/923429 css3/filters/backdrop-filter-basic-blur.html [ Failure ]
+crbug.com/923429 css3/filters/backdrop-filter-border-radius.html [ Failure ]
+crbug.com/923429 css3/filters/backdrop-filter-rendering.html [ Failure ]
 crbug.com/923429 css3/filters/backdrop-filter-rendering-no-background.html [ Failure ]
 crbug.com/923429 external/wpt/css/filter-effects/backdrop-filter-basic-background-color.html [ Failure ]
 crbug.com/923429 external/wpt/css/filter-effects/backdrop-filter-basic-opacity-2.html [ Failure ]
 crbug.com/923429 external/wpt/css/filter-effects/backdrop-filter-basic.html [ Failure ]
 crbug.com/923429 external/wpt/css/filter-effects/backdrop-filter-fixed-clip.html [ Failure ]
+crbug.com/923429 external/wpt/css/filter-effects/backdrop-filter-isolation.html [ Failure ]
+
 
 Bug(none) css3/filters/blur-filter-page-scroll-self.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 4700ab2..15a0fc59 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1918,13 +1918,10 @@
 crbug.com/497522 css3/filters/backdrop-filter-svg.html [ Failure ]
 #crbug.com/497522 css3/filters/backdrop-filter-plus-filter.html [ Failure ]
 # This fails, but only in CAP mode:
-crbug.com/497522 css3/filters/backdrop-filter-rendering.html [ Failure ]
 crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-isolation-isolate.html [ Failure ]
-crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-border-radius.html [ Failure ]
 crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-paint-order.html [ Failure ]
 crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-isolation-fixed.html [ Failure ]
 crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-edge-pixels.html [ Pass Failure ]
-crbug.com/497522 external/wpt/css/filter-effects/backdrop-filter-isolation.html [ Failure ]
 # Until backdrop filter is enabled by default, backdrop tests will not pass in virtual/stable.
 Bug(none) virtual/stable/compositing/layer-creation/fixed-position-out-of-view-with-backdrop-filter.html [ Skip ]
 Bug(none) virtual/stable/compositing/overflow/scroll-parent-absolute-with-backdrop-filter.html [ Skip ]
diff --git a/third_party/blink/web_tests/css3/filters/backdrop-filter-border-radius-expected.png b/third_party/blink/web_tests/css3/filters/backdrop-filter-border-radius-expected.png
new file mode 100644
index 0000000..1ead16785
--- /dev/null
+++ b/third_party/blink/web_tests/css3/filters/backdrop-filter-border-radius-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/css3/filters/backdrop-filter-border-radius.html b/third_party/blink/web_tests/css3/filters/backdrop-filter-border-radius.html
new file mode 100644
index 0000000..2981af3
--- /dev/null
+++ b/third_party/blink/web_tests/css3/filters/backdrop-filter-border-radius.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+
+<div style="opacity: 0.9999;">
+  <div class="circle filter"></div>
+
+</div>
+
+
+<style>
+div {
+  position: absolute;
+  width: 100px;
+  height: 100px;
+  top: 10px;
+  left: 10px;
+  background: green;
+}
+.circle {
+  top: 30px;
+  left: 30px;
+  border-radius: 50px;
+  background: #ffff0060;
+}
+.filter {
+  backdrop-filter: invert(1);
+}
+</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html
deleted file mode 100644
index e5712a23..0000000
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius-ref.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>backdrop-filter: Should clip using border radius.</title>
-<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
-
-
-
-<div>
-  <div class="circle outside"></div>
-  <div class="circle inside"></div>
-</div>
-
-
-<style>
-div {
-  position: absolute;
-  width: 100px;
-  height: 100px;
-  top: 10px;
-  left: 10px;
-  background: green;
-}
-.circle {
-  top: 30px;
-  left: 30px;
-  border-radius: 50px;
-  background: #ffff0060;
-}
-.inside {
-  background: #ffaf9f;
-  clip-path: inset(0px 30px 30px 0px);
-}
-.outside {
-  background: #ffff9f;
-}
-</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html b/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html
deleted file mode 100644
index ec93de6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/filter-effects/backdrop-filter-border-radius.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>backdrop-filter: Should clip using border radius.</title>
-<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty">
-<link rel="match"  href="backdrop-filter-border-radius-ref.html">
-
-<div style="opacity: 0.9999;">
-  <div class="circle filter"></div>
-
-</div>
-
-
-<style>
-div {
-  position: absolute;
-  width: 100px;
-  height: 100px;
-  top: 10px;
-  left: 10px;
-  background: green;
-}
-.circle {
-  top: 30px;
-  left: 30px;
-  border-radius: 50px;
-  background: #ffff0060;
-}
-.filter {
-  backdrop-filter: invert(1);
-}
-</style>