Bug 508473 part III: Pass destruction root to frame destruction methods r=bz sr=roc
[gecko.git] / layout / svg / base / src / nsSVGForeignObjectFrame.cpp
blob1bd0a5359e4cc6f49a00f374ce758aad96ed183f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the Mozilla SVG project.
17 * The Initial Developer of the Original Code is
18 * Crocodile Clips Ltd..
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Alex Fritze <alex.fritze@crocodile-clips.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsSVGForeignObjectFrame.h"
41 #include "nsIDOMSVGForeignObjectElem.h"
42 #include "nsIDOMSVGSVGElement.h"
43 #include "nsSVGOuterSVGFrame.h"
44 #include "nsRegion.h"
45 #include "nsGkAtoms.h"
46 #include "nsLayoutUtils.h"
47 #include "nsSVGUtils.h"
48 #include "nsIURI.h"
49 #include "nsSVGRect.h"
50 #include "nsSVGMatrix.h"
51 #include "nsINameSpaceManager.h"
52 #include "nsSVGForeignObjectElement.h"
53 #include "nsSVGContainerFrame.h"
54 #include "gfxContext.h"
55 #include "gfxMatrix.h"
57 //----------------------------------------------------------------------
58 // Implementation
60 nsIFrame*
61 NS_NewSVGForeignObjectFrame(nsIPresShell *aPresShell,
62 nsStyleContext *aContext)
64 return new (aPresShell) nsSVGForeignObjectFrame(aContext);
67 NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
69 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
70 : nsSVGForeignObjectFrameBase(aContext),
71 mInReflow(PR_FALSE)
73 AddStateBits(NS_FRAME_REFLOW_ROOT |
74 NS_FRAME_MAY_BE_TRANSFORMED_OR_HAVE_RENDERING_OBSERVERS);
77 //----------------------------------------------------------------------
78 // nsIFrame methods
80 NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
81 NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
82 NS_QUERYFRAME_TAIL_INHERITING(nsSVGForeignObjectFrameBase)
84 NS_IMETHODIMP
85 nsSVGForeignObjectFrame::Init(nsIContent* aContent,
86 nsIFrame* aParent,
87 nsIFrame* aPrevInFlow)
89 #ifdef DEBUG
90 nsCOMPtr<nsIDOMSVGForeignObjectElement> foreignObject = do_QueryInterface(aContent);
91 NS_ASSERTION(foreignObject, "Content is not an SVG foreignObject!");
92 #endif
94 nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
95 AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM |
96 (aParent->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD));
97 if (NS_SUCCEEDED(rv)) {
98 nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
100 return rv;
103 void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
105 nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
106 nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
109 nsIAtom *
110 nsSVGForeignObjectFrame::GetType() const
112 return nsGkAtoms::svgForeignObjectFrame;
115 NS_IMETHODIMP
116 nsSVGForeignObjectFrame::AttributeChanged(PRInt32 aNameSpaceID,
117 nsIAtom *aAttribute,
118 PRInt32 aModType)
120 if (aNameSpaceID == kNameSpaceID_None) {
121 if (aAttribute == nsGkAtoms::width ||
122 aAttribute == nsGkAtoms::height) {
123 UpdateGraphic(); // update mRect before requesting reflow
124 // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
125 RequestReflow(nsIPresShell::eStyleChange);
126 } else if (aAttribute == nsGkAtoms::x ||
127 aAttribute == nsGkAtoms::y ||
128 aAttribute == nsGkAtoms::transform) {
129 // make sure our cached transform matrix gets (lazily) updated
130 mCanvasTM = nsnull;
131 UpdateGraphic();
135 return NS_OK;
138 NS_IMETHODIMP
139 nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
140 nsHTMLReflowMetrics& aDesiredSize,
141 const nsHTMLReflowState& aReflowState,
142 nsReflowStatus& aStatus)
144 // InitialUpdate and AttributeChanged make sure mRect is up to date before
145 // we're called (UpdateCoveredRegion sets mRect).
147 NS_ASSERTION(!aReflowState.parentReflowState,
148 "should only get reflow from being reflow root");
149 NS_ASSERTION(aReflowState.ComputedWidth() == GetSize().width &&
150 aReflowState.ComputedHeight() == GetSize().height,
151 "reflow roots should be reflowed at existing size and "
152 "svg.css should ensure we have no padding/border/margin");
154 DoReflow();
156 aDesiredSize.width = aReflowState.ComputedWidth();
157 aDesiredSize.height = aReflowState.ComputedHeight();
158 aDesiredSize.mOverflowArea =
159 nsRect(0, 0, aReflowState.ComputedWidth(), aReflowState.ComputedHeight());
160 aStatus = NS_FRAME_COMPLETE;
162 return NS_OK;
165 void
166 nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect,
167 nscoord aX, nscoord aY,
168 nsIFrame* aForChild,
169 PRUint32 aFlags)
171 // This is called by our descendants when they change.
173 if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
174 return;
176 nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC)
177 ? &mSubDocDirtyRegion : &mSameDocDirtyRegion;
178 region->Or(*region, aDamageRect + nsPoint(aX, aY));
179 FlushDirtyRegion();
184 * Returns the app unit canvas bounds of a userspace rect.
186 * @param aToCanvas Transform from userspace to canvas device space.
188 static nsRect
189 ToCanvasBounds(const gfxRect &aUserspaceRect,
190 const gfxMatrix &aToCanvas,
191 const nsPresContext *presContext)
193 return nsLayoutUtils::RoundGfxRectToAppRect(
194 aToCanvas.TransformBounds(aUserspaceRect),
195 presContext->AppUnitsPerDevPixel());
198 NS_IMETHODIMP
199 nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
200 const nsIntRect *aDirtyRect)
202 if (IsDisabled())
203 return NS_OK;
205 nsIFrame* kid = GetFirstChild(nsnull);
206 if (!kid)
207 return NS_OK;
209 gfxMatrix matrix = GetCanvasTMForChildren();
211 nsIRenderingContext *ctx = aContext->GetRenderingContext(this);
213 if (!ctx || matrix.IsSingular()) {
214 NS_WARNING("Can't render foreignObject element!");
215 return NS_ERROR_FAILURE;
218 /* Check if we need to draw anything. */
219 if (aDirtyRect) {
220 PRInt32 appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
221 if (!mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect))
222 return NS_OK;
225 gfxContext *gfx = aContext->GetGfxContext();
227 gfx->Save();
229 if (GetStyleDisplay()->IsScrollableOverflow()) {
230 float x, y, width, height;
231 static_cast<nsSVGElement*>(mContent)->
232 GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
234 gfxRect clipRect =
235 nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
236 nsSVGUtils::SetClipRect(gfx, GetCanvasTM(), clipRect);
239 gfx->Multiply(matrix);
241 nsresult rv = nsLayoutUtils::PaintFrame(ctx, kid, nsRegion(kid->GetRect()),
242 NS_RGBA(0,0,0,0),
243 nsLayoutUtils::PAINT_IN_TRANSFORM);
245 gfx->Restore();
247 return rv;
250 gfxMatrix
251 nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
253 NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!");
255 /* Set the ancestor to be the outer frame. */
256 *aOutAncestor = nsSVGUtils::GetOuterSVGFrame(this);
257 NS_ASSERTION(*aOutAncestor, "How did we end up without an outer frame?");
259 /* Return the matrix back to the root, factoring in the x and y offsets. */
260 return GetCanvasTMForChildren();
263 NS_IMETHODIMP_(nsIFrame*)
264 nsSVGForeignObjectFrame::GetFrameForPoint(const nsPoint &aPoint)
266 if (IsDisabled() || (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD))
267 return nsnull;
269 nsIFrame* kid = GetFirstChild(nsnull);
270 if (!kid)
271 return nsnull;
273 float x, y, width, height;
274 static_cast<nsSVGElement*>(mContent)->
275 GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
277 gfxMatrix tm = GetCanvasTM().Invert();
278 if (tm.IsSingular())
279 return nsnull;
281 // Convert aPoint from app units in canvas space to user space:
283 gfxPoint pt = gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerDevPixel();
284 pt = tm.Transform(pt);
286 if (!gfxRect(0.0f, 0.0f, width, height).Contains(pt))
287 return nsnull;
289 // Convert pt to app units in *local* space:
291 pt = pt * nsPresContext::AppUnitsPerCSSPixel();
292 nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
294 return nsLayoutUtils::GetFrameForPoint(kid, point);
297 NS_IMETHODIMP_(nsRect)
298 nsSVGForeignObjectFrame::GetCoveredRegion()
300 return mRect;
303 NS_IMETHODIMP
304 nsSVGForeignObjectFrame::UpdateCoveredRegion()
306 if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
307 return NS_ERROR_FAILURE;
309 float x, y, w, h;
310 static_cast<nsSVGForeignObjectElement*>(mContent)->
311 GetAnimatedLengthValues(&x, &y, &w, &h, nsnull);
313 // If mRect's width or height are negative, reflow blows up! We must clamp!
314 if (w < 0.0f) w = 0.0f;
315 if (h < 0.0f) h = 0.0f;
317 // GetCanvasTM includes the x,y translation
318 mRect = ToCanvasBounds(gfxRect(0.0, 0.0, w, h), GetCanvasTM(), PresContext());
320 return NS_OK;
323 NS_IMETHODIMP
324 nsSVGForeignObjectFrame::InitialUpdate()
326 NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW,
327 "Yikes! We've been called already! Hopefully we weren't called "
328 "before our nsSVGOuterSVGFrame's initial Reflow()!!!");
330 UpdateCoveredRegion();
332 // Make sure to not allow interrupts if we're not being reflown as a root
333 nsPresContext::InterruptPreventer noInterrupts(PresContext());
334 DoReflow();
336 NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
337 "We don't actually participate in reflow");
339 // Do unset the various reflow bits, though.
340 mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
341 NS_FRAME_HAS_DIRTY_CHILDREN);
343 return NS_OK;
346 void
347 nsSVGForeignObjectFrame::NotifySVGChanged(PRUint32 aFlags)
349 PRBool reflow = PR_FALSE;
351 if (aFlags & TRANSFORM_CHANGED) {
352 // In an ideal world we would reflow when our CTM changes. This is because
353 // glyph metrics do not necessarily scale uniformly with change in scale
354 // and, as a result, CTM changes may require text to break at different
355 // points. The problem would be how to keep performance acceptable when
356 // e.g. the transform of an ancestor is animated.
357 // We also seem to get some sort of infinite loop post bug 421584 if we
358 // reflow.
359 mCanvasTM = nsnull;
360 if (!(aFlags & SUPPRESS_INVALIDATION)) {
361 UpdateGraphic();
364 } else if (aFlags & COORD_CONTEXT_CHANGED) {
365 // Our coordinate context's width/height has changed. If we have a
366 // percentage width/height our dimensions will change so we must reflow.
367 nsSVGForeignObjectElement *fO =
368 static_cast<nsSVGForeignObjectElement*>(mContent);
369 if (fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].IsPercentage() ||
370 fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].IsPercentage()) {
371 reflow = PR_TRUE;
375 if (reflow) {
376 // If we're called while the PresShell is handling reflow events then we
377 // must have been called as a result of the NotifyViewportChange() call in
378 // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
379 // at this point (i.e. during reflow) because it could confuse the
380 // PresShell and prevent it from reflowing us properly in future. Besides
381 // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
382 // synchronously, so there's no need.
383 PRBool reflowing;
384 PresContext()->PresShell()->IsReflowLocked(&reflowing);
385 if (!reflowing) {
386 UpdateGraphic(); // update mRect before requesting reflow
387 RequestReflow(nsIPresShell::eResize);
392 NS_IMETHODIMP
393 nsSVGForeignObjectFrame::NotifyRedrawSuspended()
395 return NS_OK;
398 NS_IMETHODIMP
399 nsSVGForeignObjectFrame::NotifyRedrawUnsuspended()
401 if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) {
402 if (GetStateBits() & NS_STATE_SVG_DIRTY) {
403 UpdateGraphic(); // invalidate our entire area
404 } else {
405 FlushDirtyRegion(); // only invalidate areas dirtied by our descendants
408 return NS_OK;
411 NS_IMETHODIMP
412 nsSVGForeignObjectFrame::SetMatrixPropagation(PRBool aPropagate)
414 if (aPropagate) {
415 AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
416 } else {
417 RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
419 return NS_OK;
422 PRBool
423 nsSVGForeignObjectFrame::GetMatrixPropagation()
425 return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
428 gfxRect
429 nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace)
431 NS_ASSERTION(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
432 "Should not be calling this on a non-display child");
434 nsSVGForeignObjectElement *content =
435 static_cast<nsSVGForeignObjectElement*>(mContent);
437 float x, y, w, h;
438 content->GetAnimatedLengthValues(&x, &y, &w, &h, nsnull);
440 if (w < 0.0f) w = 0.0f;
441 if (h < 0.0f) h = 0.0f;
443 if (aToBBoxUserspace.IsSingular()) {
444 // XXX ReportToConsole
445 return gfxRect(0.0, 0.0, 0.0, 0.0);
447 return aToBBoxUserspace.TransformBounds(gfxRect(0.0, 0.0, w, h));
450 //----------------------------------------------------------------------
452 gfxMatrix
453 nsSVGForeignObjectFrame::GetCanvasTM()
455 if (!mCanvasTM) {
456 NS_ASSERTION(mParent, "null parent");
458 nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(mParent);
459 nsSVGForeignObjectElement *content =
460 static_cast<nsSVGForeignObjectElement*>(mContent);
462 gfxMatrix tm = content->PrependLocalTransformTo(parent->GetCanvasTM());
464 mCanvasTM = NS_NewSVGMatrix(tm);
466 return nsSVGUtils::ConvertSVGMatrixToThebes(mCanvasTM);
469 //----------------------------------------------------------------------
470 // Implementation helpers
472 gfxMatrix
473 nsSVGForeignObjectFrame::GetCanvasTMForChildren()
475 float cssPxPerDevPx = PresContext()->
476 AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
478 return GetCanvasTM().Scale(cssPxPerDevPx, cssPxPerDevPx);
481 void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
483 if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
484 // If we haven't had an InitialUpdate yet, nothing to do.
485 return;
487 nsIFrame* kid = GetFirstChild(nsnull);
488 if (!kid)
489 return;
491 PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
494 void nsSVGForeignObjectFrame::UpdateGraphic()
496 nsSVGUtils::UpdateGraphic(this);
498 // We just invalidated our entire area, so clear the caches of areas dirtied
499 // by our descendants:
500 mSameDocDirtyRegion.SetEmpty();
501 mSubDocDirtyRegion.SetEmpty();
504 void
505 nsSVGForeignObjectFrame::MaybeReflowFromOuterSVGFrame()
507 nsIFrame* kid = GetFirstChild(nsnull);
509 // If we're already scheduled to reflow (if we or our kid is dirty) we don't
510 // want to reflow now or else our presShell will do extra work trying to
511 // reflow us a second time. (It will also complain if it finds that a reflow
512 // root scheduled for reflow isn't dirty).
514 if (kid->GetStateBits() & NS_FRAME_IS_DIRTY) {
515 return;
517 kid->AddStateBits(NS_FRAME_IS_DIRTY); // we must be fully marked dirty
518 if (kid->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN) {
519 return;
522 // Make sure to not allow interrupts if we're not being reflown as a root
523 nsPresContext::InterruptPreventer noInterrupts(PresContext());
524 DoReflow();
527 void
528 nsSVGForeignObjectFrame::DoReflow()
530 #ifdef DEBUG
531 printf("**nsSVGForeignObjectFrame::DoReflow()\n");
532 #endif
534 NS_ASSERTION(!(nsSVGUtils::GetOuterSVGFrame(this)->
535 GetStateBits() & NS_FRAME_FIRST_REFLOW),
536 "Calling InitialUpdate too early - must not call DoReflow!!!");
538 if (IsDisabled())
539 return;
541 if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
542 return;
544 nsPresContext *presContext = PresContext();
545 nsIFrame* kid = GetFirstChild(nsnull);
546 if (!kid)
547 return;
549 // initiate a synchronous reflow here and now:
550 nsSize availableSpace(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
551 nsCOMPtr<nsIRenderingContext> renderingContext;
552 nsIPresShell* presShell = presContext->PresShell();
553 NS_ASSERTION(presShell, "null presShell");
554 presShell->CreateRenderingContext(this,getter_AddRefs(renderingContext));
555 if (!renderingContext)
556 return;
558 nsSVGForeignObjectElement *fO = static_cast<nsSVGForeignObjectElement*>
559 (mContent);
561 float width =
562 fO->mLengthAttributes[nsSVGForeignObjectElement::WIDTH].GetAnimValue(fO);
563 float height =
564 fO->mLengthAttributes[nsSVGForeignObjectElement::HEIGHT].GetAnimValue(fO);
566 nsSize size(nsPresContext::CSSPixelsToAppUnits(width),
567 nsPresContext::CSSPixelsToAppUnits(height));
569 mInReflow = PR_TRUE;
571 nsHTMLReflowState reflowState(presContext, kid,
572 renderingContext,
573 nsSize(size.width, NS_UNCONSTRAINEDSIZE));
574 nsHTMLReflowMetrics desiredSize;
575 nsReflowStatus status;
577 // We don't use size.height above because that tells the child to do
578 // page/column breaking at that height.
579 NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0, 0, 0, 0) &&
580 reflowState.mComputedMargin == nsMargin(0, 0, 0, 0),
581 "style system should ensure that :-moz-svg-foreign content "
582 "does not get styled");
583 NS_ASSERTION(reflowState.ComputedWidth() == size.width,
584 "reflow state made child wrong size");
585 reflowState.SetComputedHeight(size.height);
587 ReflowChild(kid, presContext, desiredSize, reflowState, 0, 0,
588 NS_FRAME_NO_MOVE_FRAME, status);
589 NS_ASSERTION(size.width == desiredSize.width &&
590 size.height == desiredSize.height, "unexpected size");
591 FinishReflowChild(kid, presContext, &reflowState, desiredSize, 0, 0,
592 NS_FRAME_NO_MOVE_FRAME);
594 mInReflow = PR_FALSE;
595 FlushDirtyRegion();
598 void
599 nsSVGForeignObjectFrame::InvalidateDirtyRect(nsSVGOuterSVGFrame* aOuter,
600 const nsRect& aRect, PRUint32 aFlags)
602 if (aRect.IsEmpty())
603 return;
605 // The areas dirtied by children are in app units, relative to this frame.
606 // We need to convert the rect to userspace to use IntersectRect.
608 gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
609 r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
611 nsRect rect = ToCanvasBounds(r, GetCanvasTM(), PresContext());
613 // Don't invalidate areas outside our bounds:
614 rect.IntersectRect(rect, mRect);
615 if (rect.IsEmpty())
616 return;
618 // XXX invalidate the entire covered region
619 // See bug 418063
620 rect.UnionRect(rect, mRect);
622 rect = nsSVGUtils::FindFilterInvalidation(this, rect);
623 aOuter->InvalidateWithFlags(rect, aFlags);
626 void
627 nsSVGForeignObjectFrame::FlushDirtyRegion()
629 if ((mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) ||
630 mInReflow)
631 return;
633 nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
634 if (!outerSVGFrame) {
635 NS_ERROR("null outerSVGFrame");
636 return;
639 if (outerSVGFrame->IsRedrawSuspended())
640 return;
642 InvalidateDirtyRect(outerSVGFrame, mSameDocDirtyRegion.GetBounds(), 0);
643 InvalidateDirtyRect(outerSVGFrame, mSubDocDirtyRegion.GetBounds(), INVALIDATE_CROSS_DOC);
645 mSameDocDirtyRegion.SetEmpty();
646 mSubDocDirtyRegion.SetEmpty();