Bug 1298552 - Call UpdateFilter whenever the canvas's IsWriteOnly state changes. r=jrmuizel, a=ritu
authorMarkus Stange <mstange@themasta.com>
Fri, 26 Aug 2016 20:21:34 -0400
changeset 355711 d531a9166e20c44d9665db419d9e75457be82155
parent 355710 b57b64179109580af8cad33124c49ddc81ab4c5f
child 355712 f44e863b05e782664995b31a7fd01e167a92ebbf
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, ritu
bugs1298552
milestone51.0a2
Bug 1298552 - Call UpdateFilter whenever the canvas's IsWriteOnly state changes. r=jrmuizel, a=ritu MozReview-Commit-ID: 2CqWhmyzUZc
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -344,31 +344,20 @@ public:
     mFinalTarget = aFinalTarget;
     mPostFilterBounds = aPostFilterBounds;
     mOffset = aFilterSpaceToTargetOffset;
 
     nsIntRegion sourceGraphicNeededRegion;
     nsIntRegion fillPaintNeededRegion;
     nsIntRegion strokePaintNeededRegion;
 
-    if (aCtx->CurrentState().updateFilterOnWriteOnly) {
-      aCtx->UpdateFilter();
-      aCtx->CurrentState().updateFilterOnWriteOnly = false;
-    }
-
-    // This should not be empty, but if it is, we want to handle it
-    // rather than crash, as UpdateFilter() call above could have changed
-    // the number of filter primitives.
-    MOZ_ASSERT(!aCtx->CurrentState().filter.mPrimitives.IsEmpty());
-    if (!aCtx->CurrentState().filter.mPrimitives.IsEmpty()) {
-      FilterSupport::ComputeSourceNeededRegions(
-        aCtx->CurrentState().filter, mPostFilterBounds,
-        sourceGraphicNeededRegion, fillPaintNeededRegion,
-        strokePaintNeededRegion);
-    }
+    FilterSupport::ComputeSourceNeededRegions(
+      aCtx->CurrentState().filter, mPostFilterBounds,
+      sourceGraphicNeededRegion, fillPaintNeededRegion,
+      strokePaintNeededRegion);
 
     mSourceGraphicRect = sourceGraphicNeededRegion.GetBounds();
     mFillPaintRect = fillPaintNeededRegion.GetBounds();
     mStrokePaintRect = strokePaintNeededRegion.GetBounds();
 
     mSourceGraphicRect = mSourceGraphicRect.Intersect(aPreFilterBounds);
 
     if (mSourceGraphicRect.IsEmpty()) {
@@ -2791,19 +2780,16 @@ CanvasRenderingContext2D::SetFilter(cons
     filterChain.SwapElements(CurrentState().filterChain);
     if (mCanvasElement) {
       CurrentState().filterChainObserver =
         new CanvasFilterChainObserver(CurrentState().filterChain,
                                       mCanvasElement, this);
       UpdateFilter();
     }
   }
-  if (mCanvasElement && !mCanvasElement->IsWriteOnly()) {
-    CurrentState().updateFilterOnWriteOnly = true;
-  }
 }
 
 class CanvasUserSpaceMetrics : public UserSpaceMetricsWithSize
 {
 public:
   CanvasUserSpaceMetrics(const gfx::IntSize& aSize, const nsFont& aFont,
                          nsIAtom* aFontLanguage, bool aExplicitLanguage,
                          nsPresContext* aPresContext)
@@ -2862,16 +2848,18 @@ CanvasRenderingContext2D::UpdateFilter()
       CurrentState().filterChain,
       CanvasUserSpaceMetrics(GetSize(),
                              CurrentState().fontFont,
                              CurrentState().fontLanguage,
                              CurrentState().fontExplicitLanguage,
                              presShell->GetPresContext()),
       gfxRect(0, 0, mWidth, mHeight),
       CurrentState().filterAdditionalImages);
+  CurrentState().filterSourceGraphicTainted =
+    (mCanvasElement && mCanvasElement->IsWriteOnly());
 }
 
 //
 // rects
 //
 
 static bool
 ValidateRect(double& aX, double& aY, double& aWidth, double& aHeight, bool aIsZeroSizeValid)
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -870,18 +870,31 @@ protected:
   }
 
   /**
     * Returns true if the result of a drawing operation should be
     * drawn with a filter.
     */
   bool NeedToApplyFilter()
   {
+    return EnsureUpdatedFilter().mPrimitives.Length() > 0;
+  }
+
+  /**
+   * Calls UpdateFilter if the canvas's WriteOnly state has changed between the
+   * last call to UpdateFilter and now.
+   */
+  const gfx::FilterDescription& EnsureUpdatedFilter() {
     const ContextState& state = CurrentState();
-    return state.filter.mPrimitives.Length() > 0;
+    bool isWriteOnly = mCanvasElement && mCanvasElement->IsWriteOnly();
+    if (state.filterSourceGraphicTainted != isWriteOnly) {
+      UpdateFilter();
+    }
+    MOZ_ASSERT(state.filterSourceGraphicTainted == isWriteOnly);
+    return state.filter;
   }
 
   bool NeedToCalculateBounds()
   {
     return NeedToDrawShadow() || NeedToApplyFilter();
   }
 
   mozilla::gfx::CompositionOp UsedOperation()
@@ -963,17 +976,17 @@ protected:
                      globalAlpha(1.0f),
                      shadowBlur(0.0),
                      dashOffset(0.0f),
                      op(mozilla::gfx::CompositionOp::OP_OVER),
                      fillRule(mozilla::gfx::FillRule::FILL_WINDING),
                      lineCap(mozilla::gfx::CapStyle::BUTT),
                      lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
                      filterString(u"none"),
-                     updateFilterOnWriteOnly(false),
+                     filterSourceGraphicTainted(false),
                      imageSmoothingEnabled(true),
                      fontExplicitLanguage(false)
     { }
 
     ContextState(const ContextState& aOther)
         : fontGroup(aOther.fontGroup),
           fontLanguage(aOther.fontLanguage),
           fontFont(aOther.fontFont),
@@ -996,17 +1009,17 @@ protected:
           fillRule(aOther.fillRule),
           lineCap(aOther.lineCap),
           lineJoin(aOther.lineJoin),
           filterString(aOther.filterString),
           filterChain(aOther.filterChain),
           filterChainObserver(aOther.filterChainObserver),
           filter(aOther.filter),
           filterAdditionalImages(aOther.filterAdditionalImages),
-          updateFilterOnWriteOnly(aOther.updateFilterOnWriteOnly),
+          filterSourceGraphicTainted(aOther.filterSourceGraphicTainted),
           imageSmoothingEnabled(aOther.imageSmoothingEnabled),
           fontExplicitLanguage(aOther.fontExplicitLanguage)
     { }
 
     void SetColorStyle(Style aWhichStyle, nscolor aColor)
     {
       colorStyles[aWhichStyle] = aColor;
       gradientStyles[aWhichStyle] = nullptr;
@@ -1074,17 +1087,17 @@ protected:
     mozilla::gfx::CapStyle lineCap;
     mozilla::gfx::JoinStyle lineJoin;
 
     nsString filterString;
     nsTArray<nsStyleFilter> filterChain;
     RefPtr<nsSVGFilterChainObserver> filterChainObserver;
     mozilla::gfx::FilterDescription filter;
     nsTArray<RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
-    bool updateFilterOnWriteOnly;
+    bool filterSourceGraphicTainted;
 
     bool imageSmoothingEnabled;
     bool fontExplicitLanguage;
   };
 
   AutoTArray<ContextState, 3> mStyleStack;
 
   inline ContextState& CurrentState() {