Bug 489151 - Masking and clipping with objectBoundingBox and non-trivial transforms is broken. r=jwatt
authorRyo Onodera <ryoqun@gmail.com>
Fri, 24 Apr 2009 03:10:22 +0900
changeset 27686 cf138fd828e669467fb762de315bfa851af29ae2
parent 27685 72fd3bd01cbcf2863b8445fe8c819baafbc375c3
child 27687 eda6e47eb835f0de6c904f4a00e12d7b9a812cc9
push id6696
push userjwatt@jwatt.org
push dateThu, 23 Apr 2009 20:17:21 +0000
treeherdermozilla-central@cf138fd828e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs489151
milestone1.9.2a1pre
Bug 489151 - Masking and clipping with objectBoundingBox and non-trivial transforms is broken. r=jwatt
content/svg/content/src/nsSVGGraphicElement.cpp
content/svg/content/src/nsSVGSVGElement.cpp
layout/reftests/svg/objectBoundingBox-and-clipPath.svg
layout/reftests/svg/objectBoundingBox-and-mask.svg
layout/reftests/svg/reftest.list
layout/svg/base/src/nsSVGPatternFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
--- a/content/svg/content/src/nsSVGGraphicElement.cpp
+++ b/content/svg/content/src/nsSVGGraphicElement.cpp
@@ -43,16 +43,17 @@
 #include "nsGkAtoms.h"
 #include "nsSVGMatrix.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIFrame.h"
 #include "nsISVGChildFrame.h"
 #include "nsIDOMSVGPoint.h"
 #include "nsSVGUtils.h"
 #include "nsDOMError.h"
+#include "nsIDOMSVGRect.h"
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_ADDREF_INHERITED(nsSVGGraphicElement, nsSVGGraphicElementBase)
 NS_IMPL_RELEASE_INHERITED(nsSVGGraphicElement, nsSVGGraphicElementBase)
 
 NS_INTERFACE_MAP_BEGIN(nsSVGGraphicElement)
@@ -91,24 +92,18 @@ NS_IMETHODIMP nsSVGGraphicElement::GetBB
   nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
 
   if (!frame || (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
     return NS_ERROR_FAILURE;
 
   nsISVGChildFrame* svgframe = do_QueryFrame(frame);
   NS_ASSERTION(svgframe, "wrong frame type");
   if (svgframe) {
-    svgframe->SetMatrixPropagation(PR_FALSE);
-    svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
-                               nsISVGChildFrame::TRANSFORM_CHANGED);
-    nsresult rv = svgframe->GetBBox(_retval);
-    svgframe->SetMatrixPropagation(PR_TRUE);
-    svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
-                               nsISVGChildFrame::TRANSFORM_CHANGED);
-    return rv;
+    *_retval = nsSVGUtils::GetBBox(frame).get();
+    return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 /* Helper for GetCTM and GetScreenCTM */
 nsresult
 nsSVGGraphicElement::AppendLocalTransform(nsIDOMSVGMatrix *aCTM,
                                           nsIDOMSVGMatrix **_retval)
--- a/content/svg/content/src/nsSVGSVGElement.cpp
+++ b/content/svg/content/src/nsSVGSVGElement.cpp
@@ -745,24 +745,18 @@ nsSVGSVGElement::GetBBox(nsIDOMSVGRect *
 
   nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
 
   if (!frame || (frame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
     return NS_ERROR_FAILURE;
 
   nsISVGChildFrame* svgframe = do_QueryFrame(frame);
   if (svgframe) {
-    svgframe->SetMatrixPropagation(PR_FALSE);
-    svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
-                               nsISVGChildFrame::TRANSFORM_CHANGED);
-    nsresult rv = svgframe->GetBBox(_retval);
-    svgframe->SetMatrixPropagation(PR_TRUE);
-    svgframe->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
-                               nsISVGChildFrame::TRANSFORM_CHANGED);
-    return rv;
+    *_retval = nsSVGUtils::GetBBox(frame).get();
+    return NS_OK;
   } else {
     // XXX: outer svg
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 }
 
 /* nsIDOMSVGMatrix getCTM (); */
 NS_IMETHODIMP
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/objectBoundingBox-and-clipPath.svg
@@ -0,0 +1,25 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/licenses/publicdomain/
+-->
+<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=489151 -->
+
+<svg xmlns="http://www.w3.org/2000/svg">
+  <title>Test objectBoundingBox clip-path on element with ancestor transform</title>
+  <desc>
+    This test checks that the bbox calculation for an objectBoundingBox
+    clip-path is correctly getting the bbox in the userspace of the
+    clipped element, and not it's bbox in an ancestor userspace or rootspace.
+  </desc>
+  <clipPath id="clip" clipPathUnits="objectBoundingBox">
+    <rect x="0.5" width="0.5" height="1"/>
+  </clipPath>
+  <rect width="100%" height="100%" fill="lime"/>
+  <rect x="100" width="100" height="100" fill="red"/>
+  <g transform="translate(-100,0)">
+    <g clip-path="url(#clip)">
+      <rect x="100" width="100" height="100" fill="red"/>
+      <rect x="200" width="100" height="100" fill="lime"/>
+    </g>
+  </g>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/objectBoundingBox-and-mask.svg
@@ -0,0 +1,25 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/licenses/publicdomain/
+-->
+<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=489151 -->
+
+<svg xmlns="http://www.w3.org/2000/svg">
+  <title>Test objectBoundingBox mask on element with ancestor transform</title>
+  <desc>
+    This test checks that the bbox calculation for an objectBoundingBox
+    mask is correctly getting the bbox in the userspace of the masked
+    element, and not it's bbox in an ancestor userspace or rootspace.
+  </desc>
+  <mask id="mask" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
+    <rect x="0.5" width="0.5" height="1" fill="white"/>
+  </mask>
+  <rect width="100%" height="100%" fill="lime"/>
+  <rect x="100" width="100" height="100" fill="red"/>
+  <g transform="translate(-100,0)">
+    <g mask="url(#mask)">
+      <rect x="100" width="100" height="100" fill="red"/>
+      <rect x="200" width="100" height="100" fill="lime"/>
+    </g>
+  </g>
+</svg>
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -73,16 +73,18 @@ fails == inline-in-xul-basic-01.xul pass
 == image-scaling-02.svg pass.svg
 == invalid-text-01.svg pass.svg
 == linearGradient-basic-01.svg pass.svg
 == linearGradient-basic-02.svg pass.svg
 == marker-attribute-01.svg pass.svg
 # Bug 456323
 # == mask-transformed-01.svg mask-transformed-01-ref.svg
 == nested-viewBox-01.svg pass.svg
+== objectBoundingBox-and-clipPath.svg pass.svg
+== objectBoundingBox-and-mask.svg pass.svg
 == objectBoundingBox-and-pattern-01a.svg objectBoundingBox-and-pattern-01-ref.svg
 == objectBoundingBox-and-pattern-01b.svg objectBoundingBox-and-pattern-01-ref.svg
 == objectBoundingBox-and-pattern-01c.svg objectBoundingBox-and-pattern-01-ref.svg
 # skip the next test on cocoa, since behaviour depends on the -minor- version of the 10.4 OS.
 # See bugs 379610 and 432298.
 random-if(MOZ_WIDGET_TOOLKIT=="cocoa") == opacity-and-gradient-01.svg pass.svg
 == opacity-and-pattern-01.svg pass.svg
 == pseudo-classes-01.svg pass.svg
--- a/layout/svg/base/src/nsSVGPatternFrame.cpp
+++ b/layout/svg/base/src/nsSVGPatternFrame.cpp
@@ -635,32 +635,22 @@ nsSVGPatternFrame::GetCallerGeometry(nsI
                            (aSource->GetContent()->GetParent());
   } else {
     *aContent = static_cast<nsSVGElement*>(aSource->GetContent());
   }
   NS_ASSERTION(aContent,"Caller does not have any content!");
   if (!aContent)
     return NS_ERROR_FAILURE;
 
-  // Get the calling geometry's bounding box.  This
-  // will be in *device coordinates*
-  nsISVGChildFrame *callerSVGFrame;
-  if (callerType == nsGkAtoms::svgGlyphFrame)
-    callerSVGFrame = do_QueryFrame(aSource->GetParent());
-  else
-    callerSVGFrame = do_QueryFrame(aSource);
-
-  callerSVGFrame->SetMatrixPropagation(PR_FALSE);
-  callerSVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
-                                   nsISVGChildFrame::TRANSFORM_CHANGED );
-  callerSVGFrame->GetBBox(aBBox);
-  callerSVGFrame->SetMatrixPropagation(PR_TRUE);
-  callerSVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
-                                   nsISVGChildFrame::TRANSFORM_CHANGED);
-
+  if (callerType == nsGkAtoms::svgGlyphFrame) {
+    *aBBox = nsSVGUtils::GetBBox(aSource->GetParent()).get();
+  } else {
+    *aBBox = nsSVGUtils::GetBBox(aSource).get();
+  }
+  
   // Sanity check
   PRUint16 type = GetPatternUnits();
   if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     float width, height;
     (*aBBox)->GetWidth(&width);
     (*aBBox)->GetHeight(&height);
     if (width <= 0 || height <= 0) {
       return NS_ERROR_FAILURE;
--- a/layout/svg/base/src/nsSVGUtils.cpp
+++ b/layout/svg/base/src/nsSVGUtils.cpp
@@ -1397,33 +1397,23 @@ nsSVGUtils::AdjustMatrixForUnits(nsIDOMS
   nsCOMPtr<nsIDOMSVGMatrix> fini = aMatrix;
 
   if (aFrame &&
       aUnits->GetAnimValue() == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     float minx, miny, width, height;
 
     PRBool gotRect = PR_FALSE;
     if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
-      nsISVGChildFrame *svgFrame = do_QueryFrame(aFrame);
-      nsCOMPtr<nsIDOMSVGRect> rect;
-      svgFrame->GetBBox(getter_AddRefs(rect));
+      nsCOMPtr<nsIDOMSVGRect> rect = GetBBox(aFrame);
       if (rect) {
         gotRect = PR_TRUE;
         rect->GetX(&minx);
         rect->GetY(&miny);
         rect->GetWidth(&width);
         rect->GetHeight(&height);
-        // Correct for scaling in outersvg CTM
-        nsPresContext *presCtx = aFrame->PresContext();
-        float scaleInv =
-          presCtx->AppUnitsToGfxUnits(presCtx->AppUnitsPerCSSPixel());
-        minx /= scaleInv;
-        miny /= scaleInv;
-        width /= scaleInv;
-        height /= scaleInv;
       }
     } else {
       gotRect = PR_TRUE;
       gfxRect r = nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
       minx = r.X();
       miny = r.Y();
       width = r.Width();
       height = r.Height();