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/. */
8 * rendering object for replaced elements that contain a document, such
9 * as <frame>, <iframe>, and some <object>s
12 #include "nsSubDocumentFrame.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/PresShell.h"
16 #include "mozilla/StaticPrefs_layout.h"
17 #include "mozilla/Unused.h"
18 #include "mozilla/dom/Document.h"
19 #include "mozilla/dom/HTMLFrameElement.h"
20 #include "mozilla/dom/BrowserParent.h"
23 #include "nsGenericHTMLElement.h"
24 #include "nsGenericHTMLFrameElement.h"
25 #include "nsAttrValueInlines.h"
26 #include "nsIDocShell.h"
27 #include "nsIContentViewer.h"
28 #include "nsIContentInlines.h"
29 #include "nsPresContext.h"
31 #include "nsViewManager.h"
32 #include "nsGkAtoms.h"
33 #include "nsStyleConsts.h"
34 #include "nsStyleStruct.h"
35 #include "nsStyleStructInlines.h"
36 #include "nsFrameSetFrame.h"
37 #include "nsNameSpaceManager.h"
38 #include "nsDisplayList.h"
39 #include "nsIScrollableFrame.h"
40 #include "nsIObjectLoadingContent.h"
41 #include "nsLayoutUtils.h"
42 #include "nsContentUtils.h"
43 #include "nsServiceManagerUtils.h"
44 #include "nsQueryObject.h"
45 #include "RetainedDisplayListBuilder.h"
46 #include "nsObjectLoadingContent.h"
49 #include "mozilla/layers/WebRenderUserData.h"
50 #include "mozilla/layers/WebRenderScrollData.h"
51 #include "mozilla/layers/RenderRootStateManager.h"
52 #include "mozilla/layers/StackingContextHelper.h" // for StackingContextHelper
53 #include "mozilla/ProfilerLabels.h"
55 using namespace mozilla
;
56 using namespace mozilla::dom
;
57 using namespace mozilla::gfx
;
58 using namespace mozilla::layers
;
60 static Document
* GetDocumentFromView(nsView
* aView
) {
61 MOZ_ASSERT(aView
, "null view");
63 nsViewManager
* vm
= aView
->GetViewManager();
64 PresShell
* presShell
= vm
? vm
->GetPresShell() : nullptr;
65 return presShell
? presShell
->GetDocument() : nullptr;
68 nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle
* aStyle
,
69 nsPresContext
* aPresContext
)
70 : nsAtomicContainerFrame(aStyle
, aPresContext
, kClassID
),
74 mPostedReflowCallback(false),
76 mCallingShow(false) {}
79 a11y::AccType
nsSubDocumentFrame::AccessibleType() {
80 return a11y::eOuterDocType
;
84 NS_QUERYFRAME_HEAD(nsSubDocumentFrame
)
85 NS_QUERYFRAME_ENTRY(nsSubDocumentFrame
)
86 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame
)
88 class AsyncFrameInit
: public Runnable
{
90 explicit AsyncFrameInit(nsIFrame
* aFrame
)
91 : mozilla::Runnable("AsyncFrameInit"), mFrame(aFrame
) {}
92 NS_IMETHOD
Run() override
{
93 AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER
);
94 if (mFrame
.IsAlive()) {
95 static_cast<nsSubDocumentFrame
*>(mFrame
.GetFrame())->ShowViewer();
104 static void InsertViewsInReverseOrder(nsView
* aSibling
, nsView
* aParent
);
106 static void EndSwapDocShellsForViews(nsView
* aView
);
108 void nsSubDocumentFrame::Init(nsIContent
* aContent
, nsContainerFrame
* aParent
,
109 nsIFrame
* aPrevInFlow
) {
110 MOZ_ASSERT(aContent
);
111 // determine if we are a <frame> or <iframe>
112 mIsInline
= !aContent
->IsHTMLElement(nsGkAtoms::frame
);
114 nsAtomicContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
116 // CreateView() creates this frame's view, stored in mOuterView. It needs to
117 // be created first since it's the parent of the inner view, stored in
122 // Set the primary frame now so that nsDocumentViewer::FindContainerView
123 // called from within EndSwapDocShellsForViews below can find it if needed.
124 aContent
->SetPrimaryFrame(this);
126 // If we have a detached subdoc's root view on our frame loader, re-insert
127 // it into the view tree. This happens when we've been reframed, and
128 // ensures the presentation persists across reframes. If the frame element
129 // has changed documents however, we blow away the presentation.
130 RefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
132 nsCOMPtr
<Document
> oldContainerDoc
;
133 nsIFrame
* detachedFrame
=
134 frameloader
->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc
));
135 frameloader
->SetDetachedSubdocFrame(nullptr, nullptr);
136 MOZ_ASSERT(oldContainerDoc
|| !detachedFrame
);
137 if (oldContainerDoc
) {
138 nsView
* detachedView
= detachedFrame
? detachedFrame
->GetView() : nullptr;
139 if (detachedView
&& oldContainerDoc
== aContent
->OwnerDoc()) {
140 // Restore stashed presentation.
141 ::InsertViewsInReverseOrder(detachedView
, mInnerView
);
142 ::EndSwapDocShellsForViews(mInnerView
->GetFirstChild());
144 // Presentation is for a different document, don't restore it.
150 PropagateIsUnderHiddenEmbedderElementToSubView(
151 PresShell()->IsUnderHiddenEmbedderElement() ||
152 !StyleVisibility()->IsVisible());
154 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
157 void nsSubDocumentFrame::PropagateIsUnderHiddenEmbedderElementToSubView(
158 bool aIsUnderHiddenEmbedderElement
) {
159 if (mFrameLoader
&& mFrameLoader
->IsRemoteFrame()) {
160 mFrameLoader
->SendIsUnderHiddenEmbedderElement(
161 aIsUnderHiddenEmbedderElement
);
169 nsView
* subdocView
= mInnerView
->GetFirstChild();
171 if (mozilla::PresShell
* presShell
= subdocView
->GetPresShell()) {
172 presShell
->SetIsUnderHiddenEmbedderElement(aIsUnderHiddenEmbedderElement
);
174 subdocView
= subdocView
->GetNextSibling();
178 void nsSubDocumentFrame::ShowViewer() {
183 RefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
188 if (!frameloader
->IsRemoteFrame() && !PresContext()->IsDynamic()) {
189 // We let the printing code take care of loading the document and
190 // initializing the shell; just create the inner view for it to use.
191 (void)EnsureInnerView();
193 AutoWeakFrame
weakThis(this);
195 bool didCreateDoc
= frameloader
->Show(this);
196 if (!weakThis
.IsAlive()) {
199 mCallingShow
= false;
200 mDidCreateDoc
= didCreateDoc
;
202 if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW
)) {
203 frameloader
->UpdatePositionAndSize(this);
206 if (!weakThis
.IsAlive()) {
213 nsIFrame
* nsSubDocumentFrame::GetSubdocumentRootFrame() {
214 if (!mInnerView
) return nullptr;
215 nsView
* subdocView
= mInnerView
->GetFirstChild();
216 return subdocView
? subdocView
->GetFrame() : nullptr;
219 mozilla::PresShell
* nsSubDocumentFrame::GetSubdocumentPresShellForPainting(
221 if (!mInnerView
) return nullptr;
223 nsView
* subdocView
= mInnerView
->GetFirstChild();
224 if (!subdocView
) return nullptr;
226 mozilla::PresShell
* presShell
= nullptr;
228 nsIFrame
* subdocRootFrame
= subdocView
->GetFrame();
229 if (subdocRootFrame
) {
230 presShell
= subdocRootFrame
->PresShell();
233 // If painting is suppressed in the presshell, we try to look for a better
235 if (!presShell
|| (presShell
->IsPaintingSuppressed() &&
236 !(aFlags
& IGNORE_PAINT_SUPPRESSION
))) {
237 // During page transition mInnerView will sometimes have two children, the
238 // first being the new page that may not have any frame, and the second
239 // being the old page that will probably have a frame.
240 nsView
* nextView
= subdocView
->GetNextSibling();
241 nsIFrame
* frame
= nullptr;
243 frame
= nextView
->GetFrame();
246 mozilla::PresShell
* presShellForNextView
= frame
->PresShell();
247 if (!presShell
|| (presShellForNextView
&&
248 !presShellForNextView
->IsPaintingSuppressed() &&
249 StaticPrefs::layout_show_previous_page())) {
250 subdocView
= nextView
;
251 subdocRootFrame
= frame
;
252 presShell
= presShellForNextView
;
256 // If we don't have a frame we use this roundabout way to get the pres
258 if (!mFrameLoader
) return nullptr;
259 nsIDocShell
* docShell
= mFrameLoader
->GetDocShell(IgnoreErrors());
260 if (!docShell
) return nullptr;
261 presShell
= docShell
->GetPresShell();
268 ScreenIntSize
nsSubDocumentFrame::GetSubdocumentSize() {
269 if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW
)) {
270 if (RefPtr
<nsFrameLoader
> frameloader
= FrameLoader()) {
271 nsCOMPtr
<Document
> oldContainerDoc
;
272 nsIFrame
* detachedFrame
=
273 frameloader
->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc
));
274 if (nsView
* view
= detachedFrame
? detachedFrame
->GetView() : nullptr) {
275 nsSize size
= view
->GetBounds().Size();
276 nsPresContext
* presContext
= detachedFrame
->PresContext();
277 return ScreenIntSize(presContext
->AppUnitsToDevPixels(size
.width
),
278 presContext
->AppUnitsToDevPixels(size
.height
));
281 // Pick some default size for now. Using 10x10 because that's what the
283 return ScreenIntSize(10, 10);
286 nsSize docSizeAppUnits
;
287 nsPresContext
* presContext
= PresContext();
288 if (GetContent()->IsHTMLElement(nsGkAtoms::frame
)) {
289 docSizeAppUnits
= GetSize();
291 docSizeAppUnits
= GetContentRect().Size();
294 // Adjust subdocument size, according to 'object-fit' and the subdocument's
295 // intrinsic size and ratio.
296 docSizeAppUnits
= nsLayoutUtils::ComputeObjectDestRect(
297 nsRect(nsPoint(), docSizeAppUnits
), GetIntrinsicSize(),
298 GetIntrinsicRatio(), StylePosition())
301 return ScreenIntSize(
302 presContext
->AppUnitsToDevPixels(docSizeAppUnits
.width
),
303 presContext
->AppUnitsToDevPixels(docSizeAppUnits
.height
));
306 static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder
* aBuilder
,
308 nsDisplayList
* aList
) {
309 for (nsDisplayItem
* item
: aList
->TakeItems()) {
310 if (item
->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR
) {
311 nsDisplayList
tmpList(aBuilder
);
312 tmpList
.AppendToTop(item
);
313 item
= MakeDisplayItemWithIndex
<nsDisplayOwnLayer
>(
314 aBuilder
, aFrame
, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc
,
315 &tmpList
, aBuilder
->CurrentActiveScrolledRoot(),
316 nsDisplayOwnLayerFlags::None
, ScrollbarData
{}, true, false);
318 aList
->AppendToTop(item
);
322 void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
323 const nsDisplayListSet
& aLists
) {
324 if (!IsVisibleForPainting()) {
328 nsFrameLoader
* frameLoader
= FrameLoader();
329 bool isRemoteFrame
= frameLoader
&& frameLoader
->IsRemoteFrame();
331 // If we are pointer-events:none then we don't need to HitTest background
332 const bool pointerEventsNone
=
333 Style()->PointerEvents() == StylePointerEvents::None
;
334 if (!aBuilder
->IsForEventDelivery() || !pointerEventsNone
) {
335 nsDisplayListCollection
decorations(aBuilder
);
336 DisplayBorderBackgroundOutline(aBuilder
, decorations
);
338 // Wrap background colors of <iframe>s with remote subdocuments in their
339 // own layer so we generate a ColorLayer. This is helpful for optimizing
340 // compositing; we can skip compositing the ColorLayer when the
341 // remote content is opaque.
342 WrapBackgroundColorInOwnLayer(aBuilder
, this,
343 decorations
.BorderBackground());
345 decorations
.MoveTo(aLists
);
348 if (aBuilder
->IsForEventDelivery() && pointerEventsNone
) {
352 // If we're passing pointer events to children then we have to descend into
353 // subdocuments no matter what, to determine which parts are transparent for
354 // hit-testing or event regions.
355 bool needToDescend
= aBuilder
->GetDescendIntoSubdocuments();
356 if (!mInnerView
|| !needToDescend
) {
361 // We're the subdoc for <browser remote="true"> and it has
362 // painted content. Display its shadow layer tree.
363 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
364 clipState
.ClipContainingBlockDescendantsToContentBox(aBuilder
, this);
366 aLists
.Content()->AppendNewToTop
<nsDisplayRemote
>(aBuilder
, this);
370 RefPtr
<mozilla::PresShell
> presShell
= GetSubdocumentPresShellForPainting(
371 aBuilder
->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION
: 0);
377 if (aBuilder
->IsInFilter()) {
378 Document
* outerDoc
= PresShell()->GetDocument();
379 Document
* innerDoc
= presShell
->GetDocument();
380 if (outerDoc
&& innerDoc
) {
381 if (!outerDoc
->NodePrincipal()->Equals(innerDoc
->NodePrincipal())) {
382 outerDoc
->SetUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame
);
387 nsIFrame
* subdocRootFrame
= presShell
->GetRootFrame();
389 nsPresContext
* presContext
= presShell
->GetPresContext();
391 int32_t parentAPD
= PresContext()->AppUnitsPerDevPixel();
392 int32_t subdocAPD
= presContext
->AppUnitsPerDevPixel();
396 bool ignoreViewportScrolling
= false;
397 if (subdocRootFrame
) {
398 // get the dirty rect relative to the root frame of the subdoc
399 visible
= aBuilder
->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame
);
400 dirty
= aBuilder
->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame
);
401 // and convert into the appunits of the subdoc
402 visible
= visible
.ScaleToOtherAppUnitsRoundOut(parentAPD
, subdocAPD
);
403 dirty
= dirty
.ScaleToOtherAppUnitsRoundOut(parentAPD
, subdocAPD
);
405 if (nsIScrollableFrame
* rootScrollableFrame
=
406 presShell
->GetRootScrollFrameAsScrollable()) {
407 // Use a copy, so the rects don't get modified.
408 nsRect copyOfDirty
= dirty
;
409 nsRect copyOfVisible
= visible
;
410 // TODO(botond): Can we just axe this DecideScrollableLayer call?
411 rootScrollableFrame
->DecideScrollableLayer(aBuilder
, ©OfVisible
,
413 /* aSetBase = */ true);
415 ignoreViewportScrolling
= presShell
->IgnoringViewportScrolling();
418 aBuilder
->EnterPresShell(subdocRootFrame
, pointerEventsNone
);
419 aBuilder
->IncrementPresShellPaintCount(presShell
);
421 visible
= aBuilder
->GetVisibleRect();
422 dirty
= aBuilder
->GetDirtyRect();
425 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
426 clipState
.ClipContainingBlockDescendantsToContentBox(aBuilder
, this);
428 nsIScrollableFrame
* sf
= presShell
->GetRootScrollFrameAsScrollable();
429 bool constructZoomItem
= subdocRootFrame
&& parentAPD
!= subdocAPD
;
430 bool needsOwnLayer
= false;
431 if (constructZoomItem
|| presContext
->IsRootContentDocumentCrossProcess() ||
432 (sf
&& sf
->IsScrollingActive())) {
433 needsOwnLayer
= true;
436 nsDisplayList
childItems(aBuilder
);
439 DisplayListClipState::AutoSaveRestore
nestedClipState(aBuilder
);
441 // Clear current clip. There's no point in propagating it down, since
442 // the layer we will construct will be clipped by the current clip.
443 // In fact for nsDisplayZoom propagating it down would be incorrect since
444 // nsDisplayZoom changes the meaning of appunits.
445 nestedClipState
.Clear();
448 // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
449 // is used to compute the visible rect if AddCanvasBackgroundColorItem
450 // creates a display item.
451 nsIFrame
* frame
= subdocRootFrame
? subdocRootFrame
: this;
452 nsDisplayListBuilder::AutoBuildingDisplayList
building(aBuilder
, frame
,
455 if (subdocRootFrame
) {
456 nsIFrame
* rootScrollFrame
= presShell
->GetRootScrollFrame();
457 nsDisplayListBuilder::AutoCurrentScrollParentIdSetter
idSetter(
459 ignoreViewportScrolling
&& rootScrollFrame
&&
460 rootScrollFrame
->GetContent()
461 ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame
->GetContent())
462 : aBuilder
->GetCurrentScrollParentId());
464 bool hasDocumentLevelListenersForApzAwareEvents
=
465 gfxPlatform::AsyncPanZoomEnabled() &&
466 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell
);
468 aBuilder
->SetAncestorHasApzAwareEventHandler(
469 hasDocumentLevelListenersForApzAwareEvents
);
470 subdocRootFrame
->BuildDisplayListForStackingContext(aBuilder
,
474 if (!aBuilder
->IsForEventDelivery()) {
475 // If we are going to use a displayzoom below then any items we put under
476 // it need to have underlying frames from the subdocument. So we need to
477 // calculate the bounds based on which frame will be the underlying frame
478 // for the canvas background color item.
480 GetContentRectRelativeToSelf() + aBuilder
->ToReferenceFrame(this);
481 if (subdocRootFrame
) {
482 bounds
= bounds
.ScaleToOtherAppUnitsRoundOut(parentAPD
, subdocAPD
);
485 // If we are in print preview/page layout we want to paint the grey
486 // background behind the page, not the canvas color. The canvas color gets
487 // painted on the page itself.
488 if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext
)) {
489 presShell
->AddPrintPreviewBackgroundItem(aBuilder
, &childItems
, frame
,
492 // Add the canvas background color to the bottom of the list. This
493 // happens after we've built the list so that
494 // AddCanvasBackgroundColorItem can monkey with the contents if
496 presShell
->AddCanvasBackgroundColorItem(
497 aBuilder
, &childItems
, frame
, bounds
, NS_RGBA(0, 0, 0, 0),
498 AddCanvasBackgroundColorFlags::ForceDraw
);
503 if (subdocRootFrame
) {
504 aBuilder
->LeavePresShell(subdocRootFrame
, &childItems
);
507 // Generate a resolution and/or zoom item if needed. If one or both of those
508 // is created, we don't need to create a separate nsDisplaySubDocument.
510 nsDisplayOwnLayerFlags flags
=
511 nsDisplayOwnLayerFlags::GenerateSubdocInvalidations
;
512 // If ignoreViewportScrolling is true then the top most layer we create here
513 // is going to become the scrollable layer for the root scroll frame, so we
514 // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
515 // becomes the topmost. We do this below.
516 if (constructZoomItem
) {
517 nsDisplayOwnLayerFlags zoomFlags
= flags
;
518 if (ignoreViewportScrolling
) {
519 zoomFlags
|= nsDisplayOwnLayerFlags::GenerateScrollableLayer
;
521 childItems
.AppendNewToTop
<nsDisplayZoom
>(aBuilder
, subdocRootFrame
, this,
522 &childItems
, subdocAPD
, parentAPD
,
525 needsOwnLayer
= false;
527 // Wrap the zoom item in the resolution item if we have both because we want
528 // the resolution scale applied on top of the app units per dev pixel
530 if (ignoreViewportScrolling
) {
531 flags
|= nsDisplayOwnLayerFlags::GenerateScrollableLayer
;
534 // We always want top level content documents to be in their own layer.
535 nsDisplaySubDocument
* layerItem
= MakeDisplayItem
<nsDisplaySubDocument
>(
536 aBuilder
, subdocRootFrame
? subdocRootFrame
: this, this, &childItems
,
539 childItems
.AppendToTop(layerItem
);
540 layerItem
->SetShouldFlattenAway(!needsOwnLayer
);
543 if (aBuilder
->IsForFrameVisibility()) {
544 // We don't add the childItems to the return list as we're dealing with them
546 presShell
->RebuildApproximateFrameVisibilityDisplayList(childItems
);
547 childItems
.DeleteAll(aBuilder
);
549 aLists
.Content()->AppendToTop(&childItems
);
553 #ifdef DEBUG_FRAME_DUMP
554 void nsSubDocumentFrame::List(FILE* out
, const char* aPrefix
,
555 ListFlags aFlags
) const {
557 ListGeneric(str
, aPrefix
, aFlags
);
558 fprintf_stderr(out
, "%s\n", str
.get());
560 if (aFlags
.contains(ListFlag::TraverseSubdocumentFrames
)) {
561 nsSubDocumentFrame
* f
= const_cast<nsSubDocumentFrame
*>(this);
562 nsIFrame
* subdocRootFrame
= f
->GetSubdocumentRootFrame();
563 if (subdocRootFrame
) {
564 nsCString
pfx(aPrefix
);
566 subdocRootFrame
->List(out
, pfx
.get(), aFlags
);
571 nsresult
nsSubDocumentFrame::GetFrameName(nsAString
& aResult
) const {
572 return MakeFrameName(u
"FrameOuter"_ns
, aResult
);
577 nscoord
nsSubDocumentFrame::GetMinISize(gfxContext
* aRenderingContext
) {
579 DISPLAY_MIN_INLINE_SIZE(this, result
);
581 nsCOMPtr
<nsIObjectLoadingContent
> iolc
= do_QueryInterface(mContent
);
582 auto olc
= static_cast<nsObjectLoadingContent
*>(iolc
.get());
584 if (olc
&& olc
->GetSubdocumentIntrinsicSize()) {
585 // The subdocument is an SVG document, so technically we should call
586 // SVGOuterSVGFrame::GetMinISize() on its root frame. That method always
587 // returns 0, though, so we can just do that & don't need to bother with
588 // the cross-doc communication.
591 result
= GetIntrinsicISize();
598 nscoord
nsSubDocumentFrame::GetPrefISize(gfxContext
* aRenderingContext
) {
600 DISPLAY_PREF_INLINE_SIZE(this, result
);
602 // If the subdocument is an SVG document, then in theory we want to return
603 // the same thing that SVGOuterSVGFrame::GetPrefISize does. That method
604 // has some special handling of percentage values to avoid unhelpful zero
605 // sizing in the presence of orthogonal writing modes. We don't bother
606 // with that for SVG documents in <embed> and <object>, since that special
607 // handling doesn't look up across document boundaries anyway.
608 result
= GetIntrinsicISize();
614 IntrinsicSize
nsSubDocumentFrame::GetIntrinsicSize() {
615 if (StyleDisplay()->IsContainSize()) {
616 // Intrinsic size of 'contain:size' replaced elements is 0,0.
617 return IntrinsicSize(0, 0);
620 if (nsCOMPtr
<nsIObjectLoadingContent
> iolc
= do_QueryInterface(mContent
)) {
621 auto olc
= static_cast<nsObjectLoadingContent
*>(iolc
.get());
623 if (auto size
= olc
->GetSubdocumentIntrinsicSize()) {
624 // Use the intrinsic size from the child SVG document, if available.
630 return {}; // <frame> elements have no useful intrinsic size.
633 if (mContent
->IsXULElement()) {
634 return {}; // XUL <iframe> and <browser> have no useful intrinsic size
637 // We must be an HTML <iframe>. Return fallback size.
638 return IntrinsicSize(kFallbackIntrinsicSize
);
642 AspectRatio
nsSubDocumentFrame::GetIntrinsicRatio() const {
643 // FIXME(emilio): This should probably respect contain: size and return no
644 // ratio in the case subDocRoot is non-null. Otherwise we do it by virtue of
645 // using a zero-size below and reusing GetIntrinsicSize().
646 if (nsCOMPtr
<nsIObjectLoadingContent
> iolc
= do_QueryInterface(mContent
)) {
647 auto olc
= static_cast<nsObjectLoadingContent
*>(iolc
.get());
649 auto ratio
= olc
->GetSubdocumentIntrinsicRatio();
650 if (ratio
&& *ratio
) {
651 // Use the intrinsic aspect ratio from the child SVG document, if
657 // NOTE(emilio): Even though we have an intrinsic size, we may not have an
658 // intrinsic ratio. For example `<iframe style="width: 100px">` should not
659 // shrink in the vertical axis to preserve the 300x150 ratio.
660 return nsAtomicContainerFrame::GetIntrinsicRatio();
664 LogicalSize
nsSubDocumentFrame::ComputeAutoSize(
665 gfxContext
* aRenderingContext
, WritingMode aWM
, const LogicalSize
& aCBSize
,
666 nscoord aAvailableISize
, const LogicalSize
& aMargin
,
667 const LogicalSize
& aBorderPadding
, const StyleSizeOverrides
& aSizeOverrides
,
668 ComputeSizeFlags aFlags
) {
670 return nsIFrame::ComputeAutoSize(aRenderingContext
, aWM
, aCBSize
,
671 aAvailableISize
, aMargin
, aBorderPadding
,
672 aSizeOverrides
, aFlags
);
675 const WritingMode wm
= GetWritingMode();
676 LogicalSize
result(wm
, GetIntrinsicISize(), GetIntrinsicBSize());
677 return result
.ConvertTo(aWM
, wm
);
681 nsIFrame::SizeComputationResult
nsSubDocumentFrame::ComputeSize(
682 gfxContext
* aRenderingContext
, WritingMode aWM
, const LogicalSize
& aCBSize
,
683 nscoord aAvailableISize
, const LogicalSize
& aMargin
,
684 const LogicalSize
& aBorderPadding
, const StyleSizeOverrides
& aSizeOverrides
,
685 ComputeSizeFlags aFlags
) {
686 return {ComputeSizeWithIntrinsicDimensions(
687 aRenderingContext
, aWM
, GetIntrinsicSize(), GetAspectRatio(),
688 aCBSize
, aMargin
, aBorderPadding
, aSizeOverrides
, aFlags
),
689 AspectRatioUsage::None
};
692 void nsSubDocumentFrame::Reflow(nsPresContext
* aPresContext
,
693 ReflowOutput
& aDesiredSize
,
694 const ReflowInput
& aReflowInput
,
695 nsReflowStatus
& aStatus
) {
697 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
698 DISPLAY_REFLOW(aPresContext
, this, aReflowInput
, aDesiredSize
, aStatus
);
699 MOZ_ASSERT(aStatus
.IsEmpty(), "Caller should pass a fresh reflow status!");
701 NS_FRAME_TRACE_CALLS
,
702 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
703 aReflowInput
.AvailableWidth(), aReflowInput
.AvailableHeight()));
705 NS_ASSERTION(aReflowInput
.ComputedWidth() != NS_UNCONSTRAINEDSIZE
,
706 "Shouldn't have unconstrained stuff here "
707 "thanks to the rules of reflow");
708 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= aReflowInput
.ComputedHeight(),
709 "Shouldn't have unconstrained stuff here "
710 "thanks to ComputeAutoSize");
712 NS_ASSERTION(mContent
->GetPrimaryFrame() == this, "Shouldn't happen");
714 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
715 const auto wm
= aReflowInput
.GetWritingMode();
716 aDesiredSize
.SetSize(wm
, aReflowInput
.ComputedSizeWithBorderPadding(wm
));
718 // "offset" is the offset of our content area from our frame's
720 nsPoint offset
= nsPoint(aReflowInput
.ComputedPhysicalBorderPadding().left
,
721 aReflowInput
.ComputedPhysicalBorderPadding().top
);
724 const nsMargin
& bp
= aReflowInput
.ComputedPhysicalBorderPadding();
725 nsSize
innerSize(aDesiredSize
.Width() - bp
.LeftRight(),
726 aDesiredSize
.Height() - bp
.TopBottom());
728 // Size & position the view according to 'object-fit' & 'object-position'.
729 nsRect destRect
= nsLayoutUtils::ComputeObjectDestRect(
730 nsRect(offset
, innerSize
), GetIntrinsicSize(), GetIntrinsicRatio(),
733 nsViewManager
* vm
= mInnerView
->GetViewManager();
734 vm
->MoveViewTo(mInnerView
, destRect
.x
, destRect
.y
);
735 vm
->ResizeView(mInnerView
, nsRect(nsPoint(0, 0), destRect
.Size()), true);
738 aDesiredSize
.SetOverflowAreasToDesiredBounds();
740 FinishAndStoreOverflow(&aDesiredSize
);
742 if (!aPresContext
->IsRootPaginatedDocument() && !mPostedReflowCallback
) {
743 PresShell()->PostReflowCallback(this);
744 mPostedReflowCallback
= true;
748 NS_FRAME_TRACE_CALLS
,
749 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",
750 aDesiredSize
.Width(), aDesiredSize
.Height(), ToString(aStatus
).c_str()));
752 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowInput
, aDesiredSize
);
755 bool nsSubDocumentFrame::ReflowFinished() {
756 RefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
758 AutoWeakFrame
weakFrame(this);
760 frameloader
->UpdatePositionAndSize(this);
762 if (weakFrame
.IsAlive()) {
763 // Make sure that we can post a reflow callback in the future.
764 mPostedReflowCallback
= false;
767 mPostedReflowCallback
= false;
772 void nsSubDocumentFrame::ReflowCallbackCanceled() {
773 mPostedReflowCallback
= false;
776 nsresult
nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID
,
779 if (aNameSpaceID
!= kNameSpaceID_None
) {
783 // If the noResize attribute changes, dis/allow frame to be resized
784 if (aAttribute
== nsGkAtoms::noresize
) {
785 // Note that we're not doing content type checks, but that's ok -- if
786 // they'd fail we will just end up with a null framesetFrame.
787 if (mContent
->GetParent()->IsHTMLElement(nsGkAtoms::frameset
)) {
788 nsIFrame
* parentFrame
= GetParent();
791 // There is no interface for nsHTMLFramesetFrame so QI'ing to
792 // concrete class, yay!
793 nsHTMLFramesetFrame
* framesetFrame
= do_QueryFrame(parentFrame
);
795 framesetFrame
->RecalculateBorderResize();
799 } else if (aAttribute
== nsGkAtoms::marginwidth
||
800 aAttribute
== nsGkAtoms::marginheight
) {
801 // Notify the frameloader
802 if (RefPtr
<nsFrameLoader
> frameloader
= FrameLoader()) {
803 frameloader
->MarginsChanged();
810 void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle
* aOldComputedStyle
) {
811 nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle
);
813 // If this presshell has invisible ancestors, we don't need to propagate the
814 // visibility style change to the subdocument since the subdocument should
815 // have already set the IsUnderHiddenEmbedderElement flag in
816 // nsSubDocumentFrame::Init.
817 if (PresShell()->IsUnderHiddenEmbedderElement()) {
821 const bool isVisible
= StyleVisibility()->IsVisible();
822 if (!aOldComputedStyle
||
823 isVisible
!= aOldComputedStyle
->StyleVisibility()->IsVisible()) {
824 PropagateIsUnderHiddenEmbedderElementToSubView(!isVisible
);
828 nsIFrame
* NS_NewSubDocumentFrame(PresShell
* aPresShell
, ComputedStyle
* aStyle
) {
829 return new (aPresShell
)
830 nsSubDocumentFrame(aStyle
, aPresShell
->GetPresContext());
833 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame
)
835 class nsHideViewer
: public Runnable
{
837 nsHideViewer(nsIContent
* aFrameElement
, nsFrameLoader
* aFrameLoader
,
838 PresShell
* aPresShell
, bool aHideViewerIfFrameless
)
839 : mozilla::Runnable("nsHideViewer"),
840 mFrameElement(aFrameElement
),
841 mFrameLoader(aFrameLoader
),
842 mPresShell(aPresShell
),
843 mHideViewerIfFrameless(aHideViewerIfFrameless
) {
844 NS_ASSERTION(mFrameElement
, "Must have a frame element");
845 NS_ASSERTION(mFrameLoader
, "Must have a frame loader");
846 NS_ASSERTION(mPresShell
, "Must have a presshell");
849 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
Run() override
{
850 // Flush frames, to ensure any pending display:none changes are made.
851 // Note it can be unsafe to flush if we've destroyed the presentation
852 // for some other reason, like if we're shutting down.
854 // But avoid the flush if we know for sure we're away, like when we're out
855 // of the document already.
857 // FIXME(emilio): This could still be a perf footgun when removing lots of
858 // siblings where each of them cause the reframe of an ancestor which happen
859 // to contain a subdocument.
861 // We should find some way to avoid that!
862 if (!mPresShell
->IsDestroying() && mFrameElement
->IsInComposedDoc()) {
863 MOZ_KnownLive(mPresShell
)->FlushPendingNotifications(FlushType::Frames
);
866 // Either the frame has been constructed by now, or it never will be,
867 // either way we want to clear the stashed views.
868 mFrameLoader
->SetDetachedSubdocFrame(nullptr, nullptr);
870 nsSubDocumentFrame
* frame
= do_QueryFrame(mFrameElement
->GetPrimaryFrame());
871 if ((!frame
&& mHideViewerIfFrameless
) || mPresShell
->IsDestroying()) {
872 // Either the frame element has no nsIFrame or the presshell is being
873 // destroyed. Hide the nsFrameLoader, which destroys the presentation.
874 mFrameLoader
->Hide();
880 nsCOMPtr
<nsIContent
> mFrameElement
;
881 RefPtr
<nsFrameLoader
> mFrameLoader
;
882 RefPtr
<PresShell
> mPresShell
;
883 bool mHideViewerIfFrameless
;
886 static nsView
* BeginSwapDocShellsForViews(nsView
* aSibling
);
888 void nsSubDocumentFrame::DestroyFrom(nsIFrame
* aDestructRoot
,
889 PostDestroyData
& aPostDestroyData
) {
890 PropagateIsUnderHiddenEmbedderElementToSubView(true);
891 if (mPostedReflowCallback
) {
892 PresShell()->CancelReflowCallback(this);
893 mPostedReflowCallback
= false;
896 // Detach the subdocument's views and stash them in the frame loader.
897 // We can then reattach them if we're being reframed (for example if
898 // the frame has been made position:fixed).
899 RefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
901 nsView
* detachedViews
=
902 ::BeginSwapDocShellsForViews(mInnerView
->GetFirstChild());
904 if (detachedViews
&& detachedViews
->GetFrame()) {
905 frameloader
->SetDetachedSubdocFrame(detachedViews
->GetFrame(),
906 mContent
->OwnerDoc());
908 // We call nsFrameLoader::HideViewer() in a script runner so that we can
909 // safely determine whether the frame is being reframed or destroyed.
910 nsContentUtils::AddScriptRunner(new nsHideViewer(
911 mContent
, frameloader
, PresShell(), (mDidCreateDoc
|| mCallingShow
)));
913 frameloader
->SetDetachedSubdocFrame(nullptr, nullptr);
914 if (mDidCreateDoc
|| mCallingShow
) {
920 nsAtomicContainerFrame::DestroyFrom(aDestructRoot
, aPostDestroyData
);
923 nsFrameLoader
* nsSubDocumentFrame::FrameLoader() const {
928 if (RefPtr
<nsFrameLoaderOwner
> loaderOwner
= do_QueryObject(GetContent())) {
929 mFrameLoader
= loaderOwner
->GetFrameLoader();
935 auto nsSubDocumentFrame::GetRemotePaintData() const -> RemoteFramePaintData
{
936 if (mRetainedRemoteFrame
) {
937 return *mRetainedRemoteFrame
;
940 RemoteFramePaintData data
;
941 nsFrameLoader
* fl
= FrameLoader();
946 auto* rb
= fl
->GetRemoteBrowser();
950 data
.mLayersId
= rb
->GetLayersId();
951 data
.mTabId
= rb
->GetTabId();
955 void nsSubDocumentFrame::ResetFrameLoader(RetainPaintData aRetain
) {
956 if (aRetain
== RetainPaintData::Yes
&& mFrameLoader
) {
957 mRetainedRemoteFrame
= Some(GetRemotePaintData());
959 mRetainedRemoteFrame
.reset();
961 mFrameLoader
= nullptr;
963 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
966 void nsSubDocumentFrame::ClearRetainedPaintData() {
967 mRetainedRemoteFrame
.reset();
969 InvalidateFrameSubtree();
972 // XXX this should be called ObtainDocShell or something like that,
973 // to indicate that it could have side effects
974 nsIDocShell
* nsSubDocumentFrame::GetDocShell() const {
975 // How can FrameLoader() return null???
976 if (NS_WARN_IF(!FrameLoader())) {
979 return mFrameLoader
->GetDocShell(IgnoreErrors());
982 static void DestroyDisplayItemDataForFrames(nsIFrame
* aFrame
) {
983 // Destroying a WebRenderUserDataTable can cause destruction of other objects
984 // which can remove frame properties in their destructor. If we delete a frame
985 // property it runs the destructor of the stored object in the middle of
986 // updating the frame property table, so if the destruction of that object
987 // causes another update to the frame property table it would leave the frame
988 // property table in an inconsistent state. So we remove it from the table and
989 // then destroy it. (bug 1530657)
990 WebRenderUserDataTable
* userDataTable
=
991 aFrame
->TakeProperty(WebRenderUserDataProperty::Key());
993 for (const auto& data
: userDataTable
->Values()) {
994 data
->RemoveFromTable();
996 delete userDataTable
;
999 for (const auto& childList
: aFrame
->ChildLists()) {
1000 for (nsIFrame
* child
: childList
.mList
) {
1001 DestroyDisplayItemDataForFrames(child
);
1006 static CallState
BeginSwapDocShellsForDocument(Document
& aDocument
) {
1007 if (PresShell
* presShell
= aDocument
.GetPresShell()) {
1008 // Disable painting while the views are detached, see bug 946929.
1009 presShell
->SetNeverPainting(true);
1011 if (nsIFrame
* rootFrame
= presShell
->GetRootFrame()) {
1012 ::DestroyDisplayItemDataForFrames(rootFrame
);
1015 aDocument
.EnumerateSubDocuments(BeginSwapDocShellsForDocument
);
1016 return CallState::Continue
;
1019 static nsView
* BeginSwapDocShellsForViews(nsView
* aSibling
) {
1020 // Collect the removed sibling views in reverse order in 'removedViews'.
1021 nsView
* removedViews
= nullptr;
1023 if (Document
* doc
= ::GetDocumentFromView(aSibling
)) {
1024 ::BeginSwapDocShellsForDocument(*doc
);
1026 nsView
* next
= aSibling
->GetNextSibling();
1027 aSibling
->GetViewManager()->RemoveChild(aSibling
);
1028 aSibling
->SetNextSibling(removedViews
);
1029 removedViews
= aSibling
;
1032 return removedViews
;
1035 static void InsertViewsInReverseOrder(nsView
* aSibling
, nsView
* aParent
) {
1036 MOZ_ASSERT(aParent
, "null view");
1037 MOZ_ASSERT(!aParent
->GetFirstChild(), "inserting into non-empty list");
1039 nsViewManager
* vm
= aParent
->GetViewManager();
1041 nsView
* next
= aSibling
->GetNextSibling();
1042 aSibling
->SetNextSibling(nullptr);
1043 // true means 'after' in document order which is 'before' in view order,
1044 // so this call prepends the child, thus reversing the siblings as we go.
1045 vm
->InsertChild(aParent
, aSibling
, nullptr, true);
1050 nsresult
nsSubDocumentFrame::BeginSwapDocShells(nsIFrame
* aOther
) {
1051 if (!aOther
|| !aOther
->IsSubDocumentFrame()) {
1052 return NS_ERROR_NOT_IMPLEMENTED
;
1055 nsSubDocumentFrame
* other
= static_cast<nsSubDocumentFrame
*>(aOther
);
1056 if (!mFrameLoader
|| !mDidCreateDoc
|| mCallingShow
|| !other
->mFrameLoader
||
1057 !other
->mDidCreateDoc
) {
1058 return NS_ERROR_NOT_IMPLEMENTED
;
1061 ClearDisplayItems();
1062 other
->ClearDisplayItems();
1064 if (mInnerView
&& other
->mInnerView
) {
1065 nsView
* ourSubdocViews
= mInnerView
->GetFirstChild();
1066 nsView
* ourRemovedViews
= ::BeginSwapDocShellsForViews(ourSubdocViews
);
1067 nsView
* otherSubdocViews
= other
->mInnerView
->GetFirstChild();
1068 nsView
* otherRemovedViews
= ::BeginSwapDocShellsForViews(otherSubdocViews
);
1070 ::InsertViewsInReverseOrder(ourRemovedViews
, other
->mInnerView
);
1071 ::InsertViewsInReverseOrder(otherRemovedViews
, mInnerView
);
1073 mFrameLoader
.swap(other
->mFrameLoader
);
1077 static CallState
EndSwapDocShellsForDocument(Document
& aDocument
) {
1078 // Our docshell and view trees have been updated for the new hierarchy.
1079 // Now also update all nsDeviceContext::mWidget to that of the
1080 // container view in the new hierarchy.
1081 if (nsCOMPtr
<nsIDocShell
> ds
= aDocument
.GetDocShell()) {
1082 nsCOMPtr
<nsIContentViewer
> cv
;
1083 ds
->GetContentViewer(getter_AddRefs(cv
));
1085 RefPtr
<nsPresContext
> pc
= cv
->GetPresContext();
1086 if (pc
&& pc
->GetPresShell()) {
1087 pc
->GetPresShell()->SetNeverPainting(ds
->IsInvisible());
1089 nsDeviceContext
* dc
= pc
? pc
->DeviceContext() : nullptr;
1091 nsView
* v
= cv
->FindContainerView();
1092 dc
->Init(v
? v
->GetNearestWidget(nullptr) : nullptr);
1094 cv
= cv
->GetPreviousViewer();
1098 aDocument
.EnumerateSubDocuments(EndSwapDocShellsForDocument
);
1099 return CallState::Continue
;
1102 static void EndSwapDocShellsForViews(nsView
* aSibling
) {
1103 for (; aSibling
; aSibling
= aSibling
->GetNextSibling()) {
1104 if (Document
* doc
= ::GetDocumentFromView(aSibling
)) {
1105 ::EndSwapDocShellsForDocument(*doc
);
1107 nsIFrame
* frame
= aSibling
->GetFrame();
1109 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrameInProcess(frame
);
1110 if (parent
->HasAnyStateBits(NS_FRAME_IN_POPUP
)) {
1111 nsIFrame::AddInPopupStateBitToDescendants(frame
);
1113 nsIFrame::RemoveInPopupStateBitFromDescendants(frame
);
1115 if (frame
->HasInvalidFrameInSubtree()) {
1117 !parent
->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT
|
1118 NS_FRAME_IS_NONDISPLAY
)) {
1119 parent
->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT
);
1120 parent
= nsLayoutUtils::GetCrossDocParentFrameInProcess(parent
);
1127 void nsSubDocumentFrame::EndSwapDocShells(nsIFrame
* aOther
) {
1128 nsSubDocumentFrame
* other
= static_cast<nsSubDocumentFrame
*>(aOther
);
1129 AutoWeakFrame
weakThis(this);
1130 AutoWeakFrame
weakOther(aOther
);
1133 ::EndSwapDocShellsForViews(mInnerView
->GetFirstChild());
1135 if (other
->mInnerView
) {
1136 ::EndSwapDocShellsForViews(other
->mInnerView
->GetFirstChild());
1139 // Now make sure we reflow both frames, in case their contents
1140 // determine their size.
1141 // And repaint them, for good measure, in case there's nothing
1142 // interesting that happens during reflow.
1143 if (weakThis
.IsAlive()) {
1144 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::TreeChange
,
1146 InvalidateFrameSubtree();
1147 PropagateIsUnderHiddenEmbedderElementToSubView(
1148 PresShell()->IsUnderHiddenEmbedderElement() ||
1149 !StyleVisibility()->IsVisible());
1151 if (weakOther
.IsAlive()) {
1152 other
->PresShell()->FrameNeedsReflow(other
, IntrinsicDirty::TreeChange
,
1154 other
->InvalidateFrameSubtree();
1155 other
->PropagateIsUnderHiddenEmbedderElementToSubView(
1156 other
->PresShell()->IsUnderHiddenEmbedderElement() ||
1157 !other
->StyleVisibility()->IsVisible());
1161 void nsSubDocumentFrame::ClearDisplayItems() {
1162 for (nsDisplayItem
* i
: DisplayItems()) {
1163 if (i
->GetType() == DisplayItemType::TYPE_SUBDOCUMENT
) {
1164 nsIFrame
* displayRoot
= nsLayoutUtils::GetDisplayRootFrame(this);
1165 MOZ_ASSERT(displayRoot
);
1167 RetainedDisplayListBuilder
* retainedBuilder
=
1168 displayRoot
->GetProperty(RetainedDisplayListBuilder::Cached());
1169 MOZ_ASSERT(retainedBuilder
);
1171 auto* item
= static_cast<nsDisplaySubDocument
*>(i
);
1172 item
->GetChildren()->DeleteAll(retainedBuilder
->Builder());
1179 nsView
* nsSubDocumentFrame::EnsureInnerView() {
1184 // create, init, set the parent of the view
1185 nsView
* outerView
= GetView();
1186 NS_ASSERTION(outerView
, "Must have an outer view already");
1187 nsRect
viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1189 nsViewManager
* viewMan
= outerView
->GetViewManager();
1190 nsView
* innerView
= viewMan
->CreateView(viewBounds
, outerView
);
1192 NS_ERROR("Could not create inner view");
1195 mInnerView
= innerView
;
1196 viewMan
->InsertChild(outerView
, innerView
, nullptr, true);
1201 nsPoint
nsSubDocumentFrame::GetExtraOffset() const {
1202 MOZ_ASSERT(mInnerView
);
1203 return mInnerView
->GetPosition();
1206 void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
1207 if (MOZ_UNLIKELY(HasAllStateBits(NS_FRAME_IS_DIRTY
))) {
1208 // We will be reflowed soon anyway.
1212 const nsStylePosition
* pos
= StylePosition();
1213 bool dependsOnIntrinsics
=
1214 !pos
->mWidth
.ConvertsToLength() || !pos
->mHeight
.ConvertsToLength();
1216 if (dependsOnIntrinsics
|| pos
->mObjectFit
!= StyleObjectFit::Fill
) {
1217 auto dirtyHint
= dependsOnIntrinsics
? IntrinsicDirty::StyleChange
1218 : IntrinsicDirty::Resize
;
1219 PresShell()->FrameNeedsReflow(this, dirtyHint
, NS_FRAME_IS_DIRTY
);
1224 * Gets the layer-pixel offset of aContainerFrame's content rect top-left
1225 * from the nearest display item reference frame (which we assume will be
1226 * inducing a ContainerLayer).
1228 static nsPoint
GetContentRectLayerOffset(nsIFrame
* aContainerFrame
,
1229 nsDisplayListBuilder
* aBuilder
) {
1230 // Offset to the content rect in case we have borders or padding
1231 // Note that aContainerFrame could be a reference frame itself, so
1232 // we need to be careful here to ensure that we call ToReferenceFrame
1233 // on aContainerFrame and not its parent.
1234 nsPoint frameOffset
=
1235 aBuilder
->ToReferenceFrame(aContainerFrame
) +
1236 aContainerFrame
->GetContentRectRelativeToSelf().TopLeft();
1241 // Return true iff |aManager| is a "temporary layer manager". They're
1242 // used for small software rendering tasks, like drawWindow. That's
1243 // currently implemented by a BasicLayerManager without a backing
1244 // widget, and hence in non-retained mode.
1245 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder
* aBuilder
,
1246 nsSubDocumentFrame
* aFrame
)
1247 : nsPaintedDisplayItem(aBuilder
, aFrame
),
1248 mEventRegionsOverride(EventRegionsOverride::NoOverride
) {
1249 const bool frameIsPointerEventsNone
=
1250 aFrame
->Style()->PointerEvents() == StylePointerEvents::None
;
1251 if (aBuilder
->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone
) {
1252 mEventRegionsOverride
|= EventRegionsOverride::ForceEmptyHitRegion
;
1254 if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(
1255 aFrame
->PresShell())) {
1256 mEventRegionsOverride
|= EventRegionsOverride::ForceDispatchToContent
;
1259 mPaintData
= aFrame
->GetRemotePaintData();
1262 LayerIntSize
GetFrameSize(const nsIFrame
* aFrame
) {
1263 LayoutDeviceSize size
= LayoutDeviceRect::FromAppUnits(
1264 aFrame
->GetContentRectRelativeToSelf().Size(),
1265 aFrame
->PresContext()->AppUnitsPerDevPixel());
1267 return LayerIntSize::Round(size
.width
, size
.height
);
1272 void nsDisplayRemote::Paint(nsDisplayListBuilder
* aBuilder
, gfxContext
* aCtx
) {
1273 nsPresContext
* pc
= mFrame
->PresContext();
1274 nsFrameLoader
* fl
= GetFrameLoader();
1275 if (pc
->GetPrintSettings() && fl
->IsRemoteFrame()) {
1276 // See the comment below in CreateWebRenderCommands() as for why doing this.
1277 fl
->UpdatePositionAndSize(static_cast<nsSubDocumentFrame
*>(mFrame
));
1280 DrawTarget
* target
= aCtx
->GetDrawTarget();
1281 if (!target
->IsRecording() || mPaintData
.mTabId
== 0) {
1282 NS_WARNING("Remote iframe not rendered");
1286 // Rendering the inner document will apply a scale to account for its
1287 // app units per dev pixel ratio. We want to apply the inverse scaling
1288 // using our app units per dev pixel ratio, so that no actual scaling
1289 // will be applied if they match. For in-process rendering,
1290 // nsSubDocumentFrame creates an nsDisplayZoom item if the app units
1291 // per dev pixel ratio changes.
1292 int32_t appUnitsPerDevPixel
= pc
->AppUnitsPerDevPixel();
1293 gfxFloat scale
= gfxFloat(AppUnitsPerCSSPixel()) / appUnitsPerDevPixel
;
1294 gfxContextMatrixAutoSaveRestore
saveMatrix(aCtx
);
1295 aCtx
->Multiply(gfxMatrix::Scaling(scale
, scale
));
1298 NSRectToSnappedRect(GetContentRect(), AppUnitsPerCSSPixel(), *target
);
1299 target
->DrawDependentSurface(mPaintData
.mTabId
, destRect
);
1302 bool nsDisplayRemote::CreateWebRenderCommands(
1303 mozilla::wr::DisplayListBuilder
& aBuilder
,
1304 mozilla::wr::IpcResourceUpdateQueue
& aResources
,
1305 const StackingContextHelper
& aSc
,
1306 mozilla::layers::RenderRootStateManager
* aManager
,
1307 nsDisplayListBuilder
* aDisplayListBuilder
) {
1308 if (!mPaintData
.mLayersId
.IsValid()) {
1312 nsPresContext
* pc
= mFrame
->PresContext();
1313 nsFrameLoader
* fl
= GetFrameLoader();
1314 if (RefPtr
<RemoteBrowser
> remoteBrowser
= fl
->GetRemoteBrowser()) {
1315 if (pc
->GetPrintSettings()) {
1316 // HACK(emilio): Usually we update sizing/positioning from
1317 // ReflowFinished(). Print documents have no incremental reflow at all
1318 // though, so we can't rely on it firing after a frame becomes remote.
1319 // Thus, if we're painting a remote frame, update its sizing and position
1322 // UpdatePositionAndSize() can cause havoc for non-remote frames but
1323 // luckily we don't care about those, so this is fine.
1324 fl
->UpdatePositionAndSize(static_cast<nsSubDocumentFrame
*>(mFrame
));
1327 // Adjust mItemVisibleRect, which is relative to the reference frame, to be
1328 // relative to this frame
1329 nsRect visibleRect
= GetBuildingRect() - ToReferenceFrame();
1330 nsRect contentRect
= Frame()->GetContentRectRelativeToSelf();
1331 visibleRect
.IntersectRect(visibleRect
, contentRect
);
1332 visibleRect
-= contentRect
.TopLeft();
1334 // Generate an effects update notifying the browser it is visible
1335 gfx::Size scale
= aSc
.GetInheritedScale();
1337 ParentLayerToScreenScale2D transformToAncestorScale
=
1338 ParentLayerToParentLayerScale(
1339 pc
->GetPresShell() ? pc
->GetPresShell()->GetCumulativeResolution()
1341 nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
1344 aDisplayListBuilder
->AddEffectUpdate(
1346 EffectsInfo::VisibleWithinRect(visibleRect
, scale
.width
, scale
.height
,
1347 transformToAncestorScale
));
1349 // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
1351 RefPtr
<WebRenderRemoteData
> userData
=
1352 aManager
->CommandBuilder()
1353 .CreateOrRecycleWebRenderUserData
<WebRenderRemoteData
>(this,
1355 userData
->SetRemoteBrowser(remoteBrowser
);
1358 nscoord auPerDevPixel
= pc
->AppUnitsPerDevPixel();
1359 nsPoint layerOffset
= GetContentRectLayerOffset(mFrame
, aDisplayListBuilder
);
1360 mOffset
= LayoutDevicePoint::FromAppUnits(layerOffset
, auPerDevPixel
);
1362 nsRect contentRect
= mFrame
->GetContentRectRelativeToSelf();
1363 contentRect
.MoveTo(0, 0);
1364 LayoutDeviceRect rect
=
1365 LayoutDeviceRect::FromAppUnits(contentRect
, auPerDevPixel
);
1368 aBuilder
.PushIFrame(mozilla::wr::ToLayoutRect(rect
), !BackfaceIsHidden(),
1369 mozilla::wr::AsPipelineId(mPaintData
.mLayersId
),
1370 /*ignoreMissingPipelines*/ true);
1375 bool nsDisplayRemote::UpdateScrollData(
1376 mozilla::layers::WebRenderScrollData
* aData
,
1377 mozilla::layers::WebRenderLayerScrollData
* aLayerData
) {
1378 if (!mPaintData
.mLayersId
.IsValid()) {
1383 aLayerData
->SetReferentId(mPaintData
.mLayersId
);
1385 // Apply the top level resolution if we are in the same process of the top
1386 // level document. We don't need to apply it in cases where we are in OOP
1387 // iframes since it will be applied later in
1388 // HitTestingTreeNode::GetTransformToGecko by walking up the tree node.
1389 nsPresContext
* inProcessRootContext
=
1390 mFrame
->PresContext()->GetInProcessRootContentDocumentPresContext();
1391 if (inProcessRootContext
&&
1392 inProcessRootContext
->IsRootContentDocumentCrossProcess()) {
1393 float resolution
= inProcessRootContext
->PresShell()->GetResolution();
1394 aLayerData
->SetResolution(resolution
);
1397 Matrix4x4 m
= Matrix4x4::Translation(mOffset
.x
, mOffset
.y
, 0.0);
1398 aLayerData
->SetTransform(m
);
1399 aLayerData
->SetEventRegionsOverride(mEventRegionsOverride
);
1400 aLayerData
->SetRemoteDocumentSize(GetFrameSize(mFrame
));
1405 nsFrameLoader
* nsDisplayRemote::GetFrameLoader() const {
1406 return static_cast<nsSubDocumentFrame
*>(mFrame
)->FrameLoader();
1409 } // namespace mozilla