1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // Main header first:
8 #include "nsSVGForeignObjectFrame.h"
9 
10 // Keep others in (case-insensitive) order:
11 #include "ImgDrawResult.h"
12 #include "gfxContext.h"
13 #include "nsDisplayList.h"
14 #include "nsGkAtoms.h"
15 #include "nsNameSpaceManager.h"
16 #include "nsLayoutUtils.h"
17 #include "nsRegion.h"
18 #include "nsSVGContainerFrame.h"
19 #include "SVGObserverUtils.h"
20 #include "mozilla/dom/SVGForeignObjectElement.h"
21 #include "nsSVGIntegrationUtils.h"
22 #include "nsSVGOuterSVGFrame.h"
23 #include "nsSVGUtils.h"
24 #include "mozilla/AutoRestore.h"
25 
26 using namespace mozilla;
27 using namespace mozilla::dom;
28 using namespace mozilla::image;
29 
30 //----------------------------------------------------------------------
31 // Implementation
32 
NS_NewSVGForeignObjectFrame(nsIPresShell * aPresShell,nsStyleContext * aContext)33 nsContainerFrame* NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell,
34                                               nsStyleContext* aContext) {
35   return new (aPresShell) nsSVGForeignObjectFrame(aContext);
36 }
37 
NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)38 NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
39 
40 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
41     : nsContainerFrame(aContext, kClassID), mInReflow(false) {
42   AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
43                NS_FRAME_SVG_LAYOUT);
44 }
45 
46 //----------------------------------------------------------------------
47 // nsIFrame methods
48 
49 NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
NS_QUERYFRAME_ENTRY(nsSVGDisplayableFrame)50 NS_QUERYFRAME_ENTRY(nsSVGDisplayableFrame)
51 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
52 
53 void nsSVGForeignObjectFrame::Init(nsIContent* aContent,
54                                    nsContainerFrame* aParent,
55                                    nsIFrame* aPrevInFlow) {
56   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::foreignObject),
57                "Content is not an SVG foreignObject!");
58 
59   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
60   AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
61   AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER |
62                NS_FRAME_FONT_INFLATION_FLOW_ROOT);
63   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
64     nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
65   }
66 }
67 
DestroyFrom(nsIFrame * aDestructRoot,PostDestroyData & aPostDestroyData)68 void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot,
69                                           PostDestroyData& aPostDestroyData) {
70   // Only unregister if we registered in the first place:
71   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
72     nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
73   }
74   nsContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
75 }
76 
AttributeChanged(int32_t aNameSpaceID,nsAtom * aAttribute,int32_t aModType)77 nsresult nsSVGForeignObjectFrame::AttributeChanged(int32_t aNameSpaceID,
78                                                    nsAtom* aAttribute,
79                                                    int32_t aModType) {
80   if (aNameSpaceID == kNameSpaceID_None) {
81     if (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height) {
82       nsLayoutUtils::PostRestyleEvent(
83           mContent->AsElement(), nsRestyleHint(0),
84           nsChangeHint_InvalidateRenderingObservers);
85       nsSVGUtils::ScheduleReflowSVG(this);
86       // XXXjwatt: why mark intrinsic widths dirty? can't we just use eResize?
87       RequestReflow(nsIPresShell::eStyleChange);
88     } else if (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y) {
89       // make sure our cached transform matrix gets (lazily) updated
90       mCanvasTM = nullptr;
91       nsLayoutUtils::PostRestyleEvent(
92           mContent->AsElement(), nsRestyleHint(0),
93           nsChangeHint_InvalidateRenderingObservers);
94       nsSVGUtils::ScheduleReflowSVG(this);
95     } else if (aAttribute == nsGkAtoms::transform) {
96       // We don't invalidate for transform changes (the layers code does that).
97       // Also note that SVGTransformableElement::GetAttributeChangeHint will
98       // return nsChangeHint_UpdateOverflow for "transform" attribute changes
99       // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
100       mCanvasTM = nullptr;
101     } else if (aAttribute == nsGkAtoms::viewBox ||
102                aAttribute == nsGkAtoms::preserveAspectRatio) {
103       nsLayoutUtils::PostRestyleEvent(
104           mContent->AsElement(), nsRestyleHint(0),
105           nsChangeHint_InvalidateRenderingObservers);
106     }
107   }
108 
109   return NS_OK;
110 }
111 
Reflow(nsPresContext * aPresContext,ReflowOutput & aDesiredSize,const ReflowInput & aReflowInput,nsReflowStatus & aStatus)112 void nsSVGForeignObjectFrame::Reflow(nsPresContext* aPresContext,
113                                      ReflowOutput& aDesiredSize,
114                                      const ReflowInput& aReflowInput,
115                                      nsReflowStatus& aStatus) {
116   MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
117   MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
118              "Should not have been called");
119 
120   // Only InvalidateAndScheduleBoundsUpdate marks us with NS_FRAME_IS_DIRTY,
121   // so if that bit is still set we still have a resize pending. If we hit
122   // this assertion, then we should get the presShell to skip reflow roots
123   // that have a dirty parent since a reflow is going to come via the
124   // reflow root's parent anyway.
125   NS_ASSERTION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
126                "Reflowing while a resize is pending is wasteful");
127 
128   // ReflowSVG makes sure mRect is up to date before we're called.
129 
130   NS_ASSERTION(!aReflowInput.mParentReflowInput,
131                "should only get reflow from being reflow root");
132   NS_ASSERTION(aReflowInput.ComputedWidth() == GetSize().width &&
133                    aReflowInput.ComputedHeight() == GetSize().height,
134                "reflow roots should be reflowed at existing size and "
135                "svg.css should ensure we have no padding/border/margin");
136 
137   DoReflow();
138 
139   WritingMode wm = aReflowInput.GetWritingMode();
140   LogicalSize finalSize(wm, aReflowInput.ComputedISize(),
141                         aReflowInput.ComputedBSize());
142   aDesiredSize.SetSize(wm, finalSize);
143   aDesiredSize.SetOverflowAreasToDesiredBounds();
144 }
145 
BuildDisplayList(nsDisplayListBuilder * aBuilder,const nsDisplayListSet & aLists)146 void nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
147                                                const nsDisplayListSet& aLists) {
148   if (!static_cast<const nsSVGElement*>(GetContent())->HasValidDimensions()) {
149     return;
150   }
151   DisplayOutline(aBuilder, aLists);
152   BuildDisplayListForNonBlockChildren(aBuilder, aLists);
153 }
154 
IsSVGTransformed(Matrix * aOwnTransform,Matrix * aFromParentTransform) const155 bool nsSVGForeignObjectFrame::IsSVGTransformed(
156     Matrix* aOwnTransform, Matrix* aFromParentTransform) const {
157   bool foundTransform = false;
158 
159   // Check if our parent has children-only transforms:
160   nsIFrame* parent = GetParent();
161   if (parent &&
162       parent->IsFrameOfType(nsIFrame::eSVG | nsIFrame::eSVGContainer)) {
163     foundTransform =
164         static_cast<nsSVGContainerFrame*>(parent)->HasChildrenOnlyTransform(
165             aFromParentTransform);
166   }
167 
168   nsSVGElement* content = static_cast<nsSVGElement*>(GetContent());
169   nsSVGAnimatedTransformList* transformList =
170       content->GetAnimatedTransformList();
171   if ((transformList && transformList->HasTransform()) ||
172       content->GetAnimateMotionTransform()) {
173     if (aOwnTransform) {
174       *aOwnTransform = gfx::ToMatrix(
175           content->PrependLocalTransformsTo(gfxMatrix(), eUserSpaceToParent));
176     }
177     foundTransform = true;
178   }
179   return foundTransform;
180 }
181 
PaintSVG(gfxContext & aContext,const gfxMatrix & aTransform,imgDrawingParams & aImgParams,const nsIntRect * aDirtyRect)182 void nsSVGForeignObjectFrame::PaintSVG(gfxContext& aContext,
183                                        const gfxMatrix& aTransform,
184                                        imgDrawingParams& aImgParams,
185                                        const nsIntRect* aDirtyRect) {
186   NS_ASSERTION(
187       !NS_SVGDisplayListPaintingEnabled() || (mState & NS_FRAME_IS_NONDISPLAY),
188       "If display lists are enabled, only painting of non-display "
189       "SVG should take this code path");
190 
191   if (IsDisabled()) {
192     return;
193   }
194 
195   nsIFrame* kid = PrincipalChildList().FirstChild();
196   if (!kid) {
197     return;
198   }
199 
200   if (aTransform.IsSingular()) {
201     NS_WARNING("Can't render foreignObject element!");
202     return;
203   }
204 
205   nsRect kidDirtyRect = kid->GetVisualOverflowRect();
206 
207   /* Check if we need to draw anything. */
208   if (aDirtyRect) {
209     NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
210                      (mState & NS_FRAME_IS_NONDISPLAY),
211                  "Display lists handle dirty rect intersection test");
212     // Transform the dirty rect into app units in our userspace.
213     gfxMatrix invmatrix = aTransform;
214     DebugOnly<bool> ok = invmatrix.Invert();
215     NS_ASSERTION(ok, "inverse of non-singular matrix should be non-singular");
216 
217     gfxRect transDirtyRect = gfxRect(aDirtyRect->x, aDirtyRect->y,
218                                      aDirtyRect->width, aDirtyRect->height);
219     transDirtyRect = invmatrix.TransformBounds(transDirtyRect);
220 
221     kidDirtyRect.IntersectRect(
222         kidDirtyRect,
223         nsLayoutUtils::RoundGfxRectToAppRect(
224             transDirtyRect, PresContext()->AppUnitsPerCSSPixel()));
225 
226     // XXX after bug 614732 is fixed, we will compare mRect with aDirtyRect,
227     // not with kidDirtyRect. I.e.
228     // int32_t appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
229     // mRect.ToOutsidePixels(appUnitsPerDevPx).Intersects(*aDirtyRect)
230     if (kidDirtyRect.IsEmpty()) return;
231   }
232 
233   aContext.Save();
234 
235   if (StyleDisplay()->IsScrollableOverflow()) {
236     float x, y, width, height;
237     static_cast<nsSVGElement*>(GetContent())
238         ->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
239 
240     gfxRect clipRect =
241         nsSVGUtils::GetClipRectForFrame(this, 0.0f, 0.0f, width, height);
242     nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
243   }
244 
245   // SVG paints in CSS px, but normally frames paint in dev pixels. Here we
246   // multiply a CSS-px-to-dev-pixel factor onto aTransform so our children
247   // paint correctly.
248   float cssPxPerDevPx = PresContext()->AppUnitsToFloatCSSPixels(
249       PresContext()->AppUnitsPerDevPixel());
250   gfxMatrix canvasTMForChildren = aTransform;
251   canvasTMForChildren.PreScale(cssPxPerDevPx, cssPxPerDevPx);
252 
253   aContext.Multiply(canvasTMForChildren);
254 
255   using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
256   PaintFrameFlags flags = PaintFrameFlags::PAINT_IN_TRANSFORM;
257   if (SVGAutoRenderState::IsPaintingToWindow(aContext.GetDrawTarget())) {
258     flags |= PaintFrameFlags::PAINT_TO_WINDOW;
259   }
260   if (aImgParams.imageFlags & imgIContainer::FLAG_SYNC_DECODE) {
261     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
262   }
263   Unused << nsLayoutUtils::PaintFrame(
264       &aContext, kid, nsRegion(kidDirtyRect), NS_RGBA(0, 0, 0, 0),
265       nsDisplayListBuilderMode::PAINTING, flags);
266 
267   aContext.Restore();
268 }
269 
GetFrameForPoint(const gfxPoint & aPoint)270 nsIFrame* nsSVGForeignObjectFrame::GetFrameForPoint(const gfxPoint& aPoint) {
271   NS_ASSERTION(!NS_SVGDisplayListHitTestingEnabled() ||
272                    (mState & NS_FRAME_IS_NONDISPLAY),
273                "If display lists are enabled, only hit-testing of a "
274                "clipPath's contents should take this code path");
275 
276   if (IsDisabled() || (GetStateBits() & NS_FRAME_IS_NONDISPLAY)) return nullptr;
277 
278   nsIFrame* kid = PrincipalChildList().FirstChild();
279   if (!kid) return nullptr;
280 
281   float x, y, width, height;
282   static_cast<nsSVGElement*>(GetContent())
283       ->GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
284 
285   if (!gfxRect(x, y, width, height).Contains(aPoint) ||
286       !nsSVGUtils::HitTestClip(this, aPoint)) {
287     return nullptr;
288   }
289 
290   // Convert the point to app units relative to the top-left corner of the
291   // viewport that's established by the foreignObject element:
292 
293   gfxPoint pt =
294       (aPoint + gfxPoint(x, y)) * nsPresContext::AppUnitsPerCSSPixel();
295   nsPoint point = nsPoint(NSToIntRound(pt.x), NSToIntRound(pt.y));
296 
297   return nsLayoutUtils::GetFrameForPoint(kid, point);
298 }
299 
ReflowSVG()300 void nsSVGForeignObjectFrame::ReflowSVG() {
301   NS_ASSERTION(nsSVGUtils::OuterSVGIsCallingReflowSVG(this),
302                "This call is probably a wasteful mistake");
303 
304   MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_NONDISPLAY),
305              "ReflowSVG mechanism not designed for this");
306 
307   if (!nsSVGUtils::NeedsReflowSVG(this)) {
308     return;
309   }
310 
311   // We update mRect before the DoReflow call so that DoReflow uses the
312   // correct dimensions:
313 
314   float x, y, w, h;
315   static_cast<SVGForeignObjectElement*>(GetContent())
316       ->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
317 
318   // If mRect's width or height are negative, reflow blows up! We must clamp!
319   if (w < 0.0f) w = 0.0f;
320   if (h < 0.0f) h = 0.0f;
321 
322   mRect = nsLayoutUtils::RoundGfxRectToAppRect(
323       gfxRect(x, y, w, h), PresContext()->AppUnitsPerCSSPixel());
324 
325   // Fully mark our kid dirty so that it gets resized if necessary
326   // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case):
327   nsIFrame* kid = PrincipalChildList().FirstChild();
328   kid->AddStateBits(NS_FRAME_IS_DIRTY);
329 
330   // Make sure to not allow interrupts if we're not being reflown as a root:
331   nsPresContext::InterruptPreventer noInterrupts(PresContext());
332 
333   DoReflow();
334 
335   if (mState & NS_FRAME_FIRST_REFLOW) {
336     // Make sure we have our filter property (if any) before calling
337     // FinishAndStoreOverflow (subsequent filter changes are handled off
338     // nsChangeHint_UpdateEffects):
339     SVGObserverUtils::UpdateEffects(this);
340   }
341 
342   // If we have a filter, we need to invalidate ourselves because filter
343   // output can change even if none of our descendants need repainting.
344   if (StyleEffects()->HasFilters()) {
345     InvalidateFrame();
346   }
347 
348   // TODO: once we support |overflow:visible| on foreignObject, then we will
349   // need to take account of our descendants here.
350   nsRect overflow = nsRect(nsPoint(0, 0), mRect.Size());
351   nsOverflowAreas overflowAreas(overflow, overflow);
352   FinishAndStoreOverflow(overflowAreas, mRect.Size());
353 
354   // Now unset the various reflow bits:
355   RemoveStateBits(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
356                   NS_FRAME_HAS_DIRTY_CHILDREN);
357 }
358 
NotifySVGChanged(uint32_t aFlags)359 void nsSVGForeignObjectFrame::NotifySVGChanged(uint32_t aFlags) {
360   MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
361              "Invalidation logic may need adjusting");
362 
363   bool needNewBounds = false;  // i.e. mRect or visual overflow rect
364   bool needReflow = false;
365   bool needNewCanvasTM = false;
366 
367   if (aFlags & COORD_CONTEXT_CHANGED) {
368     SVGForeignObjectElement* fO =
369         static_cast<SVGForeignObjectElement*>(GetContent());
370     // Coordinate context changes affect mCanvasTM if we have a
371     // percentage 'x' or 'y'
372     if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_X].IsPercentage() ||
373         fO->mLengthAttributes[SVGForeignObjectElement::ATTR_Y].IsPercentage()) {
374       needNewBounds = true;
375       needNewCanvasTM = true;
376     }
377     // Our coordinate context's width/height has changed. If we have a
378     // percentage width/height our dimensions will change so we must reflow.
379     if (fO->mLengthAttributes[SVGForeignObjectElement::ATTR_WIDTH]
380             .IsPercentage() ||
381         fO->mLengthAttributes[SVGForeignObjectElement::ATTR_HEIGHT]
382             .IsPercentage()) {
383       needNewBounds = true;
384       needReflow = true;
385     }
386   }
387 
388   if (aFlags & TRANSFORM_CHANGED) {
389     if (mCanvasTM && mCanvasTM->IsSingular()) {
390       needNewBounds = true;  // old bounds are bogus
391     }
392     needNewCanvasTM = true;
393     // In an ideal world we would reflow when our CTM changes. This is because
394     // glyph metrics do not necessarily scale uniformly with change in scale
395     // and, as a result, CTM changes may require text to break at different
396     // points. The problem would be how to keep performance acceptable when
397     // e.g. the transform of an ancestor is animated.
398     // We also seem to get some sort of infinite loop post bug 421584 if we
399     // reflow.
400   }
401 
402   if (needNewBounds) {
403     // Ancestor changes can't affect how we render from the perspective of
404     // any rendering observers that we may have, so we don't need to
405     // invalidate them. We also don't need to invalidate ourself, since our
406     // changed ancestor will have invalidated its entire area, which includes
407     // our area.
408     nsSVGUtils::ScheduleReflowSVG(this);
409   }
410 
411   // If we're called while the PresShell is handling reflow events then we
412   // must have been called as a result of the NotifyViewportChange() call in
413   // our nsSVGOuterSVGFrame's Reflow() method. We must not call RequestReflow
414   // at this point (i.e. during reflow) because it could confuse the
415   // PresShell and prevent it from reflowing us properly in future. Besides
416   // that, nsSVGOuterSVGFrame::DidReflow will take care of reflowing us
417   // synchronously, so there's no need.
418   if (needReflow && !PresShell()->IsReflowLocked()) {
419     RequestReflow(nsIPresShell::eResize);
420   }
421 
422   if (needNewCanvasTM) {
423     // Do this after calling InvalidateAndScheduleBoundsUpdate in case we
424     // change the code and it needs to use it.
425     mCanvasTM = nullptr;
426   }
427 }
428 
GetBBoxContribution(const Matrix & aToBBoxUserspace,uint32_t aFlags)429 SVGBBox nsSVGForeignObjectFrame::GetBBoxContribution(
430     const Matrix& aToBBoxUserspace, uint32_t aFlags) {
431   SVGForeignObjectElement* content =
432       static_cast<SVGForeignObjectElement*>(GetContent());
433 
434   float x, y, w, h;
435   content->GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
436 
437   if (w < 0.0f) w = 0.0f;
438   if (h < 0.0f) h = 0.0f;
439 
440   if (aToBBoxUserspace.IsSingular()) {
441     // XXX ReportToConsole
442     return SVGBBox();
443   }
444   return aToBBoxUserspace.TransformBounds(gfx::Rect(0.0, 0.0, w, h));
445 }
446 
447 //----------------------------------------------------------------------
448 
GetCanvasTM()449 gfxMatrix nsSVGForeignObjectFrame::GetCanvasTM() {
450   if (!mCanvasTM) {
451     NS_ASSERTION(GetParent(), "null parent");
452 
453     nsSVGContainerFrame* parent =
454         static_cast<nsSVGContainerFrame*>(GetParent());
455     SVGForeignObjectElement* content =
456         static_cast<SVGForeignObjectElement*>(GetContent());
457 
458     gfxMatrix tm = content->PrependLocalTransformsTo(parent->GetCanvasTM());
459 
460     mCanvasTM = new gfxMatrix(tm);
461   }
462   return *mCanvasTM;
463 }
464 
465 //----------------------------------------------------------------------
466 // Implementation helpers
467 
RequestReflow(nsIPresShell::IntrinsicDirty aType)468 void nsSVGForeignObjectFrame::RequestReflow(
469     nsIPresShell::IntrinsicDirty aType) {
470   if (GetStateBits() & NS_FRAME_FIRST_REFLOW)
471     // If we haven't had a ReflowSVG() yet, nothing to do.
472     return;
473 
474   nsIFrame* kid = PrincipalChildList().FirstChild();
475   if (!kid) return;
476 
477   PresShell()->FrameNeedsReflow(kid, aType, NS_FRAME_IS_DIRTY);
478 }
479 
DoReflow()480 void nsSVGForeignObjectFrame::DoReflow() {
481   MarkInReflow();
482   // Skip reflow if we're zero-sized, unless this is our first reflow.
483   if (IsDisabled() && !(GetStateBits() & NS_FRAME_FIRST_REFLOW)) return;
484 
485   nsPresContext* presContext = PresContext();
486   nsIFrame* kid = PrincipalChildList().FirstChild();
487   if (!kid) return;
488 
489   // initiate a synchronous reflow here and now:
490   RefPtr<gfxContext> renderingContext =
491       presContext->PresShell()->CreateReferenceRenderingContext();
492 
493   mInReflow = true;
494 
495   WritingMode wm = kid->GetWritingMode();
496   ReflowInput reflowInput(presContext, kid, renderingContext,
497                           LogicalSize(wm, ISize(wm), NS_UNCONSTRAINEDSIZE));
498   ReflowOutput desiredSize(reflowInput);
499   nsReflowStatus status;
500 
501   // We don't use mRect.height above because that tells the child to do
502   // page/column breaking at that height.
503   NS_ASSERTION(
504       reflowInput.ComputedPhysicalBorderPadding() == nsMargin(0, 0, 0, 0) &&
505           reflowInput.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0),
506       "style system should ensure that :-moz-svg-foreign-content "
507       "does not get styled");
508   NS_ASSERTION(reflowInput.ComputedISize() == ISize(wm),
509                "reflow state made child wrong size");
510   reflowInput.SetComputedBSize(BSize(wm));
511 
512   ReflowChild(kid, presContext, desiredSize, reflowInput, 0, 0,
513               NS_FRAME_NO_MOVE_FRAME, status);
514   NS_ASSERTION(mRect.width == desiredSize.Width() &&
515                    mRect.height == desiredSize.Height(),
516                "unexpected size");
517   FinishReflowChild(kid, presContext, desiredSize, &reflowInput, 0, 0,
518                     NS_FRAME_NO_MOVE_FRAME);
519 
520   mInReflow = false;
521 }
522 
GetInvalidRegion()523 nsRect nsSVGForeignObjectFrame::GetInvalidRegion() {
524   MOZ_ASSERT(!NS_SVGDisplayListPaintingEnabled(),
525              "Only called by nsDisplayOuterSVG code");
526 
527   nsIFrame* kid = PrincipalChildList().FirstChild();
528   if (kid->HasInvalidFrameInSubtree()) {
529     gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height);
530     r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
531     nsRect rect = nsSVGUtils::ToCanvasBounds(r, GetCanvasTM(), PresContext());
532     rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect);
533     return rect;
534   }
535   return nsRect();
536 }
537 
AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox> & aResult)538 void nsSVGForeignObjectFrame::AppendDirectlyOwnedAnonBoxes(
539     nsTArray<OwnedAnonBox>& aResult) {
540   MOZ_ASSERT(PrincipalChildList().FirstChild(), "Must have our anon box");
541   aResult.AppendElement(OwnedAnonBox(PrincipalChildList().FirstChild()));
542 }
543