Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 nsIFrame*
31 NS_NewSVGForeignObjectFrame(nsIPresShell *aPresShell,
32 nsStyleContext *aContext)
33 {
34 return new (aPresShell) nsSVGForeignObjectFrame(aContext);
35 }
37 NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
39 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
40 : nsSVGForeignObjectFrameBase(aContext),
41 mInReflow(false)
42 {
43 AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
44 NS_FRAME_SVG_LAYOUT);
45 }
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 nsIFrame* aParent,
57 nsIFrame* aPrevInFlow)
58 {
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);
68 }
69 }
71 void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
72 {
73 // Only unregister if we registered in the first place:
74 if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
75 nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
76 }
77 nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
78 }
80 nsIAtom *
81 nsSVGForeignObjectFrame::GetType() const
82 {
83 return nsGkAtoms::svgForeignObjectFrame;
84 }
86 nsresult
87 nsSVGForeignObjectFrame::AttributeChanged(int32_t aNameSpaceID,
88 nsIAtom *aAttribute,
89 int32_t aModType)
90 {
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);
113 }
114 }
116 return NS_OK;
117 }
119 nsresult
120 nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
121 nsHTMLReflowMetrics& aDesiredSize,
122 const nsHTMLReflowState& aReflowState,
123 nsReflowStatus& aStatus)
124 {
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 aDesiredSize.Width() = aReflowState.ComputedWidth();
148 aDesiredSize.Height() = aReflowState.ComputedHeight();
149 aDesiredSize.SetOverflowAreasToDesiredBounds();
150 aStatus = NS_FRAME_COMPLETE;
152 return NS_OK;
153 }
155 void
156 nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
157 const nsRect& aDirtyRect,
158 const nsDisplayListSet& aLists)
159 {
160 if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
161 return;
162 }
163 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
164 }
166 bool
167 nsSVGForeignObjectFrame::IsSVGTransformed(Matrix *aOwnTransform,
168 Matrix *aFromParentTransform) const
169 {
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);
178 }
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));
188 }
189 foundTransform = true;
190 }
191 return foundTransform;
192 }
194 nsresult
195 nsSVGForeignObjectFrame::PaintSVG(nsRenderingContext *aContext,
196 const nsIntRect *aDirtyRect,
197 nsIFrame* aTransformRoot)
198 {
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;
216 }
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 invmatrix.Invert();
228 NS_ASSERTION(!invmatrix.IsSingular(),
229 "inverse of non-singular matrix should be non-singular");
231 gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
232 aDirtyRect->width, aDirtyRect->height);
233 transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
235 kidDirtyRect.IntersectRect(kidDirtyRect,
236 nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect,
237 PresContext()->AppUnitsPerCSSPixel()));
239 // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
240 // not with kidDirtyRect. I.e.
241 // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
242 // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
243 if (kidDirtyRect.IsEmpty())
244 return NS_OK;
245 }
247 gfxContext *gfx = aContext->ThebesContext();
249 gfx->Save();
251 if (StyleDisplay()->IsScrollableOverflow()) {
252 float x, y, width, height;
253 static_cast<nsSVGElement*>(mContent)->
254 GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
256 gfxRect clipRect =
257 nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
258 nsSVGUtils::SetClipRect(gfx, canvasTM, clipRect);
259 }
261 // SVG paints in CSS px, but normally frames paint in dev pixels. Here we
262 // multiply a CSS-px-to-dev-pixel factor onto canvasTM so our children paint
263 // correctly.
264 float cssPxPerDevPx = PresContext()->
265 AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
266 gfxMatrix canvasTMForChildren = canvasTM;
267 canvasTMForChildren.Scale(cssPxPerDevPx, cssPxPerDevPx);
269 gfx->Multiply(canvasTMForChildren);
271 uint32_t flags = nsLayoutUtils::PAINT_IN_TRANSFORM;
272 if (SVGAutoRenderState::IsPaintingToWindow(aContext)) {
273 flags |= nsLayoutUtils::PAINT_TO_WINDOW;
274 }
275 nsresult rv = nsLayoutUtils::PaintFrame(aContext, kid, nsRegion(kidDirtyRect),
276 NS_RGBA(0,0,0,0), flags);
278 gfx->Restore();
280 return rv;
281 }
283 nsIFrame*
284 nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
285 {
286 NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
287 (mState & NS_FRAME_IS_NONDISPLAY),
288 "If display lists are enabled, only hit-testing of a "
289 "clipPath's contents should take this code path");
291 if (IsDisabled() || (GetStateBits() & NS_FRAME_IS_NONDISPLAY))
292 return nullptr;
294 nsIFrame* kid = GetFirstPrincipalChild();
295 if (!kid)
296 return nullptr;
298 float x, y, width, height;
299 static_cast<nsSVGElement*>(mContent)->
300 GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
302 gfxMatrix tm = GetCanvasTM(FOR_HIT_TESTING).Invert();
303 if (tm.IsSingular())
304 return nullptr;
306 // Convert aPoint from app units in canvas space to user space:
308 gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerDevPixel();
309 pt = tm.Transform(pt);
311 if (!gfxRect(0.0f, 0.0f, width, height).Contains(pt))
312 return nullptr;
314 // Convert pt to app units in *local* space:
316 pt = pt * nsPresContext::AppUnitsPerCSSPixel();
317 nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
319 nsIFrame *frame = nsLayoutUtils::GetFrameForPoint(kid, point);
320 if (frame && nsSVGUtils::HitTestClip(this, aPoint))
321 return frame;
323 return nullptr;
324 }
326 nsRect
327 nsSVGForeignObjectFrame::GetCoveredRegion()
328 {
329 float x, y, w, h;
330 static_cast<SVGForeignObjectElement*>(mContent)->
331 GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
332 if (w < 0.0f) w = 0.0f;
333 if (h < 0.0f) h = 0.0f;
334 // GetCanvasTM includes the x,y translation
335 return nsSVGUtils::ToCanvasBounds(gfxRect(0.0, 0.0, w, h),
336 GetCanvasTM(FOR_OUTERSVG_TM),
337 PresContext());
338 }
340 void
341 nsSVGForeignObjectFrame::ReflowSVG()
342 {
343 NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
344 "This call is probably a wasteful mistake");
346 NS_ABORT_IF_FALSE(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
347 "ReflowSVG mechanism not designed for this");
349 if (!nsSVGUtils::NeedsReflowSVG(this)) {
350 return;
351 }
353 // We update mRect before the DoReflow call so that DoReflow uses the
354 // correct dimensions:
356 float x, y, w, h;
357 static_cast<SVGForeignObjectElement*>(mContent)->
358 GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
360 // If mRect's width or height are negative, reflow blows up! We must clamp!
361 if (w < 0.0f) w = 0.0f;
362 if (h < 0.0f) h = 0.0f;
364 mRect = nsLayoutUtils::RoundGfxRectToAppRect(
365 gfxRect(x, y, w, h),
366 PresContext()->AppUnitsPerCSSPixel());
368 // Fully mark our kid dirty so that it gets resized if necessary
369 // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
370 nsIFrame* kid = GetFirstPrincipalChild();
371 kid->AddStateBits(NS_FRAME_IS_DIRTY);
373 // Make sure to not allow interrupts if we're not being reflown as a root:
374 nsPresContext::InterruptPreventer noInterrupts(PresContext());
376 DoReflow();
378 if (mState & NS_FRAME_FIRST_REFLOW) {
379 // Make sure we have our filter property (if any) before calling
380 // FinishAndStoreOverflow (subsequent filter changes are handled off
381 // nsChangeHint_UpdateEffects):
382 nsSVGEffects::UpdateEffects(this);
383 }
385 // If we have a filter, we need to invalidate ourselves because filter
386 // output can change even if none of our descendants need repainting.
387 if (StyleSVGReset()->HasFilters()) {
388 InvalidateFrame();
389 }
391 // TODO: once we support |overflow:visible| on foreignObject, then we will
392 // need to take account of our descendants here.
393 nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
394 nsOverflowAreas overflowAreas(overflow, overflow);
395 FinishAndStoreOverflow(overflowAreas, mRect.Size());
397 // Now unset the various reflow bits:
398 mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
399 NS_FRAME_HAS_DIRTY_CHILDREN);
400 }
402 void
403 nsSVGForeignObjectFrame::NotifySVGChanged(uint32_t aFlags)
404 {
405 NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
406 "Invalidation logic may need adjusting");
408 bool needNewBounds = false; // i.e. mRect or visual overflow rect
409 bool needReflow = false;
410 bool needNewCanvasTM = false;
412 if (aFlags & COORD_CONTEXT_CHANGED) {
413 SVGForeignObjectElement *fO =
414 static_cast<SVGForeignObjectElement*>(mContent);
415 // Coordinate context changes affect mCanvasTM if we have a
416 // percentage 'x' or 'y'
417 if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_X].IsPercentage() ||
418 fO->mLengthAttributes[SVGForeignObjectElement::ATTR_Y].IsPercentage()) {
419 needNewBounds = true;
420 needNewCanvasTM = true;
421 }
422 // Our coordinate context's width/height has changed. If we have a
423 // percentage width/height our dimensions will change so we must reflow.
424 if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_WIDTH].IsPercentage() ||
425 fO->mLengthAttributes[SVGForeignObjectElement::ATTR_HEIGHT].IsPercentage()) {
426 needNewBounds = true;
427 needReflow = true;
428 }
429 }
431 if (aFlags & TRANSFORM_CHANGED) {
432 if (mCanvasTM && mCanvasTM->IsSingular()) {
433 needNewBounds = true; // old bounds are bogus
434 }
435 needNewCanvasTM = true;
436 // In an ideal world we would reflow when our CTM changes. This is because
437 // glyph metrics do not necessarily scale uniformly with change in scale
438 // and, as a result, CTM changes may require text to break at different
439 // points. The problem would be how to keep performance acceptable when
440 // e.g. the transform of an ancestor is animated.
441 // We also seem to get some sort of infinite loop post bug 421584 if we
442 // reflow.
443 }
445 if (needNewBounds) {
446 // Ancestor changes can't affect how we render from the perspective of
447 // any rendering observers that we may have, so we don't need to
448 // invalidate them. We also don't need to invalidate ourself, since our
449 // changed ancestor will have invalidated its entire area, which includes
450 // our area.
451 nsSVGUtils::ScheduleReflowSVG(this);
452 }
454 // If we're called while the PresShell is handling reflow events then we
455 // must have been called as a result of the NotifyViewportChange() call in
456 // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
457 // at this point (i.e. during reflow) because it could confuse the
458 // PresShell and prevent it from reflowing us properly in future. Besides
459 // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
460 // synchronously, so there's no need.
461 if (needReflow && !PresContext()->PresShell()->IsReflowLocked()) {
462 RequestReflow(nsIPresShell::eResize);
463 }
465 if (needNewCanvasTM) {
466 // Do this after calling InvalidateAndScheduleBoundsUpdate in case we
467 // change the code and it needs to use it.
468 mCanvasTM = nullptr;
469 }
470 }
472 SVGBBox
473 nsSVGForeignObjectFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
474 uint32_t aFlags)
475 {
476 SVGForeignObjectElement *content =
477 static_cast<SVGForeignObjectElement*>(mContent);
479 float x, y, w, h;
480 content->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
482 if (w < 0.0f) w = 0.0f;
483 if (h < 0.0f) h = 0.0f;
485 if (aToBBoxUserspace.IsSingular()) {
486 // XXX ReportToConsole
487 return SVGBBox();
488 }
489 return aToBBoxUserspace.TransformBounds(gfx::Rect(0.0, 0.0, w, h));
490 }
492 //----------------------------------------------------------------------
494 gfxMatrix
495 nsSVGForeignObjectFrame::GetCanvasTM(uint32_t aFor, nsIFrame* aTransformRoot)
496 {
497 if (!(GetStateBits() & NS_FRAME_IS_NONDISPLAY) && !aTransformRoot) {
498 if ((aFor == FOR_PAINTING && NS_SVGDisplayListPaintingEnabled()) ||
499 (aFor == FOR_HIT_TESTING && NS_SVGDisplayListHitTestingEnabled())) {
500 return nsSVGIntegrationUtils::GetCSSPxToDevPxMatrix(this);
501 }
502 }
503 if (!mCanvasTM) {
504 NS_ASSERTION(mParent, "null parent");
506 nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);
507 SVGForeignObjectElement *content =
508 static_cast<SVGForeignObjectElement*>(mContent);
510 gfxMatrix tm = content->PrependLocalTransformsTo(
511 this == aTransformRoot ? gfxMatrix() :
512 parent->GetCanvasTM(aFor, aTransformRoot));
514 mCanvasTM = new gfxMatrix(tm);
515 }
516 return *mCanvasTM;
517 }
519 //----------------------------------------------------------------------
520 // Implementation helpers
522 void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
523 {
524 if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
525 // If we haven't had a ReflowSVG() yet, nothing to do.
526 return;
528 nsIFrame* kid = GetFirstPrincipalChild();
529 if (!kid)
530 return;
532 PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
533 }
535 void
536 nsSVGForeignObjectFrame::DoReflow()
537 {
538 // Skip reflow if we're zero-sized, unless this is our first reflow.
539 if (IsDisabled() &&
540 !(GetStateBits() & NS_FRAME_FIRST_REFLOW))
541 return;
543 nsPresContext *presContext = PresContext();
544 nsIFrame* kid = GetFirstPrincipalChild();
545 if (!kid)
546 return;
548 // initiate a synchronous reflow here and now:
549 nsRefPtr<nsRenderingContext> renderingContext =
550 presContext->PresShell()->CreateReferenceRenderingContext();
552 mInReflow = true;
554 nsHTMLReflowState reflowState(presContext, kid,
555 renderingContext,
556 nsSize(mRect.width, NS_UNCONSTRAINEDSIZE));
557 nsHTMLReflowMetrics desiredSize(reflowState);
558 nsReflowStatus status;
560 // We don't use mRect.height above because that tells the child to do
561 // page/column breaking at that height.
562 NS_ASSERTION(reflowState.ComputedPhysicalBorderPadding() == nsMargin(0, 0, 0, 0) &&
563 reflowState.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
564 "style system should ensure that :-moz-svg-foreign-content "
565 "does not get styled");
566 NS_ASSERTION(reflowState.ComputedWidth() == mRect.width,
567 "reflow state made child wrong size");
568 reflowState.SetComputedHeight(mRect.height);
570 ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0,
571 NS_FRAME_NO_MOVE_FRAME, status);
572 NS_ASSERTION(mRect.width == desiredSize.Width() &&
573 mRect.height == desiredSize.Height(), "unexpected size");
574 FinishReflowChild(kid, presContext, desiredSize, &reflowState, 0, 0,
575 NS_FRAME_NO_MOVE_FRAME);
577 mInReflow = false;
578 }
580 nsRect
581 nsSVGForeignObjectFrame::GetInvalidRegion()
582 {
583 nsIFrame* kid = GetFirstPrincipalChild();
584 if (kid->HasInvalidFrameInSubtree()) {
585 gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
586 r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
587 nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(FOR_PAINTING), PresContext());
588 rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
589 return rect;
590 }
591 return nsRect();
592 }