Bumping manifests a=b2g-bump
[gecko.git] / layout / svg / nsSVGForeignObjectFrame.cpp
blob2d55d5fe295d6fc2dce2809763633a60ba15ef24
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 // Main header first:
7 #include "nsSVGForeignObjectFrame.h"
9 // Keep others in (case-insensitive) order:
10 #include "gfxContext.h"
11 #include "nsGkAtoms.h"
12 #include "nsNameSpaceManager.h"
13 #include "nsLayoutUtils.h"
14 #include "nsRegion.h"
15 #include "nsRenderingContext.h"
16 #include "nsSVGContainerFrame.h"
17 #include "nsSVGEffects.h"
18 #include "mozilla/dom/SVGForeignObjectElement.h"
19 #include "nsSVGIntegrationUtils.h"
20 #include "nsSVGOuterSVGFrame.h"
21 #include "nsSVGUtils.h"
22 #include "mozilla/AutoRestore.h"
24 using namespace mozilla;
25 using namespace mozilla::dom;
27 //----------------------------------------------------------------------
28 // Implementation
30 nsContainerFrame*
31 NS_NewSVGForeignObjectFrame(nsIPresShell *aPresShell,
32 nsStyleContext *aContext)
34 return new (aPresShell) nsSVGForeignObjectFrame(aContext);
37 NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
39 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
40 : nsSVGForeignObjectFrameBase(aContext),
41 mInReflow(false)
43 AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
44 NS_FRAME_SVG_LAYOUT);
47 //----------------------------------------------------------------------
48 // nsIFrame methods
50 NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
51 NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
52 NS_QUERYFRAME_TAIL_INHERITING(nsSVGForeignObjectFrameBase)
54 void
55 nsSVGForeignObjectFrame::Init(nsIContent* aContent,
56 nsContainerFrame* aParent,
57 nsIFrame* aPrevInFlow)
59 NS_ASSERTION(aContent->IsSVG(nsGkAtoms::foreignObject),
60 "Content is not an SVG foreignObject!");
62 nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
63 AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
64 AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER |
65 NS_FRAME_FONT_INFLATION_FLOW_ROOT);
66 if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
67 nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
71 void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
73 // Only unregister if we registered in the first place:
74 if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
75 nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
77 nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
80 nsIAtom *
81 nsSVGForeignObjectFrame::GetType() const
83 return nsGkAtoms::svgForeignObjectFrame;
86 nsresult
87 nsSVGForeignObjectFrame::AttributeChanged(int32_t aNameSpaceID,
88 nsIAtom *aAttribute,
89 int32_t aModType)
91 if (aNameSpaceID == kNameSpaceID_None) {
92 if (aAttribute == nsGkAtoms::width ||
93 aAttribute == nsGkAtoms::height) {
94 nsSVGEffects::InvalidateRenderingObservers(this);
95 nsSVGUtils::ScheduleReflowSVG(this);
96 // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
97 RequestReflow(nsIPresShell::eStyleChange);
98 } else if (aAttribute == nsGkAtoms::x ||
99 aAttribute == nsGkAtoms::y) {
100 // make sure our cached transform matrix gets (lazily) updated
101 mCanvasTM = nullptr;
102 nsSVGEffects::InvalidateRenderingObservers(this);
103 nsSVGUtils::ScheduleReflowSVG(this);
104 } else if (aAttribute == nsGkAtoms::transform) {
105 // We don't invalidate for transform changes (the layers code does that).
106 // Also note that SVGTransformableElement::GetAttributeChangeHint will
107 // return nsChangeHint_UpdateOverflow for "transform" attribute changes
108 // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
109 mCanvasTM = nullptr;
110 } else if (aAttribute == nsGkAtoms::viewBox ||
111 aAttribute == nsGkAtoms::preserveAspectRatio) {
112 nsSVGEffects::InvalidateRenderingObservers(this);
116 return NS_OK;
119 void
120 nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
121 nsHTMLReflowMetrics& aDesiredSize,
122 const nsHTMLReflowState& aReflowState,
123 nsReflowStatus& aStatus)
125 NS_ABORT_IF_FALSE(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
126 "Should not have been called");
128 // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY,
129 // so if that bit is still set we still have a resize pending. If we hit
130 // this assertion, then we should get the presShell to skip reflow roots
131 // that have a dirty parent since a reflow is going to come via the
132 // reflow root's parent anyway.
133 NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
134 "Reflowing while a resize is pending is wasteful");
136 // ReflowSVG makes sure mRect is up to date before we're called.
138 NS_ASSERTION(!aReflowState.parentReflowState,
139 "should only get reflow from being reflow root");
140 NS_ASSERTION(aReflowState.ComputedWidth() == GetSize().width &&
141 aReflowState.ComputedHeight() == GetSize().height,
142 "reflow roots should be reflowed at existing size and "
143 "svg.css should ensure we have no padding/border/margin");
145 DoReflow();
147 WritingMode wm = aReflowState.GetWritingMode();
148 LogicalSize finalSize(wm, aReflowState.ComputedISize(),
149 aReflowState.ComputedBSize());
150 aDesiredSize.SetSize(wm, finalSize);
151 aDesiredSize.SetOverflowAreasToDesiredBounds();
152 aStatus = NS_FRAME_COMPLETE;
155 void
156 nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
157 const nsRect& aDirtyRect,
158 const nsDisplayListSet& aLists)
160 if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
161 return;
163 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
166 bool
167 nsSVGForeignObjectFrame::IsSVGTransformed(Matrix *aOwnTransform,
168 Matrix *aFromParentTransform) const
170 bool foundTransform = false;
172 // Check if our parent has children-only transforms:
173 nsIFrame *parent = GetParent();
174 if (parent &&
175 parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
176 foundTransform = static_cast<nsSVGContainerFrame*>(parent)->
177 HasChildrenOnlyTransform(aFromParentTransform);
180 nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
181 nsSVGAnimatedTransformList* transformList =
182 content->GetAnimatedTransformList();
183 if ((transformList && transformList->HasTransform()) ||
184 content->GetAnimateMotionTransform()) {
185 if (aOwnTransform) {
186 *aOwnTransform = gfx::ToMatrix(content->PrependLocalTransformsTo(gfxMatrix(),
187 nsSVGElement::eUserSpaceToParent));
189 foundTransform = true;
191 return foundTransform;
194 nsresult
195 nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
196 const nsIntRect *aDirtyRect,
197 nsIFrame* aTransformRoot)
199 NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
200 (mState & NS_FRAME_IS_NONDISPLAY),
201 "If display lists are enabled, only painting of non-display "
202 "SVG should take this code path");
204 if (IsDisabled())
205 return NS_OK;
207 nsIFrame* kid = GetFirstPrincipalChild();
208 if (!kid)
209 return NS_OK;
211 gfxMatrix canvasTM = GetCanvasTM(FOR_PAINTING, aTransformRoot);
213 if (canvasTM.IsSingular()) {
214 NS_WARNING("Can't render foreignObject element!");
215 return NS_ERROR_FAILURE;
218 nsRect kidDirtyRect = kid->GetVisualOverflowRect();
220 /* Check if we need to draw anything. */
221 if (aDirtyRect) {
222 NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
223 (mState & NS_FRAME_IS_NONDISPLAY),
224 "Display lists handle dirty rect intersection test");
225 // Transform the dirty rect into app units in our userspace.
226 gfxMatrix invmatrix = canvasTM;
227 DebugOnly<bool> ok = invmatrix.Invert();
228 NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
230 gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
231 aDirtyRect->width, aDirtyRect->height);
232 transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
234 kidDirtyRect.IntersectRect(kidDirtyRect,
235 nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect,
236 PresContext()->AppUnitsPerCSSPixel()));
238 // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
239 // not with kidDirtyRect. I.e.
240 // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
241 // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
242 if (kidDirtyRect.IsEmpty())
243 return NS_OK;
246 gfxContext *gfx = aContext->ThebesContext();
248 gfx->Save();
250 if (StyleDisplay()->IsScrollableOverflow()) {
251 float x, y, width, height;
252 static_cast<nsSVGElement*>(mContent)->
253 GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
255 gfxRect clipRect =
256 nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
257 nsSVGUtils::SetClipRect(gfx, canvasTM, clipRect);
260 // SVG paints in CSS px, but normally frames paint in dev pixels. Here we
261 // multiply a CSS-px-to-dev-pixel factor onto canvasTM so our children paint
262 // correctly.
263 float cssPxPerDevPx = PresContext()->
264 AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
265 gfxMatrix canvasTMForChildren = canvasTM;
266 canvasTMForChildren.Scale(cssPxPerDevPx, cssPxPerDevPx);
268 gfx->Multiply(canvasTMForChildren);
270 uint32_t flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
271 if (SVGAutoRenderState::IsPaintingToWindow(aContext)) {
272 flags |= nsLayoutUtils::PAINT_TO_WINDOW;
274 nsresult rv = nsLayoutUtils::PaintFrame(aContext, kid, nsRegion(kidDirtyRect),
275 NS_RGBA(0,0,0,0), flags);
277 gfx->Restore();
279 return rv;
282 nsIFrame*
283 nsSVGForeignObjectFrame::GetFrameForPoint(const gfxPoint& aPoint)
285 NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
286 (mState & NS_FRAME_IS_NONDISPLAY),
287 "If display lists are enabled, only hit-testing of a "
288 "clipPath's contents should take this code path");
290 if (IsDisabled() || (GetStateBits() & NS_FRAME_IS_NONDISPLAY))
291 return nullptr;
293 nsIFrame* kid = GetFirstPrincipalChild();
294 if (!kid)
295 return nullptr;
297 float x, y, width, height;
298 static_cast<nsSVGElement*>(mContent)->
299 GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
301 if (!gfxRect(x, y, width, height).Contains(aPoint) ||
302 !nsSVGUtils::HitTestClip(this, aPoint)) {
303 return nullptr;
306 // Convert the point to app units relative to the top-left corner of the
307 // viewport that's established by the foreignObject element:
309 gfxPoint pt = (aPoint + gfxPoint(x, y)) * nsPresContext::AppUnitsPerCSSPixel();
310 nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
312 return nsLayoutUtils::GetFrameForPoint(kid, point);
315 nsRect
316 nsSVGForeignObjectFrame::GetCoveredRegion()
318 float x, y, w, h;
319 static_cast<SVGForeignObjectElement*>(mContent)->
320 GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
321 if (w < 0.0f) w = 0.0f;
322 if (h < 0.0f) h = 0.0f;
323 // GetCanvasTM includes the x,y translation
324 return nsSVGUtils::ToCanvasBounds(gfxRect(0.0, 0.0, w, h),
325 GetCanvasTM(FOR_OUTERSVG_TM),
326 PresContext());
329 void
330 nsSVGForeignObjectFrame::ReflowSVG()
332 NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
333 "This call is probably a wasteful mistake");
335 NS_ABORT_IF_FALSE(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
336 "ReflowSVG mechanism not designed for this");
338 if (!nsSVGUtils::NeedsReflowSVG(this)) {
339 return;
342 // We update mRect before the DoReflow call so that DoReflow uses the
343 // correct dimensions:
345 float x, y, w, h;
346 static_cast<SVGForeignObjectElement*>(mContent)->
347 GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
349 // If mRect's width or height are negative, reflow blows up! We must clamp!
350 if (w < 0.0f) w = 0.0f;
351 if (h < 0.0f) h = 0.0f;
353 mRect = nsLayoutUtils::RoundGfxRectToAppRect(
354 gfxRect(x, y, w, h),
355 PresContext()->AppUnitsPerCSSPixel());
357 // Fully mark our kid dirty so that it gets resized if necessary
358 // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
359 nsIFrame* kid = GetFirstPrincipalChild();
360 kid->AddStateBits(NS_FRAME_IS_DIRTY);
362 // Make sure to not allow interrupts if we're not being reflown as a root:
363 nsPresContext::InterruptPreventer noInterrupts(PresContext());
365 DoReflow();
367 if (mState & NS_FRAME_FIRST_REFLOW) {
368 // Make sure we have our filter property (if any) before calling
369 // FinishAndStoreOverflow (subsequent filter changes are handled off
370 // nsChangeHint_UpdateEffects):
371 nsSVGEffects::UpdateEffects(this);
374 // If we have a filter, we need to invalidate ourselves because filter
375 // output can change even if none of our descendants need repainting.
376 if (StyleSVGReset()->HasFilters()) {
377 InvalidateFrame();
380 // TODO: once we support |overflow:visible| on foreignObject, then we will
381 // need to take account of our descendants here.
382 nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
383 nsOverflowAreas overflowAreas(overflow, overflow);
384 FinishAndStoreOverflow(overflowAreas, mRect.Size());
386 // Now unset the various reflow bits:
387 mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
388 NS_FRAME_HAS_DIRTY_CHILDREN);
391 void
392 nsSVGForeignObjectFrame::NotifySVGChanged(uint32_t aFlags)
394 NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
395 "Invalidation logic may need adjusting");
397 bool needNewBounds = false; // i.e. mRect or visual overflow rect
398 bool needReflow = false;
399 bool needNewCanvasTM = false;
401 if (aFlags & COORD_CONTEXT_CHANGED) {
402 SVGForeignObjectElement *fO =
403 static_cast<SVGForeignObjectElement*>(mContent);
404 // Coordinate context changes affect mCanvasTM if we have a
405 // percentage 'x' or 'y'
406 if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_X].IsPercentage() ||
407 fO->mLengthAttributes[SVGForeignObjectElement::ATTR_Y].IsPercentage()) {
408 needNewBounds = true;
409 needNewCanvasTM = true;
411 // Our coordinate context's width/height has changed. If we have a
412 // percentage width/height our dimensions will change so we must reflow.
413 if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_WIDTH].IsPercentage() ||
414 fO->mLengthAttributes[SVGForeignObjectElement::ATTR_HEIGHT].IsPercentage()) {
415 needNewBounds = true;
416 needReflow = true;
420 if (aFlags & TRANSFORM_CHANGED) {
421 if (mCanvasTM && mCanvasTM->IsSingular()) {
422 needNewBounds = true; // old bounds are bogus
424 needNewCanvasTM = true;
425 // In an ideal world we would reflow when our CTM changes. This is because
426 // glyph metrics do not necessarily scale uniformly with change in scale
427 // and, as a result, CTM changes may require text to break at different
428 // points. The problem would be how to keep performance acceptable when
429 // e.g. the transform of an ancestor is animated.
430 // We also seem to get some sort of infinite loop post bug 421584 if we
431 // reflow.
434 if (needNewBounds) {
435 // Ancestor changes can't affect how we render from the perspective of
436 // any rendering observers that we may have, so we don't need to
437 // invalidate them. We also don't need to invalidate ourself, since our
438 // changed ancestor will have invalidated its entire area, which includes
439 // our area.
440 nsSVGUtils::ScheduleReflowSVG(this);
443 // If we're called while the PresShell is handling reflow events then we
444 // must have been called as a result of the NotifyViewportChange() call in
445 // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
446 // at this point (i.e. during reflow) because it could confuse the
447 // PresShell and prevent it from reflowing us properly in future. Besides
448 // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
449 // synchronously, so there's no need.
450 if (needReflow && !PresContext()->PresShell()->IsReflowLocked()) {
451 RequestReflow(nsIPresShell::eResize);
454 if (needNewCanvasTM) {
455 // Do this after calling InvalidateAndScheduleBoundsUpdate in case we
456 // change the code and it needs to use it.
457 mCanvasTM = nullptr;
461 SVGBBox
462 nsSVGForeignObjectFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
463 uint32_t aFlags)
465 SVGForeignObjectElement *content =
466 static_cast<SVGForeignObjectElement*>(mContent);
468 float x, y, w, h;
469 content->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
471 if (w < 0.0f) w = 0.0f;
472 if (h < 0.0f) h = 0.0f;
474 if (aToBBoxUserspace.IsSingular()) {
475 // XXX ReportToConsole
476 return SVGBBox();
478 return aToBBoxUserspace.TransformBounds(gfx::Rect(0.0, 0.0, w, h));
481 //----------------------------------------------------------------------
483 gfxMatrix
484 nsSVGForeignObjectFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
486 if (!(GetStateBits() & NS_FRAME_IS_NONDISPLAY) && !aTransformRoot) {
487 if (aFor == FOR_PAINTING && NS_SVGDisplayListPaintingEnabled()) {
488 return nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(this);
491 if (!mCanvasTM) {
492 NS_ASSERTION(GetParent(), "null parent");
494 nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
495 SVGForeignObjectElement *content =
496 static_cast<SVGForeignObjectElement*>(mContent);
498 gfxMatrix tm = content->PrependLocalTransformsTo(
499 this == aTransformRoot ? gfxMatrix() :
500 parent->GetCanvasTM(aFor, aTransformRoot));
502 mCanvasTM = new gfxMatrix(tm);
504 return *mCanvasTM;
507 //----------------------------------------------------------------------
508 // Implementation helpers
510 void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
512 if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
513 // If we haven't had a ReflowSVG() yet, nothing to do.
514 return;
516 nsIFrame* kid = GetFirstPrincipalChild();
517 if (!kid)
518 return;
520 PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
523 void
524 nsSVGForeignObjectFrame::DoReflow()
526 // Skip reflow if we're zero-sized, unless this is our first reflow.
527 if (IsDisabled() &&
528 !(GetStateBits() & NS_FRAME_FIRST_REFLOW))
529 return;
531 nsPresContext *presContext = PresContext();
532 nsIFrame* kid = GetFirstPrincipalChild();
533 if (!kid)
534 return;
536 // initiate a synchronous reflow here and now:
537 nsRefPtr<nsRenderingContext> renderingContext =
538 presContext->PresShell()->CreateReferenceRenderingContext();
540 mInReflow = true;
542 WritingMode wm = kid->GetWritingMode();
543 nsHTMLReflowState reflowState(presContext, kid,
544 renderingContext,
545 LogicalSize(wm, GetLogicalSize(wm).ISize(wm),
546 NS_UNCONSTRAINEDSIZE));
547 nsHTMLReflowMetrics desiredSize(reflowState);
548 nsReflowStatus status;
550 // We don't use mRect.height above because that tells the child to do
551 // page/column breaking at that height.
552 NS_ASSERTION(reflowState.ComputedPhysicalBorderPadding() == nsMargin(0, 0, 0, 0) &&
553 reflowState.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
554 "style system should ensure that :-moz-svg-foreign-content "
555 "does not get styled");
556 NS_ASSERTION(reflowState.ComputedWidth() == mRect.width,
557 "reflow state made child wrong size");
558 reflowState.SetComputedHeight(mRect.height);
560 ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0,
561 NS_FRAME_NO_MOVE_FRAME, status);
562 NS_ASSERTION(mRect.width == desiredSize.Width() &&
563 mRect.height == desiredSize.Height(), "unexpected size");
564 FinishReflowChild(kid, presContext, desiredSize, &reflowState, 0, 0,
565 NS_FRAME_NO_MOVE_FRAME);
567 mInReflow = false;
570 nsRect
571 nsSVGForeignObjectFrame::GetInvalidRegion()
573 MOZ_ASSERT(!NS_SVGDisplayListPaintingEnabled(),
574 "Only called by nsDisplayOuterSVG code");
576 nsIFrame* kid = GetFirstPrincipalChild();
577 if (kid->HasInvalidFrameInSubtree()) {
578 gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
579 r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
580 nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(FOR_OUTERSVG_TM), PresContext());
581 rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
582 return rect;
584 return nsRect();