Bug 1525372 - Add background-clip:text rendering observer so that we get notified of changes to the clipped contents. r=jwatt a=pascalc
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 18 Mar 2019 16:24:20 +0000
changeset 525693 e4ee5e511a6fe4534b6caa153e219317c7c23e27
parent 525692 1962a2d9ec9af138c578c331c9082b5e2af6cd36
child 525694 77a1f36d6cad9ce36bff4c187c0ca4111d7efc78
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt, pascalc
bugs1525372
milestone67.0
Bug 1525372 - Add background-clip:text rendering observer so that we get notified of changes to the clipped contents. r=jwatt a=pascalc Differential Revision: https://phabricator.services.mozilla.com/D20110
layout/painting/nsDisplayList.cpp
layout/svg/SVGObserverUtils.cpp
layout/svg/SVGObserverUtils.h
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -815,16 +815,18 @@ static uint64_t AddAnimationsForWebRende
 
 static bool GenerateAndPushTextMask(nsIFrame* aFrame, gfxContext* aContext,
                                     const nsRect& aFillRect,
                                     nsDisplayListBuilder* aBuilder) {
   if (aBuilder->IsForGenerateGlyphMask()) {
     return false;
   }
 
+  SVGObserverUtils::GetAndObserveBackgroundClip(aFrame);
+
   // The main function of enabling background-clip:text property value.
   // When a nsDisplayBackgroundImage detects "text" bg-clip style, it will call
   // this function to
   // 1. Generate a mask by all descendant text frames
   // 2. Push the generated mask into aContext.
 
   gfxContext* sourceCtx = aContext;
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
--- a/layout/svg/SVGObserverUtils.cpp
+++ b/layout/svg/SVGObserverUtils.cpp
@@ -454,16 +454,44 @@ class SVGMozElementObserver final : publ
 
   // We only return true here because GetAndObserveBackgroundImage uses us
   // to implement observing of arbitrary elements (including HTML elements)
   // that may require us to repaint if the referenced element is reflowed.
   // Bug 1496065 has been filed to remove that support though.
   bool ObservesReflow() override { return true; }
 };
 
+class BackgroundClipRenderingObserver : public SVGRenderingObserver {
+ public:
+  explicit BackgroundClipRenderingObserver(nsIFrame* aFrame) : mFrame(aFrame) {}
+
+  NS_DECL_ISUPPORTS
+
+ private:
+  virtual ~BackgroundClipRenderingObserver() { StopObserving(); }
+
+  Element* GetReferencedElementWithoutObserving() final {
+    return mFrame->GetContent()->AsElement();
+  }
+
+  void OnRenderingChange() final;
+  bool ObservesReflow() final { return true; }
+
+  nsIFrame* mFrame;
+};
+
+NS_IMPL_ISUPPORTS(BackgroundClipRenderingObserver, nsIMutationObserver)
+
+void BackgroundClipRenderingObserver::OnRenderingChange() {
+  for (nsIFrame* f = mFrame; f;
+       f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
+    f->InvalidateFrame();
+  }
+}
+
 /**
  * In a filter chain, there can be multiple SVG reference filters.
  * e.g. filter: url(#svg-filter-1) blur(10px) url(#svg-filter-2);
  *
  * This class keeps track of one SVG reference filter in a filter chain.
  * e.g. url(#svg-filter-1)
  *
  * It fires invalidations when the SVG filter element's id changes or when
@@ -986,16 +1014,18 @@ NS_DECLARE_FRAME_PROPERTY_RELEASABLE(Mar
 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerMidProperty, SVGMarkerObserver)
 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(MarkerEndProperty, SVGMarkerObserver)
 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(FillProperty, nsSVGPaintingProperty)
 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(StrokeProperty, nsSVGPaintingProperty)
 NS_DECLARE_FRAME_PROPERTY_RELEASABLE(HrefAsTextPathProperty,
                                      SVGTextPathObserver)
 NS_DECLARE_FRAME_PROPERTY_DELETABLE(BackgroundImageProperty,
                                     URIObserverHashtable)
+NS_DECLARE_FRAME_PROPERTY_RELEASABLE(BackgroundClipObserverProperty,
+                                     BackgroundClipRenderingObserver)
 
 template <class T>
 static T* GetEffectProperty(
     URLAndReferrerInfo* aURI, nsIFrame* aFrame,
     const mozilla::FramePropertyDescriptor<T>* aProperty) {
   if (!aURI) {
     return nullptr;
   }
@@ -1350,16 +1380,29 @@ Element* SVGObserverUtils::GetAndObserve
       static_cast<SVGMozElementObserver*>(hashtable->GetWeak(url));
   if (!observer) {
     observer = new SVGMozElementObserver(url, aFrame, /* aWatchImage */ true);
     hashtable->Put(url, observer);
   }
   return observer->GetAndObserveReferencedElement();
 }
 
+Element* SVGObserverUtils::GetAndObserveBackgroundClip(nsIFrame* aFrame) {
+  bool found;
+  BackgroundClipRenderingObserver* obs =
+      aFrame->GetProperty(BackgroundClipObserverProperty(), &found);
+  if (!found) {
+    obs = new BackgroundClipRenderingObserver(aFrame);
+    NS_ADDREF(obs);
+    aFrame->AddProperty(BackgroundClipObserverProperty(), obs);
+  }
+
+  return obs->GetAndObserveReferencedElement();
+}
+
 nsSVGPaintServerFrame* SVGObserverUtils::GetAndObservePaintServer(
     nsIFrame* aTargetFrame, nsStyleSVGPaint nsStyleSVG::*aPaint) {
   // If we're looking at a frame within SVG text, then we need to look up
   // to find the right frame to get the painting property off.  We should at
   // least look up past a text frame, and if the text frame's parent is the
   // anonymous block frame, then we look up to its parent (the SVGTextFrame).
   nsIFrame* frame = aTargetFrame;
   if (frame->GetContent()->IsText()) {
--- a/layout/svg/SVGObserverUtils.h
+++ b/layout/svg/SVGObserverUtils.h
@@ -389,16 +389,22 @@ class SVGObserverUtils {
    *
    * Note that bug 1496065 has been filed to remove support for referencing
    * arbitrary elements using '-moz-element'.
    */
   static Element* GetAndObserveBackgroundImage(nsIFrame* aFrame,
                                                const nsAtom* aHref);
 
   /**
+   * Gets an arbitrary element and starts observing it.  Used to detect
+   * invalidation changes for background-clip:text.
+   */
+  static Element* GetAndObserveBackgroundClip(nsIFrame* aFrame);
+
+  /**
    * A helper function to resolve filter URL.
    */
   static already_AddRefed<URLAndReferrerInfo> GetFilterURI(
       nsIFrame* aFrame, const nsStyleFilter& aFilter);
 
   /**
    * Return a baseURL for resolving a local-ref URL.
    *