Bug 1345853 - Part 1. Pass DrawResult from nsSVGPatternFrame::PaintPattern back to nsDisplaySVGGeometry::Paint. r=mstange,tnikkel
authorcku <cku@mozilla.com>
Thu, 16 Mar 2017 12:17:19 +0800
changeset 348185 836d16519edf994ecf98ef5791f23bc088d99fe4
parent 348184 44e9eace508aa7153318d31924f4d99695d8b3a2
child 348186 a46f3da8aba674893eccec275908b31453d7d6b0
push id88164
push usercbook@mozilla.com
push dateFri, 17 Mar 2017 13:55:35 +0000
treeherdermozilla-inbound@e46c08babe02 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, tnikkel
bugs1345853, 1258510, 1346124
milestone55.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 1345853 - Part 1. Pass DrawResult from nsSVGPatternFrame::PaintPattern back to nsDisplaySVGGeometry::Paint. r=mstange,tnikkel I did many change in many files in this patch. But the goal is pretty simple: To pass the return value of nsSVGPatternFrame::PaintPattern back to the caller (nsDisplaySVGGeometry). My suggestion is to review this patch right from nsSVGPatternFrame.cpp. I made two mistakes in bug 1258510 1. We should not return directly at [1]. RemoveStateBits at l418 will be skip. 2. nsSVGPatternFrame::PaintPattern should return both SourceSurface and draw result, so that we can update UpdateDrawResult in display item. All the other changes are to 1. make sure the return value of nsSVGPatternFrame::PaintPattern goes back to nsDisplaySVGGeometry::Paint correctly. 2. Since the return value of nsSVGPatternFrame::PaintPattern change, we need modify all existed callers. I also filed bug 1346124 for handle the returning value of PaintMarkers. [1] https://hg.mozilla.org/mozilla-central/file/c0700bedb4f7/layout/svg/nsSVGPatternFrame.cpp#l415 MozReview-Commit-ID: Iq9RPQ6Omz0
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxSVGGlyphs.h
layout/svg/SVGContextPaint.cpp
layout/svg/SVGContextPaint.h
layout/svg/SVGGeometryFrame.cpp
layout/svg/SVGGeometryFrame.h
layout/svg/SVGTextFrame.cpp
layout/svg/nsFilterInstance.cpp
layout/svg/nsSVGGradientFrame.cpp
layout/svg/nsSVGGradientFrame.h
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGMaskFrame.cpp
layout/svg/nsSVGPaintServerFrame.h
layout/svg/nsSVGPatternFrame.cpp
layout/svg/nsSVGPatternFrame.h
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1618,20 +1618,26 @@ private:
         buf.mNumGlyphs = mNumGlyphs;
 
         gfxContext::AzureState state = mRunParams.context->CurrentState();
         if (mRunParams.drawMode & DrawMode::GLYPH_FILL) {
             if (state.pattern || mFontParams.contextPaint) {
                 Pattern *pat;
 
                 RefPtr<gfxPattern> fillPattern;
-                if (!mFontParams.contextPaint ||
-                    !(fillPattern = mFontParams.contextPaint->GetFillPattern(
-                                        mRunParams.context->GetDrawTarget(),
-                                        mRunParams.context->CurrentMatrix()))) {
+                if (mFontParams.contextPaint) {
+                  mozilla::image::DrawResult result = mozilla::image::DrawResult::SUCCESS;
+                  Tie(result, fillPattern) =
+                    mFontParams.contextPaint->GetFillPattern(
+                                          mRunParams.context->GetDrawTarget(),
+                                          mRunParams.context->CurrentMatrix());
+                  // XXX cku Flush should return result to the caller?
+                  Unused << result;
+                }
+                if (!fillPattern) {
                     if (state.pattern) {
                         pat = state.pattern->GetPattern(mRunParams.dt,
                                       state.patternTransformChanged ?
                                           &state.patternTransform : nullptr);
                     } else {
                         pat = nullptr;
                     }
                 } else {
--- a/gfx/thebes/gfxSVGGlyphs.h
+++ b/gfx/thebes/gfxSVGGlyphs.h
@@ -197,34 +197,36 @@ public:
                           const gfxMatrix& aCTM) :
         mFillPattern(aFillPattern ? aFillPattern : new gfxPattern(sZero)),
         mStrokePattern(aStrokePattern ? aStrokePattern : new gfxPattern(sZero))
     {
         mFillMatrix = SetupDeviceToPatternMatrix(aFillPattern, aCTM);
         mStrokeMatrix = SetupDeviceToPatternMatrix(aStrokePattern, aCTM);
     }
 
-    already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget,
-                                                float aOpacity,
-                                                const gfxMatrix& aCTM) {
+    mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+    GetFillPattern(const DrawTarget* aDrawTarget,
+                   float aOpacity,
+                   const gfxMatrix& aCTM) {
         if (mFillPattern) {
             mFillPattern->SetMatrix(aCTM * mFillMatrix);
         }
         RefPtr<gfxPattern> fillPattern = mFillPattern;
-        return fillPattern.forget();
+        return MakePair(DrawResult::SUCCESS, Move(fillPattern));
     }
 
-    already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget,
-                                                  float aOpacity,
-                                                  const gfxMatrix& aCTM) {
+    mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+    GetStrokePattern(const DrawTarget* aDrawTarget,
+                     float aOpacity,
+                     const gfxMatrix& aCTM) {
         if (mStrokePattern) {
             mStrokePattern->SetMatrix(aCTM * mStrokeMatrix);
         }
         RefPtr<gfxPattern> strokePattern = mStrokePattern;
-        return strokePattern.forget();
+        return MakePair(DrawResult::SUCCESS, Move(strokePattern));
     }
 
     float GetFillOpacity() const {
         return mFillPattern ? 1.0f : 0.0f;
     }
 
     float GetStrokeOpacity() const {
         return mStrokePattern ? 1.0f : 0.0f;
--- a/layout/svg/SVGContextPaint.cpp
+++ b/layout/svg/SVGContextPaint.cpp
@@ -8,123 +8,134 @@
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "nsIDocument.h"
 #include "nsSVGPaintServerFrame.h"
 #include "nsSVGEffects.h"
 #include "nsSVGPaintServerFrame.h"
 
 using namespace mozilla::gfx;
+using namespace mozilla::image;
 
 namespace mozilla {
 
 /**
  * Stores in |aTargetPaint| information on how to reconstruct the current
  * fill or stroke pattern. Will also set the paint opacity to transparent if
  * the paint is set to "none".
  * @param aOuterContextPaint pattern information from the outer text context
  * @param aTargetPaint where to store the current pattern information
  * @param aFillOrStroke member pointer to the paint we are setting up
  * @param aProperty the frame property descriptor of the fill or stroke paint
  *   server frame
  */
-static void
+static DrawResult
 SetupInheritablePaint(const DrawTarget* aDrawTarget,
                       const gfxMatrix& aContextMatrix,
                       nsIFrame* aFrame,
                       float& aOpacity,
                       SVGContextPaint* aOuterContextPaint,
                       SVGContextPaintImpl::Paint& aTargetPaint,
                       nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                       nsSVGEffects::PaintingPropertyDescriptor aProperty)
 {
   const nsStyleSVG *style = aFrame->StyleSVG();
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, aFillOrStroke, aProperty);
 
+  DrawResult result = DrawResult::SUCCESS;
   if (ps) {
-    RefPtr<gfxPattern> pattern =
+    RefPtr<gfxPattern> pattern;
+    Tie(result, pattern) =
       ps->GetPaintServerPattern(aFrame, aDrawTarget, aContextMatrix,
                                 aFillOrStroke, aOpacity);
+
     if (pattern) {
       aTargetPaint.SetPaintServer(aFrame, aContextMatrix, ps);
-      return;
+      return result;
     }
   }
+
   if (aOuterContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch ((style->*aFillOrStroke).Type()) {
     case eStyleSVGPaintType_ContextFill:
-      pattern = aOuterContextPaint->GetFillPattern(aDrawTarget, aOpacity,
-                                                   aContextMatrix);
+      Tie(result, pattern) =
+        aOuterContextPaint->GetFillPattern(aDrawTarget, aOpacity,
+                                           aContextMatrix);
       break;
     case eStyleSVGPaintType_ContextStroke:
-      pattern = aOuterContextPaint->GetStrokePattern(aDrawTarget, aOpacity,
-                                                     aContextMatrix);
+       Tie(result, pattern) =
+         aOuterContextPaint->GetStrokePattern(aDrawTarget, aOpacity,
+                                              aContextMatrix);
       break;
     default:
       ;
     }
     if (pattern) {
       aTargetPaint.SetContextPaint(aOuterContextPaint, (style->*aFillOrStroke).Type());
-      return;
+      return result;
     }
   }
+
   nscolor color =
     nsSVGUtils::GetFallbackOrPaintColor(aFrame->StyleContext(), aFillOrStroke);
   aTargetPaint.SetColor(color);
+
+  return result;
 }
 
-DrawMode
+mozilla::Pair<DrawResult, DrawMode>
 SVGContextPaintImpl::Init(const DrawTarget* aDrawTarget,
                           const gfxMatrix& aContextMatrix,
                           nsIFrame* aFrame,
                           SVGContextPaint* aOuterContextPaint)
 {
   DrawMode toDraw = DrawMode(0);
 
   const nsStyleSVG *style = aFrame->StyleSVG();
+  DrawResult result = DrawResult::SUCCESS;
 
   // fill:
   if (style->mFill.Type() == eStyleSVGPaintType_None) {
     SetFillOpacity(0.0f);
   } else {
     float opacity = nsSVGUtils::GetOpacity(style->FillOpacitySource(),
                                            style->mFillOpacity,
                                            aOuterContextPaint);
 
-    SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame,
-                          opacity, aOuterContextPaint,
-                          mFillPaint, &nsStyleSVG::mFill,
-                          nsSVGEffects::FillProperty());
+    result &= SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame,
+                                    opacity, aOuterContextPaint,
+                                    mFillPaint, &nsStyleSVG::mFill,
+                                    nsSVGEffects::FillProperty());
 
     SetFillOpacity(opacity);
 
     toDraw |= DrawMode::GLYPH_FILL;
   }
 
   // stroke:
   if (style->mStroke.Type() == eStyleSVGPaintType_None) {
     SetStrokeOpacity(0.0f);
   } else {
     float opacity = nsSVGUtils::GetOpacity(style->StrokeOpacitySource(),
                                            style->mStrokeOpacity,
                                            aOuterContextPaint);
 
-    SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame,
-                          opacity, aOuterContextPaint,
-                          mStrokePaint, &nsStyleSVG::mStroke,
-                          nsSVGEffects::StrokeProperty());
+    result &= SetupInheritablePaint(aDrawTarget, aContextMatrix, aFrame,
+                                    opacity, aOuterContextPaint,
+                                    mStrokePaint, &nsStyleSVG::mStroke,
+                                    nsSVGEffects::StrokeProperty());
 
     SetStrokeOpacity(opacity);
 
     toDraw |= DrawMode::GLYPH_STROKE;
   }
 
-  return toDraw;
+  return MakePair(result, toDraw);
 }
 
 void
 SVGContextPaint::InitStrokeGeometry(gfxContext* aContext,
                                     float devUnitsPerSVGUnit)
 {
   mStrokeWidth = aContext->CurrentLineWidth() / devUnitsPerSVGUnit;
   aContext->CurrentDash(mDashes, &mDashOffset);
@@ -153,96 +164,100 @@ SVGContextPaint::GetContextPaint(nsICont
   // bit of a headache so for now we punt on that, don't reapply the constness
   // to the SVGContextPaint here, and trust that no one will add code that
   // actually modifies the object.
 
   return static_cast<SVGContextPaint*>(
            ownerDoc->GetProperty(nsGkAtoms::svgContextPaint));
 }
 
-already_AddRefed<gfxPattern>
+mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGContextPaintImpl::GetFillPattern(const DrawTarget* aDrawTarget,
                                     float aOpacity,
                                     const gfxMatrix& aCTM)
 {
   return mFillPaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mFill, aCTM);
 }
 
-already_AddRefed<gfxPattern>
+mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGContextPaintImpl::GetStrokePattern(const DrawTarget* aDrawTarget,
                                       float aOpacity,
                                       const gfxMatrix& aCTM)
 {
   return mStrokePaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mStroke, aCTM);
 }
 
-already_AddRefed<gfxPattern>
+mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGContextPaintImpl::Paint::GetPattern(const DrawTarget* aDrawTarget,
                                        float aOpacity,
                                        nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                        const gfxMatrix& aCTM)
 {
   RefPtr<gfxPattern> pattern;
   if (mPatternCache.Get(aOpacity, getter_AddRefs(pattern))) {
     // Set the pattern matrix just in case it was messed with by a previous
     // caller. We should get the same matrix each time a pattern is constructed
     // so this should be fine.
     pattern->SetMatrix(aCTM * mPatternMatrix);
-    return pattern.forget();
+    return MakePair(DrawResult::SUCCESS, Move(pattern));
   }
 
+  DrawResult result = DrawResult::SUCCESS;
   switch (mPaintType) {
   case eStyleSVGPaintType_None:
     pattern = new gfxPattern(Color());
     mPatternMatrix = gfxMatrix();
     break;
   case eStyleSVGPaintType_Color: {
     Color color = Color::FromABGR(mPaintDefinition.mColor);
     color.a *= aOpacity;
     pattern = new gfxPattern(color);
     mPatternMatrix = gfxMatrix();
     break;
   }
   case eStyleSVGPaintType_Server:
-    pattern = mPaintDefinition.mPaintServerFrame->GetPaintServerPattern(mFrame,
-                                                                        aDrawTarget,
-                                                                        mContextMatrix,
-                                                                        aFillOrStroke,
-                                                                        aOpacity);
+    Tie(result, pattern) =
+      mPaintDefinition.mPaintServerFrame->GetPaintServerPattern(mFrame,
+                                                                aDrawTarget,
+                                                                mContextMatrix,
+                                                                aFillOrStroke,
+                                                                aOpacity);
     {
       // m maps original-user-space to pattern space
       gfxMatrix m = pattern->GetMatrix();
       gfxMatrix deviceToOriginalUserSpace = mContextMatrix;
       if (!deviceToOriginalUserSpace.Invert()) {
-        return nullptr;
+        return MakePair(DrawResult::SUCCESS, RefPtr<gfxPattern>());
       }
       // mPatternMatrix maps device space to pattern space via original user space
       mPatternMatrix = deviceToOriginalUserSpace * m;
     }
     pattern->SetMatrix(aCTM * mPatternMatrix);
     break;
   case eStyleSVGPaintType_ContextFill:
-    pattern = mPaintDefinition.mContextPaint->GetFillPattern(aDrawTarget,
+    Tie(result, pattern) =
+      mPaintDefinition.mContextPaint->GetFillPattern(aDrawTarget,
                                                              aOpacity, aCTM);
     // Don't cache this. mContextPaint will have cached it anyway. If we
     // cache it, we'll have to compute mPatternMatrix, which is annoying.
-    return pattern.forget();
+    return MakePair(result, Move(pattern));
   case eStyleSVGPaintType_ContextStroke:
-    pattern = mPaintDefinition.mContextPaint->GetStrokePattern(aDrawTarget,
+    Tie(result, pattern) =
+      mPaintDefinition.mContextPaint->GetStrokePattern(aDrawTarget,
                                                                aOpacity, aCTM);
     // Don't cache this. mContextPaint will have cached it anyway. If we
     // cache it, we'll have to compute mPatternMatrix, which is annoying.
-    return pattern.forget();
+    return MakePair(result, Move(pattern));
   default:
     MOZ_ASSERT(false, "invalid paint type");
-    return nullptr;
+    return MakePair(DrawResult::SUCCESS, RefPtr<gfxPattern>());
   }
 
   mPatternCache.Put(aOpacity, pattern);
-  return pattern.forget();
+  return MakePair(result, Move(pattern));
 }
 
 AutoSetRestoreSVGContextPaint::AutoSetRestoreSVGContextPaint(
                                  const SVGContextPaint* aContextPaint,
                                  nsIDocument* aSVGDocument)
   : mSVGDocument(aSVGDocument)
   , mOuterContextPaint(aSVGDocument->GetProperty(nsGkAtoms::svgContextPaint))
 {
--- a/layout/svg/SVGContextPaint.h
+++ b/layout/svg/SVGContextPaint.h
@@ -11,16 +11,17 @@
 #include "gfxPattern.h"
 #include "gfxTypes.h"
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/gfx/2D.h"
 #include "nsColor.h"
 #include "nsStyleStruct.h"
 #include "nsTArray.h"
+#include "DrawResult.h"
 
 class gfxContext;
 class nsIDocument;
 class nsSVGPaintServerFrame;
 
 namespace mozilla {
 
 /**
@@ -47,36 +48,40 @@ namespace mozilla {
 class SVGContextPaint : public RefCounted<SVGContextPaint>
 {
 protected:
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
   SVGContextPaint() {}
 
 public:
+  typedef image::DrawResult DrawResult;
+
   MOZ_DECLARE_REFCOUNTED_TYPENAME(SVGContextPaint)
 
   virtual ~SVGContextPaint() {}
 
-  virtual already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget,
-                                                      float aOpacity,
-                                                      const gfxMatrix& aCTM) = 0;
-  virtual already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget,
-                                                        float aOpacity,
-                                                        const gfxMatrix& aCTM) = 0;
+  virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetFillPattern(const DrawTarget* aDrawTarget,
+                 float aOpacity,
+                 const gfxMatrix& aCTM) = 0;
+  virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetStrokePattern(const DrawTarget* aDrawTarget,
+                   float aOpacity,
+                   const gfxMatrix& aCTM) = 0;
   virtual float GetFillOpacity() const = 0;
   virtual float GetStrokeOpacity() const = 0;
 
-  already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget,
-                                              const gfxMatrix& aCTM) {
+  mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetFillPattern(const DrawTarget* aDrawTarget, const gfxMatrix& aCTM) {
     return GetFillPattern(aDrawTarget, GetFillOpacity(), aCTM);
   }
 
-  already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget,
-                                                const gfxMatrix& aCTM) {
+  mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetStrokePattern(const DrawTarget* aDrawTarget, const gfxMatrix& aCTM) {
     return GetStrokePattern(aDrawTarget, GetStrokeOpacity(), aCTM);
   }
 
   static SVGContextPaint* GetContextPaint(nsIContent* aContent);
 
   // XXX This gets the geometry params from the gfxContext.  We should get that
   // information from the actual paint context!
   void InitStrokeGeometry(gfxContext *aContext,
@@ -132,28 +137,34 @@ private:
 /**
  * This class should be flattened into SVGContextPaint once we get rid of the
  * other sub-class (SimpleTextContextPaint).
  */
 struct SVGContextPaintImpl : public SVGContextPaint
 {
 protected:
   typedef mozilla::gfx::DrawTarget DrawTarget;
+
 public:
-  DrawMode Init(const DrawTarget* aDrawTarget,
-                const gfxMatrix& aContextMatrix,
-                nsIFrame* aFrame,
-                SVGContextPaint* aOuterContextPaint);
+  typedef mozilla::image::DrawResult DrawResult;
 
-  already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget,
-                                              float aOpacity,
-                                              const gfxMatrix& aCTM) override;
-  already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget,
-                                                float aOpacity,
-                                                const gfxMatrix& aCTM) override;
+  mozilla::Pair<DrawResult, DrawMode>
+  Init(const DrawTarget* aDrawTarget,
+       const gfxMatrix& aContextMatrix,
+       nsIFrame* aFrame,
+       SVGContextPaint* aOuterContextPaint);
+
+  mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetFillPattern(const DrawTarget* aDrawTarget,
+                 float aOpacity,
+                 const gfxMatrix& aCTM) override;
+  mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetStrokePattern(const DrawTarget* aDrawTarget,
+                   float aOpacity,
+                   const gfxMatrix& aCTM) override;
 
   void SetFillOpacity(float aOpacity) { mFillOpacity = aOpacity; }
   float GetFillOpacity() const override { return mFillOpacity; }
 
   void SetStrokeOpacity(float aOpacity) { mStrokeOpacity = aOpacity; }
   float GetStrokeOpacity() const override { return mStrokeOpacity; }
 
   struct Paint {
@@ -193,20 +204,21 @@ public:
     // CTM defining the user space for the pattern we will use.
     gfxMatrix mContextMatrix;
     nsStyleSVGPaintType mPaintType;
 
     // Device-space-to-pattern-space
     gfxMatrix mPatternMatrix;
     nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
 
-    already_AddRefed<gfxPattern> GetPattern(const DrawTarget* aDrawTarget,
-                                            float aOpacity,
-                                            nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
-                                            const gfxMatrix& aCTM);
+    mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+    GetPattern(const DrawTarget* aDrawTarget,
+               float aOpacity,
+               nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
+               const gfxMatrix& aCTM);
   };
 
   Paint mFillPaint;
   Paint mStrokePaint;
 
   float mFillOpacity;
   float mStrokeOpacity;
 };
@@ -214,32 +226,39 @@ public:
 /**
  * This class is used to pass context paint to an SVG image when an element
  * references that image (e.g. via HTML <img> or SVG <image>, or by referencing
  * it from a CSS property such as 'background-image').  In this case we only
  * support context colors and not paint servers.
  */
 class SVGEmbeddingContextPaint : public SVGContextPaint
 {
+protected:
+  typedef mozilla::image::DrawResult DrawResult;
+
 public:
   SVGEmbeddingContextPaint() {}
 
   void SetFill(nscolor aFill);
   void SetStroke(nscolor aStroke);
 
-  already_AddRefed<gfxPattern> GetFillPattern(const DrawTarget* aDrawTarget,
-                                              float aOpacity,
-                                              const gfxMatrix& aCTM) override {
-    return do_AddRef(mFill);
+  mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetFillPattern(const DrawTarget* aDrawTarget,
+                 float aOpacity,
+                 const gfxMatrix& aCTM) override {
+    RefPtr<gfxPattern> fill = mFill;
+    return MakePair(DrawResult::SUCCESS, Move(fill));
   }
 
-  already_AddRefed<gfxPattern> GetStrokePattern(const DrawTarget* aDrawTarget,
-                                                float aOpacity,
-                                                const gfxMatrix& aCTM) override {
-    return do_AddRef(mStroke);
+  mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
+  GetStrokePattern(const DrawTarget* aDrawTarget,
+                   float aOpacity,
+                   const gfxMatrix& aCTM) override {
+    RefPtr<gfxPattern> stroke = mStroke;
+    return MakePair(DrawResult::SUCCESS, Move(stroke));
   }
 
   float GetFillOpacity() const override {
     // Always 1.0f since we don't currently allow 'context-fill-opacity'
     return 1.0f;
   };
 
   float GetStrokeOpacity() const override {
--- a/layout/svg/SVGGeometryFrame.cpp
+++ b/layout/svg/SVGGeometryFrame.cpp
@@ -288,39 +288,41 @@ SVGGeometryFrame::PaintSVG(gfxContext& a
   // Matrix to the geometry's user space:
   gfxMatrix newMatrix =
     aContext.CurrentMatrix().PreMultiply(aTransform).NudgeToIntegers();
   if (newMatrix.IsSingular()) {
     return DrawResult::BAD_ARGS;
   }
 
   uint32_t paintOrder = StyleSVG()->mPaintOrder;
+  DrawResult result = DrawResult::SUCCESS;
+
   if (paintOrder == NS_STYLE_PAINT_ORDER_NORMAL) {
-    Render(&aContext, eRenderFill | eRenderStroke, newMatrix);
+    result = Render(&aContext, eRenderFill | eRenderStroke, newMatrix);
     PaintMarkers(aContext, aTransform);
   } else {
     while (paintOrder) {
       uint32_t component =
         paintOrder & ((1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1);
       switch (component) {
         case NS_STYLE_PAINT_ORDER_FILL:
-          Render(&aContext, eRenderFill, newMatrix);
+          result &= Render(&aContext, eRenderFill, newMatrix);
           break;
         case NS_STYLE_PAINT_ORDER_STROKE:
-          Render(&aContext, eRenderStroke, newMatrix);
+          result &= Render(&aContext, eRenderStroke, newMatrix);
           break;
         case NS_STYLE_PAINT_ORDER_MARKERS:
           PaintMarkers(aContext, aTransform);
           break;
       }
       paintOrder >>= NS_STYLE_PAINT_ORDER_BITWIDTH;
     }
   }
 
-  return DrawResult::SUCCESS;
+  return result;
 }
 
 nsIFrame*
 SVGGeometryFrame::GetFrameForPoint(const gfxPoint& aPoint)
 {
   FillRule fillRule;
   uint16_t hitTestFlags;
   if (GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) {
@@ -759,17 +761,17 @@ nsSVGMarkerFrame *
 SVGGeometryFrame::MarkerProperties::GetMarkerEndFrame()
 {
   if (!mMarkerEnd)
     return nullptr;
   return static_cast<nsSVGMarkerFrame *>
     (mMarkerEnd->GetReferencedFrame(nsGkAtoms::svgMarkerFrame, nullptr));
 }
 
-void
+DrawResult
 SVGGeometryFrame::Render(gfxContext* aContext,
                          uint32_t aRenderComponents,
                          const gfxMatrix& aNewTransform)
 {
   MOZ_ASSERT(!aNewTransform.IsSingular());
 
   DrawTarget* drawTarget = aContext->GetDrawTarget();
 
@@ -795,35 +797,38 @@ SVGGeometryFrame::Render(gfxContext* aCo
     // We don't complicate this code with GetAsSimplePath since the cost of
     // masking will dwarf Path creation overhead anyway.
     RefPtr<Path> path = element->GetOrBuildPath(*drawTarget, fillRule);
     if (path) {
       ColorPattern white(ToDeviceColor(Color(1.0f, 1.0f, 1.0f, 1.0f)));
       drawTarget->Fill(path, white,
                        DrawOptions(1.0f, CompositionOp::OP_OVER, aaMode));
     }
-    return;
+    return DrawResult::SUCCESS;
   }
 
   SVGGeometryElement::SimplePath simplePath;
   RefPtr<Path> path;
 
   element->GetAsSimplePath(&simplePath);
   if (!simplePath.IsPath()) {
     path = element->GetOrBuildPath(*drawTarget, fillRule);
     if (!path) {
-      return;
+      return DrawResult::SUCCESS;
     }
   }
 
   SVGContextPaint* contextPaint = SVGContextPaint::GetContextPaint(mContent);
+  DrawResult result = DrawResult::SUCCESS;
 
   if (aRenderComponents & eRenderFill) {
     GeneralPattern fillPattern;
-    nsSVGUtils::MakeFillPatternFor(this, aContext, &fillPattern, contextPaint);
+    result = nsSVGUtils::MakeFillPatternFor(this, aContext, &fillPattern,
+                                            contextPaint);
+
     if (fillPattern.GetPattern()) {
       DrawOptions drawOptions(1.0f, CompositionOp::OP_OVER, aaMode);
       if (simplePath.IsRect()) {
         drawTarget->FillRect(simplePath.AsRect(), fillPattern, drawOptions);
       } else if (path) {
         drawTarget->Fill(path, fillPattern, drawOptions);
       }
     }
@@ -834,53 +839,58 @@ SVGGeometryFrame::Render(gfxContext* aCo
     // Account for vector-effect:non-scaling-stroke:
     gfxMatrix userToOuterSVG;
     if (nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
       // A simple Rect can't be transformed with rotate/skew, so let's switch
       // to using a real path:
       if (!path) {
         path = element->GetOrBuildPath(*drawTarget, fillRule);
         if (!path) {
-          return;
+          return DrawResult::SUCCESS;
         }
         simplePath.Reset();
       }
       // We need to transform the path back into the appropriate ancestor
       // coordinate system, and paint it it that coordinate system, in order
       // for non-scaled stroke to paint correctly.
       gfxMatrix outerSVGToUser = userToOuterSVG;
       outerSVGToUser.Invert();
       aContext->Multiply(outerSVGToUser);
       RefPtr<PathBuilder> builder =
         path->TransformedCopyToBuilder(ToMatrix(userToOuterSVG), fillRule);
       path = builder->Finish();
     }
     GeneralPattern strokePattern;
-    nsSVGUtils::MakeStrokePatternFor(this, aContext, &strokePattern, contextPaint);
+    result &=
+      nsSVGUtils::MakeStrokePatternFor(this, aContext, &strokePattern,
+                                       contextPaint);
+
     if (strokePattern.GetPattern()) {
       SVGContentUtils::AutoStrokeOptions strokeOptions;
       SVGContentUtils::GetStrokeOptions(&strokeOptions,
                                         static_cast<nsSVGElement*>(mContent),
                                         StyleContext(), contextPaint);
       // GetStrokeOptions may set the line width to zero as an optimization
       if (strokeOptions.mLineWidth <= 0) {
-        return;
+        return DrawResult::SUCCESS;
       }
       DrawOptions drawOptions(1.0f, CompositionOp::OP_OVER, aaMode);
       if (simplePath.IsRect()) {
         drawTarget->StrokeRect(simplePath.AsRect(), strokePattern,
                                strokeOptions, drawOptions);
       } else if (simplePath.IsLine()) {
         drawTarget->StrokeLine(simplePath.Point1(), simplePath.Point2(),
                                strokePattern, strokeOptions, drawOptions);
       } else {
         drawTarget->Stroke(path, strokePattern, strokeOptions, drawOptions);
       }
     }
   }
+
+  return result;
 }
 
 void
 SVGGeometryFrame::PaintMarkers(gfxContext& aContext,
                                const gfxMatrix& aTransform)
 {
   SVGContextPaint* contextPaint = SVGContextPaint::GetContextPaint(mContent);
 
--- a/layout/svg/SVGGeometryFrame.h
+++ b/layout/svg/SVGGeometryFrame.h
@@ -116,18 +116,18 @@ protected:
    * This function returns a set of bit flags indicating which parts of the
    * element (fill, stroke, bounds) should intercept pointer events. It takes
    * into account the type of element and the value of the 'pointer-events'
    * property on the element.
    */
   virtual uint16_t GetHitTestFlags();
 private:
   enum { eRenderFill = 1, eRenderStroke = 2 };
-  void Render(gfxContext* aContext, uint32_t aRenderComponents,
-              const gfxMatrix& aTransform);
+  DrawResult Render(gfxContext* aContext, uint32_t aRenderComponents,
+                    const gfxMatrix& aTransform);
 
   /**
    * @param aMatrix The transform that must be multiplied onto aContext to
    *   establish this frame's SVG user space.
    */
   void PaintMarkers(gfxContext& aContext, const gfxMatrix& aMatrix);
 
   struct MarkerProperties {
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -2924,17 +2924,17 @@ SVGTextDrawPathCallbacks::HandleTextGeom
   }
 }
 
 void
 SVGTextDrawPathCallbacks::MakeFillPattern(GeneralPattern* aOutPattern)
 {
   if (mColor == NS_SAME_AS_FOREGROUND_COLOR ||
       mColor == NS_40PERCENT_FOREGROUND_COLOR) {
-    nsSVGUtils::MakeFillPatternFor(mFrame, gfx, aOutPattern);
+    Unused << nsSVGUtils::MakeFillPatternFor(mFrame, gfx, aOutPattern);
     return;
   }
 
   if (mColor == NS_TRANSPARENT) {
     return;
   }
 
   aOutPattern->InitColorPattern(ToDeviceColor(mColor));
@@ -2995,17 +2995,18 @@ SVGTextDrawPathCallbacks::FillGeometry()
 void
 SVGTextDrawPathCallbacks::StrokeGeometry()
 {
   // We don't paint the stroke when we are filling with a selection color.
   if (mColor == NS_SAME_AS_FOREGROUND_COLOR ||
       mColor == NS_40PERCENT_FOREGROUND_COLOR) {
     if (nsSVGUtils::HasStroke(mFrame, /*aContextPaint*/ nullptr)) {
       GeneralPattern strokePattern;
-      nsSVGUtils::MakeStrokePatternFor(mFrame, gfx, &strokePattern, /*aContextPaint*/ nullptr);
+      Unused << nsSVGUtils::MakeStrokePatternFor(mFrame, gfx, &strokePattern,
+                                                 /*aContextPaint*/ nullptr);
       if (strokePattern.GetPattern()) {
         if (!mFrame->GetParent()->GetContent()->IsSVGElement()) {
           // The cast that follows would be unsafe
           MOZ_ASSERT(false, "Our nsTextFrame's parent's content should be SVG");
           return;
         }
         nsSVGElement* svgOwner =
           static_cast<nsSVGElement*>(mFrame->GetParent()->GetContent());
@@ -3640,33 +3641,35 @@ SVGTextFrame::PaintSVG(gfxContext& aCont
 
   TextRenderedRunIterator it(this, TextRenderedRunIterator::eVisibleFrames);
   TextRenderedRun run = it.Current();
 
   SVGContextPaint* outerContextPaint =
     SVGContextPaint::GetContextPaint(mContent);
 
   nsRenderingContext rendCtx(&aContext);
-
+  DrawResult finalResult = DrawResult::SUCCESS;
   while (run.mFrame) {
     nsTextFrame* frame = run.mFrame;
 
     // Determine how much of the left and right edges of the text frame we
     // need to ignore.
     SVGCharClipDisplayItem item(run);
 
     // Set up the fill and stroke so that SVG glyphs can get painted correctly
     // when they use context-fill etc.
     aContext.SetMatrix(initialMatrix);
 
     RefPtr<SVGContextPaintImpl> contextPaint = new SVGContextPaintImpl();
-    DrawMode drawMode = contextPaint->Init(&aDrawTarget,
-                                           aContext.CurrentMatrix(),
-                                           frame, outerContextPaint);
-
+    DrawMode drawMode;
+    DrawResult result = DrawResult::SUCCESS;
+    Tie(result, drawMode) = contextPaint->Init(&aDrawTarget,
+                                               aContext.CurrentMatrix(),
+                                               frame, outerContextPaint);
+    finalResult &= result;
     if (drawMode & DrawMode::GLYPH_STROKE) {
       // This may change the gfxContext's transform (for non-scaling stroke),
       // in which case this needs to happen before we call SetMatrix() below.
       nsSVGUtils::SetupCairoStrokeGeometry(frame, &aContext, outerContextPaint);
     }
 
     // Set up the transform for painting the text frame for the substring
     // indicated by the run.
@@ -3698,17 +3701,17 @@ SVGTextFrame::PaintSVG(gfxContext& aCont
       // caret with, rather than using the color property?
       caret->PaintCaret(aDrawTarget, frame, nsPoint());
       aContext.NewPath();
     }
 
     run = it.Next();
   }
 
-  return DrawResult::SUCCESS;
+  return finalResult;
 }
 
 nsIFrame*
 SVGTextFrame::GetFrameForPoint(const gfxPoint& aPoint)
 {
   NS_ASSERTION(PrincipalChildList().FirstChild(), "must have a child frame");
 
   if (mState & NS_FRAME_IS_NONDISPLAY) {
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -413,31 +413,32 @@ nsFilterInstance::BuildSourcePaint(Sourc
 
   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
   MOZ_ASSERT(ctx); // already checked the draw target above
   gfxContextAutoSaveRestore saver(ctx);
 
   ctx->SetMatrix(mPaintTransform *
                  gfxMatrix::Translation(-neededRect.TopLeft()));
   GeneralPattern pattern;
+  DrawResult result = DrawResult::SUCCESS;
   if (aSource == &mFillPaint) {
-    nsSVGUtils::MakeFillPatternFor(mTargetFrame, ctx, &pattern);
+    result = nsSVGUtils::MakeFillPatternFor(mTargetFrame, ctx, &pattern);
   } else if (aSource == &mStrokePaint) {
-    nsSVGUtils::MakeStrokePatternFor(mTargetFrame, ctx, &pattern);
+    result = nsSVGUtils::MakeStrokePatternFor(mTargetFrame, ctx, &pattern);
   }
 
   if (pattern.GetPattern()) {
     offscreenDT->FillRect(ToRect(FilterSpaceToUserSpace(ThebesRect(neededRect))),
                           pattern);
   }
 
   aSource->mSourceSurface = offscreenDT->Snapshot();
   aSource->mSurfaceRect = neededRect;
 
-  return DrawResult::SUCCESS;
+  return result;
 }
 
 DrawResult
 nsFilterInstance::BuildSourcePaints()
 {
   if (!mFillPaint.mNeededBounds.IsEmpty()) {
     DrawResult result = BuildSourcePaint(&mFillPaint);
     if (result != DrawResult::SUCCESS) {
--- a/layout/svg/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -202,17 +202,17 @@ static void GetStopInformation(nsIFrame*
   static_cast<SVGStopElement*>(stopContent)->
     GetAnimatedNumberValues(aOffset, nullptr);
 
   *aOffset = mozilla::clamped(*aOffset, 0.0f, 1.0f);
   *aStopColor = aStopFrame->StyleSVGReset()->mStopColor;
   *aStopOpacity = aStopFrame->StyleSVGReset()->mStopOpacity;
 }
 
-already_AddRefed<gfxPattern>
+mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 nsSVGGradientFrame::GetPaintServerPattern(nsIFrame* aSource,
                                           const DrawTarget* aDrawTarget,
                                           const gfxMatrix& aContextMatrix,
                                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                           float aGraphicOpacity,
                                           const gfxRect* aOverrideBounds)
 {
   uint16_t gradientUnits = GetGradientUnits();
@@ -230,55 +230,56 @@ nsSVGGradientFrame::GetPaintServerPatter
   GetStopFrames(&stopFrames);
 
   uint32_t nStops = stopFrames.Length();
 
   // SVG specification says that no stops should be treated like
   // the corresponding fill or stroke had "none" specified.
   if (nStops == 0) {
     RefPtr<gfxPattern> pattern = new gfxPattern(Color());
-    return pattern.forget();
+    return MakePair(DrawResult::SUCCESS, Move(pattern));
   }
 
   if (nStops == 1 || GradientVectorLengthIsZero()) {
     // The gradient paints a single colour, using the stop-color of the last
     // gradient step if there are more than one.
     float stopOpacity = stopFrames[nStops-1]->StyleSVGReset()->mStopOpacity;
     nscolor stopColor = stopFrames[nStops-1]->StyleSVGReset()->mStopColor;
 
     Color stopColor2 = Color::FromABGR(stopColor);
     stopColor2.a *= stopOpacity * aGraphicOpacity;
     RefPtr<gfxPattern> pattern = new gfxPattern(stopColor2);
-    return pattern.forget();
+    return MakePair(DrawResult::SUCCESS, Move(pattern));
   }
 
   // Get the transform list (if there is one). We do this after the returns
   // above since this call can be expensive when "gradientUnits" is set to
   // "objectBoundingBox" (since that requiring a GetBBox() call).
   gfxMatrix patternMatrix = GetGradientTransform(aSource, aOverrideBounds);
 
   if (patternMatrix.IsSingular()) {
-    return nullptr;
+    return MakePair(DrawResult::BAD_ARGS, RefPtr<gfxPattern>());
   }
 
   // revert any vector effect transform so that the gradient appears unchanged
   if (aFillOrStroke == &nsStyleSVG::mStroke) {
     gfxMatrix userToOuterSVG;
     if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
       patternMatrix *= userToOuterSVG;
     }
   }
 
   if (!patternMatrix.Invert()) {
-    return nullptr;
+    return MakePair(DrawResult::BAD_ARGS, RefPtr<gfxPattern>());
   }
 
   RefPtr<gfxPattern> gradient = CreateGradient();
-  if (!gradient || gradient->CairoStatus())
-    return nullptr;
+  if (!gradient || gradient->CairoStatus()) {
+    return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<gfxPattern>());
+  }
 
   uint16_t aSpread = GetSpreadMethod();
   if (aSpread == SVG_SPREADMETHOD_PAD)
     gradient->SetExtend(ExtendMode::CLAMP);
   else if (aSpread == SVG_SPREADMETHOD_REFLECT)
     gradient->SetExtend(ExtendMode::REFLECT);
   else if (aSpread == SVG_SPREADMETHOD_REPEAT)
     gradient->SetExtend(ExtendMode::REPEAT);
@@ -299,17 +300,17 @@ nsSVGGradientFrame::GetPaintServerPatter
     else
       lastOffset = offset;
 
     Color stopColor2 = Color::FromABGR(stopColor);
     stopColor2.a *= stopOpacity * aGraphicOpacity;
     gradient->AddColorStop(offset, stopColor2);
   }
 
-  return gradient.forget();
+  return MakePair(DrawResult::SUCCESS, Move(gradient));
 }
 
 // Private (helper) methods
 
 nsSVGGradientFrame *
 nsSVGGradientFrame::GetReferencedGradient()
 {
   if (mNoHRefURI)
--- a/layout/svg/nsSVGGradientFrame.h
+++ b/layout/svg/nsSVGGradientFrame.h
@@ -41,17 +41,17 @@ class nsSVGGradientFrame : public nsSVGP
 
 protected:
   explicit nsSVGGradientFrame(nsStyleContext* aContext);
 
 public:
   NS_DECL_ABSTRACT_FRAME(nsSVGGradientFrame)
 
   // nsSVGPaintServerFrame methods:
-  virtual already_AddRefed<gfxPattern>
+  virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetPaintServerPattern(nsIFrame* aSource,
                           const DrawTarget* aDrawTarget,
                           const gfxMatrix& aContextMatrix,
                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                           float aGraphicOpacity,
                           const gfxRect* aOverrideBounds) override;
 
   // nsIFrame interface:
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -1225,20 +1225,22 @@ nsSVGIntegrationUtils::DrawableFromPaint
     // frame by default, so aPaintServerSize is the whole target background fill
     // area.
     nsSVGPaintServerFrame* server =
       static_cast<nsSVGPaintServerFrame*>(aFrame);
 
     gfxRect overrideBounds(0, 0,
                            aPaintServerSize.width, aPaintServerSize.height);
     overrideBounds.ScaleInverse(aFrame->PresContext()->AppUnitsPerDevPixel());
-    RefPtr<gfxPattern> pattern =
-    server->GetPaintServerPattern(aTarget, aDrawTarget,
-                                  aContextMatrix, &nsStyleSVG::mFill, 1.0,
-                                  &overrideBounds);
+    DrawResult result = DrawResult::SUCCESS;
+    RefPtr<gfxPattern> pattern;
+    Tie(result, pattern) =
+      server->GetPaintServerPattern(aTarget, aDrawTarget,
+                                    aContextMatrix, &nsStyleSVG::mFill, 1.0,
+                                    &overrideBounds);
 
     if (!pattern)
       return nullptr;
 
     // pattern is now set up to fill aPaintServerSize. But we want it to
     // fill aRenderSize, so we need to add a scaling transform.
     // We couldn't just have set overrideBounds to aRenderSize - it would have
     // worked for gradients, but for patterns it would result in a different
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -247,34 +247,31 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(Ma
     context->CurrentMatrix() * gfxMatrix::Translation(-maskSurfaceRect.TopLeft());
 
   RefPtr<gfxContext> tmpCtx = gfxContext::CreateOrNull(maskDT);
   MOZ_ASSERT(tmpCtx); // already checked the draw target above
   tmpCtx->SetMatrix(maskSurfaceMatrix);
 
   mMatrixForChildren = GetMaskTransform(aParams.maskedFrame) *
                        aParams.toUserSpace;
-  DrawResult result;
+  DrawResult result = DrawResult::SUCCESS;
 
   for (nsIFrame* kid = mFrames.FirstChild(); kid;
        kid = kid->GetNextSibling()) {
     // The CTM of each frame referencing us can be different
     nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     if (SVGFrame) {
       SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
     }
     gfxMatrix m = mMatrixForChildren;
     if (kid->GetContent()->IsSVGElement()) {
       m = static_cast<nsSVGElement*>(kid->GetContent())->
             PrependLocalTransformsTo(m, eUserSpaceToParent);
     }
-    result = nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m);
-    if (result != DrawResult::SUCCESS) {
-      return MakePair(result, RefPtr<SourceSurface>());
-    }
+    result &= nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m);
   }
 
   RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
   if (!maskSnapshot) {
     return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
   }
   RefPtr<DataSourceSurface> maskSurface = maskSnapshot->GetDataSurface();
   DataSourceSurface::MappedSurface map;
@@ -323,17 +320,17 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(Ma
 
   // Moz2D transforms in the opposite direction to Thebes
   if (!maskSurfaceMatrix.Invert()) {
     return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
   }
 
   *aParams.maskTransform = ToMatrix(maskSurfaceMatrix);
   RefPtr<SourceSurface> surface = destMaskSurface.forget();
-  return MakePair(DrawResult::SUCCESS, Move(surface));
+  return MakePair(result, Move(surface));
 }
 
 gfxRect
 nsSVGMaskFrame::GetMaskArea(nsIFrame* aMaskedFrame)
 {
   SVGMaskElement *maskElem = static_cast<SVGMaskElement*>(mContent);
 
   uint16_t units =
--- a/layout/svg/nsSVGPaintServerFrame.h
+++ b/layout/svg/nsSVGPaintServerFrame.h
@@ -25,16 +25,17 @@ class gfxPattern;
 class nsStyleContext;
 
 struct gfxRect;
 
 class nsSVGPaintServerFrame : public nsSVGContainerFrame
 {
 protected:
   typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::image::DrawResult DrawResult;
 
   explicit nsSVGPaintServerFrame(nsStyleContext* aContext)
     : nsSVGContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
 public:
@@ -43,17 +44,17 @@ public:
   /**
    * Constructs a gfxPattern of the paint server rendering.
    *
    * @param aContextMatrix The transform matrix that is currently applied to
    *   the gfxContext that is being drawn to. This is needed by SVG patterns so
    *   that surfaces of the correct size can be created. (SVG gradients are
    *   vector based, so it's not used there.)
    */
-  virtual already_AddRefed<gfxPattern>
+  virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetPaintServerPattern(nsIFrame *aSource,
                           const DrawTarget* aDrawTarget,
                           const gfxMatrix& aContextMatrix,
                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                           float aOpacity,
                           const gfxRect *aOverrideBounds = nullptr) = 0;
 
   // nsIFrame methods:
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -225,17 +225,17 @@ GetTargetGeometry(gfxRect *aBBox,
   float scale = MaxExpansion(aContextMatrix);
   if (scale <= 0) {
     return NS_ERROR_FAILURE;
   }
   aBBox->Scale(scale);
   return NS_OK;
 }
 
-already_AddRefed<SourceSurface>
+mozilla::Pair<DrawResult, RefPtr<SourceSurface>>
 nsSVGPatternFrame::PaintPattern(const DrawTarget* aDrawTarget,
                                 Matrix* patternMatrix,
                                 const Matrix &aContextMatrix,
                                 nsIFrame *aSource,
                                 nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                 float aGraphicOpacity,
                                 const gfxRect *aOverrideBounds)
 {
@@ -248,17 +248,18 @@ nsSVGPatternFrame::PaintPattern(const Dr
    *    Calculate the content transformation matrix
    *    Get our children (we may need to get them from another Pattern)
    *    Call SVGPaint on all of our children
    *    Return
    */
 
   nsSVGPatternFrame* patternWithChildren = GetPatternWithChildren();
   if (!patternWithChildren) {
-    return nullptr; // Either no kids or a bad reference
+    // Either no kids or a bad reference
+    return MakePair(DrawResult::SUCCESS, RefPtr<SourceSurface>());
   }
   nsIFrame* firstKid = patternWithChildren->mFrames.FirstChild();
 
   const nsSVGViewBox& viewBox = GetViewBox();
 
   uint16_t patternContentUnits =
     GetEnumValue(SVGPatternElement::PATTERNCONTENTUNITS);
   uint16_t patternUnits =
@@ -287,76 +288,76 @@ nsSVGPatternFrame::PaintPattern(const Dr
   // the geometry that is being rendered with a pattern
   gfxRect callerBBox;
   if (NS_FAILED(GetTargetGeometry(&callerBBox,
                                   viewBox,
                                   patternContentUnits, patternUnits,
                                   aSource,
                                   aContextMatrix,
                                   aOverrideBounds))) {
-    return nullptr;
+    return MakePair(DrawResult::SUCCESS, RefPtr<SourceSurface>());
   }
 
   // Construct the CTM that we will provide to our children when we
   // render them into the tile.
   gfxMatrix ctm = ConstructCTM(viewBox, patternContentUnits, patternUnits,
                                callerBBox, aContextMatrix, aSource);
   if (ctm.IsSingular()) {
-    return nullptr;
+    return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
   }
 
   if (patternWithChildren->mCTM) {
     *patternWithChildren->mCTM = ctm;
   } else {
     patternWithChildren->mCTM = new gfxMatrix(ctm);
   }
 
   // Get the bounding box of the pattern.  This will be used to determine
   // the size of the surface, and will also be used to define the bounding
   // box for the pattern tile.
   gfxRect bbox = GetPatternRect(patternUnits, callerBBox, aContextMatrix, aSource);
   if (bbox.Width() <= 0.0 || bbox.Height() <= 0.0) {
-    return nullptr;
+    return MakePair(DrawResult::SUCCESS, RefPtr<SourceSurface>());
   }
 
   // Get the pattern transform
   Matrix patternTransform = ToMatrix(GetPatternTransform());
 
   // revert the vector effect transform so that the pattern appears unchanged
   if (aFillOrStroke == &nsStyleSVG::mStroke) {
     gfxMatrix userToOuterSVG;
     if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
       patternTransform *= ToMatrix(userToOuterSVG);
       if (patternTransform.IsSingular()) {
         NS_WARNING("Singular matrix painting non-scaling-stroke");
-        return nullptr;
+        return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
       }
     }
   }
 
   // Get the transformation matrix that we will hand to the renderer's pattern
   // routine.
   *patternMatrix = GetPatternMatrix(patternUnits, patternTransform,
                                     bbox, callerBBox, aContextMatrix);
   if (patternMatrix->IsSingular()) {
-    return nullptr;
+    return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
   }
 
   // Now that we have all of the necessary geometries, we can
   // create our surface.
   gfxRect transformedBBox = ThebesRect(patternTransform.TransformBounds(ToRect(bbox)));
 
   bool resultOverflows;
   IntSize surfaceSize =
     nsSVGUtils::ConvertToSurfaceSize(
       transformedBBox.Size(), &resultOverflows);
 
   // 0 disables rendering, < 0 is an error
   if (surfaceSize.width <= 0 || surfaceSize.height <= 0) {
-    return nullptr;
+    return MakePair(DrawResult::SUCCESS, RefPtr<SourceSurface>());
   }
 
   gfxFloat patternWidth = bbox.Width();
   gfxFloat patternHeight = bbox.Height();
 
   if (resultOverflows ||
       patternWidth != surfaceSize.width ||
       patternHeight != surfaceSize.height) {
@@ -370,17 +371,17 @@ nsSVGPatternFrame::PaintPattern(const Dr
     // and rescale pattern to compensate
     patternMatrix->PreScale(patternWidth / surfaceSize.width,
                             patternHeight / surfaceSize.height);
   }
 
   RefPtr<DrawTarget> dt =
     aDrawTarget->CreateSimilarDrawTarget(surfaceSize, SurfaceFormat::B8G8R8A8);
   if (!dt || !dt->IsValid()) {
-    return nullptr;
+    return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
   }
   dt->ClearRect(Rect(0, 0, surfaceSize.width, surfaceSize.height));
 
   RefPtr<gfxContext> gfx = gfxContext::CreateOrNull(dt);
   MOZ_ASSERT(gfx); // already checked the draw target above
 
   if (aGraphicOpacity != 1.0f) {
     gfx->Save();
@@ -393,47 +394,48 @@ nsSVGPatternFrame::PaintPattern(const Dr
 
   if (aSource->IsFrameOfType(nsIFrame::eSVGGeometry)) {
     // Set the geometrical parent of the pattern we are rendering
     patternWithChildren->mSource = static_cast<SVGGeometryFrame*>(aSource);
   }
 
   // Delay checking NS_FRAME_DRAWING_AS_PAINTSERVER bit until here so we can
   // give back a clear surface if there's a loop
+  DrawResult result = DrawResult::SUCCESS;
   if (!(patternWithChildren->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)) {
     patternWithChildren->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
     for (nsIFrame* kid = firstKid; kid;
          kid = kid->GetNextSibling()) {
       // The CTM of each frame referencing us can be different
       nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
       if (SVGFrame) {
         SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);
       }
       gfxMatrix tm = *(patternWithChildren->mCTM);
       if (kid->GetContent()->IsSVGElement()) {
         tm = static_cast<nsSVGElement*>(kid->GetContent())->
                PrependLocalTransformsTo(tm, eUserSpaceToParent);
       }
-      DrawResult result = nsSVGUtils::PaintFrameWithEffects(kid, *gfx, tm);
-      if (result != DrawResult::SUCCESS) {
-        return nullptr;
-      }
+
+      result &= nsSVGUtils::PaintFrameWithEffects(kid, *gfx, tm);
     }
+
     patternWithChildren->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
   }
 
   patternWithChildren->mSource = nullptr;
 
   if (aGraphicOpacity != 1.0f) {
     gfx->PopGroupAndBlend();
     gfx->Restore();
   }
 
   // caller now owns the surface
-  return dt->Snapshot();
+  RefPtr<SourceSurface> surf = dt->Snapshot();
+  return MakePair(result, Move(surf));
 }
 
 /* Will probably need something like this... */
 // How do we handle the insertion of a new frame?
 // We really don't want to rerender this every time,
 // do we?
 nsSVGPatternFrame*
 nsSVGPatternFrame::GetPatternWithChildren()
@@ -702,47 +704,49 @@ nsSVGPatternFrame::ConstructCTM(const ns
     viewBoxRect.width, viewBoxRect.height,
     GetPreserveAspectRatio());
 
   return ThebesMatrix(tm);
 }
 
 //----------------------------------------------------------------------
 // nsSVGPaintServerFrame methods:
-
-already_AddRefed<gfxPattern>
+mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 nsSVGPatternFrame::GetPaintServerPattern(nsIFrame *aSource,
                                          const DrawTarget* aDrawTarget,
                                          const gfxMatrix& aContextMatrix,
                                          nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                          float aGraphicOpacity,
                                          const gfxRect *aOverrideBounds)
 {
   if (aGraphicOpacity == 0.0f) {
     RefPtr<gfxPattern> pattern = new gfxPattern(Color());
-    return pattern.forget();
+    return MakePair(DrawResult::SUCCESS, Move(pattern));
   }
 
   // Paint it!
   Matrix pMatrix;
-  RefPtr<SourceSurface> surface =
+  RefPtr<SourceSurface> surface;
+  DrawResult result = DrawResult::SUCCESS;
+  Tie(result, surface) =
     PaintPattern(aDrawTarget, &pMatrix, ToMatrix(aContextMatrix), aSource,
                  aFillOrStroke, aGraphicOpacity, aOverrideBounds);
 
   if (!surface) {
-    return nullptr;
+    return MakePair(result, RefPtr<gfxPattern>());
   }
 
   RefPtr<gfxPattern> pattern = new gfxPattern(surface, pMatrix);
 
-  if (!pattern || pattern->CairoStatus())
-    return nullptr;
+  if (!pattern || pattern->CairoStatus()) {
+    return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<gfxPattern>());
+  }
 
   pattern->SetExtend(ExtendMode::REPEAT);
-  return pattern.forget();
+  return MakePair(result, Move(pattern));
 }
 
 // -------------------------------------------------------------------------
 // Public functions
 // -------------------------------------------------------------------------
 
 nsIFrame* NS_NewSVGPatternFrame(nsIPresShell*   aPresShell,
                                 nsStyleContext* aContext)
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -35,17 +35,17 @@ public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
                                          nsStyleContext* aContext);
 
   explicit nsSVGPatternFrame(nsStyleContext* aContext);
 
   // nsSVGPaintServerFrame methods:
-  virtual already_AddRefed<gfxPattern>
+  virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetPaintServerPattern(nsIFrame *aSource,
                           const DrawTarget* aDrawTarget,
                           const gfxMatrix& aContextMatrix,
                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                           float aOpacity,
                           const gfxRect *aOverrideBounds) override;
 
 public:
@@ -103,17 +103,17 @@ protected:
     return GetPreserveAspectRatio(mContent);
   }
   const nsSVGLength2 *GetLengthValue(uint32_t aIndex, nsIContent *aDefault);
   const nsSVGLength2 *GetLengthValue(uint32_t aIndex)
   {
     return GetLengthValue(aIndex, mContent);
   }
 
-  already_AddRefed<SourceSurface>
+  mozilla::Pair<DrawResult, RefPtr<SourceSurface>>
   PaintPattern(const DrawTarget* aDrawTarget,
                Matrix *patternMatrix,
                const Matrix &aContextMatrix,
                nsIFrame *aSource,
                nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                float aGraphicOpacity,
                const gfxRect *aOverrideBounds);
 
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1445,25 +1445,25 @@ nsSVGUtils::GetFallbackOrPaintColor(nsSt
       nscolor colors[2] = { color, paintIfVisited.GetColor() };
       return nsStyleContext::CombineVisitedColors(
                colors, aStyleContext->RelevantLinkVisited());
     }
   }
   return color;
 }
 
-/* static */ void
+/* static */ DrawResult
 nsSVGUtils::MakeFillPatternFor(nsIFrame* aFrame,
                                gfxContext* aContext,
                                GeneralPattern* aOutPattern,
                                SVGContextPaint* aContextPaint)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mFill.Type() == eStyleSVGPaintType_None) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
   const float opacity = aFrame->StyleEffects()->mOpacity;
 
   float fillOpacity = GetOpacity(style->FillOpacitySource(),
                                  style->mFillOpacity,
                                  aContextPaint);
   if (opacity < 1.0f &&
@@ -1473,65 +1473,71 @@ nsSVGUtils::MakeFillPatternFor(nsIFrame*
     fillOpacity *= opacity;
   }
 
   const DrawTarget* dt = aContext->GetDrawTarget();
 
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, &nsStyleSVG::mFill,
                                  nsSVGEffects::FillProperty());
+  DrawResult result = DrawResult::SUCCESS;
   if (ps) {
-    RefPtr<gfxPattern> pattern =
+    RefPtr<gfxPattern> pattern;
+    Tie(result, pattern) =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrix(),
                                 &nsStyleSVG::mFill, fillOpacity);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
-      return;
+      return result;
     }
   }
 
   if (aContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch (style->mFill.Type()) {
     case eStyleSVGPaintType_ContextFill:
-      pattern = aContextPaint->GetFillPattern(dt, fillOpacity,
-                                              aContext->CurrentMatrix());
+      Tie(result, pattern) =
+        aContextPaint->GetFillPattern(dt, fillOpacity,
+                                      aContext->CurrentMatrix());
       break;
     case eStyleSVGPaintType_ContextStroke:
-      pattern = aContextPaint->GetStrokePattern(dt, fillOpacity,
-                                                aContext->CurrentMatrix());
+      Tie(result, pattern) =
+        aContextPaint->GetStrokePattern(dt, fillOpacity,
+                                        aContext->CurrentMatrix());
       break;
     default:
       ;
     }
     if (pattern) {
       aOutPattern->Init(*pattern->GetPattern(dt));
-      return;
+      return result;
     }
   }
 
   // On failure, use the fallback colour in case we have an
   // objectBoundingBox where the width or height of the object is zero.
   // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
   Color color(Color::FromABGR(GetFallbackOrPaintColor(aFrame->StyleContext(),
                                                       &nsStyleSVG::mFill)));
   color.a *= fillOpacity;
   aOutPattern->InitColorPattern(ToDeviceColor(color));
+
+  return result;
 }
 
-/* static */ void
+/* static */ DrawResult
 nsSVGUtils::MakeStrokePatternFor(nsIFrame* aFrame,
                                  gfxContext* aContext,
                                  GeneralPattern* aOutPattern,
                                  SVGContextPaint* aContextPaint)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mStroke.Type() == eStyleSVGPaintType_None) {
-    return;
+    return DrawResult::SUCCESS;
   }
 
   const float opacity = aFrame->StyleEffects()->mOpacity;
 
   float strokeOpacity = GetOpacity(style->StrokeOpacitySource(),
                                    style->mStrokeOpacity,
                                    aContextPaint);
   if (opacity < 1.0f &&
@@ -1541,54 +1547,60 @@ nsSVGUtils::MakeStrokePatternFor(nsIFram
     strokeOpacity *= opacity;
   }
 
   const DrawTarget* dt = aContext->GetDrawTarget();
 
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, &nsStyleSVG::mStroke,
                                  nsSVGEffects::StrokeProperty());
+  DrawResult result = DrawResult::SUCCESS;
   if (ps) {
-    RefPtr<gfxPattern> pattern =
+    RefPtr<gfxPattern> pattern;
+    Tie(result, pattern) =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrix(),
                                 &nsStyleSVG::mStroke, strokeOpacity);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
-      return;
+      return result;
     }
   }
 
   if (aContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch (style->mStroke.Type()) {
     case eStyleSVGPaintType_ContextFill:
-      pattern = aContextPaint->GetFillPattern(dt, strokeOpacity,
-                                              aContext->CurrentMatrix());
+      Tie(result, pattern) =
+        aContextPaint->GetFillPattern(dt, strokeOpacity,
+                                      aContext->CurrentMatrix());
       break;
     case eStyleSVGPaintType_ContextStroke:
-      pattern = aContextPaint->GetStrokePattern(dt, strokeOpacity,
-                                                aContext->CurrentMatrix());
+      Tie(result, pattern) =
+        aContextPaint->GetStrokePattern(dt, strokeOpacity,
+                                        aContext->CurrentMatrix());
       break;
     default:
       ;
     }
     if (pattern) {
       aOutPattern->Init(*pattern->GetPattern(dt));
-      return;
+      return result;
     }
   }
 
   // On failure, use the fallback colour in case we have an
   // objectBoundingBox where the width or height of the object is zero.
   // See http://www.w3.org/TR/SVG11/coords.html#ObjectBoundingBox
   Color color(Color::FromABGR(GetFallbackOrPaintColor(aFrame->StyleContext(),
                                                       &nsStyleSVG::mStroke)));
   color.a *= strokeOpacity;
   aOutPattern->InitColorPattern(ToDeviceColor(color));
+
+  return DrawResult::SUCCESS;
 }
 
 /* static */ float
 nsSVGUtils::GetOpacity(nsStyleSVGOpacitySource aOpacityType,
                        const float& aOpacity,
                        SVGContextPaint *aContextPaint)
 {
   float opacity = 1.0f;
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -498,23 +498,23 @@ public:
   {
     return NS_lround(std::max(double(INT32_MIN),
                             std::min(double(INT32_MAX), aVal)));
   }
 
   static nscolor GetFallbackOrPaintColor(nsStyleContext *aStyleContext,
                                          nsStyleSVGPaint nsStyleSVG::*aFillOrStroke);
 
-  static void
+  static DrawResult
   MakeFillPatternFor(nsIFrame *aFrame,
                      gfxContext* aContext,
                      GeneralPattern* aOutPattern,
                      SVGContextPaint* aContextPaint = nullptr);
 
-  static void
+  static DrawResult
   MakeStrokePatternFor(nsIFrame* aFrame,
                        gfxContext* aContext,
                        GeneralPattern* aOutPattern,
                        SVGContextPaint* aContextPaint = nullptr);
 
   static float GetOpacity(nsStyleSVGOpacitySource aOpacityType,
                           const float& aOpacity,
                           SVGContextPaint* aContextPaint);