Bug 1021564 - Invalidate filtered frames when they move in certain ways. r=roc
☠☠ backed out by a3a5fccdbccf ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Thu, 17 Jul 2014 14:58:24 +0200
changeset 216642 87ae841e4f92c1cd0db5572e16a2a7747d758d47
parent 216641 34b3014a3112079f48f00dd60d374519571e62cf
child 216643 2ccde1bdcb7f9ddd757604fc65766184d9806bbe
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs1021564
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1021564 - Invalidate filtered frames when they move in certain ways. r=roc
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsDisplayListInvalidation.cpp
layout/base/nsDisplayListInvalidation.h
layout/reftests/bugs/1021564-1.html
layout/reftests/bugs/1021564-2.html
layout/reftests/bugs/1021564-3.html
layout/reftests/bugs/1021564-4.html
layout/reftests/bugs/1021564-ref.html
layout/reftests/bugs/reftest.list
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -20,16 +20,17 @@
 #include "nsISelectionController.h"
 #include "nsIPresShell.h"
 #include "nsRegion.h"
 #include "nsStyleStructInlines.h"
 #include "nsStyleTransformMatrix.h"
 #include "gfxMatrix.h"
 #include "gfxPrefs.h"
 #include "nsSVGIntegrationUtils.h"
+#include "nsSVGUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsIFrameInlines.h"
 #include "nsThemeConstants.h"
 #include "LayerTreeInvalidation.h"
 
 #include "imgIContainer.h"
 #include "BasicLayers.h"
@@ -5244,16 +5245,50 @@ bool nsDisplaySVGEffects::TryMerge(nsDis
     return false;
   nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
   MergeFromTrackingMergedFrames(other);
   mEffectsBounds.UnionRect(mEffectsBounds,
     other->mEffectsBounds + other->mFrame->GetOffsetTo(mFrame));
   return true;
 }
 
+gfxRect
+nsDisplaySVGEffects::BBoxInUserSpace() const
+{
+  return nsSVGUtils::GetBBox(mFrame);
+}
+
+gfxPoint
+nsDisplaySVGEffects::UserSpaceOffset() const
+{
+  return nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mFrame);
+}
+
+void
+nsDisplaySVGEffects::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                               const nsDisplayItemGeometry* aGeometry,
+                                               nsRegion* aInvalidRegion)
+{
+  const nsDisplaySVGEffectsGeometry* geometry =
+    static_cast<const nsDisplaySVGEffectsGeometry*>(aGeometry);
+  bool snap;
+  nsRect bounds = GetBounds(aBuilder, &snap);
+  if (geometry->mFrameOffsetToReferenceFrame != ToReferenceFrame() ||
+      geometry->mUserSpaceOffset != UserSpaceOffset() ||
+      !geometry->mBBox.IsEqualInterior(BBoxInUserSpace())) {
+    // Filter and mask output can depend on the location of the frame's user
+    // space and on the frame's BBox. We need to invalidate if either of these
+    // change relative to the reference frame.
+    // Invalidations from our inactive layer manager are not enough to catch
+    // some of these cases because filters can produce output even if there's
+    // nothing in the filter input.
+    aInvalidRegion->Or(bounds, geometry->mBounds);
+  }
+}
+
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplaySVGEffects::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -3127,23 +3127,27 @@ public:
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) MOZ_OVERRIDE;
  
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE;
-  
+
+  gfxRect BBoxInUserSpace() const;
+  gfxPoint UserSpaceOffset() const;
+
+  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
+  {
+    return new nsDisplaySVGEffectsGeometry(this, aBuilder);
+  }
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
-                                         nsRegion* aInvalidRegion) MOZ_OVERRIDE
-  {
-    // We don't need to compute an invalidation region since we have LayerTreeInvalidation
-  }
+                                         nsRegion* aInvalidRegion) MOZ_OVERRIDE;
 
   void PaintAsLayer(nsDisplayListBuilder* aBuilder,
                     nsRenderingContext* aCtx,
                     LayerManager* aManager);
 
 #ifdef MOZ_DUMP_PAINTING
   void PrintEffects(nsACString& aTo);
 #endif
--- a/layout/base/nsDisplayListInvalidation.cpp
+++ b/layout/base/nsDisplayListInvalidation.cpp
@@ -90,8 +90,21 @@ nsDisplayBoxShadowInnerGeometry::nsDispl
 
 void
 nsDisplayBoxShadowInnerGeometry::MoveBy(const nsPoint& aOffset)
 {
   mBounds.MoveBy(aOffset);
   mPaddingRect.MoveBy(aOffset);
 }
 
+nsDisplaySVGEffectsGeometry::nsDisplaySVGEffectsGeometry(nsDisplaySVGEffects* aItem, nsDisplayListBuilder* aBuilder)
+  : nsDisplayItemGeometry(aItem, aBuilder)
+  , mBBox(aItem->BBoxInUserSpace())
+  , mUserSpaceOffset(aItem->UserSpaceOffset())
+  , mFrameOffsetToReferenceFrame(aItem->ToReferenceFrame())
+{}
+
+void
+nsDisplaySVGEffectsGeometry::MoveBy(const nsPoint& aOffset)
+{
+  mBounds.MoveBy(aOffset);
+  mFrameOffsetToReferenceFrame += aOffset;
+}
--- a/layout/base/nsDisplayListInvalidation.h
+++ b/layout/base/nsDisplayListInvalidation.h
@@ -4,21 +4,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NSDISPLAYLISTINVALIDATION_H_
 #define NSDISPLAYLISTINVALIDATION_H_
 
 #include "mozilla/Attributes.h"
 #include "nsRect.h"
 #include "nsColor.h"
+#include "gfxRect.h"
 
 class nsDisplayItem;
 class nsDisplayListBuilder;
 class nsDisplayBackgroundImage;
 class nsDisplayThemedBackground;
+class nsDisplaySVGEffects;
 
 /**
  * This stores the geometry of an nsDisplayItem, and the area
  * that will be affected when painting the item.
  *
  * It is used to retain information about display items so they
  * can be compared against new display items in the next paint.
  */
@@ -125,9 +127,21 @@ public:
                               nscolor aColor)
     : nsDisplayItemBoundsGeometry(aItem, aBuilder)
     , mColor(aColor)
   { }
 
   nscolor mColor;
 };
 
+class nsDisplaySVGEffectsGeometry : public nsDisplayItemGeometry
+{
+public:
+  nsDisplaySVGEffectsGeometry(nsDisplaySVGEffects* aItem, nsDisplayListBuilder* aBuilder);
+
+  virtual void MoveBy(const nsPoint& aOffset) MOZ_OVERRIDE;
+
+  gfxRect mBBox;
+  gfxPoint mUserSpaceOffset;
+  nsPoint mFrameOffsetToReferenceFrame;
+};
+
 #endif /*NSDISPLAYLISTINVALIDATION_H_*/
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1021564-1.html
@@ -0,0 +1,46 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>When the filtered element's BBox relative to the page changes, the filtered element needs to be invalidated</title>
+
+<style>
+
+#spacer {
+  height: 100px;
+}
+
+#filtered {
+  width: 100px;
+  height: 100px;
+  background-color: lime;
+  filter: url(#filter);
+}
+
+</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>
+  </defs>
+</svg>
+
+<div id="spacer"></div>
+
+<div id="filtered"></div>
+
+<script>
+
+window.addEventListener("MozReftestInvalidate", function () {
+  document.getElementById("spacer").style.height = "50px";
+  document.documentElement.removeAttribute("class");
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1021564-2.html
@@ -0,0 +1,45 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>When the filtered element's BBox relative to the page changes, the filtered element needs to be invalidated</title>
+
+<style>
+
+#spacer {
+  height: 100px;
+}
+
+#filtered {
+  width: 100px;
+  height: 100px;
+  filter: url(#filter);
+}
+
+</style>
+
+<svg height="0">
+  <defs>
+    <filter id="filter" filterUnits="objectBoundingBox"
+            x="0%" y="0%" width="100%" height="100%"
+            color-interpolation-filters="sRGB">
+      <feFlood flood-color="lime"/>
+    </filter>
+  </defs>
+</svg>
+
+<div id="spacer"></div>
+
+<div id="filtered"></div>
+
+<script>
+
+window.addEventListener("MozReftestInvalidate", function () {
+  document.getElementById("spacer").style.height = "50px";
+  document.documentElement.removeAttribute("class");
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1021564-3.html
@@ -0,0 +1,46 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>When the filtered element's BBox relative to the page changes, the filtered element needs to be invalidated</title>
+
+<style>
+
+#spacer {
+  height: 100px;
+}
+
+#filtered {
+  width: 100px;
+  height: 100px;
+  background-color: lime;
+  filter: url(#filter);
+}
+
+</style>
+
+<svg height="0">
+  <defs>
+    <filter id="filter" filterUnits="userSpaceOnUse"
+            x="0" y="0" width="100" height="100"
+            color-interpolation-filters="sRGB">
+      <feMerge><feMergeNode/></feMerge>
+    </filter>
+  </defs>
+</svg>
+
+<div id="spacer"></div>
+
+<div id="filtered"></div>
+
+<script>
+
+window.addEventListener("MozReftestInvalidate", function () {
+  document.getElementById("spacer").style.height = "50px";
+  document.documentElement.removeAttribute("class");
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1021564-4.html
@@ -0,0 +1,45 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>When the filtered element's BBox relative to the page changes, the filtered element needs to be invalidated</title>
+
+<style>
+
+#spacer {
+  height: 100px;
+}
+
+#filtered {
+  width: 100px;
+  height: 100px;
+  filter: url(#filter);
+}
+
+</style>
+
+<svg height="0">
+  <defs>
+    <filter id="filter" filterUnits="userSpaceOnUse"
+            x="0" y="0" width="100" height="100"
+            color-interpolation-filters="sRGB">
+      <feFlood flood-color="lime"/>
+    </filter>
+  </defs>
+</svg>
+
+<div id="spacer"></div>
+
+<div id="filtered"></div>
+
+<script>
+
+window.addEventListener("MozReftestInvalidate", function () {
+  document.getElementById("spacer").style.height = "50px";
+  document.documentElement.removeAttribute("class");
+});
+
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1021564-ref.html
@@ -0,0 +1,28 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>When the filtered element's BBox relative to the page changes, the filtered element needs to be invalidated</title>
+
+<style>
+
+#spacer {
+  height: 50px;
+}
+
+#filtered {
+  width: 100px;
+  height: 100px;
+  background-color: lime;
+}
+
+</style>
+
+<svg height="0"></svg>
+
+<div id="spacer"></div>
+
+<div id="filtered"></div>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1807,11 +1807,15 @@ skip-if(Android) == 966510-2.html 966510
 == 983691-1.html 983691-ref.html
 == 985303-1a.html 985303-1-ref.html
 == 985303-1b.html 985303-1-ref.html
 == 987680-1.html 987680-1-ref.html
 fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,24) == 991046-1.html 991046-1-ref.html
 pref(layout.css.overflow-clip-box.enabled,true) == 992447.html 992447-ref.html
 pref(layout.css.sticky.enabled,true) == 1005405-1.html 1005405-1-ref.html
 pref(layout.css.will-change.enabled,true) == 1018522-1.html 1018522-1-ref.html
+== 1021564-1.html 1021564-ref.html
+== 1021564-2.html 1021564-ref.html
+== 1021564-3.html 1021564-ref.html
+== 1021564-4.html 1021564-ref.html
 pref(browser.display.use_document_fonts,0) == 1022481-1.html 1022481-1-ref.html
 == 1022612-1.html 1022612-1-ref.html
 == 1024473-1.html 1024473-1-ref.html