Backed out changeset f8b877aac56e (because it was landed on autoland)
authorTimothy Nikkel <tnikkel@gmail.com>
Sat, 19 Jan 2019 01:12:51 -0600
changeset 511712 860eae11637f6a9c94cc630cf15feefd6fe2a70f
parent 511711 f8b877aac56e5ef2380f7f250669595769267549
child 511713 bd1a5995cf9f4f1f0b0ec78f38c558f2a9493955
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone66.0a1
backs outf8b877aac56e5ef2380f7f250669595769267549
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
Backed out changeset f8b877aac56e (because it was landed on autoland)
layout/painting/nsDisplayList.cpp
layout/reftests/svg/filters/css-filter-chains/reftest.list
layout/reftests/svg/filters/css-filters/reftest.list
layout/reftests/svg/filters/css-svg-filter-chains/reftest.list
layout/svg/nsFilterInstance.cpp
layout/svg/nsFilterInstance.h
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGIntegrationUtils.h
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9347,43 +9347,39 @@ bool nsDisplayFilters::CreateWebRenderCS
 }
 
 bool nsDisplayFilters::CreateWebRenderCommands(
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
     mozilla::layers::RenderRootStateManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) {
+  bool snap;
   float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+  nsRect displayBounds = GetBounds(aDisplayListBuilder, &snap);
+  auto postFilterBounds = LayoutDeviceIntRect::Round(
+      LayoutDeviceRect::FromAppUnits(displayBounds, auPerDevPixel));
+  auto preFilterBounds = LayoutDeviceIntRect::Round(
+      LayoutDeviceRect::FromAppUnits(mBounds, auPerDevPixel));
 
   nsTArray<mozilla::wr::FilterOp> wrFilters;
-  Maybe<nsRect> filterClip;
   if (!CreateWebRenderCSSFilters(wrFilters) &&
-      !nsSVGIntegrationUtils::BuildWebRenderFilters(mFrame, wrFilters,
-                                                    filterClip)) {
+      !nsSVGIntegrationUtils::BuildWebRenderFilters(
+          mFrame, preFilterBounds, wrFilters, postFilterBounds)) {
     return false;
   }
 
-  wr::WrStackingContextClip clip;
-  if (filterClip) {
-    auto devPxRect = LayoutDeviceRect::FromAppUnits(
-        filterClip.value() + ToReferenceFrame(), auPerDevPixel);
-    wr::WrClipId clipId =
-        aBuilder.DefineClip(Nothing(), wr::ToRoundedLayoutRect(devPxRect));
-    clip = wr::WrStackingContextClip::ClipId(clipId);
-  } else {
-    clip = wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
-  }
-
   float opacity = mFrame->StyleEffects()->mOpacity;
   StackingContextHelper sc(
       aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, wrFilters,
       LayoutDeviceRect(), nullptr, nullptr,
       opacity != 1.0f && mHandleOpacity ? &opacity : nullptr, nullptr,
-      gfx::CompositionOp::OP_OVER, true, false, Nothing(), clip);
+      wr::ReferenceFrameKind::Transform, gfx::CompositionOp::OP_OVER, true,
+      false, Nothing(),
+      wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId()));
 
   nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc,
                                                 aManager, aDisplayListBuilder);
 
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING
--- a/layout/reftests/svg/filters/css-filter-chains/reftest.list
+++ b/layout/reftests/svg/filters/css-filter-chains/reftest.list
@@ -1,7 +1,7 @@
 # These tests verify that CSS filter chains behave properly.
 # e.g. filter: blur(3px) grayscale(0.5) invert(0.2);
 
 # Some platforms render this complex filter chain a little differently, and that's ok.
-fuzzy(0-5,0-13638) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,0-35,0-13638) fuzzy-if(webrender,4-6,12000-18946) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
+fuzzy(0-5,0-13638) fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&layersGPUAccelerated,0-35,0-13638) fuzzy-if(webrender,4-6,12000-18853) == long-chain.html long-chain-ref.html # Win10: Bug 1258241
 == moz-element.html moz-element-ref.html
-fuzzy-if(webrender,13-15,7682-7966) == same-filter.html same-filter-ref.html
+== same-filter.html same-filter-ref.html
--- a/layout/reftests/svg/filters/css-filters/reftest.list
+++ b/layout/reftests/svg/filters/css-filters/reftest.list
@@ -1,17 +1,17 @@
 # These tests verify that CSS filters behave properly.
 # e.g. filter: blur(3px)
 
 == blur.html blur-ref.html
 == blur.svg blur-ref.svg
 == blur-calc.html blur-calc-ref.html
 == blur-calc-negative.html blur-calc-negative-ref.html
 fuzzy-if(cocoaWidget&&webrender,0-1,0-2) skip-if(d2d) == blur-cap-large-radius-on-software.html blur-cap-large-radius-on-software-ref.html
-fuzzy-if(webrender,3-4,5760-6424) == blur-clip-rect.html ../feGaussianBlur-4-ref.svg
+fails-if(webrender) == blur-clip-rect.html ../feGaussianBlur-4-ref.svg
 == blur-em-radius.html blur-em-radius-ref.html
 == blur-invalid-radius.html blur-invalid-radius-ref.html
 == blur-rem-radius.html blur-rem-radius-ref.html
 == blur-zero-radius.html blur-zero-radius-ref.html
 == blur-zoomed-page.html blur-zoomed-page-ref.html
 == brightness.html brightness-ref.html
 == brightness-darken.html brightness-darken-ref.html
 == brightness-extreme.html brightness-extreme-ref.html
--- a/layout/reftests/svg/filters/css-svg-filter-chains/reftest.list
+++ b/layout/reftests/svg/filters/css-svg-filter-chains/reftest.list
@@ -1,8 +1,8 @@
 # These tests verify that filter chains of combined CSS and SVG filters behave
 # properly.
 # e.g. filter: url(#f1) blur(3px) url(#2) grayscale(0.5);
 
 == clip-input-css-filter.html clip-input-css-filter-ref.html
-fuzzy-if(webrender,0-1,0-288) == css-filter-first.html css-filter-first-ref.html
+== css-filter-first.html css-filter-first-ref.html
 == css-filter-last.html css-filter-last-ref.html
 == css-filter-middle.html css-filter-middle-ref.html
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -88,19 +88,20 @@ void nsFilterInstance::PaintFilteredFram
                             *metrics, filterChain, /* InputIsTainted */ true,
                             aPaintCallback, scaleMatrixInDevUnits, aDirtyArea,
                             nullptr, nullptr, nullptr);
   if (instance.IsInitialized()) {
     instance.Render(aCtx, aImgParams, aOpacity);
   }
 }
 
-bool nsFilterInstance::BuildWebRenderFilters(nsIFrame* aFilteredFrame,
-                                             nsTArray<wr::FilterOp>& aWrFilters,
-                                             Maybe<nsRect>& aPostFilterClip) {
+bool nsFilterInstance::BuildWebRenderFilters(
+    nsIFrame* aFilteredFrame, const LayoutDeviceIntRect& aPreFilterBounds,
+    nsTArray<wr::FilterOp>& aWrFilters,
+    LayoutDeviceIntRect& aPostFilterBounds) {
   aWrFilters.Clear();
 
   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
   UniquePtr<UserSpaceMetrics> metrics =
       UserSpaceMetricsForFrame(aFilteredFrame);
 
   // TODO: simply using an identity matrix here, was pulling the scale from a
   // gfx context for the non-wr path.
@@ -115,38 +116,68 @@ bool nsFilterInstance::BuildWebRenderFil
                             *metrics, filterChain, inputIsTainted, nullptr,
                             scaleMatrixInDevUnits, nullptr, nullptr, nullptr,
                             nullptr);
 
   if (!instance.IsInitialized()) {
     return false;
   }
 
-  Maybe<IntRect> finalClip;
+  Maybe<LayoutDeviceIntRect> finalClip;
   bool srgb = true;
   // We currently apply the clip on the stacking context after applying filters,
   // but primitive subregions imply clipping after each filter and not just the
   // end of the chain. For some types of filter it doesn't matter, but for those
   // which sample outside of the location of the destination pixel like blurs,
   // only clipping after could produce incorrect results, so we bail out in this
   // case.
   // We can lift this restriction once we have added support for primitive
   // subregions to WebRender's filters.
 
+  // During the loop this tracks whether any of the previous filters in the
+  // chain affected by the primitive subregion.
+  bool chainIsAffectedByPrimSubregion = false;
+  // During the loop this tracks whether the current filter is affected by the
+  // primitive subregion.
+  bool filterIsAffectedByPrimSubregion = false;
+
   for (const auto& primitive : instance.mFilterDescription.mPrimitives) {
+    chainIsAffectedByPrimSubregion |= filterIsAffectedByPrimSubregion;
+    filterIsAffectedByPrimSubregion = false;
+
     bool primIsSrgb = primitive.OutputColorSpace() == gfx::ColorSpace::SRGB;
     if (srgb && !primIsSrgb) {
       aWrFilters.AppendElement(wr::FilterOp::SrgbToLinear());
       srgb = false;
     } else if (!srgb && primIsSrgb) {
       aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
       srgb = true;
     }
 
     const PrimitiveAttributes& attr = primitive.Attributes();
+    auto subregion = LayoutDeviceIntRect::FromUnknownRect(
+        primitive.PrimitiveSubregion() +
+        aPreFilterBounds.TopLeft().ToUnknownPoint());
+
+    if (!subregion.Contains(aPreFilterBounds)) {
+      if (!aPostFilterBounds.Contains(subregion)) {
+        filterIsAffectedByPrimSubregion = true;
+      }
+
+      subregion = subregion.Intersect(aPostFilterBounds);
+
+      if (finalClip.isNothing()) {
+        finalClip = Some(subregion);
+      } else if (!subregion.IsEqualEdges(finalClip.value())) {
+        // We don't currently support rendering a chain of filters with
+        // different primitive subregions in WebRender so bail out in that
+        // situation.
+        return false;
+      }
+    }
 
     bool filterIsNoop = false;
 
     if (attr.is<OpacityAttributes>()) {
       float opacity = attr.as<OpacityAttributes>().mOpacity;
       aWrFilters.AppendElement(wr::FilterOp::Opacity(
           wr::PropertyBinding<float>::Value(opacity), opacity));
     } else if (attr.is<ColorMatrixAttributes>()) {
@@ -177,17 +208,17 @@ bool nsFilterInstance::BuildWebRenderFil
           transposed[0], transposed[5], transposed[10], transposed[15],
           transposed[1], transposed[6], transposed[11], transposed[16],
           transposed[2], transposed[7], transposed[12], transposed[17],
           transposed[3], transposed[8], transposed[13], transposed[18],
           transposed[4], transposed[9], transposed[14], transposed[19]};
 
       aWrFilters.AppendElement(wr::FilterOp::ColorMatrix(matrix));
     } else if (attr.is<GaussianBlurAttributes>()) {
-      if (finalClip) {
+      if (chainIsAffectedByPrimSubregion) {
         // There's a clip that needs to apply before the blur filter, but
         // WebRender only lets us apply the clip at the end of the filter
         // chain. Clipping after a blur is not equivalent to clipping before
         // a blur, so bail out.
         return false;
       }
 
       const GaussianBlurAttributes& blur = attr.as<GaussianBlurAttributes>();
@@ -199,17 +230,17 @@ bool nsFilterInstance::BuildWebRenderFil
 
       float radius = stdDev.width;
       if (radius != 0.0) {
         aWrFilters.AppendElement(wr::FilterOp::Blur(radius));
       } else {
         filterIsNoop = true;
       }
     } else if (attr.is<DropShadowAttributes>()) {
-      if (finalClip) {
+      if (chainIsAffectedByPrimSubregion) {
         // We have to bail out for the same reason we would with a blur filter.
         return false;
       }
 
       const DropShadowAttributes& shadow = attr.as<DropShadowAttributes>();
 
       const Size& stdDev = shadow.mStdDeviation;
       if (stdDev.width != stdDev.height) {
@@ -235,34 +266,28 @@ bool nsFilterInstance::BuildWebRenderFil
       // unnecessary. Remove it from the filter list.
       // This is both an optimization and a way to pass the wptest
       // css/filter-effects/filter-scale-001.html for which the needless
       // sRGB->linear->no-op->sRGB roundtrip introduces a slight error and we
       // cannot add fuzziness to the test.
       Unused << aWrFilters.PopLastElement();
       srgb = !srgb;
     }
-
-    if (!filterIsNoop) {
-      if (finalClip.isNothing()) {
-        finalClip = Some(primitive.PrimitiveSubregion());
-      } else {
-        finalClip =
-            Some(primitive.PrimitiveSubregion().Intersect(finalClip.value()));
-      }
-    }
   }
 
   if (!srgb) {
     aWrFilters.AppendElement(wr::FilterOp::LinearToSrgb());
   }
 
-  if (finalClip) {
-    aPostFilterClip = Some(instance.FilterSpaceToFrameSpace(finalClip.value()));
+  // Only adjust the post filter clip if we are able to render this without
+  // fallback.
+  if (finalClip.isSome()) {
+    aPostFilterBounds = finalClip.value();
   }
+
   return true;
 }
 
 nsRegion nsFilterInstance::GetPostFilterDirtyArea(
     nsIFrame* aFilteredFrame, const nsRegion& aPreFilterDirtyRegion) {
   if (aPreFilterDirtyRegion.IsEmpty()) {
     return nsRegion();
   }
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -117,19 +117,21 @@ class nsFilterInstance {
   static nsRect GetPostFilterBounds(nsIFrame* aFilteredFrame,
                                     const gfxRect* aOverrideBBox = nullptr,
                                     const nsRect* aPreFilterBounds = nullptr);
 
   /**
    * Try to build WebRender filters for a frame if the filters applied to it are
    * supported.
    */
-  static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
-                                    nsTArray<mozilla::wr::FilterOp>& aWrFilters,
-                                    mozilla::Maybe<nsRect>& aPostFilterClip);
+  static bool BuildWebRenderFilters(
+      nsIFrame* aFilteredFrame,
+      const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
+      nsTArray<mozilla::wr::FilterOp>& aWrFilters,
+      mozilla::LayoutDeviceIntRect& aPostFilterBounds);
 
  private:
   /**
    * @param aTargetFrame The frame of the filtered element under consideration,
    *   may be null.
    * @param aTargetContent The filtered element itself.
    * @param aMetrics The metrics to resolve SVG lengths against.
    * @param aFilterChain The list of filters to apply.
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -1081,20 +1081,22 @@ void nsSVGIntegrationUtils::PaintFilter(
                                      offsets.offsetToUserSpaceInDevPx);
   nsRegion dirtyRegion = aParams.dirtyRect - offsets.offsetToBoundingBox;
 
   nsFilterInstance::PaintFilteredFrame(frame, &context, &callback, &dirtyRegion,
                                        aParams.imgParams, opacity);
 }
 
 bool nsSVGIntegrationUtils::BuildWebRenderFilters(
-    nsIFrame* aFilteredFrame, nsTArray<mozilla::wr::FilterOp>& aWrFilters,
-    Maybe<nsRect>& aPostFilterClip) {
-  return nsFilterInstance::BuildWebRenderFilters(aFilteredFrame, aWrFilters,
-                                                 aPostFilterClip);
+    nsIFrame* aFilteredFrame,
+    const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
+    nsTArray<mozilla::wr::FilterOp>& aWrFilters,
+    mozilla::LayoutDeviceIntRect& aPostFilterBounds) {
+  return nsFilterInstance::BuildWebRenderFilters(
+      aFilteredFrame, aPreFilterBounds, aWrFilters, aPostFilterBounds);
 }
 
 class PaintFrameCallback : public gfxDrawingCallback {
  public:
   PaintFrameCallback(nsIFrame* aFrame, const nsSize aPaintServerSize,
                      const IntSize aRenderSize, uint32_t aFlags)
       : mFrame(aFrame),
         mPaintServerSize(aPaintServerSize),
--- a/layout/svg/nsSVGIntegrationUtils.h
+++ b/layout/svg/nsSVGIntegrationUtils.h
@@ -190,19 +190,21 @@ class nsSVGIntegrationUtils final {
    * Paint non-SVG frame with filter and opacity effect.
    */
   static void PaintFilter(const PaintFramesParams& aParams);
 
   /**
    * Try to build WebRender filters for a frame if the filters applied to it are
    * supported.
    */
-  static bool BuildWebRenderFilters(nsIFrame* aFilteredFrame,
-                                    nsTArray<mozilla::wr::FilterOp>& aWrFilters,
-                                    mozilla::Maybe<nsRect>& aPostFilterClip);
+  static bool BuildWebRenderFilters(
+      nsIFrame* aFilteredFrame,
+      const mozilla::LayoutDeviceIntRect& aPreFilterBounds,
+      nsTArray<mozilla::wr::FilterOp>& aWrFilters,
+      mozilla::LayoutDeviceIntRect& aPostFilterBounds);
 
   /**
    * @param aRenderingContext the target rendering context in which the paint
    * server will be rendered
    * @param aTarget the target frame onto which the paint server will be
    * rendered
    * @param aPaintServer a first-continuation frame to use as the source
    * @param aFilter a filter to be applied when scaling