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/ComputedStyleInlines.h"
15 #include "mozilla/Preferences.h"
16 #include "mozilla/PresShell.h"
17 #include "mozilla/StaticPrefs_layout.h"
18 #include "mozilla/Unused.h"
19 #include "mozilla/dom/Document.h"
20 #include "mozilla/dom/HTMLFrameElement.h"
21 #include "mozilla/dom/ImageDocument.h"
22 #include "mozilla/dom/BrowserParent.h"
25 #include "nsGenericHTMLElement.h"
26 #include "nsGenericHTMLFrameElement.h"
27 #include "nsAttrValueInlines.h"
28 #include "nsIDocShell.h"
29 #include "nsIDocumentViewer.h"
30 #include "nsIContentInlines.h"
31 #include "nsPresContext.h"
33 #include "nsViewManager.h"
34 #include "nsGkAtoms.h"
35 #include "nsStyleConsts.h"
36 #include "nsStyleStruct.h"
37 #include "nsStyleStructInlines.h"
38 #include "nsFrameSetFrame.h"
39 #include "nsNameSpaceManager.h"
40 #include "nsDisplayList.h"
41 #include "nsIScrollableFrame.h"
42 #include "nsIObjectLoadingContent.h"
43 #include "nsLayoutUtils.h"
44 #include "nsContentUtils.h"
45 #include "nsServiceManagerUtils.h"
46 #include "nsQueryObject.h"
47 #include "RetainedDisplayListBuilder.h"
48 #include "nsObjectLoadingContent.h"
50 #include "mozilla/layers/WebRenderUserData.h"
51 #include "mozilla/layers/WebRenderScrollData.h"
52 #include "mozilla/layers/RenderRootStateManager.h"
53 #include "mozilla/layers/StackingContextHelper.h" // for StackingContextHelper
54 #include "mozilla/ProfilerLabels.h"
56 using namespace mozilla
;
57 using namespace mozilla::dom
;
58 using namespace mozilla::gfx
;
59 using namespace mozilla::layers
;
61 static Document
* GetDocumentFromView(nsView
* aView
) {
62 MOZ_ASSERT(aView
, "null view");
64 nsViewManager
* vm
= aView
->GetViewManager();
65 PresShell
* presShell
= vm
? vm
->GetPresShell() : nullptr;
66 return presShell
? presShell
->GetDocument() : nullptr;
69 static void PropagateIsUnderHiddenEmbedderElement(nsFrameLoader
* aFrameLoader
,
75 if (BrowsingContext
* bc
= aFrameLoader
->GetExtantBrowsingContext()) {
76 if (bc
->IsUnderHiddenEmbedderElement() != aValue
) {
77 Unused
<< bc
->SetIsUnderHiddenEmbedderElement(aValue
);
82 nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle
* aStyle
,
83 nsPresContext
* aPresContext
)
84 : nsAtomicContainerFrame(aStyle
, aPresContext
, kClassID
),
88 mPostedReflowCallback(false),
91 mIsInObjectOrEmbed(false) {}
94 a11y::AccType
nsSubDocumentFrame::AccessibleType() {
95 return a11y::eOuterDocType
;
99 NS_QUERYFRAME_HEAD(nsSubDocumentFrame
)
100 NS_QUERYFRAME_ENTRY(nsSubDocumentFrame
)
101 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame
)
103 class AsyncFrameInit
: public Runnable
{
105 explicit AsyncFrameInit(nsIFrame
* aFrame
)
106 : mozilla::Runnable("AsyncFrameInit"), mFrame(aFrame
) {}
107 NS_IMETHOD
Run() override
{
108 AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER
);
109 if (mFrame
.IsAlive()) {
110 static_cast<nsSubDocumentFrame
*>(mFrame
.GetFrame())->ShowViewer();
119 void nsSubDocumentFrame::Init(nsIContent
* aContent
, nsContainerFrame
* aParent
,
120 nsIFrame
* aPrevInFlow
) {
121 MOZ_ASSERT(aContent
);
122 // determine if we are a <frame> or <iframe>
123 mIsInline
= !aContent
->IsHTMLElement(nsGkAtoms::frame
);
125 nsAtomicContainerFrame::Init(aContent
, aParent
, aPrevInFlow
);
127 // CreateView() creates this frame's view, stored in mOuterView. It needs to
128 // be created first since it's the parent of the inner view, stored in
133 // Set the primary frame now so that nsDocumentViewer::FindContainerView
134 // called from within EndSwapDocShellsForViews below can find it if needed.
135 aContent
->SetPrimaryFrame(this);
137 // If we have a detached subdoc's root view on our frame loader, re-insert it
138 // into the view tree. This happens when we've been reframed, and ensures the
139 // presentation persists across reframes.
140 if (RefPtr
<nsFrameLoader
> frameloader
= FrameLoader()) {
141 bool hadFrame
= false;
142 nsIFrame
* detachedFrame
= frameloader
->GetDetachedSubdocFrame(&hadFrame
);
143 frameloader
->SetDetachedSubdocFrame(nullptr);
144 nsView
* detachedView
= detachedFrame
? detachedFrame
->GetView() : nullptr;
146 // Restore stashed presentation.
147 InsertViewsInReverseOrder(detachedView
, mInnerView
);
148 EndSwapDocShellsForViews(mInnerView
->GetFirstChild());
149 } else if (hadFrame
) {
150 // Presentation is for a different document, don't restore it.
155 // NOTE: The frame loader might not yet be initialized yet. If it's not, the
156 // call in ShowViewer() should pick things up.
157 UpdateEmbeddedBrowsingContextDependentData();
158 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
161 void nsSubDocumentFrame::UpdateEmbeddedBrowsingContextDependentData() {
165 BrowsingContext
* bc
= mFrameLoader
->GetExtantBrowsingContext();
169 mIsInObjectOrEmbed
= bc
->IsEmbedderTypeObjectOrEmbed();
170 MaybeUpdateRemoteStyle();
171 MaybeUpdateEmbedderColorScheme();
172 PropagateIsUnderHiddenEmbedderElement(
173 PresShell()->IsUnderHiddenEmbedderElement() ||
174 !StyleVisibility()->IsVisible());
177 void nsSubDocumentFrame::PropagateIsUnderHiddenEmbedderElement(bool aValue
) {
178 ::PropagateIsUnderHiddenEmbedderElement(mFrameLoader
, aValue
);
181 void nsSubDocumentFrame::ShowViewer() {
186 RefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
187 if (!frameloader
|| frameloader
->IsDead()) {
191 if (!frameloader
->IsRemoteFrame() && !PresContext()->IsDynamic()) {
192 // We let the printing code take care of loading the document and
193 // initializing the shell; just create the inner view for it to use.
194 (void)EnsureInnerView();
196 AutoWeakFrame
weakThis(this);
198 bool didCreateDoc
= frameloader
->Show(this);
199 if (!weakThis
.IsAlive()) {
202 mCallingShow
= false;
203 mDidCreateDoc
= didCreateDoc
;
204 if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW
)) {
205 frameloader
->UpdatePositionAndSize(this);
207 if (!weakThis
.IsAlive()) {
210 UpdateEmbeddedBrowsingContextDependentData();
215 nsIFrame
* nsSubDocumentFrame::GetSubdocumentRootFrame() {
216 if (!mInnerView
) return nullptr;
217 nsView
* subdocView
= mInnerView
->GetFirstChild();
218 return subdocView
? subdocView
->GetFrame() : nullptr;
221 mozilla::PresShell
* nsSubDocumentFrame::GetSubdocumentPresShellForPainting(
223 if (!mInnerView
) return nullptr;
225 nsView
* subdocView
= mInnerView
->GetFirstChild();
226 if (!subdocView
) return nullptr;
228 mozilla::PresShell
* presShell
= nullptr;
230 nsIFrame
* subdocRootFrame
= subdocView
->GetFrame();
231 if (subdocRootFrame
) {
232 presShell
= subdocRootFrame
->PresShell();
235 // If painting is suppressed in the presshell, we try to look for a better
237 if (!presShell
|| (presShell
->IsPaintingSuppressed() &&
238 !(aFlags
& IGNORE_PAINT_SUPPRESSION
))) {
239 // During page transition mInnerView will sometimes have two children, the
240 // first being the new page that may not have any frame, and the second
241 // being the old page that will probably have a frame.
242 nsView
* nextView
= subdocView
->GetNextSibling();
243 nsIFrame
* frame
= nullptr;
245 frame
= nextView
->GetFrame();
248 mozilla::PresShell
* presShellForNextView
= frame
->PresShell();
249 if (!presShell
|| (presShellForNextView
&&
250 !presShellForNextView
->IsPaintingSuppressed() &&
251 StaticPrefs::layout_show_previous_page())) {
252 subdocView
= nextView
;
253 subdocRootFrame
= frame
;
254 presShell
= presShellForNextView
;
258 // If we don't have a frame we use this roundabout way to get the pres
260 if (!mFrameLoader
) return nullptr;
261 nsIDocShell
* docShell
= mFrameLoader
->GetDocShell(IgnoreErrors());
262 if (!docShell
) return nullptr;
263 presShell
= docShell
->GetPresShell();
270 nsRect
nsSubDocumentFrame::GetDestRect() {
271 nsRect rect
= GetContent()->IsHTMLElement(nsGkAtoms::frame
)
272 ? GetRectRelativeToSelf()
273 : GetContentRectRelativeToSelf();
275 // Adjust subdocument size, according to 'object-fit' and the subdocument's
276 // intrinsic size and ratio.
277 return nsLayoutUtils::ComputeObjectDestRect(
278 rect
, GetIntrinsicSize(), GetIntrinsicRatio(), StylePosition());
281 ScreenIntSize
nsSubDocumentFrame::GetSubdocumentSize() {
282 if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW
)) {
283 if (RefPtr
<nsFrameLoader
> frameloader
= FrameLoader()) {
284 nsIFrame
* detachedFrame
= frameloader
->GetDetachedSubdocFrame();
285 if (nsView
* view
= detachedFrame
? detachedFrame
->GetView() : nullptr) {
286 nsSize size
= view
->GetBounds().Size();
287 nsPresContext
* presContext
= detachedFrame
->PresContext();
288 return ScreenIntSize(presContext
->AppUnitsToDevPixels(size
.width
),
289 presContext
->AppUnitsToDevPixels(size
.height
));
292 // Pick some default size for now. Using 10x10 because that's what the
294 return ScreenIntSize(10, 10);
297 nsSize docSizeAppUnits
= GetDestRect().Size();
298 nsPresContext
* pc
= PresContext();
299 return ScreenIntSize(pc
->AppUnitsToDevPixels(docSizeAppUnits
.width
),
300 pc
->AppUnitsToDevPixels(docSizeAppUnits
.height
));
303 static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder
* aBuilder
,
305 nsDisplayList
* aList
) {
306 for (nsDisplayItem
* item
: aList
->TakeItems()) {
307 if (item
->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR
) {
308 nsDisplayList
tmpList(aBuilder
);
309 tmpList
.AppendToTop(item
);
310 item
= MakeDisplayItemWithIndex
<nsDisplayOwnLayer
>(
311 aBuilder
, aFrame
, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc
,
312 &tmpList
, aBuilder
->CurrentActiveScrolledRoot(),
313 nsDisplayOwnLayerFlags::None
, ScrollbarData
{}, true, false);
315 aList
->AppendToTop(item
);
319 void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
320 const nsDisplayListSet
& aLists
) {
321 if (!IsVisibleForPainting()) {
325 nsFrameLoader
* frameLoader
= FrameLoader();
326 bool isRemoteFrame
= frameLoader
&& frameLoader
->IsRemoteFrame();
328 // If we are pointer-events:none then we don't need to HitTest background
329 const bool pointerEventsNone
=
330 Style()->PointerEvents() == StylePointerEvents::None
;
331 if (!aBuilder
->IsForEventDelivery() || !pointerEventsNone
) {
332 nsDisplayListCollection
decorations(aBuilder
);
333 DisplayBorderBackgroundOutline(aBuilder
, decorations
);
335 // Wrap background colors of <iframe>s with remote subdocuments in their
336 // own layer so we generate a ColorLayer. This is helpful for optimizing
337 // compositing; we can skip compositing the ColorLayer when the
338 // remote content is opaque.
339 WrapBackgroundColorInOwnLayer(aBuilder
, this,
340 decorations
.BorderBackground());
342 decorations
.MoveTo(aLists
);
345 if (aBuilder
->IsForEventDelivery() && pointerEventsNone
) {
349 if (HidesContent()) {
353 // If we're passing pointer events to children then we have to descend into
354 // subdocuments no matter what, to determine which parts are transparent for
355 // hit-testing or event regions.
356 bool needToDescend
= aBuilder
->GetDescendIntoSubdocuments();
357 if (!mInnerView
|| !needToDescend
) {
362 // We're the subdoc for <browser remote="true"> and it has
363 // painted content. Display its shadow layer tree.
364 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
365 clipState
.ClipContainingBlockDescendantsToContentBox(aBuilder
, this);
367 aLists
.Content()->AppendNewToTop
<nsDisplayRemote
>(aBuilder
, this);
371 RefPtr
<mozilla::PresShell
> presShell
= GetSubdocumentPresShellForPainting(
372 aBuilder
->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION
: 0);
378 if (aBuilder
->IsInFilter()) {
379 Document
* outerDoc
= PresShell()->GetDocument();
380 Document
* innerDoc
= presShell
->GetDocument();
381 if (outerDoc
&& innerDoc
) {
382 if (!outerDoc
->NodePrincipal()->Equals(innerDoc
->NodePrincipal())) {
383 outerDoc
->SetUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame
);
388 nsIFrame
* subdocRootFrame
= presShell
->GetRootFrame();
390 nsPresContext
* presContext
= presShell
->GetPresContext();
392 int32_t parentAPD
= PresContext()->AppUnitsPerDevPixel();
393 int32_t subdocAPD
= presContext
->AppUnitsPerDevPixel();
397 bool ignoreViewportScrolling
= false;
398 if (subdocRootFrame
) {
399 // get the dirty rect relative to the root frame of the subdoc
400 visible
= aBuilder
->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame
);
401 dirty
= aBuilder
->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame
);
402 // and convert into the appunits of the subdoc
403 visible
= visible
.ScaleToOtherAppUnitsRoundOut(parentAPD
, subdocAPD
);
404 dirty
= dirty
.ScaleToOtherAppUnitsRoundOut(parentAPD
, subdocAPD
);
406 if (nsIScrollableFrame
* rootScrollableFrame
=
407 presShell
->GetRootScrollFrameAsScrollable()) {
408 // Use a copy, so the rects don't get modified.
409 nsRect copyOfDirty
= dirty
;
410 nsRect copyOfVisible
= visible
;
411 // TODO(botond): Can we just axe this DecideScrollableLayer call?
412 rootScrollableFrame
->DecideScrollableLayer(aBuilder
, ©OfVisible
,
414 /* aSetBase = */ true);
416 ignoreViewportScrolling
= presShell
->IgnoringViewportScrolling();
419 aBuilder
->EnterPresShell(subdocRootFrame
, pointerEventsNone
);
420 aBuilder
->IncrementPresShellPaintCount(presShell
);
422 visible
= aBuilder
->GetVisibleRect();
423 dirty
= aBuilder
->GetDirtyRect();
426 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
427 clipState
.ClipContainingBlockDescendantsToContentBox(aBuilder
, this);
429 nsIScrollableFrame
* sf
= presShell
->GetRootScrollFrameAsScrollable();
430 bool constructZoomItem
= subdocRootFrame
&& parentAPD
!= subdocAPD
;
431 bool needsOwnLayer
= constructZoomItem
||
432 presContext
->IsRootContentDocumentCrossProcess() ||
433 (sf
&& sf
->IsScrollingActive());
435 nsDisplayList
childItems(aBuilder
);
438 DisplayListClipState::AutoSaveRestore
nestedClipState(aBuilder
);
440 // Clear current clip. There's no point in propagating it down, since
441 // the layer we will construct will be clipped by the current clip.
442 // In fact for nsDisplayZoom propagating it down would be incorrect since
443 // nsDisplayZoom changes the meaning of appunits.
444 nestedClipState
.Clear();
447 // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
448 // is used to compute the visible rect if AddCanvasBackgroundColorItem
449 // creates a display item.
450 nsIFrame
* frame
= subdocRootFrame
? subdocRootFrame
: this;
451 nsDisplayListBuilder::AutoBuildingDisplayList
building(aBuilder
, frame
,
454 if (subdocRootFrame
) {
455 bool hasDocumentLevelListenersForApzAwareEvents
=
456 gfxPlatform::AsyncPanZoomEnabled() &&
457 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell
);
459 aBuilder
->SetAncestorHasApzAwareEventHandler(
460 hasDocumentLevelListenersForApzAwareEvents
);
461 subdocRootFrame
->BuildDisplayListForStackingContext(aBuilder
,
463 if (!aBuilder
->IsForEventDelivery()) {
464 // If we are going to use a displayzoom below then any items we put
465 // under it need to have underlying frames from the subdocument. So we
466 // need to calculate the bounds based on which frame will be the
467 // underlying frame for the canvas background color item.
469 GetContentRectRelativeToSelf() + aBuilder
->ToReferenceFrame(this);
470 bounds
= bounds
.ScaleToOtherAppUnitsRoundOut(parentAPD
, subdocAPD
);
472 // Add the canvas background color to the bottom of the list. This
473 // happens after we've built the list so that
474 // AddCanvasBackgroundColorItem can monkey with the contents if
476 presShell
->AddCanvasBackgroundColorItem(aBuilder
, &childItems
, frame
,
477 bounds
, NS_RGBA(0, 0, 0, 0));
482 if (subdocRootFrame
) {
483 aBuilder
->LeavePresShell(subdocRootFrame
, &childItems
);
486 // Generate a resolution and/or zoom item if needed. If one or both of those
487 // is created, we don't need to create a separate nsDisplaySubDocument.
489 nsDisplayOwnLayerFlags flags
=
490 nsDisplayOwnLayerFlags::GenerateSubdocInvalidations
;
491 // If ignoreViewportScrolling is true then the top most layer we create here
492 // is going to become the scrollable layer for the root scroll frame, so we
493 // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
494 // becomes the topmost. We do this below.
495 if (constructZoomItem
) {
496 nsDisplayOwnLayerFlags zoomFlags
= flags
;
497 if (ignoreViewportScrolling
) {
498 zoomFlags
|= nsDisplayOwnLayerFlags::GenerateScrollableLayer
;
500 childItems
.AppendNewToTop
<nsDisplayZoom
>(aBuilder
, subdocRootFrame
, this,
501 &childItems
, subdocAPD
, parentAPD
,
504 needsOwnLayer
= false;
506 // Wrap the zoom item in the resolution item if we have both because we want
507 // the resolution scale applied on top of the app units per dev pixel
509 if (ignoreViewportScrolling
) {
510 flags
|= nsDisplayOwnLayerFlags::GenerateScrollableLayer
;
513 // We always want top level content documents to be in their own layer.
514 nsDisplaySubDocument
* layerItem
= MakeDisplayItem
<nsDisplaySubDocument
>(
515 aBuilder
, subdocRootFrame
? subdocRootFrame
: this, this, &childItems
,
518 childItems
.AppendToTop(layerItem
);
519 layerItem
->SetShouldFlattenAway(!needsOwnLayer
);
522 if (aBuilder
->IsForFrameVisibility()) {
523 // We don't add the childItems to the return list as we're dealing with them
525 presShell
->RebuildApproximateFrameVisibilityDisplayList(childItems
);
526 childItems
.DeleteAll(aBuilder
);
528 aLists
.Content()->AppendToTop(&childItems
);
532 #ifdef DEBUG_FRAME_DUMP
533 void nsSubDocumentFrame::List(FILE* out
, const char* aPrefix
,
534 ListFlags aFlags
) const {
536 ListGeneric(str
, aPrefix
, aFlags
);
537 fprintf_stderr(out
, "%s\n", str
.get());
539 if (aFlags
.contains(ListFlag::TraverseSubdocumentFrames
)) {
540 nsSubDocumentFrame
* f
= const_cast<nsSubDocumentFrame
*>(this);
541 nsIFrame
* subdocRootFrame
= f
->GetSubdocumentRootFrame();
542 if (subdocRootFrame
) {
543 nsCString
pfx(aPrefix
);
545 subdocRootFrame
->List(out
, pfx
.get(), aFlags
);
550 nsresult
nsSubDocumentFrame::GetFrameName(nsAString
& aResult
) const {
551 return MakeFrameName(u
"FrameOuter"_ns
, aResult
);
556 nscoord
nsSubDocumentFrame::GetMinISize(gfxContext
* aRenderingContext
) {
558 DISPLAY_MIN_INLINE_SIZE(this, result
);
560 nsCOMPtr
<nsIObjectLoadingContent
> iolc
= do_QueryInterface(mContent
);
561 auto olc
= static_cast<nsObjectLoadingContent
*>(iolc
.get());
563 if (olc
&& olc
->GetSubdocumentIntrinsicSize()) {
564 // The subdocument is an SVG document, so technically we should call
565 // SVGOuterSVGFrame::GetMinISize() on its root frame. That method always
566 // returns 0, though, so we can just do that & don't need to bother with
567 // the cross-doc communication.
570 result
= GetIntrinsicISize();
577 nscoord
nsSubDocumentFrame::GetPrefISize(gfxContext
* aRenderingContext
) {
579 DISPLAY_PREF_INLINE_SIZE(this, result
);
581 // If the subdocument is an SVG document, then in theory we want to return
582 // the same thing that SVGOuterSVGFrame::GetPrefISize does. That method
583 // has some special handling of percentage values to avoid unhelpful zero
584 // sizing in the presence of orthogonal writing modes. We don't bother
585 // with that for SVG documents in <embed> and <object>, since that special
586 // handling doesn't look up across document boundaries anyway.
587 result
= GetIntrinsicISize();
593 IntrinsicSize
nsSubDocumentFrame::GetIntrinsicSize() {
594 const auto containAxes
= GetContainSizeAxes();
595 if (containAxes
.IsBoth()) {
596 // Intrinsic size of 'contain:size' replaced elements is determined by
597 // contain-intrinsic-size.
598 return FinishIntrinsicSize(containAxes
, IntrinsicSize(0, 0));
601 if (nsCOMPtr
<nsIObjectLoadingContent
> iolc
= do_QueryInterface(mContent
)) {
602 const auto* olc
= static_cast<nsObjectLoadingContent
*>(iolc
.get());
603 if (auto size
= olc
->GetSubdocumentIntrinsicSize()) {
604 // Use the intrinsic size from the child SVG document, if available.
605 return FinishIntrinsicSize(containAxes
, *size
);
610 return {}; // <frame> elements have no useful intrinsic size.
613 if (mContent
->IsXULElement()) {
614 return {}; // XUL <iframe> and <browser> have no useful intrinsic size
617 // We must be an HTML <iframe>. Return fallback size.
618 return FinishIntrinsicSize(containAxes
,
619 IntrinsicSize(kFallbackIntrinsicSize
));
623 AspectRatio
nsSubDocumentFrame::GetIntrinsicRatio() const {
624 // FIXME(emilio): This should probably respect contain: size and return no
625 // ratio in the case subDocRoot is non-null. Otherwise we do it by virtue of
626 // using a zero-size below and reusing GetIntrinsicSize().
627 if (nsCOMPtr
<nsIObjectLoadingContent
> iolc
= do_QueryInterface(mContent
)) {
628 auto olc
= static_cast<nsObjectLoadingContent
*>(iolc
.get());
630 auto ratio
= olc
->GetSubdocumentIntrinsicRatio();
631 if (ratio
&& *ratio
) {
632 // Use the intrinsic aspect ratio from the child SVG document, if
638 // NOTE(emilio): Even though we have an intrinsic size, we may not have an
639 // intrinsic ratio. For example `<iframe style="width: 100px">` should not
640 // shrink in the vertical axis to preserve the 300x150 ratio.
641 return nsAtomicContainerFrame::GetIntrinsicRatio();
645 LogicalSize
nsSubDocumentFrame::ComputeAutoSize(
646 gfxContext
* aRenderingContext
, WritingMode aWM
, const LogicalSize
& aCBSize
,
647 nscoord aAvailableISize
, const LogicalSize
& aMargin
,
648 const LogicalSize
& aBorderPadding
, const StyleSizeOverrides
& aSizeOverrides
,
649 ComputeSizeFlags aFlags
) {
651 return nsIFrame::ComputeAutoSize(aRenderingContext
, aWM
, aCBSize
,
652 aAvailableISize
, aMargin
, aBorderPadding
,
653 aSizeOverrides
, aFlags
);
656 const WritingMode wm
= GetWritingMode();
657 LogicalSize
result(wm
, GetIntrinsicISize(), GetIntrinsicBSize());
658 return result
.ConvertTo(aWM
, wm
);
662 nsIFrame::SizeComputationResult
nsSubDocumentFrame::ComputeSize(
663 gfxContext
* aRenderingContext
, WritingMode aWM
, const LogicalSize
& aCBSize
,
664 nscoord aAvailableISize
, const LogicalSize
& aMargin
,
665 const LogicalSize
& aBorderPadding
, const StyleSizeOverrides
& aSizeOverrides
,
666 ComputeSizeFlags aFlags
) {
667 return {ComputeSizeWithIntrinsicDimensions(
668 aRenderingContext
, aWM
, GetIntrinsicSize(), GetAspectRatio(),
669 aCBSize
, aMargin
, aBorderPadding
, aSizeOverrides
, aFlags
),
670 AspectRatioUsage::None
};
673 void nsSubDocumentFrame::Reflow(nsPresContext
* aPresContext
,
674 ReflowOutput
& aDesiredSize
,
675 const ReflowInput
& aReflowInput
,
676 nsReflowStatus
& aStatus
) {
678 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
679 DISPLAY_REFLOW(aPresContext
, this, aReflowInput
, aDesiredSize
, aStatus
);
680 MOZ_ASSERT(aStatus
.IsEmpty(), "Caller should pass a fresh reflow status!");
682 NS_FRAME_TRACE_CALLS
,
683 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
684 aReflowInput
.AvailableWidth(), aReflowInput
.AvailableHeight()));
686 NS_ASSERTION(aReflowInput
.ComputedISize() != NS_UNCONSTRAINEDSIZE
,
687 "Shouldn't have unconstrained inline-size here "
688 "thanks to the rules of reflow");
689 NS_ASSERTION(aReflowInput
.ComputedBSize() != NS_UNCONSTRAINEDSIZE
,
690 "Shouldn't have unconstrained block-size here "
691 "thanks to ComputeAutoSize");
693 NS_ASSERTION(mContent
->GetPrimaryFrame() == this, "Shouldn't happen");
695 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
696 const auto wm
= aReflowInput
.GetWritingMode();
697 aDesiredSize
.SetSize(wm
, aReflowInput
.ComputedSizeWithBorderPadding(wm
));
699 // "offset" is the offset of our content area from our frame's
701 nsPoint offset
= nsPoint(aReflowInput
.ComputedPhysicalBorderPadding().left
,
702 aReflowInput
.ComputedPhysicalBorderPadding().top
);
705 const nsMargin
& bp
= aReflowInput
.ComputedPhysicalBorderPadding();
706 nsSize
innerSize(aDesiredSize
.Width() - bp
.LeftRight(),
707 aDesiredSize
.Height() - bp
.TopBottom());
709 // Size & position the view according to 'object-fit' & 'object-position'.
710 nsRect destRect
= nsLayoutUtils::ComputeObjectDestRect(
711 nsRect(offset
, innerSize
), GetIntrinsicSize(), GetIntrinsicRatio(),
714 nsViewManager
* vm
= mInnerView
->GetViewManager();
715 vm
->MoveViewTo(mInnerView
, destRect
.x
, destRect
.y
);
716 vm
->ResizeView(mInnerView
, nsRect(nsPoint(0, 0), destRect
.Size()), true);
719 aDesiredSize
.SetOverflowAreasToDesiredBounds();
721 FinishAndStoreOverflow(&aDesiredSize
);
723 if (!aPresContext
->IsRootPaginatedDocument() && !mPostedReflowCallback
) {
724 PresShell()->PostReflowCallback(this);
725 mPostedReflowCallback
= true;
729 NS_FRAME_TRACE_CALLS
,
730 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",
731 aDesiredSize
.Width(), aDesiredSize
.Height(), ToString(aStatus
).c_str()));
734 bool nsSubDocumentFrame::ReflowFinished() {
735 RefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
737 AutoWeakFrame
weakFrame(this);
739 frameloader
->UpdatePositionAndSize(this);
741 if (weakFrame
.IsAlive()) {
742 // Make sure that we can post a reflow callback in the future.
743 mPostedReflowCallback
= false;
746 mPostedReflowCallback
= false;
751 void nsSubDocumentFrame::ReflowCallbackCanceled() {
752 mPostedReflowCallback
= false;
755 nsresult
nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID
,
758 if (aNameSpaceID
!= kNameSpaceID_None
) {
762 // If the noResize attribute changes, dis/allow frame to be resized
763 if (aAttribute
== nsGkAtoms::noresize
) {
764 // Note that we're not doing content type checks, but that's ok -- if
765 // they'd fail we will just end up with a null framesetFrame.
766 if (mContent
->GetParent()->IsHTMLElement(nsGkAtoms::frameset
)) {
767 nsIFrame
* parentFrame
= GetParent();
770 // There is no interface for nsHTMLFramesetFrame so QI'ing to
771 // concrete class, yay!
772 nsHTMLFramesetFrame
* framesetFrame
= do_QueryFrame(parentFrame
);
774 framesetFrame
->RecalculateBorderResize();
778 } else if (aAttribute
== nsGkAtoms::marginwidth
||
779 aAttribute
== nsGkAtoms::marginheight
) {
780 // Notify the frameloader
781 if (RefPtr
<nsFrameLoader
> frameloader
= FrameLoader()) {
782 frameloader
->MarginsChanged();
789 void nsSubDocumentFrame::MaybeUpdateEmbedderColorScheme() {
790 nsFrameLoader
* fl
= mFrameLoader
.get();
795 BrowsingContext
* bc
= fl
->GetExtantBrowsingContext();
800 auto ToOverride
= [](ColorScheme aScheme
) -> PrefersColorSchemeOverride
{
801 return aScheme
== ColorScheme::Dark
? PrefersColorSchemeOverride::Dark
802 : PrefersColorSchemeOverride::Light
;
805 EmbedderColorSchemes schemes
{
806 ToOverride(LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Used
)),
808 LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Preferred
))};
809 if (bc
->GetEmbedderColorSchemes() == schemes
) {
813 Unused
<< bc
->SetEmbedderColorSchemes(schemes
);
816 void nsSubDocumentFrame::MaybeUpdateRemoteStyle(
817 ComputedStyle
* aOldComputedStyle
) {
818 if (!mIsInObjectOrEmbed
) {
822 if (aOldComputedStyle
&&
823 aOldComputedStyle
->StyleVisibility()->mImageRendering
==
824 Style()->StyleVisibility()->mImageRendering
) {
832 if (mFrameLoader
->IsRemoteFrame()) {
833 mFrameLoader
->UpdateRemoteStyle(
834 Style()->StyleVisibility()->mImageRendering
);
838 BrowsingContext
* context
= mFrameLoader
->GetExtantBrowsingContext();
843 Document
* document
= context
->GetDocument();
848 if (document
->IsImageDocument()) {
849 document
->AsImageDocument()->UpdateRemoteStyle(
850 Style()->StyleVisibility()->mImageRendering
);
854 void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle
* aOldComputedStyle
) {
855 nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle
);
857 MaybeUpdateEmbedderColorScheme();
859 MaybeUpdateRemoteStyle(aOldComputedStyle
);
861 // If this presshell has invisible ancestors, we don't need to propagate the
862 // visibility style change to the subdocument since the subdocument should
863 // have already set the IsUnderHiddenEmbedderElement flag in
864 // nsSubDocumentFrame::Init.
865 if (PresShell()->IsUnderHiddenEmbedderElement()) {
869 const bool isVisible
= StyleVisibility()->IsVisible();
870 if (!aOldComputedStyle
||
871 isVisible
!= aOldComputedStyle
->StyleVisibility()->IsVisible()) {
872 PropagateIsUnderHiddenEmbedderElement(!isVisible
);
876 nsIFrame
* NS_NewSubDocumentFrame(PresShell
* aPresShell
, ComputedStyle
* aStyle
) {
877 return new (aPresShell
)
878 nsSubDocumentFrame(aStyle
, aPresShell
->GetPresContext());
881 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame
)
883 class nsHideViewer final
: public Runnable
{
885 nsHideViewer(nsIContent
* aFrameElement
, nsFrameLoader
* aFrameLoader
,
886 PresShell
* aPresShell
, bool aHideViewerIfFrameless
)
887 : mozilla::Runnable("nsHideViewer"),
888 mFrameElement(aFrameElement
),
889 mFrameLoader(aFrameLoader
),
890 mPresShell(aPresShell
),
891 mHideViewerIfFrameless(aHideViewerIfFrameless
) {
892 NS_ASSERTION(mFrameElement
, "Must have a frame element");
893 NS_ASSERTION(mFrameLoader
, "Must have a frame loader");
894 NS_ASSERTION(mPresShell
, "Must have a presshell");
897 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
Run() override
{
898 // Flush frames, to ensure any pending display:none changes are made.
899 // Note it can be unsafe to flush if we've destroyed the presentation
900 // for some other reason, like if we're shutting down.
902 // But avoid the flush if we know for sure we're away, like when we're out
903 // of the document already.
905 // FIXME(emilio): This could still be a perf footgun when removing lots of
906 // siblings where each of them cause the reframe of an ancestor which happen
907 // to contain a subdocument.
909 // We should find some way to avoid that!
910 if (!mPresShell
->IsDestroying() && mFrameElement
->IsInComposedDoc()) {
911 mPresShell
->FlushPendingNotifications(FlushType::Frames
);
914 // Either the frame has been constructed by now, or it never will be,
915 // either way we want to clear the stashed views.
916 mFrameLoader
->SetDetachedSubdocFrame(nullptr);
918 nsSubDocumentFrame
* frame
= do_QueryFrame(mFrameElement
->GetPrimaryFrame());
919 if (!frame
|| frame
->FrameLoader() != mFrameLoader
) {
920 PropagateIsUnderHiddenEmbedderElement(mFrameLoader
, true);
921 if (mHideViewerIfFrameless
) {
922 // The frame element has no nsIFrame for the same frame loader.
923 // Hide the nsFrameLoader, which destroys the presentation.
924 mFrameLoader
->Hide();
931 const nsCOMPtr
<nsIContent
> mFrameElement
;
932 const RefPtr
<nsFrameLoader
> mFrameLoader
;
933 const RefPtr
<PresShell
> mPresShell
;
934 const bool mHideViewerIfFrameless
;
937 static nsView
* BeginSwapDocShellsForViews(nsView
* aSibling
);
939 void nsSubDocumentFrame::Destroy(DestroyContext
& aContext
) {
940 if (mPostedReflowCallback
) {
941 PresShell()->CancelReflowCallback(this);
942 mPostedReflowCallback
= false;
945 // Detach the subdocument's views and stash them in the frame loader.
946 // We can then reattach them if we're being reframed (for example if
947 // the frame has been made position:fixed).
948 if (RefPtr
<nsFrameLoader
> frameloader
= FrameLoader()) {
951 nsView
* detachedViews
=
952 ::BeginSwapDocShellsForViews(mInnerView
->GetFirstChild());
954 frameloader
->SetDetachedSubdocFrame(
955 detachedViews
? detachedViews
->GetFrame() : nullptr);
957 // We call nsFrameLoader::HideViewer() in a script runner so that we can
958 // safely determine whether the frame is being reframed or destroyed.
959 nsContentUtils::AddScriptRunner(new nsHideViewer(
960 mContent
, frameloader
, PresShell(), (mDidCreateDoc
|| mCallingShow
)));
963 nsAtomicContainerFrame::Destroy(aContext
);
966 nsFrameLoader
* nsSubDocumentFrame::FrameLoader() const {
971 if (RefPtr
<nsFrameLoaderOwner
> loaderOwner
= do_QueryObject(GetContent())) {
972 mFrameLoader
= loaderOwner
->GetFrameLoader();
978 auto nsSubDocumentFrame::GetRemotePaintData() const -> RemoteFramePaintData
{
979 if (mRetainedRemoteFrame
) {
980 return *mRetainedRemoteFrame
;
983 RemoteFramePaintData data
;
984 nsFrameLoader
* fl
= FrameLoader();
989 auto* rb
= fl
->GetRemoteBrowser();
993 data
.mLayersId
= rb
->GetLayersId();
994 data
.mTabId
= rb
->GetTabId();
998 void nsSubDocumentFrame::ResetFrameLoader(RetainPaintData aRetain
) {
999 if (aRetain
== RetainPaintData::Yes
&& mFrameLoader
) {
1000 mRetainedRemoteFrame
= Some(GetRemotePaintData());
1002 mRetainedRemoteFrame
.reset();
1004 mFrameLoader
= nullptr;
1005 ClearDisplayItems();
1006 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
1009 void nsSubDocumentFrame::ClearRetainedPaintData() {
1010 mRetainedRemoteFrame
.reset();
1011 ClearDisplayItems();
1012 InvalidateFrameSubtree();
1015 // XXX this should be called ObtainDocShell or something like that,
1016 // to indicate that it could have side effects
1017 nsIDocShell
* nsSubDocumentFrame::GetDocShell() const {
1018 // How can FrameLoader() return null???
1019 if (NS_WARN_IF(!FrameLoader())) {
1022 return mFrameLoader
->GetDocShell(IgnoreErrors());
1025 static void DestroyDisplayItemDataForFrames(nsIFrame
* aFrame
) {
1026 // Destroying a WebRenderUserDataTable can cause destruction of other objects
1027 // which can remove frame properties in their destructor. If we delete a frame
1028 // property it runs the destructor of the stored object in the middle of
1029 // updating the frame property table, so if the destruction of that object
1030 // causes another update to the frame property table it would leave the frame
1031 // property table in an inconsistent state. So we remove it from the table and
1032 // then destroy it. (bug 1530657)
1033 WebRenderUserDataTable
* userDataTable
=
1034 aFrame
->TakeProperty(WebRenderUserDataProperty::Key());
1035 if (userDataTable
) {
1036 for (const auto& data
: userDataTable
->Values()) {
1037 data
->RemoveFromTable();
1039 delete userDataTable
;
1042 for (const auto& childList
: aFrame
->ChildLists()) {
1043 for (nsIFrame
* child
: childList
.mList
) {
1044 DestroyDisplayItemDataForFrames(child
);
1049 static CallState
BeginSwapDocShellsForDocument(Document
& aDocument
) {
1050 if (PresShell
* presShell
= aDocument
.GetPresShell()) {
1051 // Disable painting while the views are detached, see bug 946929.
1052 presShell
->SetNeverPainting(true);
1054 if (nsIFrame
* rootFrame
= presShell
->GetRootFrame()) {
1055 ::DestroyDisplayItemDataForFrames(rootFrame
);
1058 aDocument
.EnumerateSubDocuments(BeginSwapDocShellsForDocument
);
1059 return CallState::Continue
;
1062 static nsView
* BeginSwapDocShellsForViews(nsView
* aSibling
) {
1063 // Collect the removed sibling views in reverse order in 'removedViews'.
1064 nsView
* removedViews
= nullptr;
1066 if (Document
* doc
= ::GetDocumentFromView(aSibling
)) {
1067 ::BeginSwapDocShellsForDocument(*doc
);
1069 nsView
* next
= aSibling
->GetNextSibling();
1070 aSibling
->GetViewManager()->RemoveChild(aSibling
);
1071 aSibling
->SetNextSibling(removedViews
);
1072 removedViews
= aSibling
;
1075 return removedViews
;
1079 void nsSubDocumentFrame::InsertViewsInReverseOrder(nsView
* aSibling
,
1081 MOZ_ASSERT(aParent
, "null view");
1082 MOZ_ASSERT(!aParent
->GetFirstChild(), "inserting into non-empty list");
1084 nsViewManager
* vm
= aParent
->GetViewManager();
1086 nsView
* next
= aSibling
->GetNextSibling();
1087 aSibling
->SetNextSibling(nullptr);
1088 // true means 'after' in document order which is 'before' in view order,
1089 // so this call prepends the child, thus reversing the siblings as we go.
1090 vm
->InsertChild(aParent
, aSibling
, nullptr, true);
1095 nsresult
nsSubDocumentFrame::BeginSwapDocShells(nsIFrame
* aOther
) {
1096 if (!aOther
|| !aOther
->IsSubDocumentFrame()) {
1097 return NS_ERROR_NOT_IMPLEMENTED
;
1100 nsSubDocumentFrame
* other
= static_cast<nsSubDocumentFrame
*>(aOther
);
1101 if (!mFrameLoader
|| !mDidCreateDoc
|| mCallingShow
|| !other
->mFrameLoader
||
1102 !other
->mDidCreateDoc
) {
1103 return NS_ERROR_NOT_IMPLEMENTED
;
1106 ClearDisplayItems();
1107 other
->ClearDisplayItems();
1109 if (mInnerView
&& other
->mInnerView
) {
1110 nsView
* ourSubdocViews
= mInnerView
->GetFirstChild();
1111 nsView
* ourRemovedViews
= ::BeginSwapDocShellsForViews(ourSubdocViews
);
1112 nsView
* otherSubdocViews
= other
->mInnerView
->GetFirstChild();
1113 nsView
* otherRemovedViews
= ::BeginSwapDocShellsForViews(otherSubdocViews
);
1115 InsertViewsInReverseOrder(ourRemovedViews
, other
->mInnerView
);
1116 InsertViewsInReverseOrder(otherRemovedViews
, mInnerView
);
1118 mFrameLoader
.swap(other
->mFrameLoader
);
1122 static CallState
EndSwapDocShellsForDocument(Document
& aDocument
) {
1123 // Our docshell and view trees have been updated for the new hierarchy.
1124 // Now also update all nsDeviceContext::mWidget to that of the
1125 // container view in the new hierarchy.
1126 if (nsCOMPtr
<nsIDocShell
> ds
= aDocument
.GetDocShell()) {
1127 nsCOMPtr
<nsIDocumentViewer
> viewer
;
1128 ds
->GetDocViewer(getter_AddRefs(viewer
));
1130 RefPtr
<nsPresContext
> pc
= viewer
->GetPresContext();
1131 if (pc
&& pc
->GetPresShell()) {
1132 pc
->GetPresShell()->SetNeverPainting(ds
->IsInvisible());
1134 nsDeviceContext
* dc
= pc
? pc
->DeviceContext() : nullptr;
1136 nsView
* v
= viewer
->FindContainerView();
1137 dc
->Init(v
? v
->GetNearestWidget(nullptr) : nullptr);
1139 viewer
= viewer
->GetPreviousViewer();
1143 aDocument
.EnumerateSubDocuments(EndSwapDocShellsForDocument
);
1144 return CallState::Continue
;
1148 void nsSubDocumentFrame::EndSwapDocShellsForViews(nsView
* aSibling
) {
1149 for (; aSibling
; aSibling
= aSibling
->GetNextSibling()) {
1150 if (Document
* doc
= ::GetDocumentFromView(aSibling
)) {
1151 ::EndSwapDocShellsForDocument(*doc
);
1153 nsIFrame
* frame
= aSibling
->GetFrame();
1155 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrameInProcess(frame
);
1156 if (parent
->HasAnyStateBits(NS_FRAME_IN_POPUP
)) {
1157 nsIFrame::AddInPopupStateBitToDescendants(frame
);
1159 nsIFrame::RemoveInPopupStateBitFromDescendants(frame
);
1161 if (frame
->HasInvalidFrameInSubtree()) {
1163 !parent
->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT
|
1164 NS_FRAME_IS_NONDISPLAY
)) {
1165 parent
->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT
);
1166 parent
= nsLayoutUtils::GetCrossDocParentFrameInProcess(parent
);
1173 void nsSubDocumentFrame::EndSwapDocShells(nsIFrame
* aOther
) {
1174 nsSubDocumentFrame
* other
= static_cast<nsSubDocumentFrame
*>(aOther
);
1175 AutoWeakFrame
weakThis(this);
1176 AutoWeakFrame
weakOther(aOther
);
1179 EndSwapDocShellsForViews(mInnerView
->GetFirstChild());
1181 if (other
->mInnerView
) {
1182 EndSwapDocShellsForViews(other
->mInnerView
->GetFirstChild());
1185 // Now make sure we reflow both frames, in case their contents
1186 // determine their size.
1187 // And repaint them, for good measure, in case there's nothing
1188 // interesting that happens during reflow.
1189 if (weakThis
.IsAlive()) {
1190 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors
,
1192 InvalidateFrameSubtree();
1193 PropagateIsUnderHiddenEmbedderElement(
1194 PresShell()->IsUnderHiddenEmbedderElement() ||
1195 !StyleVisibility()->IsVisible());
1197 if (weakOther
.IsAlive()) {
1198 other
->PresShell()->FrameNeedsReflow(
1199 other
, IntrinsicDirty::FrameAndAncestors
, NS_FRAME_IS_DIRTY
);
1200 other
->InvalidateFrameSubtree();
1201 other
->PropagateIsUnderHiddenEmbedderElement(
1202 other
->PresShell()->IsUnderHiddenEmbedderElement() ||
1203 !other
->StyleVisibility()->IsVisible());
1207 void nsSubDocumentFrame::ClearDisplayItems() {
1208 if (auto* builder
= nsLayoutUtils::GetRetainedDisplayListBuilder(this)) {
1209 DL_LOGD("nsSubDocumentFrame::ClearDisplayItems() %p", this);
1210 builder
->ClearRetainedData();
1214 nsView
* nsSubDocumentFrame::EnsureInnerView() {
1219 // create, init, set the parent of the view
1220 nsView
* outerView
= GetView();
1221 NS_ASSERTION(outerView
, "Must have an outer view already");
1222 nsRect
viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1224 nsViewManager
* viewMan
= outerView
->GetViewManager();
1225 nsView
* innerView
= viewMan
->CreateView(viewBounds
, outerView
);
1227 NS_ERROR("Could not create inner view");
1230 mInnerView
= innerView
;
1231 viewMan
->InsertChild(outerView
, innerView
, nullptr, true);
1236 nsPoint
nsSubDocumentFrame::GetExtraOffset() const {
1237 MOZ_ASSERT(mInnerView
);
1238 return mInnerView
->GetPosition();
1241 void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
1242 const nsStylePosition
* pos
= StylePosition();
1243 bool dependsOnIntrinsics
=
1244 !pos
->mWidth
.ConvertsToLength() || !pos
->mHeight
.ConvertsToLength();
1246 if (dependsOnIntrinsics
|| pos
->mObjectFit
!= StyleObjectFit::Fill
) {
1247 auto dirtyHint
= dependsOnIntrinsics
1248 ? IntrinsicDirty::FrameAncestorsAndDescendants
1249 : IntrinsicDirty::None
;
1250 PresShell()->FrameNeedsReflow(this, dirtyHint
, NS_FRAME_IS_DIRTY
);
1255 // Return true iff |aManager| is a "temporary layer manager". They're
1256 // used for small software rendering tasks, like drawWindow. That's
1257 // currently implemented by a BasicLayerManager without a backing
1258 // widget, and hence in non-retained mode.
1259 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder
* aBuilder
,
1260 nsSubDocumentFrame
* aFrame
)
1261 : nsPaintedDisplayItem(aBuilder
, aFrame
),
1262 mEventRegionsOverride(EventRegionsOverride::NoOverride
) {
1263 const bool frameIsPointerEventsNone
=
1264 aFrame
->Style()->PointerEvents() == StylePointerEvents::None
;
1265 if (aBuilder
->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone
) {
1266 mEventRegionsOverride
|= EventRegionsOverride::ForceEmptyHitRegion
;
1268 if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(
1269 aFrame
->PresShell())) {
1270 mEventRegionsOverride
|= EventRegionsOverride::ForceDispatchToContent
;
1273 mPaintData
= aFrame
->GetRemotePaintData();
1278 void nsDisplayRemote::Paint(nsDisplayListBuilder
* aBuilder
, gfxContext
* aCtx
) {
1279 nsPresContext
* pc
= mFrame
->PresContext();
1280 nsFrameLoader
* fl
= GetFrameLoader();
1281 if (pc
->GetPrintSettings() && fl
->IsRemoteFrame()) {
1282 // See the comment below in CreateWebRenderCommands() as for why doing this.
1283 fl
->UpdatePositionAndSize(static_cast<nsSubDocumentFrame
*>(mFrame
));
1286 DrawTarget
* target
= aCtx
->GetDrawTarget();
1287 if (!target
->IsRecording() || mPaintData
.mTabId
== 0) {
1288 NS_WARNING("Remote iframe not rendered");
1292 // Rendering the inner document will apply a scale to account for its app
1293 // units per dev pixel ratio. We want to apply the inverse scaling using our
1294 // app units per dev pixel ratio, so that no actual scaling will be applied if
1295 // they match. For in-process rendering, nsSubDocumentFrame creates an
1296 // nsDisplayZoom item if the app units per dev pixel ratio changes.
1298 // Similarly, rendering the inner document will scale up by the cross process
1299 // paint scale again, so we also need to account for that.
1300 const int32_t appUnitsPerDevPixel
= pc
->AppUnitsPerDevPixel();
1302 gfxContextMatrixAutoSaveRestore
saveMatrix(aCtx
);
1303 gfxFloat targetAuPerDev
=
1304 gfxFloat(AppUnitsPerCSSPixel()) / aCtx
->GetCrossProcessPaintScale();
1306 gfxFloat scale
= targetAuPerDev
/ appUnitsPerDevPixel
;
1307 aCtx
->Multiply(gfxMatrix::Scaling(scale
, scale
));
1310 NSRectToSnappedRect(GetContentRect(), targetAuPerDev
, *target
);
1311 target
->DrawDependentSurface(mPaintData
.mTabId
, destRect
);
1314 bool nsDisplayRemote::CreateWebRenderCommands(
1315 mozilla::wr::DisplayListBuilder
& aBuilder
,
1316 mozilla::wr::IpcResourceUpdateQueue
& aResources
,
1317 const StackingContextHelper
& aSc
,
1318 mozilla::layers::RenderRootStateManager
* aManager
,
1319 nsDisplayListBuilder
* aDisplayListBuilder
) {
1320 if (!mPaintData
.mLayersId
.IsValid()) {
1324 nsPresContext
* pc
= mFrame
->PresContext();
1325 nsFrameLoader
* fl
= GetFrameLoader();
1327 auto* subDocFrame
= static_cast<nsSubDocumentFrame
*>(mFrame
);
1328 nsRect destRect
= subDocFrame
->GetDestRect();
1329 if (RefPtr
<RemoteBrowser
> remoteBrowser
= fl
->GetRemoteBrowser()) {
1330 if (pc
->GetPrintSettings()) {
1331 // HACK(emilio): Usually we update sizing/positioning from
1332 // ReflowFinished(). Print documents have no incremental reflow at all
1333 // though, so we can't rely on it firing after a frame becomes remote.
1334 // Thus, if we're painting a remote frame, update its sizing and position
1337 // UpdatePositionAndSize() can cause havoc for non-remote frames but
1338 // luckily we don't care about those, so this is fine.
1339 fl
->UpdatePositionAndSize(subDocFrame
);
1342 // Adjust mItemVisibleRect, which is relative to the reference frame, to be
1343 // relative to this frame.
1344 const nsRect buildingRect
= GetBuildingRect() - ToReferenceFrame();
1345 Maybe
<nsRect
> visibleRect
=
1346 buildingRect
.EdgeInclusiveIntersection(destRect
);
1348 *visibleRect
-= destRect
.TopLeft();
1351 // Generate an effects update notifying the browser it is visible
1352 MatrixScales scale
= aSc
.GetInheritedScale();
1354 ParentLayerToScreenScale2D transformToAncestorScale
=
1355 ParentLayerToParentLayerScale(
1356 pc
->GetPresShell() ? pc
->GetPresShell()->GetCumulativeResolution()
1358 nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
1361 aDisplayListBuilder
->AddEffectUpdate(
1362 remoteBrowser
, EffectsInfo::VisibleWithinRect(
1363 visibleRect
, scale
, transformToAncestorScale
));
1365 // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
1367 RefPtr
<WebRenderRemoteData
> userData
=
1368 aManager
->CommandBuilder()
1369 .CreateOrRecycleWebRenderUserData
<WebRenderRemoteData
>(this,
1371 userData
->SetRemoteBrowser(remoteBrowser
);
1374 nscoord auPerDevPixel
= pc
->AppUnitsPerDevPixel();
1375 nsPoint layerOffset
=
1376 aDisplayListBuilder
->ToReferenceFrame(mFrame
) + destRect
.TopLeft();
1377 mOffset
= LayoutDevicePoint::FromAppUnits(layerOffset
, auPerDevPixel
);
1379 destRect
.MoveTo(0, 0);
1380 auto rect
= LayoutDeviceRect::FromAppUnits(destRect
, auPerDevPixel
);
1383 aBuilder
.PushIFrame(rect
, !BackfaceIsHidden(),
1384 mozilla::wr::AsPipelineId(mPaintData
.mLayersId
),
1385 /*ignoreMissingPipelines*/ true);
1390 bool nsDisplayRemote::UpdateScrollData(
1391 mozilla::layers::WebRenderScrollData
* aData
,
1392 mozilla::layers::WebRenderLayerScrollData
* aLayerData
) {
1393 if (!mPaintData
.mLayersId
.IsValid()) {
1398 aLayerData
->SetReferentId(mPaintData
.mLayersId
);
1400 auto size
= static_cast<nsSubDocumentFrame
*>(mFrame
)->GetSubdocumentSize();
1401 Matrix4x4 m
= Matrix4x4::Translation(mOffset
.x
, mOffset
.y
, 0.0);
1402 aLayerData
->SetTransform(m
);
1403 aLayerData
->SetEventRegionsOverride(mEventRegionsOverride
);
1404 aLayerData
->SetRemoteDocumentSize(LayerIntSize(size
.width
, size
.height
));
1409 nsFrameLoader
* nsDisplayRemote::GetFrameLoader() const {
1410 return static_cast<nsSubDocumentFrame
*>(mFrame
)->FrameLoader();
1413 } // namespace mozilla