summaryrefslogtreecommitdiffstats
path: root/layout/svg/nsSVGForeignObjectFrame.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /layout/svg/nsSVGForeignObjectFrame.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'layout/svg/nsSVGForeignObjectFrame.cpp')
-rw-r--r--layout/svg/nsSVGForeignObjectFrame.cpp592
1 files changed, 592 insertions, 0 deletions
diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp
new file mode 100644
index 000000000..afa5912d2
--- /dev/null
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -0,0 +1,592 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Main header first:
+#include "nsSVGForeignObjectFrame.h"
+
+// Keep others in (case-insensitive) order:
+#include "DrawResult.h"
+#include "gfxContext.h"
+#include "nsDisplayList.h"
+#include "nsGkAtoms.h"
+#include "nsNameSpaceManager.h"
+#include "nsLayoutUtils.h"
+#include "nsRegion.h"
+#include "nsRenderingContext.h"
+#include "nsSVGContainerFrame.h"
+#include "nsSVGEffects.h"
+#include "mozilla/dom/SVGForeignObjectElement.h"
+#include "nsSVGIntegrationUtils.h"
+#include "nsSVGOuterSVGFrame.h"
+#include "nsSVGUtils.h"
+#include "mozilla/AutoRestore.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::image;
+
+//----------------------------------------------------------------------
+// Implementation
+
+nsContainerFrame*
+NS_NewSVGForeignObjectFrame(nsIPresShell *aPresShell,
+ nsStyleContext *aContext)
+{
+ return new (aPresShell) nsSVGForeignObjectFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
+
+nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
+ : nsContainerFrame(aContext)
+ , mInReflow(false)
+{
+ AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
+ NS_FRAME_SVG_LAYOUT);
+}
+
+//----------------------------------------------------------------------
+// nsIFrame methods
+
+NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
+ NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
+
+void
+nsSVGForeignObjectFrame::Init(nsIContent* aContent,
+ nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow)
+{
+ NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::foreignObject),
+ "Content is not an SVG foreignObject!");
+
+ nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
+ AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
+ AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER |
+ NS_FRAME_FONT_INFLATION_FLOW_ROOT);
+ if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
+ nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
+ }
+}
+
+void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+ // Only unregister if we registered in the first place:
+ if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
+ nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
+ }
+ nsContainerFrame::DestroyFrom(aDestructRoot);
+}
+
+nsIAtom *
+nsSVGForeignObjectFrame::GetType() const
+{
+ return nsGkAtoms::svgForeignObjectFrame;
+}
+
+nsresult
+nsSVGForeignObjectFrame::AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom *aAttribute,
+ int32_t aModType)
+{
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aAttribute == nsGkAtoms::width ||
+ aAttribute == nsGkAtoms::height) {
+ nsLayoutUtils::PostRestyleEvent(
+ mContent->AsElement(), nsRestyleHint(0),
+ nsChangeHint_InvalidateRenderingObservers);
+ nsSVGUtils::ScheduleReflowSVG(this);
+ // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
+ RequestReflow(nsIPresShell::eStyleChange);
+ } else if (aAttribute == nsGkAtoms::x ||
+ aAttribute == nsGkAtoms::y) {
+ // make sure our cached transform matrix gets (lazily) updated
+ mCanvasTM = nullptr;
+ nsLayoutUtils::PostRestyleEvent(
+ mContent->AsElement(), nsRestyleHint(0),
+ nsChangeHint_InvalidateRenderingObservers);
+ nsSVGUtils::ScheduleReflowSVG(this);
+ } else if (aAttribute == nsGkAtoms::transform) {
+ // We don't invalidate for transform changes (the layers code does that).
+ // Also note that SVGTransformableElement::GetAttributeChangeHint will
+ // return nsChangeHint_UpdateOverflow for "transform" attribute changes
+ // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
+ mCanvasTM = nullptr;
+ } else if (aAttribute == nsGkAtoms::viewBox ||
+ aAttribute == nsGkAtoms::preserveAspectRatio) {
+ nsLayoutUtils::PostRestyleEvent(
+ mContent->AsElement(), nsRestyleHint(0),
+ nsChangeHint_InvalidateRenderingObservers);
+ }
+ }
+
+ return NS_OK;
+}
+
+void
+nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus)
+{
+ MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
+ "Should not have been called");
+
+ // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY,
+ // so if that bit is still set we still have a resize pending. If we hit
+ // this assertion, then we should get the presShell to skip reflow roots
+ // that have a dirty parent since a reflow is going to come via the
+ // reflow root's parent anyway.
+ NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
+ "Reflowing while a resize is pending is wasteful");
+
+ // ReflowSVG makes sure mRect is up to date before we're called.
+
+ NS_ASSERTION(!aReflowInput.mParentReflowInput,
+ "should only get reflow from being reflow root");
+ NS_ASSERTION(aReflowInput.ComputedWidth() == GetSize().width &&
+ aReflowInput.ComputedHeight() == GetSize().height,
+ "reflow roots should be reflowed at existing size and "
+ "svg.css should ensure we have no padding/border/margin");
+
+ DoReflow();
+
+ WritingMode wm = aReflowInput.GetWritingMode();
+ LogicalSize finalSize(wm, aReflowInput.ComputedISize(),
+ aReflowInput.ComputedBSize());
+ aDesiredSize.SetSize(wm, finalSize);
+ aDesiredSize.SetOverflowAreasToDesiredBounds();
+ aStatus = NS_FRAME_COMPLETE;
+}
+
+void
+nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists)
+{
+ if (!static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
+ return;
+ }
+ DisplayOutline(aBuilder, aLists);
+ BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
+}
+
+bool
+nsSVGForeignObjectFrame::IsSVGTransformed(Matrix *aOwnTransform,
+ Matrix *aFromParentTransform) const
+{
+ bool foundTransform = false;
+
+ // Check if our parent has children-only transforms:
+ nsIFrame *parent = GetParent();
+ if (parent &&
+ parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
+ foundTransform = static_cast<nsSVGContainerFrame*>(parent)->
+ HasChildrenOnlyTransform(aFromParentTransform);
+ }
+
+ nsSVGElement *content = static_cast<nsSVGElement*>(mContent);
+ nsSVGAnimatedTransformList* transformList =
+ content->GetAnimatedTransformList();
+ if ((transformList && transformList->HasTransform()) ||
+ content->GetAnimateMotionTransform()) {
+ if (aOwnTransform) {
+ *aOwnTransform = gfx::ToMatrix(content->PrependLocalTransformsTo(
+ gfxMatrix(),
+ eUserSpaceToParent));
+ }
+ foundTransform = true;
+ }
+ return foundTransform;
+}
+
+DrawResult
+nsSVGForeignObjectFrame::PaintSVG(gfxContext& aContext,
+ const gfxMatrix& aTransform,
+ const nsIntRect* aDirtyRect)
+{
+ NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
+ (mState & NS_FRAME_IS_NONDISPLAY),
+ "If display lists are enabled, only painting of non-display "
+ "SVG should take this code path");
+
+ if (IsDisabled())
+ return DrawResult::SUCCESS;
+
+ nsIFrame* kid = PrincipalChildList().FirstChild();
+ if (!kid)
+ return DrawResult::SUCCESS;
+
+ if (aTransform.IsSingular()) {
+ NS_WARNING("Can't render foreignObject element!");
+ return DrawResult::BAD_ARGS;
+ }
+
+ nsRect kidDirtyRect = kid->GetVisualOverflowRect();
+
+ /* Check if we need to draw anything. */
+ if (aDirtyRect) {
+ NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
+ (mState & NS_FRAME_IS_NONDISPLAY),
+ "Display lists handle dirty rect intersection test");
+ // Transform the dirty rect into app units in our userspace.
+ gfxMatrix invmatrix = aTransform;
+ DebugOnly<bool> ok = invmatrix.Invert();
+ NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
+
+ gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
+ aDirtyRect->width, aDirtyRect->height);
+ transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
+
+ kidDirtyRect.IntersectRect(kidDirtyRect,
+ nsLayoutUtils::RoundGfxRectToAppRect(transDirtyRect,
+ PresContext()->AppUnitsPerCSSPixel()));
+
+ // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
+ // not with kidDirtyRect. I.e.
+ // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
+ // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
+ if (kidDirtyRect.IsEmpty())
+ return DrawResult::SUCCESS;
+ }
+
+ aContext.Save();
+
+ if (StyleDisplay()->IsScrollableOverflow()) {
+ float x, y, width, height;
+ static_cast<nsSVGElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+
+ gfxRect clipRect =
+ nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
+ nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
+ }
+
+ // SVG paints in CSS px, but normally frames paint in dev pixels. Here we
+ // multiply a CSS-px-to-dev-pixel factor onto aTransform so our children
+ // paint correctly.
+ float cssPxPerDevPx = PresContext()->
+ AppUnitsToFloatCSSPixels(PresContext()->AppUnitsPerDevPixel());
+ gfxMatrix canvasTMForChildren = aTransform;
+ canvasTMForChildren.Scale(cssPxPerDevPx, cssPxPerDevPx);
+
+ aContext.Multiply(canvasTMForChildren);
+
+ using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
+ PaintFrameFlags flags = PaintFrameFlags::PAINT_IN_TRANSFORM;
+ if (SVGAutoRenderState::IsPaintingToWindow(aContext.GetDrawTarget())) {
+ flags |= PaintFrameFlags::PAINT_TO_WINDOW;
+ }
+ nsRenderingContext rendCtx(&aContext);
+ nsresult rv = nsLayoutUtils::PaintFrame(&rendCtx, kid, nsRegion(kidDirtyRect),
+ NS_RGBA(0,0,0,0),
+ nsDisplayListBuilderMode::PAINTING,
+ flags);
+
+ aContext.Restore();
+
+ return NS_FAILED(rv) ? DrawResult::BAD_ARGS : DrawResult::SUCCESS;
+}
+
+nsIFrame*
+nsSVGForeignObjectFrame::GetFrameForPoint(const gfxPoint& aPoint)
+{
+ NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
+ (mState & NS_FRAME_IS_NONDISPLAY),
+ "If display lists are enabled, only hit-testing of a "
+ "clipPath's contents should take this code path");
+
+ if (IsDisabled() || (GetStateBits() & NS_FRAME_IS_NONDISPLAY))
+ return nullptr;
+
+ nsIFrame* kid = PrincipalChildList().FirstChild();
+ if (!kid)
+ return nullptr;
+
+ float x, y, width, height;
+ static_cast<nsSVGElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
+
+ if (!gfxRect(x, y, width, height).Contains(aPoint) ||
+ !nsSVGUtils::HitTestClip(this, aPoint)) {
+ return nullptr;
+ }
+
+ // Convert the point to app units relative to the top-left corner of the
+ // viewport that's established by the foreignObject element:
+
+ gfxPoint pt = (aPoint + gfxPoint(x, y)) * nsPresContext::AppUnitsPerCSSPixel();
+ nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
+
+ return nsLayoutUtils::GetFrameForPoint(kid, point);
+}
+
+nsRect
+nsSVGForeignObjectFrame::GetCoveredRegion()
+{
+ float x, y, w, h;
+ static_cast<SVGForeignObjectElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
+ if (w < 0.0f) w = 0.0f;
+ if (h < 0.0f) h = 0.0f;
+ // GetCanvasTM includes the x,y translation
+ return nsSVGUtils::ToCanvasBounds(gfxRect(0.0, 0.0, w, h),
+ GetCanvasTM(),
+ PresContext());
+}
+
+void
+nsSVGForeignObjectFrame::ReflowSVG()
+{
+ NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
+ "This call is probably a wasteful mistake");
+
+ MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
+ "ReflowSVG mechanism not designed for this");
+
+ if (!nsSVGUtils::NeedsReflowSVG(this)) {
+ return;
+ }
+
+ // We update mRect before the DoReflow call so that DoReflow uses the
+ // correct dimensions:
+
+ float x, y, w, h;
+ static_cast<SVGForeignObjectElement*>(mContent)->
+ GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
+
+ // If mRect's width or height are negative, reflow blows up! We must clamp!
+ if (w < 0.0f) w = 0.0f;
+ if (h < 0.0f) h = 0.0f;
+
+ mRect = nsLayoutUtils::RoundGfxRectToAppRect(
+ gfxRect(x, y, w, h),
+ PresContext()->AppUnitsPerCSSPixel());
+
+ // Fully mark our kid dirty so that it gets resized if necessary
+ // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
+ nsIFrame* kid = PrincipalChildList().FirstChild();
+ kid->AddStateBits(NS_FRAME_IS_DIRTY);
+
+ // Make sure to not allow interrupts if we're not being reflown as a root:
+ nsPresContext::InterruptPreventer noInterrupts(PresContext());
+
+ DoReflow();
+
+ if (mState & NS_FRAME_FIRST_REFLOW) {
+ // Make sure we have our filter property (if any) before calling
+ // FinishAndStoreOverflow (subsequent filter changes are handled off
+ // nsChangeHint_UpdateEffects):
+ nsSVGEffects::UpdateEffects(this);
+ }
+
+ // If we have a filter, we need to invalidate ourselves because filter
+ // output can change even if none of our descendants need repainting.
+ if (StyleEffects()->HasFilters()) {
+ InvalidateFrame();
+ }
+
+ // TODO: once we support |overflow:visible| on foreignObject, then we will
+ // need to take account of our descendants here.
+ nsRect overflow = nsRect(nsPoint(0,0), mRect.Size());
+ nsOverflowAreas overflowAreas(overflow, overflow);
+ FinishAndStoreOverflow(overflowAreas, mRect.Size());
+
+ // Now unset the various reflow bits:
+ mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
+ NS_FRAME_HAS_DIRTY_CHILDREN);
+}
+
+void
+nsSVGForeignObjectFrame::NotifySVGChanged(uint32_t aFlags)
+{
+ MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
+ "Invalidation logic may need adjusting");
+
+ bool needNewBounds = false; // i.e. mRect or visual overflow rect
+ bool needReflow = false;
+ bool needNewCanvasTM = false;
+
+ if (aFlags & COORD_CONTEXT_CHANGED) {
+ SVGForeignObjectElement *fO =
+ static_cast<SVGForeignObjectElement*>(mContent);
+ // Coordinate context changes affect mCanvasTM if we have a
+ // percentage 'x' or 'y'
+ if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_X].IsPercentage() ||
+ fO->mLengthAttributes[SVGForeignObjectElement::ATTR_Y].IsPercentage()) {
+ needNewBounds = true;
+ needNewCanvasTM = true;
+ }
+ // Our coordinate context's width/height has changed. If we have a
+ // percentage width/height our dimensions will change so we must reflow.
+ if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_WIDTH].IsPercentage() ||
+ fO->mLengthAttributes[SVGForeignObjectElement::ATTR_HEIGHT].IsPercentage()) {
+ needNewBounds = true;
+ needReflow = true;
+ }
+ }
+
+ if (aFlags & TRANSFORM_CHANGED) {
+ if (mCanvasTM && mCanvasTM->IsSingular()) {
+ needNewBounds = true; // old bounds are bogus
+ }
+ needNewCanvasTM = true;
+ // In an ideal world we would reflow when our CTM changes. This is because
+ // glyph metrics do not necessarily scale uniformly with change in scale
+ // and, as a result, CTM changes may require text to break at different
+ // points. The problem would be how to keep performance acceptable when
+ // e.g. the transform of an ancestor is animated.
+ // We also seem to get some sort of infinite loop post bug 421584 if we
+ // reflow.
+ }
+
+ if (needNewBounds) {
+ // Ancestor changes can't affect how we render from the perspective of
+ // any rendering observers that we may have, so we don't need to
+ // invalidate them. We also don't need to invalidate ourself, since our
+ // changed ancestor will have invalidated its entire area, which includes
+ // our area.
+ nsSVGUtils::ScheduleReflowSVG(this);
+ }
+
+ // If we're called while the PresShell is handling reflow events then we
+ // must have been called as a result of the NotifyViewportChange() call in
+ // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
+ // at this point (i.e. during reflow) because it could confuse the
+ // PresShell and prevent it from reflowing us properly in future. Besides
+ // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
+ // synchronously, so there's no need.
+ if (needReflow && !PresContext()->PresShell()->IsReflowLocked()) {
+ RequestReflow(nsIPresShell::eResize);
+ }
+
+ if (needNewCanvasTM) {
+ // Do this after calling InvalidateAndScheduleBoundsUpdate in case we
+ // change the code and it needs to use it.
+ mCanvasTM = nullptr;
+ }
+}
+
+SVGBBox
+nsSVGForeignObjectFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
+ uint32_t aFlags)
+{
+ SVGForeignObjectElement *content =
+ static_cast<SVGForeignObjectElement*>(mContent);
+
+ float x, y, w, h;
+ content->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
+
+ if (w < 0.0f) w = 0.0f;
+ if (h < 0.0f) h = 0.0f;
+
+ if (aToBBoxUserspace.IsSingular()) {
+ // XXX ReportToConsole
+ return SVGBBox();
+ }
+ return aToBBoxUserspace.TransformBounds(gfx::Rect(0.0, 0.0, w, h));
+}
+
+//----------------------------------------------------------------------
+
+gfxMatrix
+nsSVGForeignObjectFrame::GetCanvasTM()
+{
+ if (!mCanvasTM) {
+ NS_ASSERTION(GetParent(), "null parent");
+
+ nsSVGContainerFrame *parent = static_cast<nsSVGContainerFrame*>(GetParent());
+ SVGForeignObjectElement *content =
+ static_cast<SVGForeignObjectElement*>(mContent);
+
+ gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
+
+ mCanvasTM = new gfxMatrix(tm);
+ }
+ return *mCanvasTM;
+}
+
+//----------------------------------------------------------------------
+// Implementation helpers
+
+void nsSVGForeignObjectFrame::RequestReflow(nsIPresShell::IntrinsicDirty aType)
+{
+ if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
+ // If we haven't had a ReflowSVG() yet, nothing to do.
+ return;
+
+ nsIFrame* kid = PrincipalChildList().FirstChild();
+ if (!kid)
+ return;
+
+ PresContext()->PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
+}
+
+void
+nsSVGForeignObjectFrame::DoReflow()
+{
+ MarkInReflow();
+ // Skip reflow if we're zero-sized, unless this is our first reflow.
+ if (IsDisabled() &&
+ !(GetStateBits() & NS_FRAME_FIRST_REFLOW))
+ return;
+
+ nsPresContext *presContext = PresContext();
+ nsIFrame* kid = PrincipalChildList().FirstChild();
+ if (!kid)
+ return;
+
+ // initiate a synchronous reflow here and now:
+ nsRenderingContext renderingContext(
+ presContext->PresShell()->CreateReferenceRenderingContext());
+
+ mInReflow = true;
+
+ WritingMode wm = kid->GetWritingMode();
+ ReflowInput reflowInput(presContext, kid,
+ &renderingContext,
+ LogicalSize(wm, ISize(wm),
+ NS_UNCONSTRAINEDSIZE));
+ ReflowOutput desiredSize(reflowInput);
+ nsReflowStatus status;
+
+ // We don't use mRect.height above because that tells the child to do
+ // page/column breaking at that height.
+ NS_ASSERTION(reflowInput.ComputedPhysicalBorderPadding() == nsMargin(0, 0, 0, 0) &&
+ reflowInput.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
+ "style system should ensure that :-moz-svg-foreign-content "
+ "does not get styled");
+ NS_ASSERTION(reflowInput.ComputedISize() == ISize(wm),
+ "reflow state made child wrong size");
+ reflowInput.SetComputedBSize(BSize(wm));
+
+ ReflowChild(kid, presContext, desiredSize, reflowInput, 0, 0,
+ NS_FRAME_NO_MOVE_FRAME, status);
+ NS_ASSERTION(mRect.width == desiredSize.Width() &&
+ mRect.height == desiredSize.Height(), "unexpected size");
+ FinishReflowChild(kid, presContext, desiredSize, &reflowInput, 0, 0,
+ NS_FRAME_NO_MOVE_FRAME);
+
+ mInReflow = false;
+}
+
+nsRect
+nsSVGForeignObjectFrame::GetInvalidRegion()
+{
+ MOZ_ASSERT(!NS_SVGDisplayListPaintingEnabled(),
+ "Only called by nsDisplayOuterSVG code");
+
+ nsIFrame* kid = PrincipalChildList().FirstChild();
+ if (kid->HasInvalidFrameInSubtree()) {
+ gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
+ r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
+ nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(), PresContext());
+ rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
+ return rect;
+ }
+ return nsRect();
+}
+
+