Bug 1345853 - Part 4. Pass sync decode flag down to nsSVGPatternFrame::PaintPattern. r=tnikkel
authorcku <cku@mozilla.com>
Sat, 25 Mar 2017 03:19:18 +0800
changeset 350024 7427352abc976c0610191a990623e3eb43ed9016
parent 350023 87c961bde81eacc13beb8d3883fc02e5ce4bd939
child 350025 67166a1e4ebca2cd5ac146cd5eb1d1385a0ec5ed
push id31567
push userkwierso@gmail.com
push dateTue, 28 Mar 2017 20:16:07 +0000
treeherdermozilla-central@e23cf1b38ad4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1345853
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 4. Pass sync decode flag down to nsSVGPatternFrame::PaintPattern. r=tnikkel MozReview-Commit-ID: 1bHMINhs121
gfx/thebes/gfxSVGGlyphs.h
layout/svg/SVGContextPaint.cpp
layout/svg/SVGContextPaint.h
layout/svg/SVGGeometryFrame.cpp
layout/svg/SVGGeometryFrame.h
layout/svg/nsSVGGradientFrame.cpp
layout/svg/nsSVGGradientFrame.h
layout/svg/nsSVGPaintServerFrame.h
layout/svg/nsSVGPatternFrame.cpp
layout/svg/nsSVGPatternFrame.h
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/gfx/thebes/gfxSVGGlyphs.h
+++ b/gfx/thebes/gfxSVGGlyphs.h
@@ -200,28 +200,30 @@ public:
     {
         mFillMatrix = SetupDeviceToPatternMatrix(aFillPattern, aCTM);
         mStrokeMatrix = SetupDeviceToPatternMatrix(aStrokePattern, aCTM);
     }
 
     mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetFillPattern(const DrawTarget* aDrawTarget,
                    float aOpacity,
-                   const gfxMatrix& aCTM) {
+                   const gfxMatrix& aCTM,
+                   uint32_t aFlags) {
         if (mFillPattern) {
             mFillPattern->SetMatrix(aCTM * mFillMatrix);
         }
         RefPtr<gfxPattern> fillPattern = mFillPattern;
         return MakePair(DrawResult::SUCCESS, Move(fillPattern));
     }
 
     mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetStrokePattern(const DrawTarget* aDrawTarget,
                      float aOpacity,
-                     const gfxMatrix& aCTM) {
+                     const gfxMatrix& aCTM,
+                     uint32_t aFlags) {
         if (mStrokePattern) {
             mStrokePattern->SetMatrix(aCTM * mStrokeMatrix);
         }
         RefPtr<gfxPattern> strokePattern = mStrokePattern;
         return MakePair(DrawResult::SUCCESS, Move(strokePattern));
     }
 
     float GetFillOpacity() const {
--- a/layout/svg/SVGContextPaint.cpp
+++ b/layout/svg/SVGContextPaint.cpp
@@ -167,34 +167,39 @@ SVGContextPaint::GetContextPaint(nsICont
 
   return static_cast<SVGContextPaint*>(
            ownerDoc->GetProperty(nsGkAtoms::svgContextPaint));
 }
 
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGContextPaintImpl::GetFillPattern(const DrawTarget* aDrawTarget,
                                     float aOpacity,
-                                    const gfxMatrix& aCTM)
+                                    const gfxMatrix& aCTM,
+                                    uint32_t aFlags)
 {
-  return mFillPaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mFill, aCTM);
+  return mFillPaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mFill, aCTM,
+                               aFlags);
 }
 
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGContextPaintImpl::GetStrokePattern(const DrawTarget* aDrawTarget,
                                       float aOpacity,
-                                      const gfxMatrix& aCTM)
+                                      const gfxMatrix& aCTM,
+                                      uint32_t aFlags)
 {
-  return mStrokePaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mStroke, aCTM);
+  return mStrokePaint.GetPattern(aDrawTarget, aOpacity, &nsStyleSVG::mStroke,
+                                 aCTM, aFlags);
 }
 
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGContextPaintImpl::Paint::GetPattern(const DrawTarget* aDrawTarget,
                                        float aOpacity,
                                        nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
-                                       const gfxMatrix& aCTM)
+                                       const gfxMatrix& aCTM,
+                                       uint32_t aFlags)
 {
   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 MakePair(DrawResult::SUCCESS, Move(pattern));
@@ -214,40 +219,42 @@ SVGContextPaintImpl::Paint::GetPattern(c
     break;
   }
   case eStyleSVGPaintType_Server:
     Tie(result, pattern) =
       mPaintDefinition.mPaintServerFrame->GetPaintServerPattern(mFrame,
                                                                 aDrawTarget,
                                                                 mContextMatrix,
                                                                 aFillOrStroke,
-                                                                aOpacity);
+                                                                aOpacity,
+                                                                nullptr,
+                                                                aFlags);
     {
       // m maps original-user-space to pattern space
       gfxMatrix m = pattern->GetMatrix();
       gfxMatrix deviceToOriginalUserSpace = mContextMatrix;
       if (!deviceToOriginalUserSpace.Invert()) {
         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:
     Tie(result, pattern) =
       mPaintDefinition.mContextPaint->GetFillPattern(aDrawTarget,
-                                                             aOpacity, aCTM);
+                                                     aOpacity, aCTM, aFlags);
     // Don't cache this. mContextPaint will have cached it anyway. If we
     // cache it, we'll have to compute mPatternMatrix, which is annoying.
     return MakePair(result, Move(pattern));
   case eStyleSVGPaintType_ContextStroke:
     Tie(result, pattern) =
       mPaintDefinition.mContextPaint->GetStrokePattern(aDrawTarget,
-                                                               aOpacity, aCTM);
+                                                       aOpacity, aCTM, aFlags);
     // Don't cache this. mContextPaint will have cached it anyway. If we
     // cache it, we'll have to compute mPatternMatrix, which is annoying.
     return MakePair(result, Move(pattern));
   default:
     MOZ_ASSERT(false, "invalid paint type");
     return MakePair(DrawResult::SUCCESS, RefPtr<gfxPattern>());
   }
 
@@ -292,34 +299,36 @@ AutoSetRestoreSVGContextPaint::~AutoSetR
 }
 
 
 // SVGEmbeddingContextPaint
 
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGEmbeddingContextPaint::GetFillPattern(const DrawTarget* aDrawTarget,
                                          float aFillOpacity,
-                                         const gfxMatrix& aCTM)
+                                         const gfxMatrix& aCTM,
+                                         uint32_t aFlags)
 {
   if (!mFill) {
     return MakePair(DrawResult::SUCCESS, RefPtr<gfxPattern>());
   }
   // The gfxPattern that we create below depends on aFillOpacity, and since
   // different elements in the SVG image may pass in different values for
   // fill opacities we don't try to cache the gfxPattern that we create.
   Color fill = *mFill;
   fill.a *= aFillOpacity;
   RefPtr<gfxPattern> patern = new gfxPattern(fill);
   return MakePair(DrawResult::SUCCESS, Move(patern));
 }
 
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 SVGEmbeddingContextPaint::GetStrokePattern(const DrawTarget* aDrawTarget,
                                            float aStrokeOpacity,
-                                           const gfxMatrix& aCTM)
+                                           const gfxMatrix& aCTM,
+                                           uint32_t aFlags)
 {
   if (!mStroke) {
     return MakePair(DrawResult::SUCCESS, RefPtr<gfxPattern>());
   }
   Color stroke = *mStroke;
   stroke.a *= aStrokeOpacity;
   RefPtr<gfxPattern> patern = new gfxPattern(stroke);
   return MakePair(DrawResult::SUCCESS, Move(patern));
--- a/layout/svg/SVGContextPaint.h
+++ b/layout/svg/SVGContextPaint.h
@@ -58,32 +58,36 @@ public:
 
   MOZ_DECLARE_REFCOUNTED_TYPENAME(SVGContextPaint)
 
   virtual ~SVGContextPaint() {}
 
   virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
   GetFillPattern(const DrawTarget* aDrawTarget,
                  float aOpacity,
-                 const gfxMatrix& aCTM) = 0;
+                 const gfxMatrix& aCTM,
+                 uint32_t aFlags = 0) = 0;
   virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
   GetStrokePattern(const DrawTarget* aDrawTarget,
                    float aOpacity,
-                   const gfxMatrix& aCTM) = 0;
+                   const gfxMatrix& aCTM,
+                   uint32_t aFlags = 0) = 0;
   virtual float GetFillOpacity() const = 0;
   virtual float GetStrokeOpacity() const = 0;
 
   mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
-  GetFillPattern(const DrawTarget* aDrawTarget, const gfxMatrix& aCTM) {
-    return GetFillPattern(aDrawTarget, GetFillOpacity(), aCTM);
+  GetFillPattern(const DrawTarget* aDrawTarget, const gfxMatrix& aCTM,
+                 uint32_t aFlags = 0) {
+    return GetFillPattern(aDrawTarget, GetFillOpacity(), aCTM, aFlags);
   }
 
   mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
-  GetStrokePattern(const DrawTarget* aDrawTarget, const gfxMatrix& aCTM) {
-    return GetStrokePattern(aDrawTarget, GetStrokeOpacity(), aCTM);
+  GetStrokePattern(const DrawTarget* aDrawTarget, const gfxMatrix& aCTM,
+                   uint32_t aFlags) {
+    return GetStrokePattern(aDrawTarget, GetStrokeOpacity(), aCTM, aFlags);
   }
 
   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,
                           float devUnitsPerSVGUnit);
@@ -151,21 +155,23 @@ public:
   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;
+                 const gfxMatrix& aCTM,
+                 uint32_t aFlags) override;
   mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
   GetStrokePattern(const DrawTarget* aDrawTarget,
                    float aOpacity,
-                   const gfxMatrix& aCTM) override;
+                   const gfxMatrix& aCTM,
+                   uint32_t aFlags) 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 {
@@ -209,17 +215,18 @@ public:
     // Device-space-to-pattern-space
     gfxMatrix mPatternMatrix;
     nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
 
     mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetPattern(const DrawTarget* aDrawTarget,
                float aOpacity,
                nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
-               const gfxMatrix& aCTM);
+               const gfxMatrix& aCTM,
+               uint32_t aFlags);
   };
 
   Paint mFillPaint;
   Paint mStrokePaint;
 
   float mFillOpacity;
   float mStrokeOpacity;
 };
@@ -245,24 +252,24 @@ public:
     mStroke.emplace(gfx::ToDeviceColor(aStroke));
   }
 
   /**
    * Returns a pattern of type PatternType::COLOR, or else nullptr.
    */
   mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
   GetFillPattern(const DrawTarget* aDrawTarget, float aFillOpacity,
-                 const gfxMatrix& aCTM) override;
+                 const gfxMatrix& aCTM, uint32_t aFlags = 0) override;
 
   /**
    * Returns a pattern of type PatternType::COLOR, or else nullptr.
    */
   mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
   GetStrokePattern(const DrawTarget* aDrawTarget, float aStrokeOpacity,
-                   const gfxMatrix& aCTM) override;
+                   const gfxMatrix& aCTM, uint32_t aFlags = 0) override;
 
   float GetFillOpacity() const override {
     // Always 1.0f since we don't currently allow 'context-fill-opacity'
     return 1.0f;
   };
 
   float GetStrokeOpacity() const override {
     // Always 1.0f since we don't currently allow 'context-stroke-opacity'
--- a/layout/svg/SVGGeometryFrame.cpp
+++ b/layout/svg/SVGGeometryFrame.cpp
@@ -298,28 +298,28 @@ SVGGeometryFrame::PaintSVG(gfxContext& a
   if (newMatrix.IsSingular()) {
     return DrawResult::SUCCESS;
   }
 
   uint32_t paintOrder = StyleSVG()->mPaintOrder;
   DrawResult result = DrawResult::SUCCESS;
 
   if (paintOrder == NS_STYLE_PAINT_ORDER_NORMAL) {
-    result = Render(&aContext, eRenderFill | eRenderStroke, newMatrix);
+    result = Render(&aContext, eRenderFill | eRenderStroke, newMatrix, aFlags);
     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:
-          result &= Render(&aContext, eRenderFill, newMatrix);
+          result &= Render(&aContext, eRenderFill, newMatrix, aFlags);
           break;
         case NS_STYLE_PAINT_ORDER_STROKE:
-          result &= Render(&aContext, eRenderStroke, newMatrix);
+          result &= Render(&aContext, eRenderStroke, newMatrix, aFlags);
           break;
         case NS_STYLE_PAINT_ORDER_MARKERS:
           PaintMarkers(aContext, aTransform);
           break;
       }
       paintOrder >>= NS_STYLE_PAINT_ORDER_BITWIDTH;
     }
   }
@@ -756,17 +756,18 @@ SVGGeometryFrame::MarkerProperties::GetM
     return nullptr;
   return static_cast<nsSVGMarkerFrame *>
     (mMarkerEnd->GetReferencedFrame(nsGkAtoms::svgMarkerFrame, nullptr));
 }
 
 DrawResult
 SVGGeometryFrame::Render(gfxContext* aContext,
                          uint32_t aRenderComponents,
-                         const gfxMatrix& aNewTransform)
+                         const gfxMatrix& aNewTransform,
+                         uint32_t aFlags)
 {
   MOZ_ASSERT(!aNewTransform.IsSingular());
 
   DrawTarget* drawTarget = aContext->GetDrawTarget();
 
   FillRule fillRule =
     nsSVGUtils::ToFillRule((GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) ?
                              StyleSVG()->mClipRule : StyleSVG()->mFillRule);
@@ -809,17 +810,17 @@ SVGGeometryFrame::Render(gfxContext* aCo
   }
 
   SVGContextPaint* contextPaint = SVGContextPaint::GetContextPaint(mContent);
   DrawResult result = DrawResult::SUCCESS;
 
   if (aRenderComponents & eRenderFill) {
     GeneralPattern fillPattern;
     result = nsSVGUtils::MakeFillPatternFor(this, aContext, &fillPattern,
-                                            contextPaint);
+                                            contextPaint, aFlags);
 
     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);
       }
@@ -848,17 +849,17 @@ SVGGeometryFrame::Render(gfxContext* aCo
       aContext->Multiply(outerSVGToUser);
       RefPtr<PathBuilder> builder =
         path->TransformedCopyToBuilder(ToMatrix(userToOuterSVG), fillRule);
       path = builder->Finish();
     }
     GeneralPattern strokePattern;
     result &=
       nsSVGUtils::MakeStrokePatternFor(this, aContext, &strokePattern,
-                                       contextPaint);
+                                       contextPaint, aFlags);
 
     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) {
--- a/layout/svg/SVGGeometryFrame.h
+++ b/layout/svg/SVGGeometryFrame.h
@@ -117,17 +117,17 @@ protected:
    * 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 };
   DrawResult Render(gfxContext* aContext, uint32_t aRenderComponents,
-                    const gfxMatrix& aTransform);
+                    const gfxMatrix& aTransform, uint32_t aFlags);
 
   /**
    * @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/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -224,17 +224,18 @@ static void GetStopInformation(nsIFrame*
 }
 
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 nsSVGGradientFrame::GetPaintServerPattern(nsIFrame* aSource,
                                           const DrawTarget* aDrawTarget,
                                           const gfxMatrix& aContextMatrix,
                                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                           float aGraphicOpacity,
-                                          const gfxRect* aOverrideBounds)
+                                          const gfxRect* aOverrideBounds,
+                                          uint32_t aFlags)
 {
   uint16_t gradientUnits = GetGradientUnits();
   MOZ_ASSERT(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX ||
              gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE);
   if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
     // Set mSource for this consumer.
     // If this gradient is applied to text, our caller will be the glyph, which
     // is not an element, so we need to get the parent
--- a/layout/svg/nsSVGGradientFrame.h
+++ b/layout/svg/nsSVGGradientFrame.h
@@ -47,17 +47,18 @@ public:
 
   // nsSVGPaintServerFrame methods:
   virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetPaintServerPattern(nsIFrame* aSource,
                           const DrawTarget* aDrawTarget,
                           const gfxMatrix& aContextMatrix,
                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                           float aGraphicOpacity,
-                          const gfxRect* aOverrideBounds) override;
+                          const gfxRect* aOverrideBounds,
+                          uint32_t aFlags) override;
 
   // nsIFrame interface:
   virtual nsresult AttributeChanged(int32_t         aNameSpaceID,
                                     nsIAtom*        aAttribute,
                                     int32_t         aModType) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override
--- a/layout/svg/nsSVGPaintServerFrame.h
+++ b/layout/svg/nsSVGPaintServerFrame.h
@@ -76,17 +76,18 @@ public:
    *   vector based, so it's not used there.)
    */
   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;
+                          const gfxRect *aOverrideBounds = nullptr,
+                          uint32_t aFlags = 0) = 0;
 
   // nsIFrame methods:
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override {}
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -213,17 +213,18 @@ GetTargetGeometry(gfxRect *aBBox,
 
 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)
+                                const gfxRect *aOverrideBounds,
+                                uint32_t aFlags)
 {
   /*
    * General approach:
    *    Set the content geometry stuff
    *    Calculate our bbox (using x,y,width,height & patternUnits &
    *                        patternTransform)
    *    Create the surface
    *    Calculate the content transformation matrix
@@ -391,17 +392,18 @@ nsSVGPatternFrame::PaintPattern(const Dr
         SVGFrame->NotifySVGChanged(nsSVGDisplayableFrame::TRANSFORM_CHANGED);
       }
       gfxMatrix tm = *(patternWithChildren->mCTM);
       if (kid->GetContent()->IsSVGElement()) {
         tm = static_cast<nsSVGElement*>(kid->GetContent())->
                PrependLocalTransformsTo(tm, eUserSpaceToParent);
       }
 
-      result &= nsSVGUtils::PaintFrameWithEffects(kid, *ctx, tm);
+      result &= nsSVGUtils::PaintFrameWithEffects(kid, *ctx, tm, nullptr,
+                                                  aFlags);
     }
   }
 
   patternWithChildren->mSource = nullptr;
 
   if (aGraphicOpacity != 1.0f) {
     ctx->PopGroupAndBlend();
     ctx->Restore();
@@ -723,30 +725,31 @@ nsSVGPatternFrame::ConstructCTM(const ns
 //----------------------------------------------------------------------
 // nsSVGPaintServerFrame methods:
 mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
 nsSVGPatternFrame::GetPaintServerPattern(nsIFrame *aSource,
                                          const DrawTarget* aDrawTarget,
                                          const gfxMatrix& aContextMatrix,
                                          nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                          float aGraphicOpacity,
-                                         const gfxRect *aOverrideBounds)
+                                         const gfxRect *aOverrideBounds,
+                                         uint32_t aFlags)
 {
   if (aGraphicOpacity == 0.0f) {
     RefPtr<gfxPattern> pattern = new gfxPattern(Color());
     return MakePair(DrawResult::SUCCESS, Move(pattern));
   }
 
   // Paint it!
   Matrix pMatrix;
   RefPtr<SourceSurface> surface;
   DrawResult result = DrawResult::SUCCESS;
   Tie(result, surface) =
     PaintPattern(aDrawTarget, &pMatrix, ToMatrix(aContextMatrix), aSource,
-                 aFillOrStroke, aGraphicOpacity, aOverrideBounds);
+                 aFillOrStroke, aGraphicOpacity, aOverrideBounds, aFlags);
 
   if (!surface) {
     return MakePair(result, RefPtr<gfxPattern>());
   }
 
   RefPtr<gfxPattern> pattern = new gfxPattern(surface, pMatrix);
 
   if (!pattern) {
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -41,17 +41,18 @@ public:
 
   // nsSVGPaintServerFrame methods:
   virtual mozilla::Pair<DrawResult, RefPtr<gfxPattern>>
     GetPaintServerPattern(nsIFrame *aSource,
                           const DrawTarget* aDrawTarget,
                           const gfxMatrix& aContextMatrix,
                           nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                           float aOpacity,
-                          const gfxRect *aOverrideBounds) override;
+                          const gfxRect *aOverrideBounds,
+                          uint32_t aFlags) override;
 
 public:
   typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
 
   // nsSVGContainerFrame methods:
   virtual gfxMatrix GetCanvasTM() override;
 
   // nsIFrame interface:
@@ -108,17 +109,18 @@ protected:
 
   mozilla::Pair<DrawResult, RefPtr<SourceSurface>>
   PaintPattern(const DrawTarget* aDrawTarget,
                Matrix *patternMatrix,
                const Matrix &aContextMatrix,
                nsIFrame *aSource,
                nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                float aGraphicOpacity,
-               const gfxRect *aOverrideBounds);
+               const gfxRect *aOverrideBounds,
+               uint32_t aFlags);
 
   /**
    * A <pattern> element may reference another <pattern> element using
    * xlink:href and, if it doesn't have any child content of its own, then it
    * will "inherit" the children of the referenced pattern (which may itself be
    * inheriting its children if it references another <pattern>).  This
    * function returns this nsSVGPatternFrame or the first pattern along the
    * reference chain (if there is one) to have children.
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -466,16 +466,20 @@ nsSVGUtils::NotifyChildrenOfSVGChange(ns
   }
 }
 
 // ************************************************************
 
 class SVGPaintCallback : public nsSVGFilterPaintCallback
 {
 public:
+  explicit SVGPaintCallback(uint32_t aFlags)
+    : mFlags(aFlags)
+  { }
+
   virtual DrawResult Paint(gfxContext& aContext, nsIFrame *aTarget,
                            const gfxMatrix& aTransform,
                            const nsIntRect* aDirtyRect) override
   {
     nsSVGDisplayableFrame* svgFrame = do_QueryFrame(aTarget);
     NS_ASSERTION(svgFrame, "Expected SVG frame here");
 
     nsIntRect* dirtyRect = nullptr;
@@ -493,18 +497,21 @@ public:
       dirtyBounds.RoundOut();
       if (gfxUtils::GfxRectToIntRect(dirtyBounds, &tmpDirtyRect)) {
         dirtyRect = &tmpDirtyRect;
       }
     }
 
     return svgFrame->PaintSVG(aContext,
                               nsSVGUtils::GetCSSPxToDevPxMatrix(aTarget),
-                              dirtyRect);
+                              dirtyRect, mFlags);
   }
+
+private:
+  uint32_t mFlags;
 };
 
 float
 nsSVGUtils::ComputeOpacity(nsIFrame* aFrame, bool aHandleOpacity)
 {
   float opacity = aFrame->StyleEffects()->mOpacity;
 
   if (opacity != 1.0f &&
@@ -672,17 +679,18 @@ private:
   RefPtr<gfxContext> mTargetCtx;
   IntPoint mTargetOffset;
 };
 
 DrawResult
 nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
                                   gfxContext& aContext,
                                   const gfxMatrix& aTransform,
-                                  const nsIntRect *aDirtyRect)
+                                  const nsIntRect *aDirtyRect,
+                                  uint32_t aFlags)
 {
   NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
                (aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) ||
                aFrame->PresContext()->IsGlyph(),
                "If display lists are enabled, only painting of non-display "
                "SVG should take this code path");
 
   nsSVGDisplayableFrame* svgFrame = do_QueryFrame(aFrame);
@@ -876,23 +884,23 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
     }
 
     gfxContextMatrixAutoSaveRestore saver(target);
     gfxMatrix devPxToCssPxTM = nsSVGUtils::GetCSSPxToDevPxMatrix(aFrame);
     DebugOnly<bool> invertible = devPxToCssPxTM.Invert();
     MOZ_ASSERT(invertible);
     target->SetMatrix(aTransform * devPxToCssPxTM);
 
-    SVGPaintCallback paintCallback;
+    SVGPaintCallback paintCallback(aFlags);
     result =
       nsFilterInstance::PaintFilteredFrame(aFrame, target->GetDrawTarget(),
                                            aTransform, &paintCallback,
                                            dirtyRegion);
   } else {
-    result = svgFrame->PaintSVG(*target, aTransform, aDirtyRect);
+    result = svgFrame->PaintSVG(*target, aTransform, aDirtyRect, aFlags);
   }
 
   if (maskUsage.shouldApplyClipPath || maskUsage.shouldApplyBasicShape) {
     aContext.PopClip();
   }
 
   if (shouldPushMask) {
     target->PopGroupAndBlend();
@@ -1478,17 +1486,18 @@ nsSVGUtils::GetFallbackOrPaintColor(nsSt
   }
   return color;
 }
 
 /* static */ DrawResult
 nsSVGUtils::MakeFillPatternFor(nsIFrame* aFrame,
                                gfxContext* aContext,
                                GeneralPattern* aOutPattern,
-                               SVGContextPaint* aContextPaint)
+                               SVGContextPaint* aContextPaint,
+                               uint32_t aFlags)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mFill.Type() == eStyleSVGPaintType_None) {
     return DrawResult::SUCCESS;
   }
 
   const float opacity = aFrame->StyleEffects()->mOpacity;
 
@@ -1507,36 +1516,37 @@ nsSVGUtils::MakeFillPatternFor(nsIFrame*
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, &nsStyleSVG::mFill,
                                  nsSVGEffects::FillProperty());
   DrawResult result = DrawResult::SUCCESS;
   if (ps) {
     RefPtr<gfxPattern> pattern;
     Tie(result, pattern) =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrix(),
-                                &nsStyleSVG::mFill, fillOpacity);
+                                &nsStyleSVG::mFill, fillOpacity, nullptr,
+                                aFlags);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
       return result;
     }
   }
 
   if (aContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch (style->mFill.Type()) {
     case eStyleSVGPaintType_ContextFill:
       Tie(result, pattern) =
         aContextPaint->GetFillPattern(dt, fillOpacity,
-                                      aContext->CurrentMatrix());
+                                      aContext->CurrentMatrix(), aFlags);
       break;
     case eStyleSVGPaintType_ContextStroke:
       Tie(result, pattern) =
         aContextPaint->GetStrokePattern(dt, fillOpacity,
-                                        aContext->CurrentMatrix());
+                                        aContext->CurrentMatrix(), aFlags);
       break;
     default:
       ;
     }
     if (pattern) {
       aOutPattern->Init(*pattern->GetPattern(dt));
       return result;
     }
@@ -1552,17 +1562,18 @@ nsSVGUtils::MakeFillPatternFor(nsIFrame*
 
   return result;
 }
 
 /* static */ DrawResult
 nsSVGUtils::MakeStrokePatternFor(nsIFrame* aFrame,
                                  gfxContext* aContext,
                                  GeneralPattern* aOutPattern,
-                                 SVGContextPaint* aContextPaint)
+                                 SVGContextPaint* aContextPaint,
+                                 uint32_t aFlags)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mStroke.Type() == eStyleSVGPaintType_None) {
     return DrawResult::SUCCESS;
   }
 
   const float opacity = aFrame->StyleEffects()->mOpacity;
 
@@ -1581,36 +1592,37 @@ nsSVGUtils::MakeStrokePatternFor(nsIFram
   nsSVGPaintServerFrame *ps =
     nsSVGEffects::GetPaintServer(aFrame, &nsStyleSVG::mStroke,
                                  nsSVGEffects::StrokeProperty());
   DrawResult result = DrawResult::SUCCESS;
   if (ps) {
     RefPtr<gfxPattern> pattern;
     Tie(result, pattern) =
       ps->GetPaintServerPattern(aFrame, dt, aContext->CurrentMatrix(),
-                                &nsStyleSVG::mStroke, strokeOpacity);
+                                &nsStyleSVG::mStroke, strokeOpacity, nullptr,
+                                aFlags);
     if (pattern) {
       pattern->CacheColorStops(dt);
       aOutPattern->Init(*pattern->GetPattern(dt));
       return result;
     }
   }
 
   if (aContextPaint) {
     RefPtr<gfxPattern> pattern;
     switch (style->mStroke.Type()) {
     case eStyleSVGPaintType_ContextFill:
       Tie(result, pattern) =
         aContextPaint->GetFillPattern(dt, strokeOpacity,
-                                      aContext->CurrentMatrix());
+                                      aContext->CurrentMatrix(), aFlags);
       break;
     case eStyleSVGPaintType_ContextStroke:
       Tie(result, pattern) =
         aContextPaint->GetStrokePattern(dt, strokeOpacity,
-                                        aContext->CurrentMatrix());
+                                        aContext->CurrentMatrix(), aFlags);
       break;
     default:
       ;
     }
     if (pattern) {
       aOutPattern->Init(*pattern->GetPattern(dt));
       return result;
     }
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -288,17 +288,18 @@ public:
   static nsIFrame* GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame,
                                                     nsRect* aRect);
 
   /* Paint SVG frame with SVG effects - aDirtyRect is the area being
    * redrawn, in device pixel coordinates relative to the outer svg */
   static DrawResult PaintFrameWithEffects(nsIFrame *aFrame,
                                           gfxContext& aContext,
                                           const gfxMatrix& aTransform,
-                                          const nsIntRect *aDirtyRect = nullptr);
+                                          const nsIntRect *aDirtyRect = nullptr,
+                                          uint32_t aFlags = 0);
 
   /* Hit testing - check if point hits the clipPath of indicated
    * frame.  Returns true if no clipPath set. */
   static bool HitTestClip(nsIFrame *aFrame, const gfxPoint &aPoint);
 
   /**
    * Hit testing - check if point hits any children of aFrame.  aPoint is
    * expected to be in the coordinate space established by aFrame for its
@@ -507,23 +508,25 @@ public:
   }
 
   static nscolor GetFallbackOrPaintColor(nsStyleContext *aStyleContext,
                                          nsStyleSVGPaint nsStyleSVG::*aFillOrStroke);
 
   static DrawResult MakeFillPatternFor(nsIFrame *aFrame,
                                        gfxContext* aContext,
                                        GeneralPattern* aOutPattern,
-                                       SVGContextPaint* aContextPaint = nullptr);
+                                       SVGContextPaint* aContextPaint = nullptr,
+                                       uint32_t aFlags = 0);
 
   static DrawResult
   MakeStrokePatternFor(nsIFrame* aFrame,
                        gfxContext* aContext,
                        GeneralPattern* aOutPattern,
-                       SVGContextPaint* aContextPaint = nullptr);
+                       SVGContextPaint* aContextPaint = nullptr,
+                       uint32_t aFlags = 0);
 
   static float GetOpacity(nsStyleSVGOpacitySource aOpacityType,
                           const float& aOpacity,
                           SVGContextPaint* aContextPaint);
 
   /*
    * @return false if there is no stroke
    */