diff --git a/dom/svg/test/mochitest.ini b/dom/svg/test/mochitest.ini
index 3ecfed0e666..8cd2244ef83 100644
--- a/dom/svg/test/mochitest.ini
+++ b/dom/svg/test/mochitest.ini
@@ -34,6 +34,7 @@ support-files =
[test_animLengthUnits.xhtml]
[test_bbox-with-invalid-viewBox.xhtml]
[test_bbox.xhtml]
+[test_bbox-changes.xhtml]
[test_bounds.html]
[test_bug872812.html]
[test_getBBox-method.html]
diff --git a/dom/svg/test/test_bbox-changes.xhtml b/dom/svg/test/test_bbox-changes.xhtml
new file mode 100644
index 00000000000..502f6a2c967
--- /dev/null
+++ b/dom/svg/test/test_bbox-changes.xhtml
@@ -0,0 +1,78 @@
+
+
+
+
+ Test that the results of getBBox update for changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp
index 4344208a386..2dc0f7ba206 100644
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -778,6 +778,9 @@ nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
if (!aFrame->GetContent()->IsElement())
return;
+ // If the rendering has changed, the bounds may well have changed too:
+ aFrame->Properties().Delete(nsSVGUtils::ObjectBoundingBoxProperty());
+
nsSVGRenderingObserverList *observerList =
GetObserverList(aFrame->GetContent()->AsElement());
if (observerList) {
@@ -802,6 +805,12 @@ nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame)
void
nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags /* = 0 */)
{
+ nsIFrame* frame = aElement->GetPrimaryFrame();
+ if (frame) {
+ // If the rendering has changed, the bounds may well have changed too:
+ frame->Properties().Delete(nsSVGUtils::ObjectBoundingBoxProperty());
+ }
+
if (aElement->HasRenderingObservers()) {
nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
if (observerList) {
diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp
index 5bd9574a8ff..9fe3f1de180 100644
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -903,6 +903,17 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
!static_cast(content)->HasValidDimensions()) {
return bbox;
}
+
+ FrameProperties props = aFrame->Properties();
+
+ if (aFlags == eBBoxIncludeFillGeometry) {
+ gfxRect* prop =
+ static_cast(props.Get(ObjectBoundingBoxProperty()));
+ if (prop) {
+ return *prop;
+ }
+ }
+
gfxMatrix matrix;
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame ||
aFrame->GetType() == nsGkAtoms::svgUseFrame) {
@@ -971,6 +982,13 @@ nsSVGUtils::GetBBox(nsIFrame *aFrame, uint32_t aFlags)
bbox = gfxRect(0, 0, 0, 0);
}
}
+
+ if (aFlags == eBBoxIncludeFillGeometry) {
+ // Obtaining the bbox for objectBoundingBox calculations is common so we
+ // cache the result for future calls, since calculation can be expensive:
+ props.Set(ObjectBoundingBoxProperty(), new gfxRect(bbox));
+ }
+
return bbox;
}
return nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
diff --git a/layout/svg/nsSVGUtils.h b/layout/svg/nsSVGUtils.h
index ab3009de61b..70ba3fa450b 100644
--- a/layout/svg/nsSVGUtils.h
+++ b/layout/svg/nsSVGUtils.h
@@ -21,6 +21,7 @@
#include "nsColor.h"
#include "nsCOMPtr.h"
#include "nsID.h"
+#include "nsIFrame.h"
#include "nsISupportsBase.h"
#include "nsMathUtils.h"
#include "nsStyleStruct.h"
@@ -179,12 +180,20 @@ class nsSVGUtils
{
public:
typedef mozilla::dom::Element Element;
+ typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor;
typedef mozilla::gfx::AntialiasMode AntialiasMode;
typedef mozilla::gfx::FillRule FillRule;
typedef mozilla::gfx::GeneralPattern GeneralPattern;
static void Init();
+ static void DestroyObjectBoundingBoxProperty(void* aPropertyValue) {
+ delete static_cast(aPropertyValue);
+ }
+
+ NS_DECLARE_FRAME_PROPERTY(ObjectBoundingBoxProperty,
+ DestroyObjectBoundingBoxProperty);
+
/**
* Gets the nearest nsSVGInnerSVGFrame or nsSVGOuterSVGFrame frame. aFrame
* must be an SVG frame. If aFrame is of type nsGkAtoms::svgOuterSVGFrame,
@@ -394,6 +403,8 @@ public:
* aFrame's userspace.
*/
static gfxRect GetBBox(nsIFrame *aFrame,
+ // If the default arg changes, update the handling for
+ // ObjectBoundingBoxProperty() in the implementation.
uint32_t aFlags = eBBoxIncludeFillGeometry);
/*