LazyLoad: Fix lazyloading of pseudo css background styles

This CL passes PseudoElement to StyleResolverState, so that
ElementStyleResources::LoadPendingResources() can listen on the
appropriate pseudo element to defer and lazyload the background image.

(cherry picked from commit 9b78d5ebfc641eb10eb77b335314b1d0273c61e4)

Bug: 950503
Change-Id: Ieab6c4284ac6d405ba49d0d2535d3b05ce95fea2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1632595
Commit-Queue: rajendrant <rajendrant@chromium.org>
Reviewed-by: Fernando Serboncini <fserb@chromium.org>
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#665713}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1642246
Reviewed-by: rajendrant <rajendrant@chromium.org>
Cr-Commit-Position: refs/branch-heads/3809@{#56}
Cr-Branched-From: d82dec1a818f378c464ba307ddd9c92133eac355-refs/heads/master@{#665002}
diff --git a/third_party/blink/renderer/core/animation/animation_test_helper.cc b/third_party/blink/renderer/core/animation/animation_test_helper.cc
index f69c570..a913190 100644
--- a/third_party/blink/renderer/core/animation/animation_test_helper.cc
+++ b/third_party/blink/renderer/core/animation/animation_test_helper.cc
@@ -43,7 +43,8 @@
   // require our callers to propertly register every animation they pass in
   // here, which the current tests do not do.
   auto style = ComputedStyle::Create();
-  StyleResolverState state(document, element, style.get(), style.get());
+  StyleResolverState state(document, element, nullptr /* pseudo_element */,
+                           style.get(), style.get());
   state.SetStyle(style);
   CSSInterpolationTypesMap map(state.GetDocument().GetPropertyRegistry(),
                                state.GetDocument());
diff --git a/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc b/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc
index 8bdbfd10..eb6ff4ed 100644
--- a/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/css_variable_resolver_test.cc
@@ -275,7 +275,8 @@
 
 TEST_F(CSSVariableResolverTest, NeedsResolutionClearedByResolver) {
   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
-  StyleResolverState state(GetDocument(), nullptr, initial, initial);
+  StyleResolverState state(GetDocument(), nullptr /* element */,
+                           nullptr /* pseudo_element */, initial, initial);
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   style->InheritFrom(*initial);
@@ -462,7 +463,8 @@
   using CSSUnsetValue = cssvalue::CSSUnsetValue;
 
   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
-  StyleResolverState state(GetDocument(), nullptr, initial, initial);
+  StyleResolverState state(GetDocument(), nullptr /* element */,
+                           nullptr /* pseudo_element */, initial, initial);
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   style->InheritFrom(*initial);
diff --git a/third_party/blink/renderer/core/css/resolver/element_style_resources.cc b/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
index 69184f8..9278785 100644
--- a/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
+++ b/third_party/blink/renderer/core/css/resolver/element_style_resources.cc
@@ -29,6 +29,7 @@
 #include "third_party/blink/renderer/core/css/css_uri_value.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/pseudo_element.h"
 #include "third_party/blink/renderer/core/dom/tree_scope.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
@@ -54,8 +55,11 @@
 using namespace cssvalue;
 
 ElementStyleResources::ElementStyleResources(Element& element,
-                                             float device_scale_factor)
-    : element_(&element), device_scale_factor_(device_scale_factor) {}
+                                             float device_scale_factor,
+                                             PseudoElement* pseudo_element)
+    : element_(&element),
+      device_scale_factor_(device_scale_factor),
+      pseudo_element_(pseudo_element) {}
 
 StyleImage* ElementStyleResources::GetStyleImage(CSSPropertyID property,
                                                  const CSSValue& value) {
@@ -217,8 +221,10 @@
             StyleImage* new_image =
                 LoadPendingImage(style, To<StylePendingImage>(background_image),
                                  image_request_optimization);
-            if (new_image && new_image->IsLazyloadPossiblyDeferred())
-              LazyLoadImageObserver::StartMonitoring(element_);
+            if (new_image && new_image->IsLazyloadPossiblyDeferred()) {
+              LazyLoadImageObserver::StartMonitoring(
+                  pseudo_element_ ? pseudo_element_ : element_.Get());
+            }
             background_layer->SetImage(new_image);
           }
         }
diff --git a/third_party/blink/renderer/core/css/resolver/element_style_resources.h b/third_party/blink/renderer/core/css/resolver/element_style_resources.h
index 72e025d..a61766b3 100644
--- a/third_party/blink/renderer/core/css/resolver/element_style_resources.h
+++ b/third_party/blink/renderer/core/css/resolver/element_style_resources.h
@@ -41,6 +41,7 @@
 class CSSValue;
 class ComputedStyle;
 class Element;
+class PseudoElement;
 class SVGResource;
 class StyleImage;
 class StylePendingImage;
@@ -58,7 +59,9 @@
   STACK_ALLOCATED();
 
  public:
-  ElementStyleResources(Element&, float device_scale_factor);
+  ElementStyleResources(Element&,
+                        float device_scale_factor,
+                        PseudoElement* pseudo_element);
 
   StyleImage* GetStyleImage(CSSPropertyID, const CSSValue&);
   StyleImage* CachedOrPendingFromValue(CSSPropertyID, const CSSImageValue&);
@@ -88,6 +91,7 @@
   Member<Element> element_;
   HashSet<CSSPropertyID> pending_image_properties_;
   float device_scale_factor_;
+  Member<PseudoElement> pseudo_element_;
   DISALLOW_COPY_AND_ASSIGN(ElementStyleResources);
 };
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index a56192af..6a77809f 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -719,7 +719,8 @@
 
   ElementResolveContext element_context(*element);
 
-  StyleResolverState state(GetDocument(), element_context, default_parent,
+  StyleResolverState state(GetDocument(), element_context,
+                           nullptr /* pseudo_element */, default_parent,
                            default_layout_parent);
 
   const ComputedStyle* base_computed_style =
@@ -860,7 +861,8 @@
     const CSSValue* value) {
   // TODO(alancutter): Avoid creating a StyleResolverState just to apply a
   // single value on a ComputedStyle.
-  StyleResolverState state(element.GetDocument(), &element, parent_style,
+  StyleResolverState state(element.GetDocument(), &element,
+                           nullptr /* pseudo_element */, parent_style,
                            parent_style);
   state.SetStyle(ComputedStyle::Clone(base_style));
   if (value) {
@@ -962,8 +964,10 @@
   if (!element)
     return nullptr;
 
-  StyleResolverState state(GetDocument(), element, parent_style,
-                           parent_layout_object_style);
+  StyleResolverState state(
+      GetDocument(), element,
+      element->GetPseudoElement(pseudo_style_request.pseudo_id), parent_style,
+      parent_layout_object_style);
   if (!PseudoStyleForElementInternal(*element, pseudo_style_request, state)) {
     if (pseudo_style_request.type == PseudoStyleRequest::kForRenderer)
       return nullptr;
@@ -982,7 +986,8 @@
   scoped_refptr<ComputedStyle> initial_style =
       InitialStyleForElement(GetDocument());
   StyleResolverState state(GetDocument(), GetDocument().documentElement(),
-                           initial_style.get(), initial_style.get());
+                           nullptr /* pseudo_element */, initial_style.get(),
+                           initial_style.get());
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   const ComputedStyle* root_element_style =
@@ -1076,7 +1081,8 @@
 StyleRuleList* StyleResolver::StyleRulesForElement(Element* element,
                                                    unsigned rules_to_include) {
   DCHECK(element);
-  StyleResolverState state(GetDocument(), element);
+  StyleResolverState state(GetDocument(), element,
+                           nullptr /* pseudo_element */);
   ElementRuleCollector collector(state.ElementContext(), selector_filter_,
                                  state.Style());
   collector.SetMode(SelectorChecker::kCollectingStyleRules);
@@ -1090,7 +1096,8 @@
     PseudoId pseudo_id,
     unsigned rules_to_include) {
   DCHECK(element);
-  StyleResolverState state(GetDocument(), element);
+  StyleResolverState state(GetDocument(), element,
+                           nullptr /* pseudo_element */);
   ElementRuleCollector collector(state.ElementContext(), selector_filter_,
                                  state.Style());
   collector.SetMode(SelectorChecker::kCollectingCSSRules);
@@ -1978,7 +1985,8 @@
   };
 
   // TODO(timloh): This is weird, the style is being used as its own parent
-  StyleResolverState state(GetDocument(), nullptr, style, style);
+  StyleResolverState state(GetDocument(), nullptr /* element */,
+                           nullptr /* pseudo_element */, style, style);
   state.SetStyle(style);
 
   for (const CSSProperty* property : properties) {
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 2effcd7..9726e5e 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -33,6 +33,7 @@
 StyleResolverState::StyleResolverState(
     Document& document,
     const ElementResolveContext& element_context,
+    PseudoElement* pseudo_element,
     const ComputedStyle* parent_style,
     const ComputedStyle* layout_parent_style)
     : element_context_(element_context),
@@ -46,7 +47,9 @@
       apply_property_to_visited_link_style_(false),
       has_dir_auto_attribute_(false),
       font_builder_(&document),
-      element_style_resources_(*GetElement(), document.DevicePixelRatio()) {
+      element_style_resources_(*GetElement(),
+                               document.DevicePixelRatio(),
+                               pseudo_element) {
   DCHECK(!!parent_style_ == !!layout_parent_style_);
 
   if (!parent_style_) {
@@ -64,11 +67,13 @@
 
 StyleResolverState::StyleResolverState(Document& document,
                                        Element* element,
+                                       PseudoElement* pseudo_element,
                                        const ComputedStyle* parent_style,
                                        const ComputedStyle* layout_parent_style)
     : StyleResolverState(document,
                          element ? ElementResolveContext(*element)
                                  : ElementResolveContext(document),
+                         pseudo_element,
                          parent_style,
                          layout_parent_style) {}
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
index f86cf27..e56cdd3 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
@@ -42,6 +42,7 @@
 
 class ComputedStyle;
 class FontDescription;
+class PseudoElement;
 
 // A per-element object which wraps an ElementResolveContext. It collects state
 // throughout the process of computing the style. It also gives convenient
@@ -52,10 +53,12 @@
  public:
   StyleResolverState(Document&,
                      const ElementResolveContext&,
+                     PseudoElement* pseudo_element,
                      const ComputedStyle* parent_style,
                      const ComputedStyle* layout_parent_style);
   StyleResolverState(Document&,
                      Element*,
+                     PseudoElement* pseudo_element,
                      const ComputedStyle* parent_style = nullptr,
                      const ComputedStyle* layout_parent_style = nullptr);
   ~StyleResolverState();
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
index 6eb71c3..be795514 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
@@ -9,6 +9,7 @@
 #include "base/optional.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/dom/pseudo_element.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
@@ -57,9 +58,18 @@
     GetDocument().UpdateStyleAndLayoutTree();
   }
 
-  void ExpectCSSBackgroundImageDeferredState(bool deferred) {
-    const ComputedStyle* deferred_image_style =
-        GetDocument().getElementById("deferred_image")->GetComputedStyle();
+  const ComputedStyle* GetElementComputedStyle(const Element& element,
+                                               PseudoId pseudo_id) {
+    if (pseudo_id == kPseudoIdNone)
+      return element.GetComputedStyle();
+    return element.GetPseudoElement(pseudo_id)->GetComputedStyle();
+  }
+
+  void ExpectCSSBackgroundImageDeferredState(const char* element_id,
+                                             PseudoId pseudo_id,
+                                             bool deferred) {
+    const ComputedStyle* deferred_image_style = GetElementComputedStyle(
+        *GetDocument().getElementById(element_id), pseudo_id);
     EXPECT_TRUE(deferred_image_style->HasBackgroundImage());
     bool is_background_image_found = false;
     for (const FillLayer* background_layer =
@@ -75,6 +85,51 @@
     EXPECT_TRUE(is_background_image_found);
   }
 
+  void VerifyCSSBackgroundImageInPseudoStyleDeferred(
+      const char* style,
+      const char* deferred_div_classes,
+      const Vector<PseudoId>& background_pseudo_ids) {
+    bool is_lazyload_image_enabled = GetParam();
+    SetLazyLoadEnabled(is_lazyload_image_enabled);
+    SimRequest image_resource("https://example.com/img.png", "image/png");
+    LoadMainResource(String::Format(R"HTML(
+      <html>
+      <head>
+      <style>
+      %s
+      </style>
+      </head>
+      <body>
+      <div style='height:10000px;'></div>
+      <div id="deferred_image" class="%s"></div>
+      </body>
+      </html>
+    )HTML",
+                                    style, deferred_div_classes));
+
+    if (!is_lazyload_image_enabled)
+      image_resource.Complete(ReadTestImage());
+
+    Compositor().BeginFrame();
+    test::RunPendingTasks();
+    for (const auto& pseudo_id : background_pseudo_ids) {
+      ExpectCSSBackgroundImageDeferredState("deferred_image", pseudo_id,
+                                            is_lazyload_image_enabled);
+    }
+    if (is_lazyload_image_enabled) {
+      // Scroll down until the background image is visible.
+      GetDocument().View()->LayoutViewport()->SetScrollOffset(
+          ScrollOffset(0, 10000), kProgrammaticScroll);
+      Compositor().BeginFrame();
+      test::RunPendingTasks();
+      image_resource.Complete(ReadTestImage());
+      for (const auto& pseudo_id : background_pseudo_ids) {
+        ExpectCSSBackgroundImageDeferredState("deferred_image", pseudo_id,
+                                              false);
+      }
+    }
+  }
+
   void VerifyImageElementWithDimensionDeferred(const char* img_attribute) {
     bool is_lazyload_image_enabled = GetParam();
     SetLazyLoadEnabled(is_lazyload_image_enabled);
@@ -135,7 +190,8 @@
 
   Compositor().BeginFrame();
   test::RunPendingTasks();
-  ExpectCSSBackgroundImageDeferredState(is_lazyload_image_enabled);
+  ExpectCSSBackgroundImageDeferredState("deferred_image", kPseudoIdNone,
+                                        is_lazyload_image_enabled);
 
   if (is_lazyload_image_enabled) {
     // Scroll down until the background image is visible.
@@ -144,10 +200,60 @@
     Compositor().BeginFrame();
     test::RunPendingTasks();
     image_resource.Complete(ReadTestImage());
-    ExpectCSSBackgroundImageDeferredState(false);
+    ExpectCSSBackgroundImageDeferredState("deferred_image", kPseudoIdNone,
+                                          false);
   }
 }
 
+TEST_P(LazyLoadImagesSimTest, CSSBackgroundImagePseudoStyleBefore) {
+  VerifyCSSBackgroundImageInPseudoStyleDeferred(R"HTML(
+    .pseudo-element::before {
+      content: '';
+      height: 50px;
+      background-image: url('img.png');
+    })HTML",
+                                                "pseudo-element",
+                                                {kPseudoIdBefore});
+}
+
+TEST_P(LazyLoadImagesSimTest, CSSBackgroundImagePseudoStyleAfter) {
+  VerifyCSSBackgroundImageInPseudoStyleDeferred(R"HTML(
+    .pseudo-element::after {
+      content: '';
+      height: 50px;
+      background-image: url('img.png');
+    })HTML",
+                                                "pseudo-element",
+                                                {kPseudoIdAfter});
+}
+
+TEST_P(LazyLoadImagesSimTest, CSSBackgroundImagePseudoStyleBeforeBlock) {
+  VerifyCSSBackgroundImageInPseudoStyleDeferred(R"HTML(
+    .pseudo-element::before {
+      content: '';
+      display: block;
+      height: 50px;
+      width: 50px;
+      background-image: url('img.png');
+    })HTML",
+                                                "pseudo-element",
+                                                {kPseudoIdBefore});
+}
+
+TEST_P(LazyLoadImagesSimTest,
+       CSSBackgroundImagePseudoStyleBeforeAndAfterBlock) {
+  VerifyCSSBackgroundImageInPseudoStyleDeferred(R"HTML(
+    .pseudo-element::before {
+      content: '';
+      display: block;
+      height: 50px;
+      width: 50px;
+      background-image: url('img.png');
+    })HTML",
+                                                "pseudo-element",
+                                                {kPseudoIdBefore});
+}
+
 TEST_P(LazyLoadImagesSimTest, LargeImageHeight100Width100) {
   VerifyImageElementWithDimensionDeferred("height='100px' width='100px'");
 }
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index 04d7d61..8ad4313 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -503,8 +503,9 @@
 
   dummy_page_holder_->GetDocument().GetSettings()->SetPreferredColorScheme(
       PreferredColorScheme::kDark);
-  StyleResolverState state(dummy_page_holder_->GetDocument(), nullptr, initial,
-                           initial);
+  StyleResolverState state(dummy_page_holder_->GetDocument(),
+                           nullptr /* element */, nullptr /* pseudo_element */,
+                           initial, initial);
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   state.SetStyle(style);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
index d840e5182..9f03fb2 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -336,9 +336,9 @@
     // Must set font in case the filter uses any font-relative units (em, ex)
     filter_style->SetFont(font_for_filter_);
 
-    StyleResolverState resolver_state(style_resolution_host->GetDocument(),
-                                      style_resolution_host, filter_style.get(),
-                                      filter_style.get());
+    StyleResolverState resolver_state(
+        style_resolution_host->GetDocument(), style_resolution_host,
+        nullptr /* pseudo_element */, filter_style.get(), filter_style.get());
     resolver_state.SetStyle(filter_style);
 
     StyleBuilder::ApplyProperty(GetCSSPropertyFilter(), resolver_state,