forked from mirrors/gecko-dev
		
	 8b358b41b7
			
		
	
	
		8b358b41b7
		
	
	
	
	
		
			
			Make the ScrollMetadata's mScrollParentId match what is found in the active scroll root tree. Depends on D148662 Differential Revision: https://phabricator.services.mozilla.com/D149925
		
			
				
	
	
		
			1450 lines
		
	
	
	
		
			51 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1450 lines
		
	
	
	
		
			51 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| /*
 | |
|  * rendering object for replaced elements that contain a document, such
 | |
|  * as <frame>, <iframe>, and some <object>s
 | |
|  */
 | |
| 
 | |
| #include "nsSubDocumentFrame.h"
 | |
| 
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "mozilla/PresShell.h"
 | |
| #include "mozilla/StaticPrefs_layout.h"
 | |
| #include "mozilla/Unused.h"
 | |
| #include "mozilla/dom/Document.h"
 | |
| #include "mozilla/dom/HTMLFrameElement.h"
 | |
| #include "mozilla/dom/ImageDocument.h"
 | |
| #include "mozilla/dom/BrowserParent.h"
 | |
| 
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsGenericHTMLElement.h"
 | |
| #include "nsGenericHTMLFrameElement.h"
 | |
| #include "nsAttrValueInlines.h"
 | |
| #include "nsIDocShell.h"
 | |
| #include "nsIContentViewer.h"
 | |
| #include "nsIContentInlines.h"
 | |
| #include "nsPresContext.h"
 | |
| #include "nsView.h"
 | |
| #include "nsViewManager.h"
 | |
| #include "nsGkAtoms.h"
 | |
| #include "nsStyleConsts.h"
 | |
| #include "nsStyleStruct.h"
 | |
| #include "nsStyleStructInlines.h"
 | |
| #include "nsFrameSetFrame.h"
 | |
| #include "nsNameSpaceManager.h"
 | |
| #include "nsDisplayList.h"
 | |
| #include "nsIScrollableFrame.h"
 | |
| #include "nsIObjectLoadingContent.h"
 | |
| #include "nsLayoutUtils.h"
 | |
| #include "nsContentUtils.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| #include "nsQueryObject.h"
 | |
| #include "RetainedDisplayListBuilder.h"
 | |
| #include "nsObjectLoadingContent.h"
 | |
| 
 | |
| #include "mozilla/layers/WebRenderUserData.h"
 | |
| #include "mozilla/layers/WebRenderScrollData.h"
 | |
| #include "mozilla/layers/RenderRootStateManager.h"
 | |
| #include "mozilla/layers/StackingContextHelper.h"  // for StackingContextHelper
 | |
| #include "mozilla/ProfilerLabels.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::dom;
 | |
| using namespace mozilla::gfx;
 | |
| using namespace mozilla::layers;
 | |
| 
 | |
| static Document* GetDocumentFromView(nsView* aView) {
 | |
|   MOZ_ASSERT(aView, "null view");
 | |
| 
 | |
|   nsViewManager* vm = aView->GetViewManager();
 | |
|   PresShell* presShell = vm ? vm->GetPresShell() : nullptr;
 | |
|   return presShell ? presShell->GetDocument() : nullptr;
 | |
| }
 | |
| 
 | |
| nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle,
 | |
|                                        nsPresContext* aPresContext)
 | |
|     : nsAtomicContainerFrame(aStyle, aPresContext, kClassID),
 | |
|       mOuterView(nullptr),
 | |
|       mInnerView(nullptr),
 | |
|       mIsInline(false),
 | |
|       mPostedReflowCallback(false),
 | |
|       mDidCreateDoc(false),
 | |
|       mCallingShow(false),
 | |
|       mIsInObjectOrEmbed(false) {}
 | |
| 
 | |
| #ifdef ACCESSIBILITY
 | |
| a11y::AccType nsSubDocumentFrame::AccessibleType() {
 | |
|   return a11y::eOuterDocType;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
 | |
|   NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
 | |
| NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
 | |
| 
 | |
| class AsyncFrameInit : public Runnable {
 | |
|  public:
 | |
|   explicit AsyncFrameInit(nsIFrame* aFrame)
 | |
|       : mozilla::Runnable("AsyncFrameInit"), mFrame(aFrame) {}
 | |
|   NS_IMETHOD Run() override {
 | |
|     AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER);
 | |
|     if (mFrame.IsAlive()) {
 | |
|       static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
 | |
|     }
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   WeakFrame mFrame;
 | |
| };
 | |
| 
 | |
| static void InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent);
 | |
| 
 | |
| static void EndSwapDocShellsForViews(nsView* aView);
 | |
| 
 | |
| void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
 | |
|                               nsIFrame* aPrevInFlow) {
 | |
|   MOZ_ASSERT(aContent);
 | |
|   // determine if we are a <frame> or <iframe>
 | |
|   mIsInline = !aContent->IsHTMLElement(nsGkAtoms::frame);
 | |
| 
 | |
|   nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
 | |
| 
 | |
|   // CreateView() creates this frame's view, stored in mOuterView.  It needs to
 | |
|   // be created first since it's the parent of the inner view, stored in
 | |
|   // mInnerView.
 | |
|   CreateView();
 | |
|   EnsureInnerView();
 | |
| 
 | |
|   // Set the primary frame now so that nsDocumentViewer::FindContainerView
 | |
|   // called from within EndSwapDocShellsForViews below can find it if needed.
 | |
|   aContent->SetPrimaryFrame(this);
 | |
| 
 | |
|   // If we have a detached subdoc's root view on our frame loader, re-insert
 | |
|   // it into the view tree. This happens when we've been reframed, and
 | |
|   // ensures the presentation persists across reframes. If the frame element
 | |
|   // has changed documents however, we blow away the presentation.
 | |
|   RefPtr<nsFrameLoader> frameloader = FrameLoader();
 | |
|   if (frameloader) {
 | |
|     nsCOMPtr<Document> oldContainerDoc;
 | |
|     nsIFrame* detachedFrame =
 | |
|         frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
 | |
|     frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
 | |
|     MOZ_ASSERT(oldContainerDoc || !detachedFrame);
 | |
|     if (oldContainerDoc) {
 | |
|       nsView* detachedView = detachedFrame ? detachedFrame->GetView() : nullptr;
 | |
|       if (detachedView && oldContainerDoc == aContent->OwnerDoc()) {
 | |
|         // Restore stashed presentation.
 | |
|         ::InsertViewsInReverseOrder(detachedView, mInnerView);
 | |
|         ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
 | |
|       } else {
 | |
|         // Presentation is for a different document, don't restore it.
 | |
|         frameloader->Hide();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (RefPtr<BrowsingContext> bc = frameloader->GetExtantBrowsingContext()) {
 | |
|       mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   MaybeUpdateRemoteStyle();
 | |
| 
 | |
|   PropagateIsUnderHiddenEmbedderElementToSubView(
 | |
|       PresShell()->IsUnderHiddenEmbedderElement() ||
 | |
|       !StyleVisibility()->IsVisible());
 | |
| 
 | |
|   nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::PropagateIsUnderHiddenEmbedderElementToSubView(
 | |
|     bool aIsUnderHiddenEmbedderElement) {
 | |
|   if (mFrameLoader && mFrameLoader->IsRemoteFrame()) {
 | |
|     mFrameLoader->SendIsUnderHiddenEmbedderElement(
 | |
|         aIsUnderHiddenEmbedderElement);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!mInnerView) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   nsView* subdocView = mInnerView->GetFirstChild();
 | |
|   while (subdocView) {
 | |
|     if (mozilla::PresShell* presShell = subdocView->GetPresShell()) {
 | |
|       presShell->SetIsUnderHiddenEmbedderElement(aIsUnderHiddenEmbedderElement);
 | |
|     }
 | |
|     subdocView = subdocView->GetNextSibling();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::ShowViewer() {
 | |
|   if (mCallingShow) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<nsFrameLoader> frameloader = FrameLoader();
 | |
|   if (!frameloader || frameloader->IsDead()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!frameloader->IsRemoteFrame() && !PresContext()->IsDynamic()) {
 | |
|     // We let the printing code take care of loading the document and
 | |
|     // initializing the shell; just create the inner view for it to use.
 | |
|     (void)EnsureInnerView();
 | |
|   } else {
 | |
|     AutoWeakFrame weakThis(this);
 | |
|     mCallingShow = true;
 | |
|     bool didCreateDoc = frameloader->Show(this);
 | |
|     if (!weakThis.IsAlive()) {
 | |
|       return;
 | |
|     }
 | |
|     mCallingShow = false;
 | |
|     mDidCreateDoc = didCreateDoc;
 | |
| 
 | |
|     if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
 | |
|       frameloader->UpdatePositionAndSize(this);
 | |
|     }
 | |
| 
 | |
|     MaybeUpdateEmbedderColorScheme();
 | |
| 
 | |
|     if (!weakThis.IsAlive()) {
 | |
|       return;
 | |
|     }
 | |
|     InvalidateFrame();
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsIFrame* nsSubDocumentFrame::GetSubdocumentRootFrame() {
 | |
|   if (!mInnerView) return nullptr;
 | |
|   nsView* subdocView = mInnerView->GetFirstChild();
 | |
|   return subdocView ? subdocView->GetFrame() : nullptr;
 | |
| }
 | |
| 
 | |
| mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShellForPainting(
 | |
|     uint32_t aFlags) {
 | |
|   if (!mInnerView) return nullptr;
 | |
| 
 | |
|   nsView* subdocView = mInnerView->GetFirstChild();
 | |
|   if (!subdocView) return nullptr;
 | |
| 
 | |
|   mozilla::PresShell* presShell = nullptr;
 | |
| 
 | |
|   nsIFrame* subdocRootFrame = subdocView->GetFrame();
 | |
|   if (subdocRootFrame) {
 | |
|     presShell = subdocRootFrame->PresShell();
 | |
|   }
 | |
| 
 | |
|   // If painting is suppressed in the presshell, we try to look for a better
 | |
|   // presshell to use.
 | |
|   if (!presShell || (presShell->IsPaintingSuppressed() &&
 | |
|                      !(aFlags & IGNORE_PAINT_SUPPRESSION))) {
 | |
|     // During page transition mInnerView will sometimes have two children, the
 | |
|     // first being the new page that may not have any frame, and the second
 | |
|     // being the old page that will probably have a frame.
 | |
|     nsView* nextView = subdocView->GetNextSibling();
 | |
|     nsIFrame* frame = nullptr;
 | |
|     if (nextView) {
 | |
|       frame = nextView->GetFrame();
 | |
|     }
 | |
|     if (frame) {
 | |
|       mozilla::PresShell* presShellForNextView = frame->PresShell();
 | |
|       if (!presShell || (presShellForNextView &&
 | |
|                          !presShellForNextView->IsPaintingSuppressed() &&
 | |
|                          StaticPrefs::layout_show_previous_page())) {
 | |
|         subdocView = nextView;
 | |
|         subdocRootFrame = frame;
 | |
|         presShell = presShellForNextView;
 | |
|       }
 | |
|     }
 | |
|     if (!presShell) {
 | |
|       // If we don't have a frame we use this roundabout way to get the pres
 | |
|       // shell.
 | |
|       if (!mFrameLoader) return nullptr;
 | |
|       nsIDocShell* docShell = mFrameLoader->GetDocShell(IgnoreErrors());
 | |
|       if (!docShell) return nullptr;
 | |
|       presShell = docShell->GetPresShell();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return presShell;
 | |
| }
 | |
| 
 | |
| nsRect nsSubDocumentFrame::GetDestRect() {
 | |
|   nsRect rect = GetContent()->IsHTMLElement(nsGkAtoms::frame)
 | |
|                     ? GetRectRelativeToSelf()
 | |
|                     : GetContentRectRelativeToSelf();
 | |
| 
 | |
|   // Adjust subdocument size, according to 'object-fit' and the subdocument's
 | |
|   // intrinsic size and ratio.
 | |
|   return nsLayoutUtils::ComputeObjectDestRect(
 | |
|       rect, GetIntrinsicSize(), GetIntrinsicRatio(), StylePosition());
 | |
| }
 | |
| 
 | |
| ScreenIntSize nsSubDocumentFrame::GetSubdocumentSize() {
 | |
|   if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
 | |
|     if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
 | |
|       nsCOMPtr<Document> oldContainerDoc;
 | |
|       nsIFrame* detachedFrame =
 | |
|           frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
 | |
|       if (nsView* view = detachedFrame ? detachedFrame->GetView() : nullptr) {
 | |
|         nsSize size = view->GetBounds().Size();
 | |
|         nsPresContext* presContext = detachedFrame->PresContext();
 | |
|         return ScreenIntSize(presContext->AppUnitsToDevPixels(size.width),
 | |
|                              presContext->AppUnitsToDevPixels(size.height));
 | |
|       }
 | |
|     }
 | |
|     // Pick some default size for now.  Using 10x10 because that's what the
 | |
|     // code used to do.
 | |
|     return ScreenIntSize(10, 10);
 | |
|   }
 | |
| 
 | |
|   nsSize docSizeAppUnits = GetDestRect().Size();
 | |
|   nsPresContext* pc = PresContext();
 | |
|   return ScreenIntSize(pc->AppUnitsToDevPixels(docSizeAppUnits.width),
 | |
|                        pc->AppUnitsToDevPixels(docSizeAppUnits.height));
 | |
| }
 | |
| 
 | |
| static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
 | |
|                                           nsIFrame* aFrame,
 | |
|                                           nsDisplayList* aList) {
 | |
|   for (nsDisplayItem* item : aList->TakeItems()) {
 | |
|     if (item->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) {
 | |
|       nsDisplayList tmpList(aBuilder);
 | |
|       tmpList.AppendToTop(item);
 | |
|       item = MakeDisplayItemWithIndex<nsDisplayOwnLayer>(
 | |
|           aBuilder, aFrame, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc,
 | |
|           &tmpList, aBuilder->CurrentActiveScrolledRoot(),
 | |
|           nsDisplayOwnLayerFlags::None, ScrollbarData{}, true, false);
 | |
|     }
 | |
|     aList->AppendToTop(item);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
 | |
|                                           const nsDisplayListSet& aLists) {
 | |
|   if (!IsVisibleForPainting()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   nsFrameLoader* frameLoader = FrameLoader();
 | |
|   bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame();
 | |
| 
 | |
|   // If we are pointer-events:none then we don't need to HitTest background
 | |
|   const bool pointerEventsNone =
 | |
|       Style()->PointerEvents() == StylePointerEvents::None;
 | |
|   if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
 | |
|     nsDisplayListCollection decorations(aBuilder);
 | |
|     DisplayBorderBackgroundOutline(aBuilder, decorations);
 | |
|     if (isRemoteFrame) {
 | |
|       // Wrap background colors of <iframe>s with remote subdocuments in their
 | |
|       // own layer so we generate a ColorLayer. This is helpful for optimizing
 | |
|       // compositing; we can skip compositing the ColorLayer when the
 | |
|       // remote content is opaque.
 | |
|       WrapBackgroundColorInOwnLayer(aBuilder, this,
 | |
|                                     decorations.BorderBackground());
 | |
|     }
 | |
|     decorations.MoveTo(aLists);
 | |
|   }
 | |
| 
 | |
|   if (aBuilder->IsForEventDelivery() && pointerEventsNone) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (HidesContent()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // If we're passing pointer events to children then we have to descend into
 | |
|   // subdocuments no matter what, to determine which parts are transparent for
 | |
|   // hit-testing or event regions.
 | |
|   bool needToDescend = aBuilder->GetDescendIntoSubdocuments();
 | |
|   if (!mInnerView || !needToDescend) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (isRemoteFrame) {
 | |
|     // We're the subdoc for <browser remote="true"> and it has
 | |
|     // painted content.  Display its shadow layer tree.
 | |
|     DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 | |
|     clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
 | |
| 
 | |
|     aLists.Content()->AppendNewToTop<nsDisplayRemote>(aBuilder, this);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   RefPtr<mozilla::PresShell> presShell = GetSubdocumentPresShellForPainting(
 | |
|       aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0);
 | |
| 
 | |
|   if (!presShell) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (aBuilder->IsInFilter()) {
 | |
|     Document* outerDoc = PresShell()->GetDocument();
 | |
|     Document* innerDoc = presShell->GetDocument();
 | |
|     if (outerDoc && innerDoc) {
 | |
|       if (!outerDoc->NodePrincipal()->Equals(innerDoc->NodePrincipal())) {
 | |
|         outerDoc->SetUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsIFrame* subdocRootFrame = presShell->GetRootFrame();
 | |
| 
 | |
|   nsPresContext* presContext = presShell->GetPresContext();
 | |
| 
 | |
|   int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
 | |
|   int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
 | |
| 
 | |
|   nsRect visible;
 | |
|   nsRect dirty;
 | |
|   bool ignoreViewportScrolling = false;
 | |
|   if (subdocRootFrame) {
 | |
|     // get the dirty rect relative to the root frame of the subdoc
 | |
|     visible = aBuilder->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame);
 | |
|     dirty = aBuilder->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame);
 | |
|     // and convert into the appunits of the subdoc
 | |
|     visible = visible.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
 | |
|     dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
 | |
| 
 | |
|     if (nsIScrollableFrame* rootScrollableFrame =
 | |
|             presShell->GetRootScrollFrameAsScrollable()) {
 | |
|       // Use a copy, so the rects don't get modified.
 | |
|       nsRect copyOfDirty = dirty;
 | |
|       nsRect copyOfVisible = visible;
 | |
|       // TODO(botond): Can we just axe this DecideScrollableLayer call?
 | |
|       rootScrollableFrame->DecideScrollableLayer(aBuilder, ©OfVisible,
 | |
|                                                  ©OfDirty,
 | |
|                                                  /* aSetBase = */ true);
 | |
| 
 | |
|       ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
 | |
|     }
 | |
| 
 | |
|     aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone);
 | |
|     aBuilder->IncrementPresShellPaintCount(presShell);
 | |
|   } else {
 | |
|     visible = aBuilder->GetVisibleRect();
 | |
|     dirty = aBuilder->GetDirtyRect();
 | |
|   }
 | |
| 
 | |
|   DisplayListClipState::AutoSaveRestore clipState(aBuilder);
 | |
|   clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
 | |
| 
 | |
|   nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
 | |
|   bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
 | |
|   bool needsOwnLayer = false;
 | |
|   if (constructZoomItem || presContext->IsRootContentDocumentCrossProcess() ||
 | |
|       (sf && sf->IsScrollingActive())) {
 | |
|     needsOwnLayer = true;
 | |
|   }
 | |
| 
 | |
|   nsDisplayList childItems(aBuilder);
 | |
| 
 | |
|   {
 | |
|     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
 | |
|     if (needsOwnLayer) {
 | |
|       // Clear current clip. There's no point in propagating it down, since
 | |
|       // the layer we will construct will be clipped by the current clip.
 | |
|       // In fact for nsDisplayZoom propagating it down would be incorrect since
 | |
|       // nsDisplayZoom changes the meaning of appunits.
 | |
|       nestedClipState.Clear();
 | |
|     }
 | |
| 
 | |
|     // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
 | |
|     // is used to compute the visible rect if AddCanvasBackgroundColorItem
 | |
|     // creates a display item.
 | |
|     nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
 | |
|     nsDisplayListBuilder::AutoBuildingDisplayList building(aBuilder, frame,
 | |
|                                                            visible, dirty);
 | |
| 
 | |
|     if (subdocRootFrame) {
 | |
|       bool hasDocumentLevelListenersForApzAwareEvents =
 | |
|           gfxPlatform::AsyncPanZoomEnabled() &&
 | |
|           nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell);
 | |
| 
 | |
|       aBuilder->SetAncestorHasApzAwareEventHandler(
 | |
|           hasDocumentLevelListenersForApzAwareEvents);
 | |
|       subdocRootFrame->BuildDisplayListForStackingContext(aBuilder,
 | |
|                                                           &childItems);
 | |
|     }
 | |
| 
 | |
|     if (!aBuilder->IsForEventDelivery()) {
 | |
|       // If we are going to use a displayzoom below then any items we put under
 | |
|       // it need to have underlying frames from the subdocument. So we need to
 | |
|       // calculate the bounds based on which frame will be the underlying frame
 | |
|       // for the canvas background color item.
 | |
|       nsRect bounds =
 | |
|           GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
 | |
|       if (subdocRootFrame) {
 | |
|         bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
 | |
|       }
 | |
| 
 | |
|       // If we are in print preview/page layout we want to paint the grey
 | |
|       // background behind the page, not the canvas color. The canvas color gets
 | |
|       // painted on the page itself.
 | |
|       if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
 | |
|         presShell->AddPrintPreviewBackgroundItem(aBuilder, &childItems, frame,
 | |
|                                                  bounds);
 | |
|       } else {
 | |
|         // Add the canvas background color to the bottom of the list. This
 | |
|         // happens after we've built the list so that
 | |
|         // AddCanvasBackgroundColorItem can monkey with the contents if
 | |
|         // necessary.
 | |
|         presShell->AddCanvasBackgroundColorItem(
 | |
|             aBuilder, &childItems, frame, bounds, NS_RGBA(0, 0, 0, 0),
 | |
|             AddCanvasBackgroundColorFlags::ForceDraw);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (subdocRootFrame) {
 | |
|     aBuilder->LeavePresShell(subdocRootFrame, &childItems);
 | |
|   }
 | |
| 
 | |
|   // Generate a resolution and/or zoom item if needed. If one or both of those
 | |
|   // is created, we don't need to create a separate nsDisplaySubDocument.
 | |
| 
 | |
|   nsDisplayOwnLayerFlags flags =
 | |
|       nsDisplayOwnLayerFlags::GenerateSubdocInvalidations;
 | |
|   // If ignoreViewportScrolling is true then the top most layer we create here
 | |
|   // is going to become the scrollable layer for the root scroll frame, so we
 | |
|   // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
 | |
|   // becomes the topmost. We do this below.
 | |
|   if (constructZoomItem) {
 | |
|     nsDisplayOwnLayerFlags zoomFlags = flags;
 | |
|     if (ignoreViewportScrolling) {
 | |
|       zoomFlags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer;
 | |
|     }
 | |
|     childItems.AppendNewToTop<nsDisplayZoom>(aBuilder, subdocRootFrame, this,
 | |
|                                              &childItems, subdocAPD, parentAPD,
 | |
|                                              zoomFlags);
 | |
| 
 | |
|     needsOwnLayer = false;
 | |
|   }
 | |
|   // Wrap the zoom item in the resolution item if we have both because we want
 | |
|   // the resolution scale applied on top of the app units per dev pixel
 | |
|   // conversion.
 | |
|   if (ignoreViewportScrolling) {
 | |
|     flags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer;
 | |
|   }
 | |
| 
 | |
|   // We always want top level content documents to be in their own layer.
 | |
|   nsDisplaySubDocument* layerItem = MakeDisplayItem<nsDisplaySubDocument>(
 | |
|       aBuilder, subdocRootFrame ? subdocRootFrame : this, this, &childItems,
 | |
|       flags);
 | |
|   if (layerItem) {
 | |
|     childItems.AppendToTop(layerItem);
 | |
|     layerItem->SetShouldFlattenAway(!needsOwnLayer);
 | |
|   }
 | |
| 
 | |
|   if (aBuilder->IsForFrameVisibility()) {
 | |
|     // We don't add the childItems to the return list as we're dealing with them
 | |
|     // here.
 | |
|     presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
 | |
|     childItems.DeleteAll(aBuilder);
 | |
|   } else {
 | |
|     aLists.Content()->AppendToTop(&childItems);
 | |
|   }
 | |
| }
 | |
| 
 | |
| #ifdef DEBUG_FRAME_DUMP
 | |
| void nsSubDocumentFrame::List(FILE* out, const char* aPrefix,
 | |
|                               ListFlags aFlags) const {
 | |
|   nsCString str;
 | |
|   ListGeneric(str, aPrefix, aFlags);
 | |
|   fprintf_stderr(out, "%s\n", str.get());
 | |
| 
 | |
|   if (aFlags.contains(ListFlag::TraverseSubdocumentFrames)) {
 | |
|     nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
 | |
|     nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
 | |
|     if (subdocRootFrame) {
 | |
|       nsCString pfx(aPrefix);
 | |
|       pfx += "  ";
 | |
|       subdocRootFrame->List(out, pfx.get(), aFlags);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const {
 | |
|   return MakeFrameName(u"FrameOuter"_ns, aResult);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* virtual */
 | |
| nscoord nsSubDocumentFrame::GetMinISize(gfxContext* aRenderingContext) {
 | |
|   nscoord result;
 | |
|   DISPLAY_MIN_INLINE_SIZE(this, result);
 | |
| 
 | |
|   nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent);
 | |
|   auto olc = static_cast<nsObjectLoadingContent*>(iolc.get());
 | |
| 
 | |
|   if (olc && olc->GetSubdocumentIntrinsicSize()) {
 | |
|     // The subdocument is an SVG document, so technically we should call
 | |
|     // SVGOuterSVGFrame::GetMinISize() on its root frame.  That method always
 | |
|     // returns 0, though, so we can just do that & don't need to bother with
 | |
|     // the cross-doc communication.
 | |
|     result = 0;
 | |
|   } else {
 | |
|     result = GetIntrinsicISize();
 | |
|   }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| /* virtual */
 | |
| nscoord nsSubDocumentFrame::GetPrefISize(gfxContext* aRenderingContext) {
 | |
|   nscoord result;
 | |
|   DISPLAY_PREF_INLINE_SIZE(this, result);
 | |
| 
 | |
|   // If the subdocument is an SVG document, then in theory we want to return
 | |
|   // the same thing that SVGOuterSVGFrame::GetPrefISize does.  That method
 | |
|   // has some special handling of percentage values to avoid unhelpful zero
 | |
|   // sizing in the presence of orthogonal writing modes.  We don't bother
 | |
|   // with that for SVG documents in <embed> and <object>, since that special
 | |
|   // handling doesn't look up across document boundaries anyway.
 | |
|   result = GetIntrinsicISize();
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| /* virtual */
 | |
| IntrinsicSize nsSubDocumentFrame::GetIntrinsicSize() {
 | |
|   const auto containAxes = GetContainSizeAxes();
 | |
|   if (containAxes.IsBoth()) {
 | |
|     // Intrinsic size of 'contain:size' replaced elements is determined by
 | |
|     // contain-intrinsic-size.
 | |
|     return containAxes.ContainIntrinsicSize(IntrinsicSize(0, 0), *this);
 | |
|   }
 | |
| 
 | |
|   if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
 | |
|     auto olc = static_cast<nsObjectLoadingContent*>(iolc.get());
 | |
| 
 | |
|     if (auto size = olc->GetSubdocumentIntrinsicSize()) {
 | |
|       // Use the intrinsic size from the child SVG document, if available.
 | |
|       return containAxes.ContainIntrinsicSize(*size, *this);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!IsInline()) {
 | |
|     return {};  // <frame> elements have no useful intrinsic size.
 | |
|   }
 | |
| 
 | |
|   if (mContent->IsXULElement()) {
 | |
|     return {};  // XUL <iframe> and <browser> have no useful intrinsic size
 | |
|   }
 | |
| 
 | |
|   // We must be an HTML <iframe>. Return fallback size.
 | |
|   return containAxes.ContainIntrinsicSize(IntrinsicSize(kFallbackIntrinsicSize),
 | |
|                                           *this);
 | |
| }
 | |
| 
 | |
| /* virtual */
 | |
| AspectRatio nsSubDocumentFrame::GetIntrinsicRatio() const {
 | |
|   // FIXME(emilio): This should probably respect contain: size and return no
 | |
|   // ratio in the case subDocRoot is non-null. Otherwise we do it by virtue of
 | |
|   // using a zero-size below and reusing GetIntrinsicSize().
 | |
|   if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
 | |
|     auto olc = static_cast<nsObjectLoadingContent*>(iolc.get());
 | |
| 
 | |
|     auto ratio = olc->GetSubdocumentIntrinsicRatio();
 | |
|     if (ratio && *ratio) {
 | |
|       // Use the intrinsic aspect ratio from the child SVG document, if
 | |
|       // available.
 | |
|       return *ratio;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // NOTE(emilio): Even though we have an intrinsic size, we may not have an
 | |
|   // intrinsic ratio. For example `<iframe style="width: 100px">` should not
 | |
|   // shrink in the vertical axis to preserve the 300x150 ratio.
 | |
|   return nsAtomicContainerFrame::GetIntrinsicRatio();
 | |
| }
 | |
| 
 | |
| /* virtual */
 | |
| LogicalSize nsSubDocumentFrame::ComputeAutoSize(
 | |
|     gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
 | |
|     nscoord aAvailableISize, const LogicalSize& aMargin,
 | |
|     const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
 | |
|     ComputeSizeFlags aFlags) {
 | |
|   if (!IsInline()) {
 | |
|     return nsIFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize,
 | |
|                                      aAvailableISize, aMargin, aBorderPadding,
 | |
|                                      aSizeOverrides, aFlags);
 | |
|   }
 | |
| 
 | |
|   const WritingMode wm = GetWritingMode();
 | |
|   LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
 | |
|   return result.ConvertTo(aWM, wm);
 | |
| }
 | |
| 
 | |
| /* virtual */
 | |
| nsIFrame::SizeComputationResult nsSubDocumentFrame::ComputeSize(
 | |
|     gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
 | |
|     nscoord aAvailableISize, const LogicalSize& aMargin,
 | |
|     const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
 | |
|     ComputeSizeFlags aFlags) {
 | |
|   return {ComputeSizeWithIntrinsicDimensions(
 | |
|               aRenderingContext, aWM, GetIntrinsicSize(), GetAspectRatio(),
 | |
|               aCBSize, aMargin, aBorderPadding, aSizeOverrides, aFlags),
 | |
|           AspectRatioUsage::None};
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
 | |
|                                 ReflowOutput& aDesiredSize,
 | |
|                                 const ReflowInput& aReflowInput,
 | |
|                                 nsReflowStatus& aStatus) {
 | |
|   MarkInReflow();
 | |
|   DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
 | |
|   DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
 | |
|   MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
 | |
|   NS_FRAME_TRACE(
 | |
|       NS_FRAME_TRACE_CALLS,
 | |
|       ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
 | |
|        aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
 | |
| 
 | |
|   NS_ASSERTION(aReflowInput.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
 | |
|                "Shouldn't have unconstrained stuff here "
 | |
|                "thanks to the rules of reflow");
 | |
|   NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedHeight(),
 | |
|                "Shouldn't have unconstrained stuff here "
 | |
|                "thanks to ComputeAutoSize");
 | |
| 
 | |
|   NS_ASSERTION(mContent->GetPrimaryFrame() == this, "Shouldn't happen");
 | |
| 
 | |
|   // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
 | |
|   const auto wm = aReflowInput.GetWritingMode();
 | |
|   aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
 | |
| 
 | |
|   // "offset" is the offset of our content area from our frame's
 | |
|   // top-left corner.
 | |
|   nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left,
 | |
|                            aReflowInput.ComputedPhysicalBorderPadding().top);
 | |
| 
 | |
|   if (mInnerView) {
 | |
|     const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding();
 | |
|     nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
 | |
|                      aDesiredSize.Height() - bp.TopBottom());
 | |
| 
 | |
|     // Size & position the view according to 'object-fit' & 'object-position'.
 | |
|     nsRect destRect = nsLayoutUtils::ComputeObjectDestRect(
 | |
|         nsRect(offset, innerSize), GetIntrinsicSize(), GetIntrinsicRatio(),
 | |
|         StylePosition());
 | |
| 
 | |
|     nsViewManager* vm = mInnerView->GetViewManager();
 | |
|     vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
 | |
|     vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
 | |
|   }
 | |
| 
 | |
|   aDesiredSize.SetOverflowAreasToDesiredBounds();
 | |
| 
 | |
|   FinishAndStoreOverflow(&aDesiredSize);
 | |
| 
 | |
|   if (!aPresContext->IsRootPaginatedDocument() && !mPostedReflowCallback) {
 | |
|     PresShell()->PostReflowCallback(this);
 | |
|     mPostedReflowCallback = true;
 | |
|   }
 | |
| 
 | |
|   NS_FRAME_TRACE(
 | |
|       NS_FRAME_TRACE_CALLS,
 | |
|       ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",
 | |
|        aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus).c_str()));
 | |
| }
 | |
| 
 | |
| bool nsSubDocumentFrame::ReflowFinished() {
 | |
|   RefPtr<nsFrameLoader> frameloader = FrameLoader();
 | |
|   if (frameloader) {
 | |
|     AutoWeakFrame weakFrame(this);
 | |
| 
 | |
|     frameloader->UpdatePositionAndSize(this);
 | |
| 
 | |
|     if (weakFrame.IsAlive()) {
 | |
|       // Make sure that we can post a reflow callback in the future.
 | |
|       mPostedReflowCallback = false;
 | |
|     }
 | |
|   } else {
 | |
|     mPostedReflowCallback = false;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::ReflowCallbackCanceled() {
 | |
|   mPostedReflowCallback = false;
 | |
| }
 | |
| 
 | |
| nsresult nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
 | |
|                                               nsAtom* aAttribute,
 | |
|                                               int32_t aModType) {
 | |
|   if (aNameSpaceID != kNameSpaceID_None) {
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|   // If the noResize attribute changes, dis/allow frame to be resized
 | |
|   if (aAttribute == nsGkAtoms::noresize) {
 | |
|     // Note that we're not doing content type checks, but that's ok -- if
 | |
|     // they'd fail we will just end up with a null framesetFrame.
 | |
|     if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) {
 | |
|       nsIFrame* parentFrame = GetParent();
 | |
| 
 | |
|       if (parentFrame) {
 | |
|         // There is no interface for nsHTMLFramesetFrame so QI'ing to
 | |
|         // concrete class, yay!
 | |
|         nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
 | |
|         if (framesetFrame) {
 | |
|           framesetFrame->RecalculateBorderResize();
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } else if (aAttribute == nsGkAtoms::marginwidth ||
 | |
|              aAttribute == nsGkAtoms::marginheight) {
 | |
|     // Notify the frameloader
 | |
|     if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
 | |
|       frameloader->MarginsChanged();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::MaybeUpdateEmbedderColorScheme() {
 | |
|   nsFrameLoader* fl = mFrameLoader.get();
 | |
|   if (!fl) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   BrowsingContext* bc = fl->GetExtantBrowsingContext();
 | |
|   if (!bc) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto ToOverride = [](ColorScheme aScheme) -> PrefersColorSchemeOverride {
 | |
|     return aScheme == ColorScheme::Dark ? PrefersColorSchemeOverride::Dark
 | |
|                                         : PrefersColorSchemeOverride::Light;
 | |
|   };
 | |
| 
 | |
|   EmbedderColorSchemes schemes{
 | |
|       ToOverride(LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Used)),
 | |
|       ToOverride(
 | |
|           LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Preferred))};
 | |
|   if (bc->GetEmbedderColorSchemes() == schemes) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Unused << bc->SetEmbedderColorSchemes(schemes);
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::MaybeUpdateRemoteStyle(
 | |
|     ComputedStyle* aOldComputedStyle) {
 | |
|   if (!mIsInObjectOrEmbed) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (aOldComputedStyle &&
 | |
|       aOldComputedStyle->StyleVisibility()->mImageRendering ==
 | |
|           Style()->StyleVisibility()->mImageRendering) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!mFrameLoader) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (mFrameLoader->IsRemoteFrame()) {
 | |
|     mFrameLoader->UpdateRemoteStyle(
 | |
|         Style()->StyleVisibility()->mImageRendering);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   BrowsingContext* context = mFrameLoader->GetExtantBrowsingContext();
 | |
|   if (!context) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   Document* document = context->GetDocument();
 | |
|   if (!document) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (document->IsImageDocument()) {
 | |
|     document->AsImageDocument()->UpdateRemoteStyle(
 | |
|         Style()->StyleVisibility()->mImageRendering);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
 | |
|   nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle);
 | |
| 
 | |
|   MaybeUpdateEmbedderColorScheme();
 | |
| 
 | |
|   MaybeUpdateRemoteStyle(aOldComputedStyle);
 | |
| 
 | |
|   // If this presshell has invisible ancestors, we don't need to propagate the
 | |
|   // visibility style change to the subdocument since the subdocument should
 | |
|   // have already set the IsUnderHiddenEmbedderElement flag in
 | |
|   // nsSubDocumentFrame::Init.
 | |
|   if (PresShell()->IsUnderHiddenEmbedderElement()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   const bool isVisible = StyleVisibility()->IsVisible();
 | |
|   if (!aOldComputedStyle ||
 | |
|       isVisible != aOldComputedStyle->StyleVisibility()->IsVisible()) {
 | |
|     PropagateIsUnderHiddenEmbedderElementToSubView(!isVisible);
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsIFrame* NS_NewSubDocumentFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
 | |
|   return new (aPresShell)
 | |
|       nsSubDocumentFrame(aStyle, aPresShell->GetPresContext());
 | |
| }
 | |
| 
 | |
| NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
 | |
| 
 | |
| class nsHideViewer : public Runnable {
 | |
|  public:
 | |
|   nsHideViewer(nsIContent* aFrameElement, nsFrameLoader* aFrameLoader,
 | |
|                PresShell* aPresShell, bool aHideViewerIfFrameless)
 | |
|       : mozilla::Runnable("nsHideViewer"),
 | |
|         mFrameElement(aFrameElement),
 | |
|         mFrameLoader(aFrameLoader),
 | |
|         mPresShell(aPresShell),
 | |
|         mHideViewerIfFrameless(aHideViewerIfFrameless) {
 | |
|     NS_ASSERTION(mFrameElement, "Must have a frame element");
 | |
|     NS_ASSERTION(mFrameLoader, "Must have a frame loader");
 | |
|     NS_ASSERTION(mPresShell, "Must have a presshell");
 | |
|   }
 | |
| 
 | |
|   MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override {
 | |
|     // Flush frames, to ensure any pending display:none changes are made.
 | |
|     // Note it can be unsafe to flush if we've destroyed the presentation
 | |
|     // for some other reason, like if we're shutting down.
 | |
|     //
 | |
|     // But avoid the flush if we know for sure we're away, like when we're out
 | |
|     // of the document already.
 | |
|     //
 | |
|     // FIXME(emilio): This could still be a perf footgun when removing lots of
 | |
|     // siblings where each of them cause the reframe of an ancestor which happen
 | |
|     // to contain a subdocument.
 | |
|     //
 | |
|     // We should find some way to avoid that!
 | |
|     if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) {
 | |
|       MOZ_KnownLive(mPresShell)->FlushPendingNotifications(FlushType::Frames);
 | |
|     }
 | |
| 
 | |
|     // Either the frame has been constructed by now, or it never will be,
 | |
|     // either way we want to clear the stashed views.
 | |
|     mFrameLoader->SetDetachedSubdocFrame(nullptr, nullptr);
 | |
| 
 | |
|     nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
 | |
|     if ((!frame && mHideViewerIfFrameless) || mPresShell->IsDestroying()) {
 | |
|       // Either the frame element has no nsIFrame or the presshell is being
 | |
|       // destroyed. Hide the nsFrameLoader, which destroys the presentation.
 | |
|       mFrameLoader->Hide();
 | |
|     }
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   nsCOMPtr<nsIContent> mFrameElement;
 | |
|   RefPtr<nsFrameLoader> mFrameLoader;
 | |
|   RefPtr<PresShell> mPresShell;
 | |
|   bool mHideViewerIfFrameless;
 | |
| };
 | |
| 
 | |
| static nsView* BeginSwapDocShellsForViews(nsView* aSibling);
 | |
| 
 | |
| void nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot,
 | |
|                                      PostDestroyData& aPostDestroyData) {
 | |
|   PropagateIsUnderHiddenEmbedderElementToSubView(true);
 | |
|   if (mPostedReflowCallback) {
 | |
|     PresShell()->CancelReflowCallback(this);
 | |
|     mPostedReflowCallback = false;
 | |
|   }
 | |
| 
 | |
|   // Detach the subdocument's views and stash them in the frame loader.
 | |
|   // We can then reattach them if we're being reframed (for example if
 | |
|   // the frame has been made position:fixed).
 | |
|   RefPtr<nsFrameLoader> frameloader = FrameLoader();
 | |
|   if (frameloader) {
 | |
|     ClearDisplayItems();
 | |
| 
 | |
|     nsView* detachedViews =
 | |
|         ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
 | |
| 
 | |
|     if (detachedViews && detachedViews->GetFrame()) {
 | |
|       frameloader->SetDetachedSubdocFrame(detachedViews->GetFrame(),
 | |
|                                           mContent->OwnerDoc());
 | |
| 
 | |
|       // We call nsFrameLoader::HideViewer() in a script runner so that we can
 | |
|       // safely determine whether the frame is being reframed or destroyed.
 | |
|       nsContentUtils::AddScriptRunner(new nsHideViewer(
 | |
|           mContent, frameloader, PresShell(), (mDidCreateDoc || mCallingShow)));
 | |
|     } else {
 | |
|       frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
 | |
|       if (mDidCreateDoc || mCallingShow) {
 | |
|         frameloader->Hide();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsAtomicContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
 | |
| }
 | |
| 
 | |
| nsFrameLoader* nsSubDocumentFrame::FrameLoader() const {
 | |
|   if (mFrameLoader) {
 | |
|     return mFrameLoader;
 | |
|   }
 | |
| 
 | |
|   if (RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(GetContent())) {
 | |
|     mFrameLoader = loaderOwner->GetFrameLoader();
 | |
|   }
 | |
| 
 | |
|   return mFrameLoader;
 | |
| }
 | |
| 
 | |
| auto nsSubDocumentFrame::GetRemotePaintData() const -> RemoteFramePaintData {
 | |
|   if (mRetainedRemoteFrame) {
 | |
|     return *mRetainedRemoteFrame;
 | |
|   }
 | |
| 
 | |
|   RemoteFramePaintData data;
 | |
|   nsFrameLoader* fl = FrameLoader();
 | |
|   if (!fl) {
 | |
|     return data;
 | |
|   }
 | |
| 
 | |
|   auto* rb = fl->GetRemoteBrowser();
 | |
|   if (!rb) {
 | |
|     return data;
 | |
|   }
 | |
|   data.mLayersId = rb->GetLayersId();
 | |
|   data.mTabId = rb->GetTabId();
 | |
|   return data;
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::ResetFrameLoader(RetainPaintData aRetain) {
 | |
|   if (aRetain == RetainPaintData::Yes && mFrameLoader) {
 | |
|     mRetainedRemoteFrame = Some(GetRemotePaintData());
 | |
|   } else {
 | |
|     mRetainedRemoteFrame.reset();
 | |
|   }
 | |
|   mFrameLoader = nullptr;
 | |
|   ClearDisplayItems();
 | |
|   nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::ClearRetainedPaintData() {
 | |
|   mRetainedRemoteFrame.reset();
 | |
|   ClearDisplayItems();
 | |
|   InvalidateFrameSubtree();
 | |
| }
 | |
| 
 | |
| // XXX this should be called ObtainDocShell or something like that,
 | |
| // to indicate that it could have side effects
 | |
| nsIDocShell* nsSubDocumentFrame::GetDocShell() const {
 | |
|   // How can FrameLoader() return null???
 | |
|   if (NS_WARN_IF(!FrameLoader())) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return mFrameLoader->GetDocShell(IgnoreErrors());
 | |
| }
 | |
| 
 | |
| static void DestroyDisplayItemDataForFrames(nsIFrame* aFrame) {
 | |
|   // Destroying a WebRenderUserDataTable can cause destruction of other objects
 | |
|   // which can remove frame properties in their destructor. If we delete a frame
 | |
|   // property it runs the destructor of the stored object in the middle of
 | |
|   // updating the frame property table, so if the destruction of that object
 | |
|   // causes another update to the frame property table it would leave the frame
 | |
|   // property table in an inconsistent state. So we remove it from the table and
 | |
|   // then destroy it. (bug 1530657)
 | |
|   WebRenderUserDataTable* userDataTable =
 | |
|       aFrame->TakeProperty(WebRenderUserDataProperty::Key());
 | |
|   if (userDataTable) {
 | |
|     for (const auto& data : userDataTable->Values()) {
 | |
|       data->RemoveFromTable();
 | |
|     }
 | |
|     delete userDataTable;
 | |
|   }
 | |
| 
 | |
|   for (const auto& childList : aFrame->ChildLists()) {
 | |
|     for (nsIFrame* child : childList.mList) {
 | |
|       DestroyDisplayItemDataForFrames(child);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| static CallState BeginSwapDocShellsForDocument(Document& aDocument) {
 | |
|   if (PresShell* presShell = aDocument.GetPresShell()) {
 | |
|     // Disable painting while the views are detached, see bug 946929.
 | |
|     presShell->SetNeverPainting(true);
 | |
| 
 | |
|     if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
 | |
|       ::DestroyDisplayItemDataForFrames(rootFrame);
 | |
|     }
 | |
|   }
 | |
|   aDocument.EnumerateSubDocuments(BeginSwapDocShellsForDocument);
 | |
|   return CallState::Continue;
 | |
| }
 | |
| 
 | |
| static nsView* BeginSwapDocShellsForViews(nsView* aSibling) {
 | |
|   // Collect the removed sibling views in reverse order in 'removedViews'.
 | |
|   nsView* removedViews = nullptr;
 | |
|   while (aSibling) {
 | |
|     if (Document* doc = ::GetDocumentFromView(aSibling)) {
 | |
|       ::BeginSwapDocShellsForDocument(*doc);
 | |
|     }
 | |
|     nsView* next = aSibling->GetNextSibling();
 | |
|     aSibling->GetViewManager()->RemoveChild(aSibling);
 | |
|     aSibling->SetNextSibling(removedViews);
 | |
|     removedViews = aSibling;
 | |
|     aSibling = next;
 | |
|   }
 | |
|   return removedViews;
 | |
| }
 | |
| 
 | |
| static void InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent) {
 | |
|   MOZ_ASSERT(aParent, "null view");
 | |
|   MOZ_ASSERT(!aParent->GetFirstChild(), "inserting into non-empty list");
 | |
| 
 | |
|   nsViewManager* vm = aParent->GetViewManager();
 | |
|   while (aSibling) {
 | |
|     nsView* next = aSibling->GetNextSibling();
 | |
|     aSibling->SetNextSibling(nullptr);
 | |
|     // true means 'after' in document order which is 'before' in view order,
 | |
|     // so this call prepends the child, thus reversing the siblings as we go.
 | |
|     vm->InsertChild(aParent, aSibling, nullptr, true);
 | |
|     aSibling = next;
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsresult nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther) {
 | |
|   if (!aOther || !aOther->IsSubDocumentFrame()) {
 | |
|     return NS_ERROR_NOT_IMPLEMENTED;
 | |
|   }
 | |
| 
 | |
|   nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
 | |
|   if (!mFrameLoader || !mDidCreateDoc || mCallingShow || !other->mFrameLoader ||
 | |
|       !other->mDidCreateDoc) {
 | |
|     return NS_ERROR_NOT_IMPLEMENTED;
 | |
|   }
 | |
| 
 | |
|   ClearDisplayItems();
 | |
|   other->ClearDisplayItems();
 | |
| 
 | |
|   if (mInnerView && other->mInnerView) {
 | |
|     nsView* ourSubdocViews = mInnerView->GetFirstChild();
 | |
|     nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
 | |
|     nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
 | |
|     nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
 | |
| 
 | |
|     ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
 | |
|     ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
 | |
|   }
 | |
|   mFrameLoader.swap(other->mFrameLoader);
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| static CallState EndSwapDocShellsForDocument(Document& aDocument) {
 | |
|   // Our docshell and view trees have been updated for the new hierarchy.
 | |
|   // Now also update all nsDeviceContext::mWidget to that of the
 | |
|   // container view in the new hierarchy.
 | |
|   if (nsCOMPtr<nsIDocShell> ds = aDocument.GetDocShell()) {
 | |
|     nsCOMPtr<nsIContentViewer> cv;
 | |
|     ds->GetContentViewer(getter_AddRefs(cv));
 | |
|     while (cv) {
 | |
|       RefPtr<nsPresContext> pc = cv->GetPresContext();
 | |
|       if (pc && pc->GetPresShell()) {
 | |
|         pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
 | |
|       }
 | |
|       nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
 | |
|       if (dc) {
 | |
|         nsView* v = cv->FindContainerView();
 | |
|         dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr);
 | |
|       }
 | |
|       cv = cv->GetPreviousViewer();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   aDocument.EnumerateSubDocuments(EndSwapDocShellsForDocument);
 | |
|   return CallState::Continue;
 | |
| }
 | |
| 
 | |
| static void EndSwapDocShellsForViews(nsView* aSibling) {
 | |
|   for (; aSibling; aSibling = aSibling->GetNextSibling()) {
 | |
|     if (Document* doc = ::GetDocumentFromView(aSibling)) {
 | |
|       ::EndSwapDocShellsForDocument(*doc);
 | |
|     }
 | |
|     nsIFrame* frame = aSibling->GetFrame();
 | |
|     if (frame) {
 | |
|       nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(frame);
 | |
|       if (parent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
 | |
|         nsIFrame::AddInPopupStateBitToDescendants(frame);
 | |
|       } else {
 | |
|         nsIFrame::RemoveInPopupStateBitFromDescendants(frame);
 | |
|       }
 | |
|       if (frame->HasInvalidFrameInSubtree()) {
 | |
|         while (parent &&
 | |
|                !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT |
 | |
|                                         NS_FRAME_IS_NONDISPLAY)) {
 | |
|           parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
 | |
|           parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(parent);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther) {
 | |
|   nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
 | |
|   AutoWeakFrame weakThis(this);
 | |
|   AutoWeakFrame weakOther(aOther);
 | |
| 
 | |
|   if (mInnerView) {
 | |
|     ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
 | |
|   }
 | |
|   if (other->mInnerView) {
 | |
|     ::EndSwapDocShellsForViews(other->mInnerView->GetFirstChild());
 | |
|   }
 | |
| 
 | |
|   // Now make sure we reflow both frames, in case their contents
 | |
|   // determine their size.
 | |
|   // And repaint them, for good measure, in case there's nothing
 | |
|   // interesting that happens during reflow.
 | |
|   if (weakThis.IsAlive()) {
 | |
|     PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors,
 | |
|                                   NS_FRAME_IS_DIRTY);
 | |
|     InvalidateFrameSubtree();
 | |
|     PropagateIsUnderHiddenEmbedderElementToSubView(
 | |
|         PresShell()->IsUnderHiddenEmbedderElement() ||
 | |
|         !StyleVisibility()->IsVisible());
 | |
|   }
 | |
|   if (weakOther.IsAlive()) {
 | |
|     other->PresShell()->FrameNeedsReflow(
 | |
|         other, IntrinsicDirty::FrameAndAncestors, NS_FRAME_IS_DIRTY);
 | |
|     other->InvalidateFrameSubtree();
 | |
|     other->PropagateIsUnderHiddenEmbedderElementToSubView(
 | |
|         other->PresShell()->IsUnderHiddenEmbedderElement() ||
 | |
|         !other->StyleVisibility()->IsVisible());
 | |
|   }
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::ClearDisplayItems() {
 | |
|   if (auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(this)) {
 | |
|     DL_LOGD("nsSubDocumentFrame::ClearDisplayItems() %p", this);
 | |
|     builder->ClearRetainedData();
 | |
|   }
 | |
| }
 | |
| 
 | |
| nsView* nsSubDocumentFrame::EnsureInnerView() {
 | |
|   if (mInnerView) {
 | |
|     return mInnerView;
 | |
|   }
 | |
| 
 | |
|   // create, init, set the parent of the view
 | |
|   nsView* outerView = GetView();
 | |
|   NS_ASSERTION(outerView, "Must have an outer view already");
 | |
|   nsRect viewBounds(0, 0, 0, 0);  // size will be fixed during reflow
 | |
| 
 | |
|   nsViewManager* viewMan = outerView->GetViewManager();
 | |
|   nsView* innerView = viewMan->CreateView(viewBounds, outerView);
 | |
|   if (!innerView) {
 | |
|     NS_ERROR("Could not create inner view");
 | |
|     return nullptr;
 | |
|   }
 | |
|   mInnerView = innerView;
 | |
|   viewMan->InsertChild(outerView, innerView, nullptr, true);
 | |
| 
 | |
|   return mInnerView;
 | |
| }
 | |
| 
 | |
| nsPoint nsSubDocumentFrame::GetExtraOffset() const {
 | |
|   MOZ_ASSERT(mInnerView);
 | |
|   return mInnerView->GetPosition();
 | |
| }
 | |
| 
 | |
| void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
 | |
|   const nsStylePosition* pos = StylePosition();
 | |
|   bool dependsOnIntrinsics =
 | |
|       !pos->mWidth.ConvertsToLength() || !pos->mHeight.ConvertsToLength();
 | |
| 
 | |
|   if (dependsOnIntrinsics || pos->mObjectFit != StyleObjectFit::Fill) {
 | |
|     auto dirtyHint = dependsOnIntrinsics
 | |
|                          ? IntrinsicDirty::FrameAncestorsAndDescendants
 | |
|                          : IntrinsicDirty::None;
 | |
|     PresShell()->FrameNeedsReflow(this, dirtyHint, NS_FRAME_IS_DIRTY);
 | |
|     InvalidateFrame();
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Return true iff |aManager| is a "temporary layer manager".  They're
 | |
| // used for small software rendering tasks, like drawWindow.  That's
 | |
| // currently implemented by a BasicLayerManager without a backing
 | |
| // widget, and hence in non-retained mode.
 | |
| nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
 | |
|                                  nsSubDocumentFrame* aFrame)
 | |
|     : nsPaintedDisplayItem(aBuilder, aFrame),
 | |
|       mEventRegionsOverride(EventRegionsOverride::NoOverride) {
 | |
|   const bool frameIsPointerEventsNone =
 | |
|       aFrame->Style()->PointerEvents() == StylePointerEvents::None;
 | |
|   if (aBuilder->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone) {
 | |
|     mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion;
 | |
|   }
 | |
|   if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(
 | |
|           aFrame->PresShell())) {
 | |
|     mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
 | |
|   }
 | |
| 
 | |
|   mPaintData = aFrame->GetRemotePaintData();
 | |
| }
 | |
| 
 | |
| namespace mozilla {
 | |
| 
 | |
| void nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
 | |
|   nsPresContext* pc = mFrame->PresContext();
 | |
|   nsFrameLoader* fl = GetFrameLoader();
 | |
|   if (pc->GetPrintSettings() && fl->IsRemoteFrame()) {
 | |
|     // See the comment below in CreateWebRenderCommands() as for why doing this.
 | |
|     fl->UpdatePositionAndSize(static_cast<nsSubDocumentFrame*>(mFrame));
 | |
|   }
 | |
| 
 | |
|   DrawTarget* target = aCtx->GetDrawTarget();
 | |
|   if (!target->IsRecording() || mPaintData.mTabId == 0) {
 | |
|     NS_WARNING("Remote iframe not rendered");
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Rendering the inner document will apply a scale to account for its app
 | |
|   // units per dev pixel ratio. We want to apply the inverse scaling using our
 | |
|   // app units per dev pixel ratio, so that no actual scaling will be applied if
 | |
|   // they match. For in-process rendering, nsSubDocumentFrame creates an
 | |
|   // nsDisplayZoom item if the app units per dev pixel ratio changes.
 | |
|   //
 | |
|   // Similarly, rendering the inner document will scale up by the cross process
 | |
|   // paint scale again, so we also need to account for that.
 | |
|   const int32_t appUnitsPerDevPixel = pc->AppUnitsPerDevPixel();
 | |
| 
 | |
|   gfxContextMatrixAutoSaveRestore saveMatrix(aCtx);
 | |
|   gfxFloat targetAuPerDev =
 | |
|       gfxFloat(AppUnitsPerCSSPixel()) / aCtx->GetCrossProcessPaintScale();
 | |
| 
 | |
|   gfxFloat scale = targetAuPerDev / appUnitsPerDevPixel;
 | |
|   aCtx->Multiply(gfxMatrix::Scaling(scale, scale));
 | |
| 
 | |
|   Rect destRect =
 | |
|       NSRectToSnappedRect(GetContentRect(), targetAuPerDev, *target);
 | |
|   target->DrawDependentSurface(mPaintData.mTabId, destRect);
 | |
| }
 | |
| 
 | |
| bool nsDisplayRemote::CreateWebRenderCommands(
 | |
|     mozilla::wr::DisplayListBuilder& aBuilder,
 | |
|     mozilla::wr::IpcResourceUpdateQueue& aResources,
 | |
|     const StackingContextHelper& aSc,
 | |
|     mozilla::layers::RenderRootStateManager* aManager,
 | |
|     nsDisplayListBuilder* aDisplayListBuilder) {
 | |
|   if (!mPaintData.mLayersId.IsValid()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   nsPresContext* pc = mFrame->PresContext();
 | |
|   nsFrameLoader* fl = GetFrameLoader();
 | |
| 
 | |
|   auto* subDocFrame = static_cast<nsSubDocumentFrame*>(mFrame);
 | |
|   nsRect destRect = subDocFrame->GetDestRect();
 | |
|   if (RefPtr<RemoteBrowser> remoteBrowser = fl->GetRemoteBrowser()) {
 | |
|     if (pc->GetPrintSettings()) {
 | |
|       // HACK(emilio): Usually we update sizing/positioning from
 | |
|       // ReflowFinished(). Print documents have no incremental reflow at all
 | |
|       // though, so we can't rely on it firing after a frame becomes remote.
 | |
|       // Thus, if we're painting a remote frame, update its sizing and position
 | |
|       // now.
 | |
|       //
 | |
|       // UpdatePositionAndSize() can cause havoc for non-remote frames but
 | |
|       // luckily we don't care about those, so this is fine.
 | |
|       fl->UpdatePositionAndSize(subDocFrame);
 | |
|     }
 | |
| 
 | |
|     // Adjust mItemVisibleRect, which is relative to the reference frame, to be
 | |
|     // relative to this frame
 | |
|     nsRect visibleRect = GetBuildingRect() - ToReferenceFrame();
 | |
|     visibleRect.IntersectRect(visibleRect, destRect);
 | |
|     visibleRect -= destRect.TopLeft();
 | |
| 
 | |
|     // Generate an effects update notifying the browser it is visible
 | |
|     MatrixScales scale = aSc.GetInheritedScale();
 | |
| 
 | |
|     ParentLayerToScreenScale2D transformToAncestorScale =
 | |
|         ParentLayerToParentLayerScale(
 | |
|             pc->GetPresShell() ? pc->GetPresShell()->GetCumulativeResolution()
 | |
|                                : 1.f) *
 | |
|         nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
 | |
|             mFrame);
 | |
| 
 | |
|     aDisplayListBuilder->AddEffectUpdate(
 | |
|         remoteBrowser, EffectsInfo::VisibleWithinRect(
 | |
|                            visibleRect, scale, transformToAncestorScale));
 | |
| 
 | |
|     // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
 | |
|     // longer visible
 | |
|     RefPtr<WebRenderRemoteData> userData =
 | |
|         aManager->CommandBuilder()
 | |
|             .CreateOrRecycleWebRenderUserData<WebRenderRemoteData>(this,
 | |
|                                                                    nullptr);
 | |
|     userData->SetRemoteBrowser(remoteBrowser);
 | |
|   }
 | |
| 
 | |
|   nscoord auPerDevPixel = pc->AppUnitsPerDevPixel();
 | |
|   nsPoint layerOffset =
 | |
|       aDisplayListBuilder->ToReferenceFrame(mFrame) + destRect.TopLeft();
 | |
|   mOffset = LayoutDevicePoint::FromAppUnits(layerOffset, auPerDevPixel);
 | |
| 
 | |
|   destRect.MoveTo(0, 0);
 | |
|   auto rect = LayoutDeviceRect::FromAppUnits(destRect, auPerDevPixel);
 | |
|   rect += mOffset;
 | |
| 
 | |
|   aBuilder.PushIFrame(rect, !BackfaceIsHidden(),
 | |
|                       mozilla::wr::AsPipelineId(mPaintData.mLayersId),
 | |
|                       /*ignoreMissingPipelines*/ true);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool nsDisplayRemote::UpdateScrollData(
 | |
|     mozilla::layers::WebRenderScrollData* aData,
 | |
|     mozilla::layers::WebRenderLayerScrollData* aLayerData) {
 | |
|   if (!mPaintData.mLayersId.IsValid()) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   if (aLayerData) {
 | |
|     aLayerData->SetReferentId(mPaintData.mLayersId);
 | |
| 
 | |
|     // Apply the top level resolution if we are in the same process of the top
 | |
|     // level document. We don't need to apply it in cases where we are in OOP
 | |
|     // iframes since it will be applied later in
 | |
|     // HitTestingTreeNode::GetTransformToGecko by walking up the tree node.
 | |
|     nsPresContext* inProcessRootContext =
 | |
|         mFrame->PresContext()->GetInProcessRootContentDocumentPresContext();
 | |
|     if (inProcessRootContext &&
 | |
|         inProcessRootContext->IsRootContentDocumentCrossProcess()) {
 | |
|       float resolution = inProcessRootContext->PresShell()->GetResolution();
 | |
|       aLayerData->SetResolution(resolution);
 | |
|     }
 | |
| 
 | |
|     auto size = static_cast<nsSubDocumentFrame*>(mFrame)->GetSubdocumentSize();
 | |
|     Matrix4x4 m = Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0);
 | |
|     aLayerData->SetTransform(m);
 | |
|     aLayerData->SetEventRegionsOverride(mEventRegionsOverride);
 | |
|     aLayerData->SetRemoteDocumentSize(LayerIntSize(size.width, size.height));
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| nsFrameLoader* nsDisplayRemote::GetFrameLoader() const {
 | |
|   return static_cast<nsSubDocumentFrame*>(mFrame)->FrameLoader();
 | |
| }
 | |
| 
 | |
| }  // namespace mozilla
 |