Bug 931769, part 3 - Move MaxExpansion() from nsSVGUtils to nsSVGPatternFrame, and convert it to Moz2D. r=dholbert
authorJonathan Watt <jwatt@jwatt.org>
Tue, 29 Oct 2013 08:14:40 +0000
changeset 152607 05d9c6a32d8b32b3f2a80431c23dfd49bd9f72b3
parent 152606 6123376c20f14aa5938eeb1c7e1c6bc5794c923b
child 152608 48b467409db954ba3ed1b7feca7f28fc09adc532
push id35591
push userjwatt@jwatt.org
push dateTue, 29 Oct 2013 08:15:00 +0000
treeherdermozilla-inbound@e09fa7cac06b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs931769
milestone28.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 931769, part 3 - Move MaxExpansion() from nsSVGUtils to nsSVGPatternFrame, and convert it to Moz2D. r=dholbert
layout/svg/nsSVGPatternFrame.cpp
layout/svg/nsSVGPatternFrame.h
layout/svg/nsSVGUtils.cpp
layout/svg/nsSVGUtils.h
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -2,35 +2,38 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Main header first:
 #include "nsSVGPatternFrame.h"
 
 // Keep others in (case-insensitive) order:
+#include "gfx2DGlue.h"
 #include "gfxContext.h"
 #include "gfxMatrix.h"
 #include "gfxPattern.h"
 #include "gfxPlatform.h"
+#include "mozilla/gfx/2D.h"
 #include "nsContentUtils.h"
 #include "nsGkAtoms.h"
 #include "nsISVGChildFrame.h"
 #include "nsRenderingContext.h"
 #include "nsStyleContext.h"
 #include "nsSVGEffects.h"
 #include "nsSVGGeometryFrame.h"
 #include "mozilla/dom/SVGPatternElement.h"
 #include "nsSVGUtils.h"
 #include "nsSVGAnimatedTransformList.h"
 #include "SVGContentUtils.h"
 #include "gfxColor.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::gfx;
 
 //----------------------------------------------------------------------
 // Helper classes
 
 class nsSVGPatternFrame::AutoPatternReferencer
 {
 public:
   AutoPatternReferencer(nsSVGPatternFrame *aFrame)
@@ -135,16 +138,33 @@ nsSVGPatternFrame::GetCanvasTM(uint32_t 
   // We get here when geometry in the <pattern> container is updated
   return gfxMatrix();
 }
 
 // -------------------------------------------------------------------------
 // Helper functions
 // -------------------------------------------------------------------------
 
+/** Calculate the maximum expansion of a matrix */
+static float
+MaxExpansion(const Matrix &aMatrix)
+{
+  // maximum expansion derivation from
+  // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
+  // and also implemented in cairo_matrix_transformed_circle_major_axis
+  double a = aMatrix._11;
+  double b = aMatrix._12;
+  double c = aMatrix._21;
+  double d = aMatrix._22;
+  double f = (a * a + b * b + c * c + d * d) / 2;
+  double g = (a * a + b * b - c * c - d * d) / 2;
+  double h = a * c + b * d;
+  return sqrt(f + sqrt(g * g + h * h));
+}
+
 // The SVG specification says that the 'patternContentUnits' attribute "has no effect if
 // attribute ‘viewBox’ is specified". We still need to include a bbox scale
 // if the viewBox is specified and _patternUnits_ is set to or defaults to
 // objectBoundingBox though, since in that case the viewBox is relative to the bbox
 static bool
 IncludeBBoxScale(const nsSVGViewBox& aViewBox,
                  uint32_t aPatternContentUnits, uint32_t aPatternUnits)
 {
@@ -156,55 +176,55 @@ IncludeBBoxScale(const nsSVGViewBox& aVi
 
 // Given the matrix for the pattern element's own transform, this returns a
 // combined matrix including the transforms applicable to its target.
 static gfxMatrix
 GetPatternMatrix(uint16_t aPatternUnits,
                  const gfxMatrix &patternTransform,
                  const gfxRect &bbox,
                  const gfxRect &callerBBox,
-                 const gfxMatrix &callerCTM)
+                 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 / nsSVGUtils::MaxExpansion(callerCTM);
+  float scale = 1.0f / MaxExpansion(callerCTM);
   gfxMatrix patternMatrix = patternTransform;
   patternMatrix.Scale(scale, scale);
   patternMatrix.Translate(gfxPoint(minx, miny));
 
   return patternMatrix;
 }
 
 static nsresult
 GetTargetGeometry(gfxRect *aBBox,
                   const nsSVGViewBox &aViewBox,
                   uint16_t aPatternContentUnits,
                   uint16_t aPatternUnits,
                   nsIFrame *aTarget,
-                  const gfxMatrix &aContextMatrix,
+                  const Matrix &aContextMatrix,
                   const gfxRect *aOverrideBounds)
 {
   *aBBox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aTarget);
 
   // Sanity check
   if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits) &&
       (aBBox->Width() <= 0 || aBBox->Height() <= 0)) {
     return NS_ERROR_FAILURE;
   }
 
   // OK, now fix up the bounding box to reflect user coordinates
   // We handle device unit scaling in pattern matrix
-  float scale = nsSVGUtils::MaxExpansion(aContextMatrix);
+  float scale = MaxExpansion(aContextMatrix);
   if (scale <= 0) {
     return NS_ERROR_FAILURE;
   }
   aBBox->Scale(scale);
   return NS_OK;
 }
 
 nsresult
@@ -262,54 +282,54 @@ 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,
-                                  aContextMatrix,
+                                  ToMatrix(aContextMatrix),
                                   aOverrideBounds)))
     return NS_ERROR_FAILURE;
 
   // 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);
+                               callerBBox, ToMatrix(aContextMatrix), aSource);
   if (ctm.IsSingular()) {
     return NS_ERROR_FAILURE;
   }
 
   // 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, aContextMatrix, aSource);
+  gfxRect bbox = GetPatternRect(patternUnits, callerBBox, ToMatrix(aContextMatrix), aSource);
 
   // Get the pattern transform
   gfxMatrix patternTransform = GetPatternTransform();
 
   // revert the vector effect transform so that the pattern appears unchanged
   if (aFillOrStroke == &nsStyleSVG::mStroke) {
     patternTransform.Multiply(nsSVGUtils::GetStrokeTransform(aSource).Invert());
   }
 
   // Get the transformation matrix that we will hand to the renderer's pattern
   // routine.
   *patternMatrix = GetPatternMatrix(patternUnits, patternTransform,
-                                    bbox, callerBBox, aContextMatrix);
+                                    bbox, callerBBox, ToMatrix(aContextMatrix));
   if (patternMatrix->IsSingular()) {
     return NS_ERROR_FAILURE;
   }
 
   // Now that we have all of the necessary geometries, we can
   // create our surface.
   gfxRect transformedBBox = patternTransform.TransformBounds(bbox);
 
@@ -569,17 +589,17 @@ nsSVGPatternFrame::GetReferencedPatternI
   }
 
   return referenced;
 }
 
 gfxRect
 nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits,
                                   const gfxRect &aTargetBBox,
-                                  const gfxMatrix &aTargetCTM,
+                                  const Matrix &aTargetCTM,
                                   nsIFrame *aTarget)
 {
   // We need to initialize our box
   float x,y,width,height;
 
   // Get the pattern x,y,width, and height
   const nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
   tmpX = GetLengthValue(SVGPatternElement::ATTR_X);
@@ -588,46 +608,46 @@ nsSVGPatternFrame::GetPatternRect(uint16
   tmpWidth = GetLengthValue(SVGPatternElement::ATTR_WIDTH);
 
   if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     x = nsSVGUtils::ObjectSpace(aTargetBBox, tmpX);
     y = nsSVGUtils::ObjectSpace(aTargetBBox, tmpY);
     width = nsSVGUtils::ObjectSpace(aTargetBBox, tmpWidth);
     height = nsSVGUtils::ObjectSpace(aTargetBBox, tmpHeight);
   } else {
-    float scale = nsSVGUtils::MaxExpansion(aTargetCTM);
+    float scale = MaxExpansion(aTargetCTM);
     x = nsSVGUtils::UserSpace(aTarget, tmpX) * scale;
     y = nsSVGUtils::UserSpace(aTarget, tmpY) * scale;
     width = nsSVGUtils::UserSpace(aTarget, tmpWidth) * scale;
     height = nsSVGUtils::UserSpace(aTarget, tmpHeight) * scale;
   }
 
   return gfxRect(x, y, width, height);
 }
 
 gfxMatrix
 nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox,
                                 uint16_t aPatternContentUnits,
                                 uint16_t aPatternUnits,
                                 const gfxRect &callerBBox,
-                                const gfxMatrix &callerCTM,
+                                const Matrix &callerCTM,
                                 nsIFrame *aTarget)
 {
   gfxMatrix tCTM;
   SVGSVGElement *ctx = nullptr;
   nsIContent* targetContent = aTarget->GetContent();
 
   // The objectBoundingBox conversion must be handled in the CTM:
   if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits)) {
     tCTM.Scale(callerBBox.Width(), callerBBox.Height());
   } else {
     if (targetContent->IsSVG()) {
       ctx = static_cast<nsSVGElement*>(targetContent)->GetCtx();
     }
-    float scale = nsSVGUtils::MaxExpansion(callerCTM);
+    float scale = MaxExpansion(callerCTM);
     tCTM.Scale(scale, scale);
   }
 
   if (!aViewBox.IsExplicitlySet()) {
     return tCTM;
   }
   const nsSVGViewBoxRect viewBoxRect = aViewBox.GetAnimValue();
 
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * 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 "nsSVGPaintServerFrame.h"
 
 class gfxASurface;
 class gfxContext;
 class nsIFrame;
 class nsSVGElement;
 class nsSVGLength2;
 class nsSVGViewBox;
@@ -25,16 +26,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::Matrix Matrix;
+
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
                                          nsStyleContext* aContext);
 
   nsSVGPatternFrame(nsStyleContext* aContext);
 
@@ -112,23 +115,23 @@ protected:
                         const gfxMatrix &aContextMatrix,
                         nsIFrame *aSource,
                         nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
                         float aGraphicOpacity,
                         const gfxRect *aOverrideBounds);
   nsIFrame*  GetPatternFirstChild();
   gfxRect    GetPatternRect(uint16_t aPatternUnits,
                             const gfxRect &bbox,
-                            const gfxMatrix &callerCTM,
+                            const Matrix &callerCTM,
                             nsIFrame *aTarget);
   gfxMatrix  ConstructCTM(const nsSVGViewBox& aViewBox,
                           uint16_t aPatternContentUnits,
                           uint16_t aPatternUnits,
                           const gfxRect &callerBBox,
-                          const gfxMatrix &callerCTM,
+                          const Matrix &callerCTM,
                           nsIFrame *aTarget);
 
 private:
   // this is a *temporary* reference to the frame of the element currently
   // referencing our pattern.  This must be temporary because different
   // referencing frames will all reference this one frame
   nsSVGGeometryFrame               *mSource;
   nsAutoPtr<gfxMatrix>              mCTM;
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -1290,32 +1290,16 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame 
   if (style->mFill.mType == eStyleSVGPaintType_None ||
       style->mFillOpacity <= 0 ||
       !HasStroke(aFrame)) {
     return true;
   }
   return false;
 }
 
-float
-nsSVGUtils::MaxExpansion(const gfxMatrix &aMatrix)
-{
-  // maximum expansion derivation from
-  // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
-  // and also implemented in cairo_matrix_transformed_circle_major_axis
-  double a = aMatrix.xx;
-  double b = aMatrix.yx;
-  double c = aMatrix.xy;
-  double d = aMatrix.yy;
-  double f = (a * a + b * b + c * c + d * d) / 2;
-  double g = (a * a + b * b - c * c - d * d) / 2;
-  double h = a * c + b * d;
-  return sqrt(f + sqrt(g * g + h * h));
-}
-
 gfxMatrix
 nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix &aMatrix,
                                  nsSVGEnum *aUnits,
                                  nsIFrame *aFrame)
 {
   if (aFrame &&
       aUnits->GetAnimValue() == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     gfxRect bbox = GetBBox(aFrame);
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -502,20 +502,16 @@ public:
   /* Using group opacity instead of fill or stroke opacity on a
    * geometry object seems to be a common authoring mistake.  If we're
    * not applying filters and not both stroking and filling, we can
    * generate the same result without going through the overhead of a
    * push/pop group. */
   static bool
   CanOptimizeOpacity(nsIFrame *aFrame);
 
-  /* Calculate the maximum expansion of a matrix */
-  static float
-  MaxExpansion(const gfxMatrix &aMatrix);
-
   /**
    * Take the CTM to userspace for an element, and adjust it to a CTM to its
    * object bounding box space if aUnits is SVG_UNIT_TYPE_OBJECTBOUNDINGBOX.
    * (I.e. so that [0,0] is at the top left of its bbox, and [1,1] is at the
    * bottom right of its bbox).
    *
    * If the bbox is empty, this will return a singular matrix.
    */