Bug 1073012 , part 1 - Replace nsSVGUtils::SetupCairoFillPaint with a helper that returns a gfxPattern. r=longsonr
authorJonathan Watt <jwatt@jwatt.org>
Mon, 29 Sep 2014 14:12:06 +0100
changeset 207684 cc8e1611058a08bc099afcee5056672b40c82624
parent 207683 3255a9151456d395eacb7bbb9a183bf87e21730a
child 207685 5b31389a7033a922420544932c3e1dffd6dbbbce
push id27564
push userryanvm@gmail.com
push dateMon, 29 Sep 2014 18:57:04 +0000
treeherdermozilla-central@ce9a0b34225e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr
bugs1073012
milestone35.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 1073012 , part 1 - Replace nsSVGUtils::SetupCairoFillPaint with a helper that returns a gfxPattern. r=longsonr
layout/svg/SVGTextFrame.cpp
layout/svg/nsFilterInstance.cpp
layout/svg/nsSVGPathGeometryFrame.cpp
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -2722,31 +2722,29 @@ public:
   void NotifyBeforeSelectionBackground(nscolor aColor) MOZ_OVERRIDE;
   void NotifySelectionBackgroundPathEmitted() MOZ_OVERRIDE;
   void NotifyBeforeDecorationLine(nscolor aColor) MOZ_OVERRIDE;
   void NotifyDecorationLinePathEmitted() MOZ_OVERRIDE;
   void NotifyBeforeSelectionDecorationLine(nscolor aColor) MOZ_OVERRIDE;
   void NotifySelectionDecorationLinePathEmitted() MOZ_OVERRIDE;
 
 private:
-  void FillWithOpacity();
-
   void SetupContext();
 
   /**
    * Paints a piece of text geometry.  This is called when glyphs
    * or text decorations have been emitted to the gfxContext.
    */
   void HandleTextGeometry();
 
   /**
    * Sets the gfxContext paint to the appropriate color or pattern
    * for filling text geometry.
    */
-  bool SetFillColor();
+  already_AddRefed<gfxPattern> MakeFillPattern();
 
   /**
    * Fills and strokes a piece of text geometry, using group opacity
    * if the selection style requires it.
    */
   void FillAndStrokeGeometry();
 
   /**
@@ -2822,18 +2820,21 @@ SVGTextDrawPathCallbacks::NotifyBeforeSe
 void
 SVGTextDrawPathCallbacks::NotifySelectionBackgroundPathEmitted()
 {
   if (mRenderMode != SVGAutoRenderState::NORMAL) {
     // Don't paint selection backgrounds when in a clip path.
     return;
   }
 
-  if (SetFillColor()) {
-    FillWithOpacity();
+  nsRefPtr<gfxPattern> fillPattern = MakeFillPattern();
+  if (fillPattern) {
+    gfx->SetPattern(fillPattern);
+    gfx->SetFillRule(nsSVGUtils::ThebesFillRule(mFrame->StyleSVG()->mFillRule));
+    gfx->FillWithOpacity(mColor == NS_40PERCENT_FOREGROUND_COLOR ? 0.4 : 1.0);
   }
   gfx->Restore();
 }
 
 void
 SVGTextDrawPathCallbacks::NotifyBeforeDecorationLine(nscolor aColor)
 {
   mColor = aColor;
@@ -2868,22 +2869,16 @@ SVGTextDrawPathCallbacks::NotifySelectio
     return;
   }
 
   FillAndStrokeGeometry();
   gfx->Restore();
 }
 
 void
-SVGTextDrawPathCallbacks::FillWithOpacity()
-{
-  gfx->FillWithOpacity(mColor == NS_40PERCENT_FOREGROUND_COLOR ? 0.4 : 1.0);
-}
-
-void
 SVGTextDrawPathCallbacks::SetupContext()
 {
   gfx->Save();
 
   // XXX This is copied from nsSVGGlyphFrame::Render, but cairo doesn't actually
   // seem to do anything with the antialias mode.  So we can perhaps remove it,
   // or make SetAntialiasMode set cairo text antialiasing too.
   switch (mFrame->StyleSVG()->mTextRendering) {
@@ -2909,30 +2904,30 @@ SVGTextDrawPathCallbacks::HandleTextGeom
     // Normal painting.
     gfxContextMatrixAutoSaveRestore saveMatrix(gfx);
     gfx->SetMatrix(mCanvasTM);
 
     FillAndStrokeGeometry();
   }
 }
 
-bool
-SVGTextDrawPathCallbacks::SetFillColor()
+already_AddRefed<gfxPattern>
+SVGTextDrawPathCallbacks::MakeFillPattern()
 {
   if (mColor == NS_SAME_AS_FOREGROUND_COLOR ||
       mColor == NS_40PERCENT_FOREGROUND_COLOR) {
-    return nsSVGUtils::SetupCairoFillPaint(mFrame, gfx);
+    return nsSVGUtils::MakeFillPatternFor(mFrame, gfx);
   }
 
   if (mColor == NS_TRANSPARENT) {
-    return false;
-  }
-
-  gfx->SetColor(gfxRGBA(mColor));
-  return true;
+    return nullptr;
+  }
+
+  nsRefPtr<gfxPattern> pattern = new gfxPattern(gfxRGBA(mColor));
+  return pattern.forget();
 }
 
 void
 SVGTextDrawPathCallbacks::FillAndStrokeGeometry()
 {
   bool pushedGroup = false;
   if (mColor == NS_40PERCENT_FOREGROUND_COLOR) {
     pushedGroup = true;
@@ -2963,17 +2958,20 @@ SVGTextDrawPathCallbacks::FillAndStrokeG
     gfx->PopGroupToSource();
     gfx->Paint(0.4);
   }
 }
 
 void
 SVGTextDrawPathCallbacks::FillGeometry()
 {
-  if (SetFillColor()) {
+  nsRefPtr<gfxPattern> fillPattern = MakeFillPattern();
+  if (fillPattern) {
+    gfx->SetPattern(fillPattern);
+    gfx->SetFillRule(nsSVGUtils::ThebesFillRule(mFrame->StyleSVG()->mFillRule));
     gfx->Fill();
   }
 }
 
 void
 SVGTextDrawPathCallbacks::StrokeGeometry()
 {
   if (mColor == NS_SAME_AS_FOREGROUND_COLOR ||
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -363,20 +363,25 @@ nsFilterInstance::BuildSourcePaint(Sourc
 
   if (!mPaintTransform.IsSingular()) {
     nsRefPtr<gfxContext> gfx = new gfxContext(offscreenDT);
     gfx->Save();
     gfx->Multiply(mPaintTransform *
                   deviceToFilterSpace *
                   gfxMatrix::Translation(-neededRect.TopLeft()));
     gfx->Rectangle(FilterSpaceToUserSpace(neededRect));
-    if ((aSource == &mFillPaint &&
-         nsSVGUtils::SetupCairoFillPaint(mTargetFrame, gfx)) ||
-        (aSource == &mStrokePaint &&
-         nsSVGUtils::SetupCairoStrokePaint(mTargetFrame, gfx))) {
+    if (aSource == &mFillPaint) {
+      nsRefPtr<gfxPattern> fillPattern =
+        nsSVGUtils::MakeFillPatternFor(mTargetFrame, gfx);
+      if (fillPattern) {
+        gfx->SetPattern(fillPattern);
+        gfx->Fill();
+      }
+    } else if (aSource == &mStrokePaint &&
+               nsSVGUtils::SetupCairoStrokePaint(mTargetFrame, gfx)) {
       gfx->Fill();
     }
     gfx->Restore();
   }
 
 
   aSource->mSourceSurface = offscreenDT->Snapshot();
   aSource->mSurfaceRect = ToIntRect(neededRect);
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -680,19 +680,24 @@ nsSVGPathGeometryFrame::Render(nsRenderi
 
   gfxContextAutoSaveRestore autoSaveRestore(gfx);
 
   GeneratePath(gfx, ToMatrix(aTransform));
 
   gfxTextContextPaint *contextPaint =
     (gfxTextContextPaint*)aContext->GetDrawTarget()->GetUserData(&gfxTextContextPaint::sUserDataKey);
 
-  if ((aRenderComponents & eRenderFill) &&
-      nsSVGUtils::SetupCairoFillPaint(this, gfx, contextPaint)) {
-    gfx->Fill();
+  if ((aRenderComponents & eRenderFill)) {
+    nsRefPtr<gfxPattern> fillPattern =
+      nsSVGUtils::MakeFillPatternFor(this, gfx, contextPaint);
+    if (fillPattern) {
+      gfx->SetPattern(fillPattern);
+      gfx->SetFillRule(nsSVGUtils::ThebesFillRule(StyleSVG()->mFillRule));
+      gfx->Fill();
+    }
   }
 
   if ((aRenderComponents & eRenderStroke) &&
        nsSVGUtils::SetupCairoStroke(this, gfx, contextPaint)) {
     gfx->Stroke();
   }
 
   gfx->NewPath();
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1284,49 +1284,70 @@ nsSVGUtils::SetupContextPaint(gfxContext
     return false;
   }
 
   aContext->SetPattern(pattern);
 
   return true;
 }
 
-bool
-nsSVGUtils::SetupCairoFillPaint(nsIFrame *aFrame, gfxContext* aContext,
-                                gfxTextContextPaint *aContextPaint)
+/* static */ already_AddRefed<gfxPattern>
+nsSVGUtils::MakeFillPatternFor(nsIFrame *aFrame,
+                               gfxContext* aContext,
+                               gfxTextContextPaint *aContextPaint)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
-  if (style->mFill.mType == eStyleSVGPaintType_None)
-    return false;
-
-  if (style->mFillRule == NS_STYLE_FILL_RULE_EVENODD)
-    aContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
-  else
-    aContext->SetFillRule(gfxContext::FILL_RULE_WINDING);
+  if (style->mFill.mType == eStyleSVGPaintType_None) {
+    return nullptr;
+  }
 
   float opacity = MaybeOptimizeOpacity(aFrame,
                                        GetOpacity(style->mFillOpacitySource,
                                                   style->mFillOpacity,
                                                   aContextPaint));
+  nsRefPtr<gfxPattern> pattern;
+
   nsSVGPaintServerFrame *ps =
-    nsSVGEffects::GetPaintServer(aFrame, &style->mFill, nsSVGEffects::FillProperty());
-  if (ps && ps->SetupPaintServer(aContext, aFrame, &nsStyleSVG::mFill, opacity))
-    return true;
+    nsSVGEffects::GetPaintServer(aFrame, &style->mFill,
+                                 nsSVGEffects::FillProperty());
+  if (ps) {
+    pattern = ps->GetPaintServerPattern(aFrame, aContext->CurrentMatrix(),
+                                        &nsStyleSVG::mFill, opacity);
+    if (pattern) {
+      pattern->CacheColorStops(aContext->GetDrawTarget());
+      return pattern.forget();
+    }
+  }
 
-  if (SetupContextPaint(aContext, aContextPaint, style->mFill, opacity)) {
-    return true;
+  if (aContextPaint) {
+    switch (style->mFill.mType) {
+    case eStyleSVGPaintType_ContextFill:
+      pattern = aContextPaint->GetFillPattern(opacity, aContext->CurrentMatrix());
+      break;
+    case eStyleSVGPaintType_ContextStroke:
+      pattern = aContextPaint->GetStrokePattern(opacity, aContext->CurrentMatrix());
+      break;
+    default:
+      ;
+    }
+    if (pattern) {
+      return pattern.forget();
+    }
   }
 
   // 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
-  SetupFallbackOrPaintColor(aContext, aFrame->StyleContext(),
-                            &nsStyleSVG::mFill, opacity);
-
-  return true;
+  nscolor color = GetFallbackOrPaintColor(aContext, aFrame->StyleContext(),
+                                          &nsStyleSVG::mFill);
+  pattern = new gfxPattern(gfxRGBA(NS_GET_R(color)/255.0,
+                                   NS_GET_G(color)/255.0,
+                                   NS_GET_B(color)/255.0,
+                                   NS_GET_A(color)/255.0 * opacity));
+  return pattern.forget();
 }
 
 bool
 nsSVGUtils::SetupCairoStrokePaint(nsIFrame *aFrame, gfxContext* aContext,
                                   gfxTextContextPaint *aContextPaint)
 {
   const nsStyleSVG* style = aFrame->StyleSVG();
   if (style->mStroke.mType == eStyleSVGPaintType_None)
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -509,22 +509,20 @@ public:
   /**
    * Set up cairo context with an object pattern
    */
   static bool SetupContextPaint(gfxContext *aContext,
                                 gfxTextContextPaint *aContextPaint,
                                 const nsStyleSVGPaint& aPaint,
                                 float aOpacity);
 
-  /**
-   * Sets the current paint on the specified gfxContent to be the SVG 'fill'
-   * for the given frame.
-   */
-  static bool SetupCairoFillPaint(nsIFrame* aFrame, gfxContext* aContext,
-                                  gfxTextContextPaint *aContextPaint = nullptr);
+  static already_AddRefed<gfxPattern>
+  MakeFillPatternFor(nsIFrame *aFrame,
+                     gfxContext* aContext,
+                     gfxTextContextPaint *aContextPaint = nullptr);
 
   /**
    * Sets the current paint on the specified gfxContent to be the SVG 'stroke'
    * for the given frame.
    */
   static bool SetupCairoStrokePaint(nsIFrame* aFrame, gfxContext* aContext,
                                     gfxTextContextPaint *aContextPaint = nullptr);
 
@@ -565,16 +563,21 @@ public:
   /**
    * 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.
    */
   static uint16_t GetGeometryHitTestFlags(nsIFrame* aFrame);
 
+  static gfxContext::FillRule ThebesFillRule(uint8_t aFillRule) {
+    return aFillRule == NS_STYLE_FILL_RULE_EVENODD ?
+             gfxContext::FILL_RULE_EVEN_ODD : gfxContext::FILL_RULE_WINDING;
+  }
+
   /**
    * Render a SVG glyph.
    * @param aElement the SVG glyph element to render
    * @param aContext the thebes aContext to draw to
    * @param aDrawMode fill or stroke or both (see DrawMode)
    * @return true if rendering succeeded
    */
   static bool PaintSVGGlyph(Element* aElement, gfxContext* aContext,