Bug 1287316 - Release assert or deal with empty arrays. r=mstange, a=lizzard
authorMilan Sreckovic <milan@mozilla.com>
Tue, 30 Aug 2016 18:38:30 -0400
changeset 347956 7521a722866717c7bc4665c3a1f5d3882f52dc05
parent 347955 2031351aaad91af6de7d332f05af8c135d243054
child 347957 fa475195cce705f74806ff304e31e12850715d4a
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, lizzard
bugs1287316
milestone50.0a2
Bug 1287316 - Release assert or deal with empty arrays. r=mstange, a=lizzard
dom/canvas/CanvasRenderingContext2D.cpp
gfx/src/FilterSupport.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -346,19 +346,26 @@ public:
     nsIntRegion fillPaintNeededRegion;
     nsIntRegion strokePaintNeededRegion;
 
     if (aCtx->CurrentState().updateFilterOnWriteOnly) {
       aCtx->UpdateFilter();
       aCtx->CurrentState().updateFilterOnWriteOnly = false;
     }
 
-    FilterSupport::ComputeSourceNeededRegions(
-      aCtx->CurrentState().filter, mPostFilterBounds,
-      sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion);
+    // 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);
+    }
 
     mSourceGraphicRect = sourceGraphicNeededRegion.GetBounds();
     mFillPaintRect = fillPaintNeededRegion.GetBounds();
     mStrokePaintRect = strokePaintNeededRegion.GetBounds();
 
     mSourceGraphicRect = mSourceGraphicRect.Intersect(aPreFilterBounds);
 
     if (mSourceGraphicRect.IsEmpty()) {
@@ -423,28 +430,29 @@ public:
     RefPtr<SourceSurface> fillPaint =
       DoSourcePaint(mFillPaintRect, CanvasRenderingContext2D::Style::FILL);
     RefPtr<SourceSurface> strokePaint =
       DoSourcePaint(mStrokePaintRect, CanvasRenderingContext2D::Style::STROKE);
 
     AutoRestoreTransform autoRestoreTransform(mFinalTarget);
     mFinalTarget->SetTransform(Matrix());
 
+    MOZ_RELEASE_ASSERT(!mCtx->CurrentState().filter.mPrimitives.IsEmpty());
     gfx::FilterSupport::RenderFilterDescription(
       mFinalTarget, mCtx->CurrentState().filter,
       gfx::Rect(mPostFilterBounds),
       snapshot, mSourceGraphicRect,
       fillPaint, mFillPaintRect,
       strokePaint, mStrokePaintRect,
       mCtx->CurrentState().filterAdditionalImages,
       mPostFilterBounds.TopLeft() - mOffset,
       DrawOptions(1.0f, mCompositionOp));
 
     const gfx::FilterDescription& filter = mCtx->CurrentState().filter;
-    MOZ_ASSERT(!filter.mPrimitives.IsEmpty());
+    MOZ_RELEASE_ASSERT(!filter.mPrimitives.IsEmpty());
     if (filter.mPrimitives.LastElement().IsTainted() && mCtx->mCanvasElement) {
       mCtx->mCanvasElement->SetWriteOnly();
     }
   }
 
   DrawTarget* DT()
   {
     return mTarget;
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -1233,16 +1233,17 @@ FilterNodeGraphFromDescription(DrawTarge
                                const IntRect& aSourceGraphicRect,
                                SourceSurface* aFillPaint,
                                const IntRect& aFillPaintRect,
                                SourceSurface* aStrokePaint,
                                const IntRect& aStrokePaintRect,
                                nsTArray<RefPtr<SourceSurface>>& aAdditionalImages)
 {
   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
+  MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
 
   RefPtr<FilterCachedColorModels> sourceFilters[4];
   nsTArray<RefPtr<FilterCachedColorModels> > primitiveFilters;
 
   for (size_t i = 0; i < primitives.Length(); ++i) {
     const FilterPrimitiveDescription& descr = primitives[i];
 
     nsTArray<RefPtr<FilterNode> > inputFilterNodes;
@@ -1323,16 +1324,17 @@ FilterNodeGraphFromDescription(DrawTarge
     ColorModel outputColorModel(descr.OutputColorSpace(),
       OutputAlphaModelForPrimitive(descr, inputAlphaModels));
     RefPtr<FilterCachedColorModels> primitiveFilter =
       new FilterCachedColorModels(aDT, primitiveFilterNode, outputColorModel);
 
     primitiveFilters.AppendElement(primitiveFilter);
   }
 
+  MOZ_RELEASE_ASSERT(!primitiveFilters.IsEmpty());
   return primitiveFilters.LastElement()->ForColorModel(ColorModel::PremulSRGB());
 }
 
 // FilterSupport
 
 void
 FilterSupport::RenderFilterDescription(DrawTarget* aDT,
                                        const FilterDescription& aFilter,
@@ -1472,16 +1474,18 @@ ResultChangeRegionForPrimitive(const Fil
 
 /* static */ nsIntRegion
 FilterSupport::ComputeResultChangeRegion(const FilterDescription& aFilter,
                                          const nsIntRegion& aSourceGraphicChange,
                                          const nsIntRegion& aFillPaintChange,
                                          const nsIntRegion& aStrokePaintChange)
 {
   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
+  MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
+
   nsTArray<nsIntRegion> resultChangeRegions;
 
   for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
     const FilterPrimitiveDescription& descr = primitives[i];
 
     nsTArray<nsIntRegion> inputChangeRegions;
     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
       int32_t inputIndex = descr.InputPrimitiveIndex(j);
@@ -1493,16 +1497,17 @@ FilterSupport::ComputeResultChangeRegion
       inputChangeRegions.AppendElement(inputChangeRegion);
     }
     nsIntRegion changeRegion =
       ResultChangeRegionForPrimitive(descr, inputChangeRegions);
     changeRegion.And(changeRegion, descr.PrimitiveSubregion());
     resultChangeRegions.AppendElement(changeRegion);
   }
 
+  MOZ_RELEASE_ASSERT(!resultChangeRegions.IsEmpty());
   return resultChangeRegions[resultChangeRegions.Length() - 1];
 }
 
 static float
 ResultOfZeroUnderTransferFunction(const AttributeMap& aFunctionAttributes)
 {
   switch (aFunctionAttributes.GetUint(eComponentTransferFunctionType)) {
     case SVG_FECOMPONENTTRANSFER_TYPE_TABLE:
@@ -1633,16 +1638,17 @@ FilterSupport::PostFilterExtentsForPrimi
   }
 }
 
 /* static */ nsIntRegion
 FilterSupport::ComputePostFilterExtents(const FilterDescription& aFilter,
                                         const nsIntRegion& aSourceGraphicExtents)
 {
   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
+  MOZ_RELEASE_ASSERT(!primitives.IsEmpty());
   nsTArray<nsIntRegion> postFilterExtents;
 
   for (int32_t i = 0; i < int32_t(primitives.Length()); ++i) {
     const FilterPrimitiveDescription& descr = primitives[i];
     nsIntRegion filterSpace = descr.FilterSpaceBounds();
 
     nsTArray<nsIntRegion> inputExtents;
     for (size_t j = 0; j < descr.NumberOfInputs(); j++) {
@@ -1653,16 +1659,17 @@ FilterSupport::ComputePostFilterExtents(
                         aSourceGraphicExtents, filterSpace, filterSpace);
       inputExtents.AppendElement(inputExtent);
     }
     nsIntRegion extent = PostFilterExtentsForPrimitive(descr, inputExtents);
     extent.And(extent, descr.PrimitiveSubregion());
     postFilterExtents.AppendElement(extent);
   }
 
+  MOZ_RELEASE_ASSERT(!postFilterExtents.IsEmpty());
   return postFilterExtents[postFilterExtents.Length() - 1];
 }
 
 static nsIntRegion
 SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
                                const nsIntRegion& aResultNeededRegion,
                                int32_t aInputIndex)
 {
@@ -1763,16 +1770,21 @@ SourceNeededRegionForPrimitive(const Fil
 /* static */ void
 FilterSupport::ComputeSourceNeededRegions(const FilterDescription& aFilter,
                                           const nsIntRegion& aResultNeededRegion,
                                           nsIntRegion& aSourceGraphicNeededRegion,
                                           nsIntRegion& aFillPaintNeededRegion,
                                           nsIntRegion& aStrokePaintNeededRegion)
 {
   const nsTArray<FilterPrimitiveDescription>& primitives = aFilter.mPrimitives;
+  MOZ_ASSERT(!primitives.IsEmpty());
+  if (primitives.IsEmpty()) {
+    return;
+  }
+
   nsTArray<nsIntRegion> primitiveNeededRegions;
   primitiveNeededRegions.AppendElements(primitives.Length());
 
   primitiveNeededRegions[primitives.Length() - 1] = aResultNeededRegion;
 
   for (int32_t i = primitives.Length() - 1; i >= 0; --i) {
     const FilterPrimitiveDescription& descr = primitives[i];
     nsIntRegion neededRegion = primitiveNeededRegions[i];
@@ -1786,21 +1798,19 @@ FilterSupport::ComputeSourceNeededRegion
                          aSourceGraphicNeededRegion,
                          aFillPaintNeededRegion, aStrokePaintNeededRegion));
       inputNeededRegion->Or(*inputNeededRegion,
         SourceNeededRegionForPrimitive(descr, neededRegion, j));
     }
   }
 
   // Clip original SourceGraphic to first filter region.
-  if (primitives.Length() > 0) {
-    const FilterPrimitiveDescription& firstDescr = primitives[0];
-    aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
-                                   firstDescr.FilterSpaceBounds());
-  }
+  const FilterPrimitiveDescription& firstDescr = primitives[0];
+  aSourceGraphicNeededRegion.And(aSourceGraphicNeededRegion,
+                                 firstDescr.FilterSpaceBounds());
 }
 
 // FilterPrimitiveDescription
 
 FilterPrimitiveDescription::FilterPrimitiveDescription()
  : mType(PrimitiveType::Empty)
  , mOutputColorSpace(ColorSpace::SRGB)
  , mIsTainted(false)