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