Backed out changeset 2e429a8f2949 (bug 933354) for reftest failures on all platforms. a=backout
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 21 Nov 2013 07:53:33 -0500
changeset 166547 599e2ddfb6a9db399cca618ab7b8a79e3173020f
parent 166546 2e429a8f2949c8e0c1aff69eadac193133299546
child 166548 d60b630fdd37ae95427843da8093eb898be162cd
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs933354
milestone27.0a2
backs out2e429a8f2949c8e0c1aff69eadac193133299546
Backed out changeset 2e429a8f2949 (bug 933354) for reftest failures on all platforms. a=backout CLOSED TREE
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/reftests/transform/reftest.list
layout/reftests/transform/transform-origin-svg-1-ref.svg
layout/reftests/transform/transform-origin-svg-1a.svg
layout/reftests/transform/transform-origin-svg-1b.svg
layout/reftests/transform/transform-origin-svg-2-ref.svg
layout/reftests/transform/transform-origin-svg-2a.svg
layout/reftests/transform/transform-origin-svg-2b.svg
layout/svg/nsSVGTextFrame2.cpp
layout/svg/svg.css
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3827,35 +3827,37 @@ bool nsDisplayZoom::ComputeVisibility(ns
 #ifndef UNIFIED_CONTINUATIONS
 
 nsRect
 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
 {
   NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
 
   if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
-    // TODO: SVG needs to define what percentage translations resolve against.
-    return nsRect();
+    gfxRect bbox = nsSVGUtils::GetBBox(const_cast<nsIFrame*>(aFrame));
+    return nsLayoutUtils::RoundGfxRectToAppRect(bbox,
+      aFrame->PresContext()->AppUnitsPerCSSPixel()) - aFrame->GetPosition();
   }
 
   return nsRect(nsPoint(0, 0), aFrame->GetSize());
 }
 
 #else
 
 nsRect
 nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
 {
   NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
 
   nsRect result;
 
   if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
-    // TODO: SVG needs to define what percentage translations resolve against.
-    return result;
+    gfxRect bbox = nsSVGUtils::GetBBox(const_cast<nsIFrame*>(aFrame));
+    return nsLayoutUtils::RoundGfxRectToAppRect(bbox,
+      aFrame->PresContext()->AppUnitsPerCSSPixel()) - aFrame->GetPosition();
   }
 
   /* Iterate through the continuation list, unioning together all the
    * bounding rects.
    */
   for (const nsIFrame *currFrame = aFrame->FirstContinuation();
        currFrame != nullptr;
        currFrame = currFrame->GetNextContinuation())
@@ -3915,61 +3917,66 @@ nsDisplayTransform::GetDeltaToTransformO
   NS_PRECONDITION(aFrame->IsTransformed(),
                   "Shouldn't get a delta for an untransformed frame!");
 
   /* For both of the coordinates, if the value of -moz-transform is a
    * percentage, it's relative to the size of the frame.  Otherwise, if it's
    * a distance, it's already computed for us!
    */
   const nsStyleDisplay* display = aFrame->StyleDisplay();
-  nsRect boundingRect = (aBoundsOverride ? *aBoundsOverride :
-                         nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
+  nsRect boundingRect;
+  if (aBoundsOverride) {
+    boundingRect = *aBoundsOverride;
+  } else if (display->mTransformOrigin[0].GetUnit() != eStyleUnit_Coord ||
+             display->mTransformOrigin[1].GetUnit() != eStyleUnit_Coord) {
+    // GetFrameBoundsForTransform is expensive for SVG frames and we don't need
+    // it if the origin is coords (which it is by default for SVG).
+    boundingRect = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
+  }
 
   /* Allows us to access named variables by index. */
-  float coords[3];
-  const nscoord* dimensions[2] =
-    {&boundingRect.width, &boundingRect.height};
+  float coords[2];
+  nscoord boundingOffsets[2] = {boundingRect.x, boundingRect.y};
+  nscoord boundingDimensions[2] = {boundingRect.width, boundingRect.height};
+  nscoord frameOffsets[2] = {aFrame->GetPosition().x, aFrame->GetPosition().y};
 
   for (uint8_t index = 0; index < 2; ++index) {
     /* If the -moz-transform-origin specifies a percentage, take the percentage
      * of the size of the box.
      */
     const nsStyleCoord &coord = display->mTransformOrigin[index];
-    if (coord.GetUnit() == eStyleUnit_Calc) {
-      const nsStyleCoord::Calc *calc = coord.GetCalcValue();
+    if (coord.GetUnit() == eStyleUnit_Percent) {
       coords[index] =
-        NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
-          calc->mPercent +
-        NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
-    } else if (coord.GetUnit() == eStyleUnit_Percent) {
-      coords[index] =
-        NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
-        coord.GetPercentValue();
+        NSAppUnitsToFloatPixels(boundingDimensions[index], aAppUnitsPerPixel) *
+          coord.GetPercentValue() +
+        NSAppUnitsToFloatPixels(boundingOffsets[index], aAppUnitsPerPixel);
     } else {
-      NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
-      coords[index] =
-        NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
+      if (coord.GetUnit() == eStyleUnit_Calc) {
+        const nsStyleCoord::Calc *calc = coord.GetCalcValue();
+        coords[index] =
+          NSAppUnitsToFloatPixels(boundingDimensions[index], aAppUnitsPerPixel) *
+            calc->mPercent +
+          NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
+      } else {
+        NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
+        coords[index] =
+          NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
+      }
+      if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
+        // <length> values represent offsets from the origin of the SVG element's
+        // user space, not the top left of its border-box, so we must
+        // convert them to be relative to the border-box.
+        coords[index] -= NSAppUnitsToFloatPixels(frameOffsets[index], aAppUnitsPerPixel);
+      }
     }
-    if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
-        coord.GetUnit() != eStyleUnit_Percent) {
-      // <length> values represent offsets from the origin of the SVG element's
-      // user space, not the top left of its bounds, so we must adjust for that:
-      nscoord offset =
-        (index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y;
-      coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
-    }
-  }
-
-  coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
-                                      aAppUnitsPerPixel);
-  /* Adjust based on the origin of the rectangle. */
-  coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
-  coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
-
-  return gfxPoint3D(coords[0], coords[1], coords[2]);
+  }
+
+  return gfxPoint3D(coords[0], coords[1],
+                    NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
+                                            aAppUnitsPerPixel));
 }
 
 /* Returns the delta specified by the -moz-perspective-origin property.
  * This is a positive delta, meaning that it indicates the direction to move
  * to get from (0, 0) of the frame to the perspective origin. This function is
  * called off the main thread.
  */
 /* static */ gfxPoint3D
@@ -4033,26 +4040,28 @@ nsDisplayTransform::GetDeltaToPerspectiv
 }
 
 nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsIFrame* aFrame,
                                                                        float aAppUnitsPerPixel,
                                                                        const nsRect* aBoundsOverride)
   : mFrame(aFrame)
   , mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform)
   , mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
-  , mToPerspectiveOrigin(GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel))
   , mChildPerspective(0)
 {
   const nsStyleDisplay* parentDisp = nullptr;
   nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent();
   if (parentStyleContext) {
     parentDisp = parentStyleContext->StyleDisplay();
   }
   if (parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
     mChildPerspective = parentDisp->mChildPerspective.GetCoordValue();
+    if (mChildPerspective > 0.0) {
+      mToPerspectiveOrigin = GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
+    }
   }
 }
 
 /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
  * translates from local coordinate space to transform coordinate space, then
  * hands it back.
  */
 gfx3DMatrix
@@ -4142,17 +4151,17 @@ nsDisplayTransform::GetResultingTransfor
 
   if (aProperties.mChildPerspective > 0.0) {
     gfx3DMatrix perspective;
     perspective._34 =
       -1.0 / NSAppUnitsToFloatPixels(aProperties.mChildPerspective, aAppUnitsPerPixel);
     /* At the point when perspective is applied, we have been translated to the transform origin.
      * The translation to the perspective origin is the difference between these values.
      */
-    result = result * nsLayoutUtils::ChangeMatrixBasis(aProperties.mToPerspectiveOrigin - aProperties.mToTransformOrigin, perspective);
+    result = result * nsLayoutUtils::ChangeMatrixBasis(aProperties.GetToPerspectiveOrigin() - aProperties.mToTransformOrigin, perspective);
   }
 
   gfxPoint3D rounded(hasSVGTransforms ? newOrigin.x : NS_round(newOrigin.x),
                      hasSVGTransforms ? newOrigin.y : NS_round(newOrigin.y),
                      0);
 
   if (frame && frame->Preserves3D()) {
       // Include the transform set on our parent
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -3037,25 +3037,34 @@ public:
                              const nsRect* aBoundsOverride);
     FrameTransformProperties(const nsCSSValueList* aTransformList,
                              const gfxPoint3D& aToTransformOrigin,
                              const gfxPoint3D& aToPerspectiveOrigin,
                              nscoord aChildPerspective)
       : mFrame(nullptr)
       , mTransformList(aTransformList)
       , mToTransformOrigin(aToTransformOrigin)
+      , mChildPerspective(aChildPerspective)
       , mToPerspectiveOrigin(aToPerspectiveOrigin)
-      , mChildPerspective(aChildPerspective)
     {}
 
     const nsIFrame* mFrame;
     const nsCSSValueList* mTransformList;
     const gfxPoint3D mToTransformOrigin;
-    const gfxPoint3D mToPerspectiveOrigin;
     nscoord mChildPerspective;
+
+    const gfxPoint3D& GetToPerspectiveOrigin() const
+    {
+      NS_ASSERTION(mChildPerspective > 0, "Only valid with mChildPerspective > 0");
+      return mToPerspectiveOrigin;
+    }
+
+  private:
+    // mToPerspectiveOrigin is only valid if mChildPerspective > 0.
+    gfxPoint3D mToPerspectiveOrigin;
   };
 
   /**
    * Given a frame with the -moz-transform property or an SVG transform,
    * returns the transformation matrix for that frame.
    *
    * @param aFrame The frame to get the matrix from.
    * @param aOrigin Relative to which point this transform should be applied.
--- a/layout/reftests/transform/reftest.list
+++ b/layout/reftests/transform/reftest.list
@@ -119,8 +119,12 @@ skip-if(B2G) fails-if(Android) fuzzy-if(
 # Bug 722777
 == table-1a.html table-1-ref.html
 == table-1b.html table-1-ref.html
 == table-1c.html table-1-ref.html
 == table-2a.html table-2-ref.html
 == table-2b.html table-2-ref.html
 # Bug 722463
 == inline-1a.html inline-1-ref.html
+== transform-origin-svg-1a.svg transform-origin-svg-1-ref.svg
+== transform-origin-svg-1b.svg transform-origin-svg-1-ref.svg
+== transform-origin-svg-2a.svg transform-origin-svg-2-ref.svg
+== transform-origin-svg-2b.svg transform-origin-svg-2-ref.svg
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/transform-origin-svg-1-ref.svg
@@ -0,0 +1,3 @@
+<svg xmlns='http://www.w3.org/2000/svg'>
+<rect x='40' y='140' width='100' height='100' fill='lime'/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/transform-origin-svg-1a.svg
@@ -0,0 +1,6 @@
+<svg xmlns='http://www.w3.org/2000/svg'>
+<g transform="translate(30,30)">
+  <rect x='10' y='10' width='100' height='100' fill='lime'
+        style="transform:rotate(90deg); transform-origin:left bottom;"/>
+</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/transform-origin-svg-1b.svg
@@ -0,0 +1,7 @@
+<svg xmlns='http://www.w3.org/2000/svg'>
+<g transform="translate(30,30)">
+  <rect x='10' y='10' width='100' height='100' fill='lime'
+        style="transform:rotate(90deg); transform-origin:10px 110px;
+               -webkit-transform:rotate(90deg); -webkit-transform-origin:10px 110px;"/>
+</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/transform-origin-svg-2-ref.svg
@@ -0,0 +1,3 @@
+<svg xmlns='http://www.w3.org/2000/svg'>
+<rect x='40' y='140' width='100' height='100' fill='lime' stroke-width='20' stroke='blue'/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/transform-origin-svg-2a.svg
@@ -0,0 +1,6 @@
+<svg xmlns='http://www.w3.org/2000/svg'>
+<g transform="translate(30,30)">
+  <rect x='10' y='10' width='100' height='100' fill='lime' stroke-width='20' stroke='blue'
+        style="transform:rotate(90deg); transform-origin:left bottom;"/>
+</g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/transform-origin-svg-2b.svg
@@ -0,0 +1,7 @@
+<svg xmlns='http://www.w3.org/2000/svg'>
+<g transform="translate(30,30)">
+  <rect x='10' y='10' width='100' height='100' fill='lime' stroke-width='20' stroke='blue'
+        style="transform:rotate(90deg); transform-origin:10px 110px;
+               -webkit-transform:rotate(90deg); -webkit-transform-origin:10px 110px;"/>
+</g>
+</svg>
--- a/layout/svg/nsSVGTextFrame2.cpp
+++ b/layout/svg/nsSVGTextFrame2.cpp
@@ -3760,24 +3760,26 @@ nsSVGTextFrame2::ReflowSVG()
 
   if (mState & NS_FRAME_FIRST_REFLOW) {
     // Make sure we have our filter property (if any) before calling
     // FinishAndStoreOverflow (subsequent filter changes are handled off
     // nsChangeHint_UpdateEffects):
     nsSVGEffects::UpdateEffects(this);
   }
 
+  // Now unset the various reflow bits. Do this before calling
+  // FinishAndStoreOverflow since FinishAndStoreOverflow can require glyph
+  // positions (to resolve transform-origin).
+  mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
+              NS_FRAME_HAS_DIRTY_CHILDREN);
+
   nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
   nsOverflowAreas overflowAreas(overflow, overflow);
   FinishAndStoreOverflow(overflowAreas, mRect.Size());
 
-  // Now unset the various reflow bits:
-  mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
-              NS_FRAME_HAS_DIRTY_CHILDREN);
-
   // XXX nsSVGContainerFrame::ReflowSVG only looks at its nsISVGChildFrame
   // children, and calls ConsiderChildOverflow on them.  Does it matter
   // that ConsiderChildOverflow won't be called on our children?
   nsSVGTextFrame2Base::ReflowSVG();
 }
 
 /**
  * Converts nsSVGUtils::eBBox* flags into TextRenderedRun flags appropriate
--- a/layout/svg/svg.css
+++ b/layout/svg/svg.css
@@ -46,17 +46,17 @@ foreignObject {
 
 *|*::-moz-svg-foreign-content {
   display: block !important;
   /* We need to be an absolute and fixed container */
   transform: translate(0) !important;
   text-indent: 0;
 }
 
-/* Set |transform-origin:0% 0%;| for all SVG elements except outer-<svg>,
+/* Set |transform-origin:0 0;| for all SVG elements except outer-<svg>,
    noting that 'svg' as a child of 'foreignObject' counts as outer-<svg>.
 */
 *:not(svg),
 *:not(foreignObject) > svg {
   transform-origin:0 0;
 }
 
 *|*::-moz-svg-text {