Bug 932198 - Convert nsSVGPatternFrame from using gfxASurface to using Moz2D APIs. r=longsonr, a=lmandel
authorJonathan Watt <jwatt@jwatt.org>
Wed, 18 Jun 2014 01:07:21 +0100
changeset 208378 c2830085b9e92c09ed2d53dae1f8449bb6cb8b83
parent 208377 b6fe1fea0b30ef3ed438887beb3184c82f18c8f7
child 208379 006afc4e12202a8892ddeec543c0fdd1eb74197e
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslongsonr, lmandel
bugs932198
milestone32.0a2
Bug 932198 - Convert nsSVGPatternFrame from using gfxASurface to using Moz2D APIs. r=longsonr, a=lmandel
layout/reftests/text-svgglyphs/reftest.list
layout/svg/nsSVGPatternFrame.cpp
layout/svg/nsSVGPatternFrame.h
--- a/layout/reftests/text-svgglyphs/reftest.list
+++ b/layout/reftests/text-svgglyphs/reftest.list
@@ -5,19 +5,19 @@ pref(gfx.font_rendering.opentype_svg.ena
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-positioning.svg svg-glyph-positioning-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-html.html svg-glyph-html-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-direct.svg svg-glyph-direct-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-invalid.html svg-glyph-invalid-ref.html
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-objectfill-solid.svg svg-glyph-objectfill-solid-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-objectstroke-solid.svg svg-glyph-objectstroke-solid-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy(1,6) == svg-glyph-objectgradient.svg svg-glyph-objectgradient-ref.svg # see bug 871961#c5
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-objectgradient-zoom.svg svg-glyph-objectgradient-zoom-ref.svg
-pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-objectpattern.svg svg-glyph-objectpattern-ref.svg
+pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(gtk2Widget,1,1438) fuzzy-if(winWidget,1,1954) fuzzy-if(Android||B2G,8,3795) == svg-glyph-objectpattern.svg svg-glyph-objectpattern-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == clip.html clip-ref.html
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy(1,12) == svg-glyph-objectopacity.svg svg-glyph-objectopacity-ref.svg # see bug 871961#c5
-pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-objectopacity2.svg svg-glyph-objectopacity2-ref.svg
+pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(gtk2Widget,1,2268) fuzzy-if(winWidget,1,3074) fuzzy-if(Android||B2G,5,4715) == svg-glyph-objectopacity2.svg svg-glyph-objectopacity2-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-paintnone.svg svg-glyph-paintnone-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-cachedopacity.svg svg-glyph-cachedopacity-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fuzzy-if(cocoaWidget,255,100) == svg-glyph-objectvalue.svg svg-glyph-objectvalue-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    fails == svg-glyph-mask.svg svg-glyph-mask-ref.svg # bug 872483
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-paint-server.svg svg-glyph-paint-server-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    == svg-glyph-transform.svg svg-glyph-transform-ref.svg
 pref(gfx.font_rendering.opentype_svg.enabled,true)    random-if(B2G&&browserIsRemote) == svg-glyph-extents.html svg-glyph-extents-ref.html
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -174,36 +174,36 @@ IncludeBBoxScale(const nsSVGViewBox& aVi
   return (!aViewBox.IsExplicitlySet() &&
           aPatternContentUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) ||
          (aViewBox.IsExplicitlySet() &&
           aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
 }
 
 // Given the matrix for the pattern element's own transform, this returns a
 // combined matrix including the transforms applicable to its target.
-static gfxMatrix
+static Matrix
 GetPatternMatrix(uint16_t aPatternUnits,
-                 const gfxMatrix &patternTransform,
+                 const Matrix &patternTransform,
                  const gfxRect &bbox,
                  const gfxRect &callerBBox,
                  const Matrix &callerCTM)
 {
   // We really want the pattern matrix to handle translations
   gfxFloat minx = bbox.X();
   gfxFloat miny = bbox.Y();
 
   if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     minx += callerBBox.X();
     miny += callerBBox.Y();
   }
 
   float scale = 1.0f / MaxExpansion(callerCTM);
-  gfxMatrix patternMatrix = patternTransform;
+  Matrix patternMatrix = patternTransform;
   patternMatrix.Scale(scale, scale);
-  patternMatrix.Translate(gfxPoint(minx, miny));
+  patternMatrix.Translate(minx, miny);
 
   return patternMatrix;
 }
 
 static nsresult
 GetTargetGeometry(gfxRect *aBBox,
                   const nsSVGViewBox &aViewBox,
                   uint16_t aPatternContentUnits,
@@ -225,42 +225,41 @@ GetTargetGeometry(gfxRect *aBBox,
   float scale = MaxExpansion(aContextMatrix);
   if (scale <= 0) {
     return NS_ERROR_FAILURE;
   }
   aBBox->Scale(scale);
   return NS_OK;
 }
 
-nsresult
-nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
-                                gfxMatrix* patternMatrix,
-                                const gfxMatrix &aContextMatrix,
+TemporaryRef<SourceSurface>
+nsSVGPatternFrame::PaintPattern(Matrix* patternMatrix,
+                                const Matrix &aContextMatrix,
                                 nsIFrame *aSource,
                                 nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                                 float aGraphicOpacity,
                                 const gfxRect *aOverrideBounds)
 {
   /*
    * 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
    *    Get our children (we may need to get them from another Pattern)
    *    Call SVGPaint on all of our children
    *    Return
    */
-  *surface = nullptr;
 
   // Get the first child of the pattern data we will render
   nsIFrame* firstKid = GetPatternFirstChild();
-  if (!firstKid)
-    return NS_ERROR_FAILURE; // Either no kids or a bad reference
+  if (!firstKid) {
+    return nullptr; // Either no kids or a bad reference
+  }
 
   const nsSVGViewBox& viewBox = GetViewBox();
 
   uint16_t patternContentUnits =
     GetEnumValue(SVGPatternElement::PATTERNCONTENTUNITS);
   uint16_t patternUnits =
     GetEnumValue(SVGPatternElement::PATTERNUNITS);
 
@@ -285,73 +284,80 @@ nsSVGPatternFrame::PaintPattern(gfxASurf
 
   // Get all of the information we need from our "caller" -- i.e.
   // the geometry that is being rendered with a pattern
   gfxRect callerBBox;
   if (NS_FAILED(GetTargetGeometry(&callerBBox,
                                   viewBox,
                                   patternContentUnits, patternUnits,
                                   aSource,
-                                  ToMatrix(aContextMatrix),
-                                  aOverrideBounds)))
-    return NS_ERROR_FAILURE;
+                                  aContextMatrix,
+                                  aOverrideBounds))) {
+    return nullptr;
+  }
 
   // Construct the CTM that we will provide to our children when we
   // render them into the tile.
   gfxMatrix ctm = ConstructCTM(viewBox, patternContentUnits, patternUnits,
-                               callerBBox, ToMatrix(aContextMatrix), aSource);
+                               callerBBox, aContextMatrix, aSource);
   if (ctm.IsSingular()) {
-    return NS_ERROR_FAILURE;
+    return nullptr;
   }
 
   // Get the pattern we are going to render
   nsSVGPatternFrame *patternFrame =
     static_cast<nsSVGPatternFrame*>(firstKid->GetParent());
   if (patternFrame->mCTM) {
     *patternFrame->mCTM = ctm;
   } else {
     patternFrame->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, ToMatrix(aContextMatrix), aSource);
+  gfxRect bbox = GetPatternRect(patternUnits, callerBBox, aContextMatrix, aSource);
   if (bbox.Width() <= 0.0 || bbox.Height() <= 0.0) {
-    return NS_ERROR_FAILURE;
+    return nullptr;
   }
 
   // Get the pattern transform
-  gfxMatrix patternTransform = GetPatternTransform();
+  Matrix patternTransform = ToMatrix(GetPatternTransform());
 
   // revert the vector effect transform so that the pattern appears unchanged
   if (aFillOrStroke == &nsStyleSVG::mStroke) {
-    patternTransform.Multiply(nsSVGUtils::GetStrokeTransform(aSource).Invert());
+    Matrix strokeTransform = ToMatrix(nsSVGUtils::GetStrokeTransform(aSource).Invert());
+    if (strokeTransform.IsSingular()) {
+      NS_WARNING("Should we get here if the stroke transform is singular?");
+      return nullptr;
+    }
+    patternTransform *= strokeTransform;
   }
 
   // Get the transformation matrix that we will hand to the renderer's pattern
   // routine.
   *patternMatrix = GetPatternMatrix(patternUnits, patternTransform,
-                                    bbox, callerBBox, ToMatrix(aContextMatrix));
+                                    bbox, callerBBox, aContextMatrix);
   if (patternMatrix->IsSingular()) {
-    return NS_ERROR_FAILURE;
+    return nullptr;
   }
 
   // Now that we have all of the necessary geometries, we can
   // create our surface.
-  gfxRect transformedBBox = patternTransform.TransformBounds(bbox);
+  gfxRect transformedBBox = ThebesRect(patternTransform.TransformBounds(ToRect(bbox)));
 
   bool resultOverflows;
   IntSize surfaceSize =
     nsSVGUtils::ConvertToSurfaceSize(
       transformedBBox.Size(), &resultOverflows).ToIntSize();
 
   // 0 disables rendering, < 0 is an error
-  if (surfaceSize.width <= 0 || surfaceSize.height <= 0)
-    return NS_ERROR_FAILURE;
+  if (surfaceSize.width <= 0 || surfaceSize.height <= 0) {
+    return nullptr;
+  }
 
   gfxFloat patternWidth = bbox.Width();
   gfxFloat patternHeight = bbox.Height();
 
   if (resultOverflows ||
       patternWidth != surfaceSize.width ||
       patternHeight != surfaceSize.height) {
     // scale drawing to pattern surface size
@@ -361,24 +367,25 @@ nsSVGPatternFrame::PaintPattern(gfxASurf
                 0.0f, 0.0f);
     patternFrame->mCTM->PreMultiply(tempTM);
 
     // and rescale pattern to compensate
     patternMatrix->Scale(patternWidth / surfaceSize.width,
                          patternHeight / surfaceSize.height);
   }
 
-  nsRefPtr<gfxASurface> tmpSurface =
-    gfxPlatform::GetPlatform()->CreateOffscreenSurface(surfaceSize,
-                                                       gfxContentType::COLOR_ALPHA);
-  if (!tmpSurface || tmpSurface->CairoStatus())
-    return NS_ERROR_FAILURE;
+  RefPtr<DrawTarget> dt =
+    gfxPlatform::GetPlatform()->
+      CreateOffscreenContentDrawTarget(surfaceSize,  SurfaceFormat::B8G8R8A8);
+  if (!dt) {
+    return nullptr;
+  }
 
   nsRefPtr<nsRenderingContext> context(new nsRenderingContext());
-  context->Init(aSource->PresContext()->DeviceContext(), tmpSurface);
+  context->Init(aSource->PresContext()->DeviceContext(), dt);
   gfxContext* gfx = context->ThebesContext();
 
   // Fill with transparent black
   gfx->SetOperator(gfxContext::OPERATOR_CLEAR);
   gfx->Paint();
   gfx->SetOperator(gfxContext::OPERATOR_OVER);
 
   if (aGraphicOpacity != 1.0f) {
@@ -415,18 +422,17 @@ nsSVGPatternFrame::PaintPattern(gfxASurf
 
   if (aGraphicOpacity != 1.0f) {
     gfx->PopGroupToSource();
     gfx->Paint(aGraphicOpacity);
     gfx->Restore();
   }
 
   // caller now owns the surface
-  tmpSurface.forget(surface);
-  return NS_OK;
+  return dt->Snapshot();
 }
 
 /* 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?
 nsIFrame*
 nsSVGPatternFrame::GetPatternFirstChild()
@@ -702,33 +708,30 @@ nsSVGPatternFrame::GetPaintServerPattern
                                          const gfxRect *aOverrideBounds)
 {
   if (aGraphicOpacity == 0.0f) {
     nsRefPtr<gfxPattern> pattern = new gfxPattern(gfxRGBA(0, 0, 0, 0));
     return pattern.forget();
   }
 
   // Paint it!
-  nsRefPtr<gfxASurface> surface;
-  gfxMatrix pMatrix;
-  nsresult rv = PaintPattern(getter_AddRefs(surface), &pMatrix, aContextMatrix,
-                             aSource, aFillOrStroke, aGraphicOpacity, aOverrideBounds);
+  Matrix pMatrix;
+  RefPtr<SourceSurface> surface =
+    PaintPattern(&pMatrix, ToMatrix(aContextMatrix), aSource, aFillOrStroke,
+                 aGraphicOpacity, aOverrideBounds);
 
-  if (NS_FAILED(rv)) {
+  if (!surface) {
     return nullptr;
   }
 
-  pMatrix.Invert();
-
-  nsRefPtr<gfxPattern> pattern = new gfxPattern(surface);
+  nsRefPtr<gfxPattern> pattern = new gfxPattern(surface, pMatrix);
 
   if (!pattern || pattern->CairoStatus())
     return nullptr;
 
-  pattern->SetMatrix(pMatrix);
   pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
   return pattern.forget();
 }
 
 // -------------------------------------------------------------------------
 // Public functions
 // -------------------------------------------------------------------------
 
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NS_SVGPATTERNFRAME_H__
 #define __NS_SVGPATTERNFRAME_H__
 
 #include "mozilla/Attributes.h"
 #include "gfxMatrix.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/RefPtr.h"
 #include "nsSVGPaintServerFrame.h"
 
 class gfxASurface;
 class gfxContext;
 class nsIFrame;
 class nsSVGElement;
 class nsSVGLength2;
 class nsSVGPathGeometryFrame;
@@ -27,16 +28,18 @@ class nsSVGAnimatedTransformList;
 typedef nsSVGPaintServerFrame  nsSVGPatternFrameBase;
 
 /**
  * Patterns can refer to other patterns. We create an nsSVGPaintingProperty
  * with property type nsGkAtoms::href to track the referenced pattern.
  */
 class nsSVGPatternFrame : public nsSVGPatternFrameBase
 {
+  typedef mozilla::gfx::SourceSurface SourceSurface;
+
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
                                          nsStyleContext* aContext);
 
   nsSVGPatternFrame(nsStyleContext* aContext);
 
@@ -104,23 +107,23 @@ protected:
     return GetPreserveAspectRatio(mContent);
   }
   const nsSVGLength2 *GetLengthValue(uint32_t aIndex, nsIContent *aDefault);
   const nsSVGLength2 *GetLengthValue(uint32_t aIndex)
   {
     return GetLengthValue(aIndex, mContent);
   }
 
-  nsresult PaintPattern(gfxASurface **surface,
-                        gfxMatrix *patternMatrix,
-                        const gfxMatrix &aContextMatrix,
-                        nsIFrame *aSource,
-                        nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
-                        float aGraphicOpacity,
-                        const gfxRect *aOverrideBounds);
+  mozilla::TemporaryRef<SourceSurface>
+  PaintPattern(Matrix *patternMatrix,
+               const Matrix &aContextMatrix,
+               nsIFrame *aSource,
+               nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
+               float aGraphicOpacity,
+               const gfxRect *aOverrideBounds);
   nsIFrame*  GetPatternFirstChild();
   gfxRect    GetPatternRect(uint16_t aPatternUnits,
                             const gfxRect &bbox,
                             const Matrix &callerCTM,
                             nsIFrame *aTarget);
   gfxMatrix  ConstructCTM(const nsSVGViewBox& aViewBox,
                           uint16_t aPatternContentUnits,
                           uint16_t aPatternUnits,