tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 381884b9d7dea0ddb4c77b5b364ef8364459d865
parent 611a8170c1e6c3c82d6417012f0a95bf008185ef
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date:   Tue, 11 Nov 2025 07:30:41 +0000

Bug 1994942 - Don't use views for subdocs. r=tnikkel,jwatt

This allows to clean up even more view code, since views now are just a
link between layout and widget at the root and little else (so the whole
view children and so on can go), but that will be done in separate
patches since these patches are not risk-free.

Notable changes:

 * PresShell::WillPaint() now recurses into subdocuments. That was done
   previously via CallWillPaintOnObservers().
 * Embedder frame is tracked directly by nsSubDocumentFrame an
   PresShell. It might be possible to simplify this further,
   if bug 1997773 sticks.

Differential Revision: https://phabricator.services.mozilla.com/D232057

Diffstat:
Mdocshell/base/nsDocShell.cpp | 79++++---------------------------------------------------------------------------
Mdocshell/base/nsIDocumentViewer.idl | 6+++---
Mdom/base/Document.cpp | 9++++++++-
Mdom/base/Document.h | 3++-
Mdom/base/nsContentUtils.h | 1-
Mdom/base/nsFrameLoader.cpp | 39++++++++-------------------------------
Mdom/base/nsFrameLoader.h | 27+++++++++++++--------------
Mdom/ipc/BrowserParent.cpp | 40++++++++++++----------------------------
Mlayout/base/PresShell.cpp | 165+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mlayout/base/PresShell.h | 7+++++--
Mlayout/base/nsDocumentViewer.cpp | 121++++++++++++++++++++++++-------------------------------------------------------
Mlayout/base/nsLayoutUtils.cpp | 89+++++++++++++++++++++++++++----------------------------------------------------
Mlayout/base/nsLayoutUtils.h | 16+++-------------
Mlayout/generic/FrameClasses.py | 2+-
Mlayout/generic/nsSubDocumentFrame.cpp | 399++++++++++++++++++++++++++++---------------------------------------------------
Mlayout/generic/nsSubDocumentFrame.h | 36++++++++++++++++++++++++------------
Mlayout/printing/nsPrintJob.cpp | 75++++++++++++++++++++++++++++++---------------------------------------------
Mlayout/printing/nsPrintJob.h | 7+++----
Mlayout/xul/nsMenuPopupFrame.cpp | 3+--
Mview/nsView.cpp | 76+++++++++++++---------------------------------------------------------------
Mview/nsView.h | 18+++---------------
Mview/nsViewManager.cpp | 61+++++++++++++++++++------------------------------------------
Mview/nsViewManager.h | 22+++-------------------
Mwidget/PuppetWidget.cpp | 2+-
24 files changed, 456 insertions(+), 847 deletions(-)

diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp @@ -7480,10 +7480,7 @@ nsresult nsDocShell::RestoreFromHistory() { // In cases where we use a transient about:blank viewer between loads, // we never show the transient viewer, so _its_ previous viewer is never - // unhooked from the view hierarchy. Destroy any such previous viewer now, - // before we grab the root view sibling, so that we don't grab a view - // that's about to go away. - + // destroyed. Destroy any such previous viewer now. if (mDocumentViewer) { // Make sure to hold a strong ref to previousViewer here while we // drop the reference to it from mDocumentViewer. @@ -7495,38 +7492,12 @@ nsresult nsDocShell::RestoreFromHistory() { } } - // Save off the root view's parent and sibling so that we can insert the - // new content viewer's root view at the same position. Also save the - // bounds of the root view's widget. - - nsView* rootViewSibling = nullptr; - nsView* rootViewParent = nullptr; + // Save the bounds of the root view's widget. LayoutDeviceIntRect newBounds(0, 0, 0, 0); PresShell* oldPresShell = GetPresShell(); if (oldPresShell) { - nsViewManager* vm = oldPresShell->GetViewManager(); - if (vm) { - nsView* oldRootView = vm->GetRootView(); - - if (oldRootView) { - rootViewSibling = oldRootView->GetNextSibling(); - rootViewParent = oldRootView->GetParent(); - - mDocumentViewer->GetBounds(newBounds); - } - } - } - - nsCOMPtr<nsIContent> container; - RefPtr<Document> sibling; - if (rootViewParent && rootViewParent->GetParent()) { - nsIFrame* frame = rootViewParent->GetParent()->GetFrame(); - container = frame ? frame->GetContent() : nullptr; - } - if (rootViewSibling) { - nsIFrame* frame = rootViewSibling->GetFrame(); - sibling = frame ? frame->PresShell()->GetDocument() : nullptr; + mDocumentViewer->GetBounds(newBounds); } // Transfer ownership to mDocumentViewer. By ensuring that either the @@ -7729,39 +7700,6 @@ nsresult nsDocShell::RestoreFromHistory() { nsViewManager* newVM = presShell ? presShell->GetViewManager() : nullptr; nsView* newRootView = newVM ? newVM->GetRootView() : nullptr; - // Insert the new root view at the correct location in the view tree. - if (container) { - nsSubDocumentFrame* subDocFrame = - do_QueryFrame(container->GetPrimaryFrame()); - rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr; - } else { - rootViewParent = nullptr; - } - if (sibling && sibling->GetPresShell() && - sibling->GetPresShell()->GetViewManager()) { - rootViewSibling = sibling->GetPresShell()->GetViewManager()->GetRootView(); - } else { - rootViewSibling = nullptr; - } - if (rootViewParent && newRootView && - newRootView->GetParent() != rootViewParent) { - nsViewManager* parentVM = rootViewParent->GetViewManager(); - if (parentVM) { - // InsertChild(parent, child, sib, true) inserts the child after - // sib in content order, which is before sib in view order. BUT - // when sib is null it inserts at the end of the the document - // order, i.e., first in view order. But when oldRootSibling is - // null, the old root as at the end of the view list --- last in - // content order --- and we want to call InsertChild(parent, child, - // nullptr, false) in that case. - parentVM->InsertChild(rootViewParent, newRootView, rootViewSibling, - rootViewSibling ? true : false); - - NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling, - "error in InsertChild"); - } - } - nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow(); // If parent is suspended, increase suspension count. @@ -7798,15 +7736,6 @@ nsresult nsDocShell::RestoreFromHistory() { // presentation. If this is not the same size we showed it at last time, // then we need to resize the widget. - // XXXbryner This interacts poorly with Firefox's infobar. If the old - // presentation had the infobar visible, then we will resize the new - // presentation to that smaller size. However, firing the locationchanged - // event will hide the infobar, which will immediately resize the window - // back to the larger size. A future optimization might be to restore - // the presentation at the "wrong" size, then fire the locationchanged - // event and check whether the docshell's new size is the same as the - // cached viewer size (skipping the resize if they are equal). - if (newRootView) { if (!newBounds.IsEmpty() && !newBounds.ToUnknownRect().IsEqualEdges(oldBounds)) { @@ -7822,7 +7751,7 @@ nsresult nsDocShell::RestoreFromHistory() { // The FinishRestore call below can kill these, null them out so we don't // have invalid pointer lying around. - newRootView = rootViewSibling = rootViewParent = nullptr; + newRootView = nullptr; newVM = nullptr; // If the IsUnderHiddenEmbedderElement() state has been changed, we need to diff --git a/docshell/base/nsIDocumentViewer.idl b/docshell/base/nsIDocumentViewer.idl @@ -18,7 +18,7 @@ webidl Node; class nsIWidget; class nsPresContext; -class nsView; +class nsSubDocumentFrame; class nsDOMNavigationTiming; namespace mozilla { class Encoding; @@ -35,7 +35,7 @@ class RemotePrintJobChild; [ptr] native nsIWidgetPtr(nsIWidget); [ref] native LayoutDeviceIntRectRef(mozilla::LayoutDeviceIntRect); [ptr] native nsPresContextPtr(nsPresContext); -[ptr] native nsViewPtr(nsView); +[ptr] native nsSubDocumentFramePtr(nsSubDocumentFrame); [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming); [ptr] native Encoding(const mozilla::Encoding); [ptr] native PresShellPtr(mozilla::PresShell); @@ -251,7 +251,7 @@ interface nsIDocumentViewer : nsISupports * case, if mParentWidget is null then this document should not even * be displayed. */ - [noscript,notxpcom,nostdcall] nsViewPtr findContainerView(); + [noscript,notxpcom,nostdcall] nsSubDocumentFramePtr findContainerFrame(); /** * Set collector for navigation timing data (load, unload events). */ diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp @@ -7509,7 +7509,8 @@ static inline void AssertNoStaleServoDataIn(nsINode& aSubtreeRoot) { } already_AddRefed<PresShell> Document::CreatePresShell( - nsPresContext* aContext, nsViewManager* aViewManager) { + nsPresContext* aContext, nsViewManager* aViewManager, + nsSubDocumentFrame* aEmbedderFrame) { MOZ_DIAGNOSTIC_ASSERT(!mPresShell, "We have a presshell already!"); NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr); @@ -7520,6 +7521,12 @@ already_AddRefed<PresShell> Document::CreatePresShell( // Note: we don't hold a ref to the shell (it holds a ref to us) mPresShell = presShell; + if (aEmbedderFrame) { + // It's important to do this as soon as possible so that + // GetRootPresContext() and so on do the right thing from the get go. + aEmbedderFrame->AddEmbeddingPresShell(presShell); + } + if (!mStyleSetFilled) { FillStyleSet(); } diff --git a/dom/base/Document.h b/dom/base/Document.h @@ -1175,7 +1175,8 @@ class Document : public nsINode, * presshell if the presshell should observe document mutations. */ MOZ_CAN_RUN_SCRIPT already_AddRefed<PresShell> CreatePresShell( - nsPresContext* aContext, nsViewManager* aViewManager); + nsPresContext* aContext, nsViewManager* aViewManager, + nsSubDocumentFrame* aEmbedderFrame); void DeletePresShell(); PresShell* GetPresShell() const { diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h @@ -118,7 +118,6 @@ class nsNodeInfoManager; class nsParser; class nsPIWindowRoot; class nsPresContext; -class nsView; class nsWrapperCache; enum class WindowMediatorFilter : uint8_t; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp @@ -117,7 +117,6 @@ #include "nsSubDocumentFrame.h" #include "nsThreadUtils.h" #include "nsUnicharUtils.h" -#include "nsView.h" #include "nsViewManager.h" #include "nsXPCOMPrivate.h" // for XUL_DLL #include "nsXULPopupManager.h" @@ -168,7 +167,6 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, BrowsingContext* aBrowsingContext, bool aIsRemoteFrame, bool aNetworkCreated) : mPendingBrowsingContext(aBrowsingContext), mOwnerContent(aOwner), - mDetachedSubdocFrame(nullptr), mPendingSwitchID(0), mChildID(0), mRemoteType(NOT_REMOTE_TYPE), @@ -971,13 +969,8 @@ bool nsFrameLoader::Show(nsSubDocumentFrame* aFrame) { const bool marginsChanged = ds->UpdateFrameMargins(GetMarginAttributes(mOwnerContent)); - nsView* view = aFrame->EnsureInnerView(); - if (!view) { - return false; - } - // If we already have a pres shell (which can happen with <object> / <embed>) - // then hook it up in the view tree. + // then hook it up to the frame. if (PresShell* presShell = ds->GetPresShell()) { // Ensure root scroll frame is reflowed in case margins have changed. if (marginsChanged) { @@ -987,24 +980,12 @@ bool nsFrameLoader::Show(nsSubDocumentFrame* aFrame) { IntrinsicDirty::None, NS_FRAME_IS_DIRTY); } } - nsView* childView = presShell->GetViewManager()->GetRootView(); - MOZ_DIAGNOSTIC_ASSERT(childView); - if (childView->GetParent() == view) { - // We were probably doing a docshell swap and succeeded before getting - // here, hooray, nothing else to do. - return true; - } - - // We did layout before due to <object> or <embed> and now we need to fix - // up our stuff and initialize our docshell below too. - MOZ_DIAGNOSTIC_ASSERT(!view->GetFirstChild()); - MOZ_DIAGNOSTIC_ASSERT(!childView->GetParent(), "Stale view?"); - nsSubDocumentFrame::InsertViewsInReverseOrder(childView, view); - nsSubDocumentFrame::EndSwapDocShellsForViews(view->GetFirstChild()); + aFrame->EnsureEmbeddingPresShell(presShell); + MOZ_DIAGNOSTIC_ASSERT(presShell->GetViewManager()->GetRootView()); } RefPtr<nsDocShell> baseWindow = GetDocShell(); - baseWindow->InitWindow(view->GetWidget(), 0, 0, size.width, size.height); + baseWindow->InitWindow(nullptr, 0, 0, size.width, size.height); baseWindow->SetVisibility(true); NS_ENSURE_TRUE(GetDocShell(), false); @@ -3041,16 +3022,12 @@ nsFrameLoader::GetLazyLoadFrameResumptionState() { return sEmpty; } -void nsFrameLoader::SetDetachedSubdocFrame(nsIFrame* aDetachedFrame) { - mDetachedSubdocFrame = aDetachedFrame; - mHadDetachedFrame = !!aDetachedFrame; +void nsFrameLoader::SetDetachedSubdocs(WeakPresShellArray&& aDocs) { + mDetachedSubdocs = std::move(aDocs); } -nsIFrame* nsFrameLoader::GetDetachedSubdocFrame(bool* aOutIsSet) const { - if (aOutIsSet) { - *aOutIsSet = mHadDetachedFrame; - } - return mDetachedSubdocFrame.GetFrame(); +auto nsFrameLoader::TakeDetachedSubdocs() -> WeakPresShellArray { + return std::move(mDetachedSubdocs); } void nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags) { diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h @@ -365,18 +365,17 @@ class nsFrameLoader final : public nsStubMutationObserver, mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; } /** - * Stashes a detached nsIFrame on the frame loader. We do this when we're - * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is - * being reframed we'll restore the detached nsIFrame when it's recreated, - * otherwise we'll discard the old presentation and set the detached - * subdoc nsIFrame to null. + * Stashes a list of detached pres shells on the frame loader. We do this when + * we're destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is being + * reframed we'll restore the detached shells when they're recreated, + * otherwise we'll discard the old presentation and clear these. */ - void SetDetachedSubdocFrame(nsIFrame* aDetachedFrame); - - /** - * Retrieves the detached nsIFrame as set by SetDetachedSubdocFrame(). - */ - nsIFrame* GetDetachedSubdocFrame(bool* aOutIsSet = nullptr) const; + using WeakPresShellArray = nsTArray<nsWeakPtr>; + void SetDetachedSubdocs(WeakPresShellArray&&); + WeakPresShellArray TakeDetachedSubdocs(); + const WeakPresShellArray& GetDetachedSubdocs() const { + return mDetachedSubdocs; + } /** * Applies a new set of sandbox flags. These are merged with the sandbox @@ -508,9 +507,9 @@ class nsFrameLoader final : public nsStubMutationObserver, // our <browser> element. RefPtr<mozilla::dom::Element> mOwnerContentStrong; - // Stores the root frame of the subdocument while the subdocument is being - // reframed. Used to restore the presentation after reframing. - WeakFrame mDetachedSubdocFrame; + // Stores the detached pres shells of subdocuments. + // Used to restore the presentation after reframing. + WeakPresShellArray mDetachedSubdocs; // When performing a process switch, this value is used rather than mURIToLoad // to identify the process-switching load which should be resumed in the diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp @@ -1126,7 +1126,7 @@ void BrowserParent::UpdateDimensions(const LayoutDeviceIntRect& rect, LayoutDeviceIntPoint clientOffset = GetClientOffset(); LayoutDeviceIntPoint chromeOffset = !GetBrowserBridgeParent() - ? -GetChildProcessOffset() + ? GetChildProcessOffset() : LayoutDeviceIntPoint(); if (!mUpdatedDimensions || mDimensions != size || !mRect.IsEqualEdges(rect) || @@ -2717,7 +2717,7 @@ BrowserParent::GetChildToParentConversionMatrix() { if (mChildToParentConversionMatrix) { return *mChildToParentConversionMatrix; } - LayoutDevicePoint offset(-GetChildProcessOffset()); + LayoutDevicePoint offset(GetChildProcessOffset()); return LayoutDeviceToLayoutDeviceMatrix4x4::Translation(offset); } @@ -2741,34 +2741,20 @@ void BrowserParent::SetChildToParentConversionMatrix( LayoutDeviceIntPoint BrowserParent::GetChildProcessOffset() { // The "toplevel widget" in child processes is always at position // 0,0. Map the event coordinates to match that. - - LayoutDeviceIntPoint offset(0, 0); RefPtr<nsFrameLoader> frameLoader = GetFrameLoader(); if (!frameLoader) { - return offset; + return {}; } nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent(); if (!targetFrame) { - return offset; + return {}; } nsCOMPtr<nsIWidget> widget = GetWidget(); if (!widget) { - return offset; - } - - nsPresContext* presContext = targetFrame->PresContext(); - nsIFrame* rootFrame = presContext->PresShell()->GetRootFrame(); - nsView* rootView = rootFrame ? rootFrame->GetView() : nullptr; - if (!rootView) { - return offset; + return {}; } - // Note that we don't want to take into account transforms here: -#if 0 - nsPoint pt(0, 0); - nsLayoutUtils::TransformPoint(targetFrame, rootFrame, pt); -#endif // In practice, when transforms are applied to this frameLoader, we currently // get the wrong results whether we take transforms into account here or not. // But applying transforms here gives us the wrong results in all @@ -2780,15 +2766,13 @@ LayoutDeviceIntPoint BrowserParent::GetChildProcessOffset() { // What we actually need to do is apply the transforms to the coordinates of // any events we send to the child, and reverse them for any screen // coordinates that we retrieve from the child. - - // TODO: Once we take into account transforms here, set viewportType - // correctly. For now we use Visual as this means we don't apply - // the layout-to-visual transform in TranslateViewToWidget(). - ViewportType viewportType = ViewportType::Visual; - - nsPoint pt = targetFrame->GetOffsetTo(rootFrame); - return -nsLayoutUtils::TranslateViewToWidget(presContext, rootView, pt, - viewportType, widget); + auto point = nsLayoutUtils::FrameToWidgetOffset(targetFrame, widget); + if (!point) { + return {}; + } + nsPresContext* pc = targetFrame->PresContext(); + return LayoutDeviceIntPoint::FromAppUnitsRounded(*point, + pc->AppUnitsPerDevPixel()); } LayoutDeviceIntPoint BrowserParent::GetClientOffset() { diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp @@ -1243,6 +1243,13 @@ void PresShell::Destroy() { weakFrame->Clear(this); } + // Clear the embedding frame only after tearing down the frame tree, since we + // rely on reaching the display root frame from frame destruction. + if (nsSubDocumentFrame* f = GetInProcessEmbedderFrame()) { + f->RemoveEmbeddingPresShell(this); + } + mEmbedderFrame = nullptr; + // Terminate AccessibleCaretEventHub after tearing down the frame tree so that // we don't need to remove caret element's frame in // AccessibleCaret::RemoveCaretElement(). @@ -1284,6 +1291,15 @@ nsRefreshDriver* PresShell::GetRefreshDriver() const { return mPresContext ? mPresContext->RefreshDriver() : nullptr; } +// NOTE(emilio): It'd be ideal if instead of this explicit tracking we could +// rely on mDocument->GetEmbedderElement()->GetPrimaryFrame() + relevant +// null-checks. However, given how things are set up now, the embedder element +// in BrowsingContext / Window get cleared before tearing down the pres shell, +// and RDL relies on getting ahold of it to get the display root. +void PresShell::SetInProcessEmbedderFrame(nsSubDocumentFrame* aFrame) { + mEmbedderFrame = aFrame; +} + void PresShell::SetAuthorStyleDisabled(bool aStyleDisabled) { if (aStyleDisabled != StyleSet()->GetAuthorStyleDisabled()) { StyleSet()->SetAuthorStyleDisabled(aStyleDisabled); @@ -6162,20 +6178,17 @@ void PresShell::RebuildApproximateFrameVisibilityDisplayList( DecApproximateVisibleCount(oldApproximatelyVisibleFrames); } -/* static */ -void PresShell::ClearApproximateFrameVisibilityVisited(nsView* aView, - bool aClear) { - nsViewManager* vm = aView->GetViewManager(); - if (aClear) { - PresShell* presShell = vm->GetPresShell(); - if (!presShell->mApproximateFrameVisibilityVisited) { - presShell->ClearApproximatelyVisibleFramesList(); - } - presShell->mApproximateFrameVisibilityVisited = false; - } - for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { - ClearApproximateFrameVisibilityVisited(v, v->GetViewManager() != vm); +void PresShell::ClearApproximateFrameVisibilityVisited() { + if (!mApproximateFrameVisibilityVisited) { + ClearApproximatelyVisibleFramesList(); } + mApproximateFrameVisibilityVisited = false; + mDocument->EnumerateSubDocuments([](Document& aSubdoc) { + if (auto* ps = aSubdoc.GetPresShell()) { + ps->ClearApproximateFrameVisibilityVisited(); + } + return CallState::Continue; + }); } void PresShell::ClearApproximatelyVisibleFramesList( @@ -6383,7 +6396,7 @@ void PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly) { } RebuildApproximateFrameVisibility(/* aRect = */ nullptr, aRemoveOnly); - ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true); + ClearApproximateFrameVisibilityVisited(); #ifdef DEBUG_FRAME_VISIBILITY_DISPLAY_LIST // This can be used to debug the frame walker by comparing beforeFrameList @@ -6414,7 +6427,7 @@ void PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly) { RebuildApproximateFrameVisibilityDisplayList(list); - ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true); + ClearApproximateFrameVisibilityVisited(); list.DeleteAll(&builder); #endif @@ -6971,17 +6984,16 @@ void PresShell::DisableNonTestMouseEvents(bool aDisable) { nsPoint PresShell::GetEventLocation(const WidgetMouseEvent& aEvent) const { nsIFrame* rootFrame = GetRootFrame(); - if (rootFrame) { - RelativeTo relativeTo{rootFrame}; - if (rootFrame->PresContext()->IsRootContentDocumentCrossProcess()) { - relativeTo.mViewportType = ViewportType::Visual; - } - return nsLayoutUtils::GetEventCoordinatesRelativeTo(&aEvent, relativeTo); + if (!rootFrame) { + // Matches old TranslateWidgetToView behavior + return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); } - nsView* rootView = mViewManager->GetRootView(); - return nsLayoutUtils::TranslateWidgetToView(mPresContext, aEvent.mWidget, - aEvent.mRefPoint, rootView); + RelativeTo relativeTo{rootFrame}; + if (rootFrame->PresContext()->IsRootContentDocumentCrossProcess()) { + relativeTo.mViewportType = ViewportType::Visual; + } + return nsLayoutUtils::GetEventCoordinatesRelativeTo(&aEvent, relativeTo); } void PresShell::RecordPointerLocation(WidgetGUIEvent* aEvent) { @@ -9985,22 +9997,24 @@ bool PresShell::EventHandler::AdjustContextMenuKeyEvent( // up in the upper left of the relevant content area before we create // the DOM event. Since we never call InitMouseEvent() on the event, // the client X/Y will be 0,0. We can make use of that if the widget is null. - // Use the root view manager's widget since it's most likely to have one, - // and the coordinates returned by GetCurrentItemAndPositionForElement - // are relative to the widget of the root of the root view manager. + // Use the root widget since it's most likely to exist, and the coordinates + // returned by GetCurrentItemAndPositionForElement are relative to it. nsRootPresContext* rootPC = GetPresContext()->GetRootPresContext(); - aMouseEvent->mRefPoint = LayoutDeviceIntPoint(0, 0); + aMouseEvent->mRefPoint = LayoutDeviceIntPoint(); if (rootPC) { aMouseEvent->mWidget = rootPC->PresShell()->GetRootWidget(); if (aMouseEvent->mWidget) { // default the refpoint to the topleft of our document - nsPoint offset(0, 0); - nsIFrame* rootFrame = FrameConstructor()->GetRootFrame(); - if (rootFrame) { - nsView* view = rootFrame->GetClosestView(&offset); - offset += view->GetOffsetToWidget(aMouseEvent->mWidget); - aMouseEvent->mRefPoint = LayoutDeviceIntPoint::FromAppUnitsToNearest( - offset, GetPresContext()->AppUnitsPerDevPixel()); + nsPoint frameToWidgetOffset; + if (nsIFrame* rootFrame = FrameConstructor()->GetRootFrame()) { + nsIWidget* widget = rootFrame->GetNearestWidget(frameToWidgetOffset); + MOZ_ASSERT(widget, "If rootPC has a widget, so should we"); + auto widgetToWidgetOffset = + nsLayoutUtils::WidgetToWidgetOffset(widget, aMouseEvent->mWidget); + aMouseEvent->mRefPoint = + widgetToWidgetOffset + + LayoutDeviceIntPoint::FromAppUnitsToNearest( + frameToWidgetOffset, GetPresContext()->AppUnitsPerDevPixel()); } } } else { @@ -10133,22 +10147,24 @@ bool PresShell::EventHandler::PrepareToUseCaretPosition( nsPresContext* presContext = GetPresContext(); - // get caret position relative to the closest view + // get caret position relative to the closest widget nsRect caretCoords; nsIFrame* caretFrame = caret->GetGeometry(&caretCoords); if (!caretFrame) { return false; } - nsPoint viewOffset; - nsView* view = caretFrame->GetClosestView(&viewOffset); - if (!view) { + nsPoint widgetOffset; + nsIWidget* widget = caretFrame->GetNearestWidget(widgetOffset); + if (!widget) { return false; } // and then get the caret coords relative to the event widget if (aEventWidget) { - viewOffset += view->GetOffsetToWidget(aEventWidget); + widgetOffset += LayoutDeviceIntPoint::ToAppUnits( + nsLayoutUtils::WidgetToWidgetOffset(widget, aEventWidget), + presContext->AppUnitsPerDevPixel()); } - caretCoords.MoveBy(viewOffset); + caretCoords.MoveBy(widgetOffset); // caret coordinates are in app units, convert to pixels aTargetPt.x = @@ -10238,21 +10254,21 @@ void PresShell::EventHandler::GetCurrentItemAndPositionForElement( focusedContent = item; } - nsIFrame* frame = focusedContent->GetPrimaryFrame(); - if (frame) { + if (nsIFrame* frame = focusedContent->GetPrimaryFrame()) { NS_ASSERTION( frame->PresContext() == GetPresContext(), "handling event for focused content that is not in our document?"); - nsPoint frameOrigin(0, 0); + nsPoint widgetOffset(0, 0); - // Get the frame's origin within its view - nsView* view = frame->GetClosestView(&frameOrigin); - NS_ASSERTION(view, "No view for frame"); + // Get the frame's origin within its closest widget + nsIWidget* widget = frame->GetNearestWidget(widgetOffset); - // View's origin relative the widget + // And make it relative to aRootWidget if (aRootWidget) { - frameOrigin += view->GetOffsetToWidget(aRootWidget); + widgetOffset += LayoutDeviceIntPoint::ToAppUnits( + nsLayoutUtils::WidgetToWidgetOffset(widget, aRootWidget), + frame->PresContext()->AppUnitsPerDevPixel()); } // Start context menu down and to the right from top left of frame @@ -10284,9 +10300,9 @@ void PresShell::EventHandler::GetCurrentItemAndPositionForElement( } } - aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x); + aTargetPt.x = presContext->AppUnitsToDevPixels(widgetOffset.x); aTargetPt.y = - presContext->AppUnitsToDevPixels(frameOrigin.y + extra + extraTreeY); + presContext->AppUnitsToDevPixels(widgetOffset.y + extra + extraTreeY); } NS_IF_ADDREF(*aTargetToUse = focusedContent); @@ -10327,6 +10343,18 @@ void PresShell::WillPaint() { FlushPendingNotifications(ChangesToFlush(FlushType::InterruptibleLayout, /* aFlushAnimations = */ false, /* aUpdateRelevancy = */ false)); + if (mIsDestroying) { + return; + } + mDocument->EnumerateSubDocuments( + [](Document& aSubdoc) MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA { + if (RefPtr ps = aSubdoc.GetPresShell()) { + if (!ps->IsUnderHiddenEmbedderElement()) { + ps->WillPaint(); + } + } + return CallState::Continue; + }); } void PresShell::DidPaintWindow() { @@ -10351,26 +10379,9 @@ void PresShell::DidPaintWindow() { } nsSubDocumentFrame* PresShell::GetInProcessEmbedderFrame() const { - if (!mViewManager) { - return nullptr; - } - // We may not have a root frame yet, so use views. - nsView* view = mViewManager->GetRootView(); - if (!view) { - return nullptr; - } - view = view->GetParent(); // anonymous inner view - if (!view) { - return nullptr; - } - view = view->GetParent(); // subdocumentframe's view - if (!view) { - return nullptr; - } - - nsIFrame* f = view->GetFrame(); + nsIFrame* f = mEmbedderFrame.GetFrame(); MOZ_ASSERT_IF(f, f->IsSubDocumentFrame()); - return do_QueryFrame(f); + return static_cast<nsSubDocumentFrame*>(f); } bool PresShell::IsVisible() const { @@ -12231,7 +12242,19 @@ void PresShell::UpdateImageLockingState() { } nsIWidget* PresShell::GetRootWidget() const { - return mViewManager ? mViewManager->GetRootWidget() : nullptr; + if (!mPresContext) { + return nullptr; + } + for (nsPresContext* pc = mPresContext; pc; pc = pc->GetParentPresContext()) { + if (auto* vm = pc->PresShell()->GetViewManager()) { + if (auto* view = vm->GetRootView()) { + if (auto* widget = view->GetWidget()) { + return widget; + } + } + } + } + return nullptr; } PresShell* PresShell::GetRootPresShell() const { diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h @@ -463,6 +463,7 @@ class PresShell final : public nsStubDocumentObserver, // Get the current frame of our embedder, if it's in our same process. nsSubDocumentFrame* GetInProcessEmbedderFrame() const; + void SetInProcessEmbedderFrame(nsSubDocumentFrame*); /** * Get root scroll container frame from the frame constructor. @@ -3157,8 +3158,7 @@ class PresShell final : public nsStubDocumentObserver, void ClearApproximatelyVisibleFramesList( const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()); - static void ClearApproximateFrameVisibilityVisited(nsView* aView, - bool aClear); + void ClearApproximateFrameVisibilityVisited(); static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList); void MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame, const nsRect& aRect, @@ -3359,6 +3359,9 @@ class PresShell final : public nsStubDocumentObserver, // The focus sequence number of the last processed input event uint64_t mAPZFocusSequenceNumber; + // The nsSubDocumentFrame* that is embedding us. + WeakFrame mEmbedderFrame; + nscoord mLastAnchorScrollPositionY = 0; // Most recent canvas background color. diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp @@ -126,11 +126,9 @@ #include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/WindowGlobalChild.h" -namespace mozilla { -namespace dom { +namespace mozilla::dom { class PrintPreviewResultInfo; -} // namespace dom -} // namespace mozilla +} // namespace mozilla::dom using namespace mozilla; using namespace mozilla::dom; @@ -339,15 +337,9 @@ class nsDocumentViewer final : public nsIDocumentViewer, * Creates a view manager, root view, and widget for the root view, setting * mViewManager and mWindow. * @param aSize the initial size in appunits - * @param aContainerView the container view to hook our root view up - * to as a child, or null if this will be the root view manager */ - void MakeWindow(const nsSize& aSize, nsView* aContainerView); - - /** - * Create our device context - */ - nsresult CreateDeviceContext(nsView* aContainerView); + void MakeWindow(const nsSize& aSize); + nsresult CreateDeviceContext(nsSubDocumentFrame* aContainerFrame); /** * If aDoCreation is true, this creates the device context, creates a @@ -692,7 +684,8 @@ nsresult nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow) { nsCOMPtr<Document> doc = mDocument; RefPtr<nsPresContext> presContext = mPresContext; RefPtr<nsViewManager> viewManager = mViewManager; - mPresShell = doc->CreatePresShell(presContext, viewManager); + mPresShell = + doc->CreatePresShell(presContext, viewManager, FindContainerFrame()); if (!mPresShell) { return NS_ERROR_FAILURE; } @@ -769,8 +762,8 @@ nsresult nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow) { static already_AddRefed<nsPresContext> CreatePresContext( Document* aDocument, nsPresContext::nsPresContextType aType, - nsView* aContainerView) { - RefPtr<nsPresContext> result = aContainerView + nsIFrame* aContainerFrame) { + RefPtr<nsPresContext> result = aContainerFrame ? new nsPresContext(aDocument, aType) : new nsRootPresContext(aDocument, aType); @@ -797,11 +790,11 @@ nsresult nsDocumentViewer::InitInternal( nsresult rv = NS_OK; NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER); - nsView* containerView = FindContainerView(); + nsSubDocumentFrame* containerFrame = FindContainerFrame(); bool makeCX = false; if (aDoCreation) { - nsresult rv = CreateDeviceContext(containerView); + nsresult rv = CreateDeviceContext(containerFrame); NS_ENSURE_SUCCESS(rv, rv); // XXXbz this is a nasty hack to do with the fact that we create @@ -809,7 +802,7 @@ nsresult nsDocumentViewer::InitInternal( // it in one place (Show()) and require that callers call init(), open(), // show() in that order or something. if (!mPresContext && - (aParentWidget || containerView || mDocument->IsBeingUsedAsImage() || + (aParentWidget || containerFrame || mDocument->IsBeingUsedAsImage() || (mDocument->GetDisplayDocument() && mDocument->GetDisplayDocument()->GetPresShell()))) { // Create presentation context @@ -818,7 +811,7 @@ nsresult nsDocumentViewer::InitInternal( // is calling this method } else { mPresContext = CreatePresContext( - mDocument, nsPresContext::eContext_Galley, containerView); + mDocument, nsPresContext::eContext_Galley, containerFrame); } NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY); @@ -846,8 +839,7 @@ nsresult nsDocumentViewer::InitInternal( // FlushPendingNotifications() calls down the road... MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width), - mPresContext->DevPixelsToAppUnits(aBounds.height)), - containerView); + mPresContext->DevPixelsToAppUnits(aBounds.height))); Hide(); #ifdef NS_PRINT_PREVIEW @@ -896,7 +888,6 @@ nsresult nsDocumentViewer::InitInternal( if (aDoCreation && mPresContext) { // The ViewManager and Root View was created above (in // MakeWindow())... - rv = InitPresentationStuff(!makeCX); } @@ -1606,32 +1597,9 @@ nsDocumentViewer::Destroy() { mSHEntry->SetSticky(mIsSticky); mIsSticky = true; - // Remove our root view from the view hierarchy. - if (mPresShell) { - nsViewManager* vm = mPresShell->GetViewManager(); - if (vm) { - nsView* rootView = vm->GetRootView(); - - if (rootView) { - nsView* rootViewParent = rootView->GetParent(); - if (rootViewParent) { - nsView* subdocview = rootViewParent->GetParent(); - if (subdocview) { - nsIFrame* f = subdocview->GetFrame(); - if (f) { - nsSubDocumentFrame* s = do_QueryFrame(f); - if (s) { - s->ClearDisplayItems(); - } - } - } - nsViewManager* parentVM = rootViewParent->GetViewManager(); - if (parentVM) { - parentVM->RemoveChild(rootView); - } - } - } - } + // Clear our display items. + if (nsSubDocumentFrame* f = FindContainerFrame()) { + f->ClearDisplayItems(); } Hide(); @@ -2073,16 +2041,16 @@ nsDocumentViewer::Show() { } } - nsView* containerView = FindContainerView(); + nsSubDocumentFrame* containerFrame = FindContainerFrame(); - nsresult rv = CreateDeviceContext(containerView); + nsresult rv = CreateDeviceContext(containerFrame); NS_ENSURE_SUCCESS(rv, rv); // Create presentation context NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!"); mPresContext = CreatePresContext(mDocument, nsPresContext::eContext_Galley, - containerView); + containerFrame); NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY); rv = mPresContext->Init(mDeviceContext); @@ -2092,8 +2060,7 @@ nsDocumentViewer::Show() { } MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width), - mPresContext->DevPixelsToAppUnits(mBounds.height)), - containerView); + mPresContext->DevPixelsToAppUnits(mBounds.height))); if (mPresContext) { Hide(); @@ -2208,7 +2175,7 @@ nsDocumentViewer::ClearHistoryEntry() { //------------------------------------------------------- -void nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView) { +void nsDocumentViewer::MakeWindow(const nsSize& aSize) { if (GetIsPrintPreview()) { return; } @@ -2218,8 +2185,7 @@ void nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView) { // The root view is always at 0,0. nsRect tbounds(nsPoint(), aSize); // Create a view - nsView* view = mViewManager->CreateView(tbounds, aContainerView); - MOZ_ASSERT(view); + nsView* view = mViewManager->CreateView(tbounds, nullptr); // Create a widget if we were given a parent widget or don't have a // container view that we can hook up to without a widget. @@ -2227,7 +2193,7 @@ void nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView) { // because when they're displayed, they're painted into *another* document's // widget. if (!mDocument->IsResourceDoc()) { - MOZ_ASSERT_IF(!aContainerView, mParentWidget); + MOZ_ASSERT_IF(!FindContainerFrame(), mParentWidget); if (mParentWidget) { // Reuse the top level parent widget. view->AttachToTopLevelWidget(mParentWidget); @@ -2256,7 +2222,7 @@ void nsDocumentViewer::DetachFromTopLevelWidget() { mAttachedToParent = false; } -nsView* nsDocumentViewer::FindContainerView() { +nsSubDocumentFrame* nsDocumentViewer::FindContainerFrame() { if (!mContainer) { return nullptr; } @@ -2287,22 +2253,20 @@ nsView* nsDocumentViewer::FindContainerView() { return nullptr; } - NS_ASSERTION(subdocFrame->GetView(), "Subdoc frames must have views"); - return static_cast<nsSubDocumentFrame*>(subdocFrame)->EnsureInnerView(); + return static_cast<nsSubDocumentFrame*>(subdocFrame); } -nsresult nsDocumentViewer::CreateDeviceContext(nsView* aContainerView) { +nsresult nsDocumentViewer::CreateDeviceContext( + nsSubDocumentFrame* aContainerFrame) { MOZ_ASSERT(!mPresShell && !mWindow, "This will screw up our existing presentation"); MOZ_ASSERT(mDocument, "Gotta have a document here"); - Document* doc = mDocument->GetDisplayDocument(); - if (doc) { - NS_ASSERTION(!aContainerView, + if (Document* doc = mDocument->GetDisplayDocument()) { + NS_ASSERTION(!aContainerFrame, "External resource document embedded somewhere?"); // We want to use our display document's device context if possible - nsPresContext* ctx = doc->GetPresContext(); - if (ctx) { + if (nsPresContext* ctx = doc->GetPresContext()) { mDeviceContext = ctx->DeviceContext(); return NS_OK; } @@ -2311,8 +2275,8 @@ nsresult nsDocumentViewer::CreateDeviceContext(nsView* aContainerView) { // Create a device context even if we already have one, since our widget // might have changed. nsIWidget* widget = nullptr; - if (aContainerView) { - widget = aContainerView->GetNearestWidget(nullptr); + if (aContainerFrame) { + widget = aContainerFrame->GetNearestWidget(); } if (!widget) { widget = mParentWidget; @@ -3345,14 +3309,13 @@ NS_IMETHODIMP nsDocumentViewer::SetPrintSettingsForSubdocument( NS_ENSURE_SUCCESS(rv, rv); mPresContext = CreatePresContext( - mDocument, nsPresContext::eContext_PrintPreview, FindContainerView()); + mDocument, nsPresContext::eContext_PrintPreview, FindContainerFrame()); mPresContext->SetPrintSettings(aPrintSettings); rv = mPresContext->Init(mDeviceContext); NS_ENSURE_SUCCESS(rv, rv); MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width), - mPresContext->DevPixelsToAppUnits(mBounds.height)), - FindContainerView()); + mPresContext->DevPixelsToAppUnits(mBounds.height))); MOZ_TRY(InitPresentationStuff(true)); } @@ -3388,7 +3351,7 @@ NS_IMETHODIMP nsDocumentViewer::SetPageModeForTesting( NS_ENSURE_STATE(mDocument); if (aPageMode) { mPresContext = CreatePresContext( - mDocument, nsPresContext::eContext_PageLayout, FindContainerView()); + mDocument, nsPresContext::eContext_PageLayout, FindContainerFrame()); NS_ENSURE_TRUE(mPresContext, NS_ERROR_OUT_OF_MEMORY); mPresContext->SetPaginatedScrolling(true); mPresContext->SetPrintSettings(aPrintSettings); @@ -3448,18 +3411,8 @@ void nsDocumentViewer::DestroyPresShell() { } void nsDocumentViewer::InvalidatePotentialSubDocDisplayItem() { - if (mViewManager) { - if (nsView* rootView = mViewManager->GetRootView()) { - if (nsView* rootViewParent = rootView->GetParent()) { - if (nsView* subdocview = rootViewParent->GetParent()) { - if (nsIFrame* f = subdocview->GetFrame()) { - if (nsSubDocumentFrame* s = do_QueryFrame(f)) { - s->MarkNeedsDisplayItemRebuild(); - } - } - } - } - } + if (nsSubDocumentFrame* f = FindContainerFrame()) { + f->MarkNeedsDisplayItemRebuild(); } } diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp @@ -1211,37 +1211,6 @@ nsIFrame* nsLayoutUtils::GetLastSibling(nsIFrame* aFrame) { } // static -nsView* nsLayoutUtils::FindSiblingViewFor(nsView* aParentView, - nsIFrame* aFrame) { - nsIFrame* parentViewFrame = aParentView->GetFrame(); - nsIContent* parentViewContent = - parentViewFrame ? parentViewFrame->GetContent() : nullptr; - for (nsView* insertBefore = aParentView->GetFirstChild(); insertBefore; - insertBefore = insertBefore->GetNextSibling()) { - nsIFrame* f = insertBefore->GetFrame(); - if (!f) { - // this view could be some anonymous view attached to a meaningful parent - for (nsView* searchView = insertBefore->GetParent(); searchView; - searchView = searchView->GetParent()) { - f = searchView->GetFrame(); - if (f) { - break; - } - } - NS_ASSERTION(f, "Can't find a frame anywhere!"); - } - if (!f || !aFrame->GetContent() || !f->GetContent() || - nsContentUtils::CompareTreePosition<TreeKind::Flat>( - aFrame->GetContent(), f->GetContent(), parentViewContent) > 0) { - // aFrame's content is after f's content (or we just don't know), - // so put our view before f's view - return insertBefore; - } - } - return nullptr; -} - -// static ScrollContainerFrame* nsLayoutUtils::GetScrollContainerFrameFor( const nsIFrame* aScrolledFrame) { nsIFrame* frame = aScrolledFrame->GetParent(); @@ -1516,15 +1485,21 @@ nsPoint GetEventCoordinatesRelativeTo(nsIWidget* aWidget, rootFrame = f; } - nsView* rootView = rootFrame->GetView(); - if (!rootView) { - return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); - } - - nsPoint widgetToView = nsLayoutUtils::TranslateWidgetToView( - rootFrame->PresContext(), aWidget, aPoint, rootView); + nsPoint widgetToRoot = [&] { + nsPresContext* pc = rootFrame->PresContext(); + nsPoint widgetOffset; + nsIWidget* widget = rootFrame->GetNearestWidget(widgetOffset); + if (NS_WARN_IF(!widget)) { + return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); + } + LayoutDeviceIntPoint widgetPoint = + aPoint + nsLayoutUtils::WidgetToWidgetOffset(aWidget, widget); + nsPoint widgetAppUnits(pc->DevPixelsToAppUnits(widgetPoint.x), + pc->DevPixelsToAppUnits(widgetPoint.y)); + return widgetAppUnits - widgetOffset; + }(); - if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) { + if (widgetToRoot == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) { return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); } @@ -1532,20 +1507,20 @@ nsPoint GetEventCoordinatesRelativeTo(nsIWidget* aWidget, // is in. int32_t rootAPD = rootFrame->PresContext()->AppUnitsPerDevPixel(); int32_t localAPD = frame->PresContext()->AppUnitsPerDevPixel(); - widgetToView = widgetToView.ScaleToOtherAppUnits(rootAPD, localAPD); + widgetToRoot = widgetToRoot.ScaleToOtherAppUnits(rootAPD, localAPD); /* If we encountered a transform, we can't do simple arithmetic to figure * out how to convert back to aFrame's coordinates and must use the CTM. */ if (transformFound || frame->IsInSVGTextSubtree()) { return nsLayoutUtils::TransformRootPointToFrame(ViewportType::Visual, - aFrame, widgetToView); + aFrame, widgetToRoot); } /* Otherwise, all coordinate systems are translations of one another, * so we can just subtract out the difference. */ - return widgetToView - frame->GetOffsetToCrossDoc(rootFrame); + return widgetToRoot - frame->GetOffsetToCrossDoc(rootFrame); } nsPoint nsLayoutUtils::GetEventCoordinatesRelativeTo( @@ -2384,6 +2359,19 @@ nsRect nsLayoutUtils::TransformFrameRectToAncestor( result, aAncestor.mFrame->PresContext()->AppUnitsPerDevPixel()); } +Maybe<nsPoint> nsLayoutUtils::FrameToWidgetOffset(const nsIFrame* aFrame, + nsIWidget* aWidget) { + nsPoint toNearestOffset; + auto* nearest = aFrame->GetNearestWidget(toNearestOffset); + if (!nearest) { + return {}; + } + return Some(toNearestOffset + + LayoutDeviceIntPoint::ToAppUnits( + WidgetToWidgetOffset(nearest, aWidget), + aFrame->PresContext()->AppUnitsPerDevPixel())); +} + LayoutDeviceIntPoint nsLayoutUtils::WidgetToWidgetOffset(nsIWidget* aFrom, nsIWidget* aTo) { if (aFrom == aTo) { @@ -2394,23 +2382,6 @@ LayoutDeviceIntPoint nsLayoutUtils::WidgetToWidgetOffset(nsIWidget* aFrom, return fromOffset - toOffset; } -nsPoint nsLayoutUtils::TranslateWidgetToView(nsPresContext* aPresContext, - nsIWidget* aWidget, - const LayoutDeviceIntPoint& aPt, - nsView* aView) { - nsPoint viewOffset; - nsIWidget* viewWidget = aView->GetNearestWidget(&viewOffset); - if (!viewWidget) { - return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); - } - - LayoutDeviceIntPoint widgetPoint = - aPt + WidgetToWidgetOffset(aWidget, viewWidget); - nsPoint widgetAppUnits(aPresContext->DevPixelsToAppUnits(widgetPoint.x), - aPresContext->DevPixelsToAppUnits(widgetPoint.y)); - return widgetAppUnits - viewOffset; -} - LayoutDeviceIntPoint nsLayoutUtils::TranslateViewToWidget( nsPresContext* aPresContext, nsView* aView, nsPoint aPt, ViewportType aViewportType, nsIWidget* aWidget) { diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h @@ -740,19 +740,6 @@ class nsLayoutUtils { int32_t* aOffset); /** - * Translate from widget coordinates to the view's coordinates - * @param aPresContext the PresContext for the view - * @param aWidget the widget - * @param aPt the point relative to the widget - * @param aView view to which returned coordinates are relative - * @return the point in the view's coordinates - */ - static nsPoint TranslateWidgetToView(nsPresContext* aPresContext, - nsIWidget* aWidget, - const mozilla::LayoutDeviceIntPoint& aPt, - nsView* aView); - - /** * Translate from view coordinates to the widget's coordinates. * @param aPresContext the PresContext for the view * @param aView the view @@ -768,6 +755,9 @@ class nsLayoutUtils { static mozilla::LayoutDeviceIntPoint WidgetToWidgetOffset( nsIWidget* aFromWidget, nsIWidget* aToWidget); + static mozilla::Maybe<nsPoint> FrameToWidgetOffset(const nsIFrame* aFrame, + nsIWidget* aWidget); + enum class FrameForPointOption { /** * When set, paint suppression is ignored, so we'll return non-root page diff --git a/layout/generic/FrameClasses.py b/layout/generic/FrameClasses.py @@ -117,7 +117,7 @@ FRAME_CLASSES = [ Frame("nsPageSequenceFrame", "PageSequence", COMMON), Frame("nsSliderFrame", "Slider", COMMON), Frame("nsSplitterFrame", "SimpleXULLeaf", COMMON | LEAF), - Frame("nsSubDocumentFrame", "SubDocument", REPLACED_SIZING | LEAF | MAY_HAVE_VIEW), + Frame("nsSubDocumentFrame", "SubDocument", REPLACED_SIZING | LEAF), Frame("PrintedSheetFrame", "PrintedSheet", COMMON), Frame("SVGAFrame", "SVGA", SVG_CONTAINER), Frame("SVGClipPathFrame", "SVGClipPath", SVG_RENDERING_OBSERVER_CONTAINER), diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp @@ -30,6 +30,7 @@ #include "nsAttrValueInlines.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" +#include "nsDeviceContext.h" #include "nsDisplayList.h" #include "nsFrameSetFrame.h" #include "nsGenericHTMLElement.h" @@ -39,6 +40,7 @@ #include "nsIDocShell.h" #include "nsIDocumentViewer.h" #include "nsIObjectLoadingContent.h" +#include "nsIWeakReferenceUtils.h" #include "nsLayoutUtils.h" #include "nsNameSpaceManager.h" #include "nsObjectLoadingContent.h" @@ -48,22 +50,12 @@ #include "nsStyleConsts.h" #include "nsStyleStruct.h" #include "nsStyleStructInlines.h" -#include "nsView.h" -#include "nsViewManager.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; -} - static void PropagateIsUnderHiddenEmbedderElement(nsFrameLoader* aFrameLoader, bool aValue) { if (!aFrameLoader) { @@ -80,8 +72,6 @@ static void PropagateIsUnderHiddenEmbedderElement(nsFrameLoader* aFrameLoader, nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle, nsPresContext* aPresContext) : nsAtomicContainerFrame(aStyle, aPresContext, kClassID), - mOuterView(nullptr), - mInnerView(nullptr), mIsInline(false), mPostedReflowCallback(false), mDidCreateDoc(false), @@ -114,6 +104,34 @@ class AsyncFrameInit : public Runnable { WeakFrame mFrame; }; +void nsSubDocumentFrame::EnsureEmbeddingPresShell(class PresShell* aPs) { + MOZ_ASSERT(aPs); + nsWeakPtr weakRef = do_GetWeakReference(aPs); + if (!mInProcessPresShells.Contains(weakRef)) { + aPs->SetInProcessEmbedderFrame(this); + mInProcessPresShells.AppendElement(std::move(weakRef)); + } +} + +void nsSubDocumentFrame::AddEmbeddingPresShell(class PresShell* aPs) { + MOZ_ASSERT(aPs); + nsWeakPtr weakRef = do_GetWeakReference(aPs); + MOZ_ASSERT(!mInProcessPresShells.Contains(weakRef)); + aPs->SetInProcessEmbedderFrame(this); + mInProcessPresShells.AppendElement(std::move(weakRef)); +} + +void nsSubDocumentFrame::RemoveEmbeddingPresShell(class PresShell* aPs) { + MOZ_ASSERT(aPs); + nsWeakPtr weakRef = do_GetWeakReference(aPs); + MOZ_ASSERT(mInProcessPresShells.Contains(weakRef)); + aPs->SetInProcessEmbedderFrame(nullptr); + if (mLastPaintedPresShell == weakRef) { + mLastPaintedPresShell = nullptr; + } + mInProcessPresShells.RemoveElement(weakRef); +} + void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) { MOZ_ASSERT(aContent); @@ -122,29 +140,16 @@ void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, 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 (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { - bool hadFrame = false; - nsIFrame* detachedFrame = frameloader->GetDetachedSubdocFrame(&hadFrame); - frameloader->SetDetachedSubdocFrame(nullptr); - nsView* detachedView = detachedFrame ? detachedFrame->GetView() : nullptr; - if (detachedView) { - // Restore stashed presentation. - InsertViewsInReverseOrder(detachedView, mInnerView); - EndSwapDocShellsForViews(mInnerView->GetFirstChild()); - } else if (hadFrame) { + mInProcessPresShells = frameloader->TakeDetachedSubdocs(); + const bool anyLiveShell = FixUpInProcessPresShellsAfterAttach(); + if (!mInProcessPresShells.IsEmpty() && !anyLiveShell) { + mInProcessPresShells.Clear(); // Presentation is for a different document, don't restore it. frameloader->Hide(); } @@ -189,8 +194,7 @@ void nsSubDocumentFrame::ShowViewer() { 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(); + // initializing the shell. } else { AutoWeakFrame weakThis(this); mCallingShow = true; @@ -211,94 +215,36 @@ void nsSubDocumentFrame::ShowViewer() { } } -void nsSubDocumentFrame::CreateView() { - MOZ_ASSERT(!GetView()); - - nsView* parentView = GetParent()->GetClosestView(); - MOZ_ASSERT(parentView, "no parent with view"); - - nsViewManager* viewManager = parentView->GetViewManager(); - MOZ_ASSERT(viewManager, "null view manager"); - - nsView* view = viewManager->CreateView(GetRect(), parentView); - SyncFrameViewProperties(view); - - nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, this); - // we insert this view 'above' the insertBefore view, unless insertBefore is - // null, in which case we want to call with aAbove == false to insert at the - // beginning in document order - viewManager->InsertChild(parentView, view, insertBefore, - insertBefore != nullptr); - - // Remember our view - SetView(view); +Document* nsSubDocumentFrame::GetExtantSubdocument() { + nsIDocShell* ds = GetExtantDocShell(); + return ds ? ds->GetExtantDocument() : nullptr; +} - NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, - ("nsIFrame::CreateView: frame=%p view=%p", this, view)); +mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShell() { + Document* doc = GetExtantSubdocument(); + return doc ? doc->GetPresShell() : nullptr; } nsIFrame* nsSubDocumentFrame::GetSubdocumentRootFrame() { - if (!mInnerView) { - return nullptr; - } - nsView* subdocView = mInnerView->GetFirstChild(); - return subdocView ? subdocView->GetFrame() : nullptr; + mozilla::PresShell* ps = GetSubdocumentPresShell(); + return ps ? ps->GetRootFrame() : 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(); + mozilla::PresShell* presShell = GetSubdocumentPresShell(); + if (presShell && (!presShell->IsPaintingSuppressed() || + (aFlags & IGNORE_PAINT_SUPPRESSION))) { + return presShell; + } + // If painting is suppressed in the presshell or there's no presShell, we try + // to look for a better presshell to use. + if (StaticPrefs::layout_show_previous_page()) { + RefPtr<mozilla::PresShell> old = do_QueryReferent(mLastPaintedPresShell); + if (old && old->GetInProcessEmbedderFrame() == this) { + return old; } } - return presShell; } @@ -319,12 +265,14 @@ nsRect nsSubDocumentFrame::GetDestRect(const nsRect& aConstraintRect) const { LayoutDeviceIntSize nsSubDocumentFrame::GetInitialSubdocumentSize() const { if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { - nsIFrame* detachedFrame = frameloader->GetDetachedSubdocFrame(); - if (nsView* view = detachedFrame ? detachedFrame->GetView() : nullptr) { - nsSize size = view->GetBounds().Size(); - nsPresContext* presContext = detachedFrame->PresContext(); - return LayoutDeviceIntSize(presContext->AppUnitsToDevPixels(size.width), - presContext->AppUnitsToDevPixels(size.height)); + for (const auto& detachedShell : frameloader->GetDetachedSubdocs()) { + if (RefPtr<mozilla::PresShell> ps = do_QueryReferent(detachedShell)) { + if (nsPresContext* pc = ps->GetPresContext()) { + return LayoutDeviceIntSize( + pc->AppUnitsToDevPixels(pc->GetVisibleArea().width), + pc->AppUnitsToDevPixels(pc->GetVisibleArea().height)); + } + } } } // Pick some default size for now. Using 10x10 because that's what the @@ -399,7 +347,7 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // 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. - if (!mInnerView || !aBuilder->GetDescendIntoSubdocuments()) { + if (!aBuilder->GetDescendIntoSubdocuments()) { return; } @@ -420,6 +368,10 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return; } + if (aBuilder->IsForPainting() && !aBuilder->IsIgnoringPaintSuppression()) { + mLastPaintedPresShell = do_GetWeakReference(presShell); + } + if (aBuilder->IsInFilter()) { Document* outerDoc = PresShell()->GetDocument(); Document* innerDoc = presShell->GetDocument(); @@ -701,16 +653,18 @@ void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left, aReflowInput.ComputedPhysicalBorderPadding().top); - if (mInnerView) { + if (nsCOMPtr<nsIDocShell> ds = GetExtantDocShell()) { 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 = GetDestRect(nsRect(offset, innerSize)); - nsViewManager* vm = mInnerView->GetViewManager(); - vm->MoveViewTo(mInnerView, destRect.x, destRect.y); - vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size())); + const nsRect destRect = GetDestRect(nsRect(offset, innerSize)); + auto rect = LayoutDeviceIntRect::FromAppUnitsToInside( + destRect, PresContext()->AppUnitsPerDevPixel()); + mExtraOffset = destRect.TopLeft(); + nsDocShell::Cast(ds)->SetPositionAndSize(0, 0, rect.width, rect.height, + nsIBaseWindow::eDelayResize); } aDesiredSize.SetOverflowAreasToDesiredBounds(); @@ -943,7 +897,7 @@ class nsHideViewer final : public Runnable { // 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); + mFrameLoader->SetDetachedSubdocs({}); nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame()); if (!frame || frame->FrameLoader() != mFrameLoader) { @@ -964,8 +918,6 @@ class nsHideViewer final : public Runnable { const bool mHideViewerIfFrameless; }; -static nsView* BeginSwapDocShellsForViews(nsView* aSibling); - void nsSubDocumentFrame::Destroy(DestroyContext& aContext) { if (mPostedReflowCallback) { PresShell()->CancelReflowCallback(this); @@ -978,11 +930,8 @@ void nsSubDocumentFrame::Destroy(DestroyContext& aContext) { if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { ClearDisplayItems(); - nsView* detachedViews = - ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild()); - - frameloader->SetDetachedSubdocFrame( - detachedViews ? detachedViews->GetFrame() : nullptr); + PrepareInProcessPresShellsForDetach(); + frameloader->SetDetachedSubdocs(std::move(mInProcessPresShells)); // We call nsFrameLoader::HideViewer() in a script runner so that we can // safely determine whether the frame is being reframed or destroyed. @@ -1052,6 +1001,10 @@ nsIDocShell* nsSubDocumentFrame::GetDocShell() const { return mFrameLoader->GetDocShell(IgnoreErrors()); } +nsIDocShell* nsSubDocumentFrame::GetExtantDocShell() const { + return mFrameLoader ? mFrameLoader->GetExistingDocShell() : nullptr; +} + 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 @@ -1076,52 +1029,6 @@ static void DestroyDisplayItemDataForFrames(nsIFrame* aFrame) { } } -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 nsSubDocumentFrame::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; @@ -1136,23 +1043,17 @@ nsresult nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther) { ClearDisplayItems(); other->ClearDisplayItems(); - if (mInnerView && other->mInnerView) { - nsView* ourSubdocViews = mInnerView->GetFirstChild(); - nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews); - nsView* otherSubdocViews = other->mInnerView->GetFirstChild(); - nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews); + PrepareInProcessPresShellsForDetach(); + other->PrepareInProcessPresShellsForDetach(); - 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. + // Our docshell 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<nsIDocumentViewer> viewer; ds->GetDocViewer(getter_AddRefs(viewer)); @@ -1163,8 +1064,12 @@ static CallState EndSwapDocShellsForDocument(Document& aDocument) { } nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr; if (dc) { - nsView* v = viewer->FindContainerView(); - dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr); + nsSubDocumentFrame* f = viewer->FindContainerFrame(); + nsIWidget* widget = f ? f->GetNearestWidget() : nullptr; + if (widget) { + widget = widget->GetTopLevelWidget(); + } + dc->Init(widget); } viewer = viewer->GetPreviousViewer(); } @@ -1174,64 +1079,65 @@ static CallState EndSwapDocShellsForDocument(Document& aDocument) { return CallState::Continue; } -/* static */ -void nsSubDocumentFrame::EndSwapDocShellsForViews(nsView* aSibling) { - for (; aSibling; aSibling = aSibling->GetNextSibling()) { - if (Document* doc = ::GetDocumentFromView(aSibling)) { - ::EndSwapDocShellsForDocument(*doc); +static CallState BeginSwapDocShellsForDocument(Document& aDocument) { + if (PresShell* presShell = aDocument.GetPresShell()) { + // Disable painting while the presentation shell is detached. + presShell->SetNeverPainting(true); + + if (nsIFrame* rootFrame = presShell->GetRootFrame()) { + ::DestroyDisplayItemDataForFrames(rootFrame); } - 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); - } + } + aDocument.EnumerateSubDocuments(BeginSwapDocShellsForDocument); + return CallState::Continue; +} + +void nsSubDocumentFrame::PrepareInProcessPresShellsForDetach() { + for (const auto& shell : mInProcessPresShells) { + if (RefPtr<class PresShell> ps = do_QueryReferent(shell)) { + BeginSwapDocShellsForDocument(*ps->GetDocument()); + } + } +} + +bool nsSubDocumentFrame::FixUpInProcessPresShellsAfterAttach() { + bool anyLiveShell = false; + for (auto& shell : mInProcessPresShells) { + if (RefPtr<mozilla::PresShell> ps = do_QueryReferent(shell)) { + if (ps && !ps->IsDestroying()) { + anyLiveShell = true; + ps->SetInProcessEmbedderFrame(this); + EndSwapDocShellsForDocument(*ps->GetDocument()); } } } + return anyLiveShell; } void nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther) { - nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther); - AutoWeakFrame weakThis(this); - AutoWeakFrame weakOther(aOther); + auto* other = static_cast<nsSubDocumentFrame*>(aOther); - if (mInnerView) { - EndSwapDocShellsForViews(mInnerView->GetFirstChild()); - } - if (other->mInnerView) { - EndSwapDocShellsForViews(other->mInnerView->GetFirstChild()); - } + mInProcessPresShells.SwapElements(other->mInProcessPresShells); + FixUpInProcessPresShellsAfterAttach(); + other->FixUpInProcessPresShellsAfterAttach(); // 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(); - PropagateIsUnderHiddenEmbedderElement( - PresShell()->IsUnderHiddenEmbedderElement() || - !StyleVisibility()->IsVisible()); - } - if (weakOther.IsAlive()) { - other->PresShell()->FrameNeedsReflow( - other, IntrinsicDirty::FrameAndAncestors, NS_FRAME_IS_DIRTY); - other->InvalidateFrameSubtree(); - other->PropagateIsUnderHiddenEmbedderElement( - other->PresShell()->IsUnderHiddenEmbedderElement() || - !other->StyleVisibility()->IsVisible()); - } + PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors, + NS_FRAME_IS_DIRTY); + InvalidateFrameSubtree(); + PropagateIsUnderHiddenEmbedderElement( + PresShell()->IsUnderHiddenEmbedderElement() || + !StyleVisibility()->IsVisible()); + + other->PresShell()->FrameNeedsReflow(other, IntrinsicDirty::FrameAndAncestors, + NS_FRAME_IS_DIRTY); + other->InvalidateFrameSubtree(); + other->PropagateIsUnderHiddenEmbedderElement( + other->PresShell()->IsUnderHiddenEmbedderElement() || + !other->StyleVisibility()->IsVisible()); } void nsSubDocumentFrame::ClearDisplayItems() { @@ -1241,33 +1147,6 @@ void nsSubDocumentFrame::ClearDisplayItems() { } } -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(); const auto anchorResolutionParams = AnchorPosResolutionParams::From(this); diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h @@ -55,6 +55,8 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame, mozilla::IntrinsicSize GetIntrinsicSize() override; mozilla::AspectRatio GetIntrinsicRatio() const override; + const nsPoint& GetExtraOffset() const { return mExtraOffset; } + SizeComputationResult ComputeSize( gfxContext* aRenderingContext, mozilla::WritingMode aWM, const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize, @@ -89,14 +91,12 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame, bool aIgnoreContainment = false) const; nsIDocShell* GetDocShell() const; + nsIDocShell* GetExtantDocShell() const; nsresult BeginSwapDocShells(nsIFrame* aOther); void EndSwapDocShells(nsIFrame* aOther); - static void InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent); - static void EndSwapDocShellsForViews(nsView* aView); - - nsView* EnsureInnerView(); - nsPoint GetExtraOffset() const; + mozilla::dom::Document* GetExtantSubdocument(); + mozilla::PresShell* GetSubdocumentPresShell(); nsIFrame* GetSubdocumentRootFrame(); enum { IGNORE_PAINT_SUPPRESSION = 0x1 }; mozilla::PresShell* GetSubdocumentPresShellForPainting(uint32_t aFlags); @@ -151,6 +151,10 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame, const Maybe<nsRect>& GetVisibleRect() const { return mVisibleRect; } void SetVisibleRect(const Maybe<nsRect>& aRect) { mVisibleRect = aRect; } + void AddEmbeddingPresShell(mozilla::PresShell*); + void EnsureEmbeddingPresShell(mozilla::PresShell*); + void RemoveEmbeddingPresShell(mozilla::PresShell*); + protected: friend class AsyncFrameInit; @@ -160,6 +164,11 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame, void PropagateIsUnderHiddenEmbedderElement(bool aValue); void UpdateEmbeddedBrowsingContextDependentData(); + // Makes sure that all the live pres shells are pointing to `this`. Returns + // true if there's any live shells. + bool FixUpInProcessPresShellsAfterAttach(); + void PrepareInProcessPresShellsForDetach(); + bool IsInline() const { return mIsInline; } // Show our document viewer. The document viewer is hidden via a script @@ -167,24 +176,27 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame, // being reframed. void ShowViewer(); - nsView* GetViewInternal() const override { return mOuterView; } - void SetViewInternal(nsView* aView) override { mOuterView = aView; } - void CreateView(); - mutable RefPtr<nsFrameLoader> mFrameLoader; - nsView* mOuterView; - nsView* mInnerView; - + // The in-process pres shells that we're currently embedding. May be multiple + // because of in-process BFCache. + // TODO(emilio): Maybe that's not relevant anymore? We definitely hit that + // code-path, but maybe it could be simplified nowadays? + AutoTArray<nsWeakPtr, 1> mInProcessPresShells; // When process-switching a remote tab, we might temporarily paint the old // one. Maybe<RemoteFramePaintData> mRetainedRemoteFrame; + nsWeakPtr mLastPaintedPresShell; // The raster scale from our last paint. mozilla::gfx::MatrixScales mRasterScale; // The visible rect from our last paint. Maybe<nsRect> mVisibleRect; + // The extra offset from our padding box to the child, needed to deal with + // object-fit and co. + nsPoint mExtraOffset; + bool mIsInline : 1; bool mPostedReflowCallback : 1; bool mDidCreateDoc : 1; diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp @@ -40,6 +40,7 @@ #include "nsPrintObject.h" #include "nsQueryObject.h" #include "nsReadableUtils.h" +#include "nsSubDocumentFrame.h" #include "nsView.h" // Print Options @@ -719,11 +720,9 @@ nsresult nsPrintJob::ReconstructAndReflow() { bool documentIsTopLevel = true; if (po->mParent) { nsSize adjSize; - bool doReturn; - nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize); - - MOZ_ASSERT(!documentIsTopLevel, "How could this happen?"); - + bool doReturn = false; + nsresult rv = + SetRootView(po, /* aDocumentIsTopLevel = */ false, doReturn, adjSize); if (NS_FAILED(rv) || doReturn) { return rv; } @@ -1181,26 +1180,12 @@ nsresult nsPrintJob::UpdateSelectionAndShrinkPrintObject( return NS_OK; } -nsView* nsPrintJob::GetParentViewForRoot() { - if (mIsCreatingPrintPreview) { - if (nsCOMPtr<nsIDocumentViewer> viewer = - do_QueryInterface(mDocViewerPrint)) { - return viewer->FindContainerView(); - } - } - return nullptr; -} - -nsresult nsPrintJob::SetRootView(nsPrintObject* aPO, bool& doReturn, - bool& documentIsTopLevel, nsSize& adjSize) { +nsresult nsPrintJob::SetRootView(nsPrintObject* aPO, bool aDocumentIsTopLevel, + bool& doReturn, nsSize& adjSize) { bool canCreateScrollbars = true; nsView* rootView; - nsView* parentView = nullptr; - - doReturn = false; - - if (aPO->mParent && aPO->mParent->PrintingIsEnabled()) { + if (!aDocumentIsTopLevel) { nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr; // Without a frame, this document can't be displayed; therefore, there is no @@ -1215,38 +1200,28 @@ nsresult nsPrintJob::SetRootView(nsPrintObject* aPO, bool& doReturn, // zoom this would be wrong as we use the same mPrt->mPrintDC for all // subdocuments. adjSize = frame->GetContentRect().Size(); - documentIsTopLevel = false; // presshell exists because parent is printable // the top nsPrintObject's widget will always have scrollbars if (frame && frame->IsSubDocumentFrame()) { - nsView* view = frame->GetView(); - NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); - view = view->GetFirstChild(); - NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); - parentView = view; canCreateScrollbars = false; } } else { adjSize = mPrt->mPrintDC->GetDeviceSurfaceDimensions(); - documentIsTopLevel = true; - parentView = GetParentViewForRoot(); } - if (aPO->mViewManager->GetRootView()) { - // Reuse the root view that is already on the root frame. - rootView = aPO->mViewManager->GetRootView(); + if ((rootView = aPO->mViewManager->GetRootView())) { // Remove it from its existing parent if necessary aPO->mViewManager->RemoveChild(rootView); - rootView->SetParent(parentView); + rootView->SetParent(nullptr); } else { // Create a child window of the parent that is our "root view/window" - nsRect tbounds = nsRect(nsPoint(0, 0), adjSize); - rootView = aPO->mViewManager->CreateView(tbounds, parentView); + nsRect tbounds = nsRect(nsPoint(), adjSize); + rootView = aPO->mViewManager->CreateView(tbounds, nullptr); NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY); } - if (mIsCreatingPrintPreview && documentIsTopLevel) { + if (mIsCreatingPrintPreview && aDocumentIsTopLevel) { aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars); } @@ -1275,9 +1250,21 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) { nsPresContext::nsPresContextType type = mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview : nsPresContext::eContext_Print; - const bool shouldBeRoot = - (!aPO->mParent || !aPO->mParent->PrintingIsEnabled()) && - !GetParentViewForRoot(); + const bool documentIsTopLevel = + !aPO->mParent || !aPO->mParent->PrintingIsEnabled(); + auto* embedderFrame = [&]() -> nsSubDocumentFrame* { + if (documentIsTopLevel) { + if (nsCOMPtr<nsIDocumentViewer> viewer = + do_QueryInterface(mDocViewerPrint)) { + return viewer->FindContainerFrame(); + } + } else if (aPO->mContent) { + return do_QueryFrame(aPO->mContent->GetPrimaryFrame()); + } + return nullptr; + }(); + + const bool shouldBeRoot = documentIsTopLevel && !embedderFrame; aPO->mPresContext = shouldBeRoot ? new nsRootPresContext(aPO->mDocument, type) : new nsPresContext(aPO->mDocument, type); aPO->mPresContext->SetPrintSettings(mPrintSettings); @@ -1288,11 +1275,8 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) { aPO->mViewManager = new nsViewManager(printData->mPrintDC); bool doReturn = false; - bool documentIsTopLevel = false; nsSize adjSize; - - nsresult rv = SetRootView(aPO.get(), doReturn, documentIsTopLevel, adjSize); - + nsresult rv = SetRootView(aPO.get(), documentIsTopLevel, doReturn, adjSize); if (NS_FAILED(rv) || doReturn) { return rv; } @@ -1338,7 +1322,8 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) { RefPtr<nsPresContext> presContext = aPO->mPresContext; RefPtr<nsViewManager> viewManager = aPO->mViewManager; - aPO->mPresShell = doc->CreatePresShell(presContext, viewManager); + aPO->mPresShell = + doc->CreatePresShell(presContext, viewManager, embedderFrame); if (!aPO->mPresShell) { return NS_ERROR_FAILURE; } diff --git a/layout/printing/nsPrintJob.h b/layout/printing/nsPrintJob.h @@ -24,6 +24,7 @@ // Classes class nsIFrame; +class nsSubDocumentFrame; class nsIPrintSettings; class nsPrintData; class nsPagePrintTimer; @@ -34,7 +35,6 @@ class nsPrintObject; class nsIDocShell; class nsPageSequenceFrame; class nsPIDOMWindowOuter; -class nsView; namespace mozilla { class PresShell; @@ -223,9 +223,8 @@ class nsPrintJob final : public nsIWebProgressListener, bool ShouldResumePrint() const; - nsresult SetRootView(nsPrintObject* aPO, bool& aDoReturn, - bool& aDocumentIsTopLevel, nsSize& aAdjSize); - nsView* GetParentViewForRoot(); + nsresult SetRootView(nsPrintObject* aPO, bool aDocumentIsTopLevel, + bool& aDoReturn, nsSize& aAdjSize); void UpdateZoomRatio(nsPrintObject* aPO); MOZ_CAN_RUN_SCRIPT nsresult ReconstructAndReflow(); MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult UpdateSelectionAndShrinkPrintObject( diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp @@ -341,8 +341,7 @@ void nsMenuPopupFrame::CreateWidget() { LayoutDeviceIntRect nsMenuPopupFrame::CalcWidgetBounds() const { return nsView::CalcWidgetBounds( GetRect(), PresContext()->AppUnitsPerDevPixel(), - PresShell()->GetViewManager()->GetRootView(), nullptr, - widget::WindowType::Popup, + PresShell()->GetRootFrame(), nullptr, widget::WindowType::Popup, nsLayoutUtils::GetFrameTransparency(this, this)); } diff --git a/view/nsView.cpp b/view/nsView.cpp @@ -187,14 +187,16 @@ struct WidgetViewBounds { int32_t mRoundTo = 1; }; -static WidgetViewBounds CalcWidgetViewBounds( - const nsRect& aBounds, int32_t aAppUnitsPerDevPixel, nsView* aParentView, - nsIWidget* aThisWidget, WindowType aType, TransparencyMode aTransparency) { +static WidgetViewBounds CalcWidgetViewBounds(const nsRect& aBounds, + int32_t aAppUnitsPerDevPixel, + nsIFrame* aParentFrame, + nsIWidget* aThisWidget, + WindowType aType) { nsRect viewBounds(aBounds); nsIWidget* parentWidget = nullptr; - if (aParentView) { + if (aParentFrame) { nsPoint offset; - parentWidget = aParentView->GetNearestWidget(&offset, aAppUnitsPerDevPixel); + parentWidget = aParentFrame->GetNearestWidget(offset); // make viewBounds be relative to the parent widget, in appunits viewBounds += offset; @@ -237,8 +239,9 @@ static LayoutDeviceIntRect WidgetViewBoundsToDevicePixels( LayoutDeviceIntRect nsView::CalcWidgetBounds(WindowType aType, TransparencyMode aTransparency) { int32_t p2a = mViewManager->AppUnitsPerDevPixel(); - auto viewBounds = CalcWidgetViewBounds(mDimBounds, p2a, GetParent(), - mWindow.get(), aType, aTransparency); + auto viewBounds = CalcWidgetViewBounds( + mDimBounds, p2a, GetParent() ? GetParent()->GetFrame() : nullptr, + mWindow.get(), aType); auto newBounds = WidgetViewBoundsToDevicePixels(viewBounds, p2a, aType, aTransparency); @@ -258,11 +261,10 @@ LayoutDeviceIntRect nsView::CalcWidgetBounds(WindowType aType, } LayoutDeviceIntRect nsView::CalcWidgetBounds( - const nsRect& aBounds, int32_t aAppUnitsPerDevPixel, nsView* aParentView, + const nsRect& aBounds, int32_t aAppUnitsPerDevPixel, nsIFrame* aParentFrame, nsIWidget* aThisWidget, WindowType aType, TransparencyMode aTransparency) { - auto viewBounds = - CalcWidgetViewBounds(aBounds, aAppUnitsPerDevPixel, aParentView, - aThisWidget, aType, aTransparency); + auto viewBounds = CalcWidgetViewBounds(aBounds, aAppUnitsPerDevPixel, + aParentFrame, aThisWidget, aType); return WidgetViewBoundsToDevicePixels(viewBounds, aAppUnitsPerDevPixel, aType, aTransparency); } @@ -310,16 +312,6 @@ void nsView::SetVisibility(ViewVisibility aVisibility) { NotifyEffectiveVisibilityChanged(IsEffectivelyVisible()); } -void nsView::InvalidateHierarchy() { - if (mViewManager->GetRootView() == this) { - mViewManager->InvalidateHierarchy(); - } - - for (nsView* child = mFirstChild; child; child = child->GetNextSibling()) { - child->InvalidateHierarchy(); - } -} - void nsView::InsertChild(nsView* aChild, nsView* aSibling) { MOZ_ASSERT(nullptr != aChild, "null ptr"); @@ -337,14 +329,6 @@ void nsView::InsertChild(nsView* aChild, nsView* aSibling) { mFirstChild = aChild; } aChild->SetParent(this); - - // If we just inserted a root view, then update the RootViewManager - // on all view managers in the new subtree. - - nsViewManager* vm = aChild->GetViewManager(); - if (vm->GetRootView() == aChild) { - aChild->InvalidateHierarchy(); - } } } @@ -370,14 +354,6 @@ void nsView::RemoveChild(nsView* child) { kid = kid->GetNextSibling(); } NS_ASSERTION(found, "tried to remove non child"); - - // If we just removed a root view, then update the RootViewManager - // on all view managers in the removed subtree. - - nsViewManager* vm = child->GetViewManager(); - if (vm->GetRootView() == child) { - child->InvalidateHierarchy(); - } } } @@ -546,32 +522,6 @@ nsPoint nsView::GetOffsetTo(const nsView* aOther, const int32_t aAPD) const { return offset; } -nsPoint nsView::GetOffsetToWidget(nsIWidget* aWidget) const { - nsPoint pt; - // Get the view for widget - nsView* widgetView = GetViewFor(aWidget); - if (!widgetView) { - return pt; - } - - // Get the offset to the widget view in the widget view's APD - // We get the offset in the widget view's APD first and then convert to our - // APD afterwards so that we can include the widget view's ViewToWidgetOffset - // in the sum in its native APD, and then convert the whole thing to our APD - // so that we don't have to convert the APD of the relatively small - // ViewToWidgetOffset by itself with a potentially large relative rounding - // error. - pt = -widgetView->GetOffsetTo(this); - // Add in the offset to the widget. - pt += widgetView->ViewToWidgetOffset(); - - // Convert to our appunits. - int32_t widgetAPD = widgetView->GetViewManager()->AppUnitsPerDevPixel(); - int32_t ourAPD = GetViewManager()->AppUnitsPerDevPixel(); - pt = pt.ScaleToOtherAppUnits(widgetAPD, ourAPD); - return pt; -} - nsIWidget* nsView::GetNearestWidget(nsPoint* aOffset) const { return GetNearestWidget(aOffset, GetViewManager()->AppUnitsPerDevPixel()); } diff --git a/view/nsView.h b/view/nsView.h @@ -205,15 +205,6 @@ class nsView final : public nsIWidgetListener { nsPoint GetOffsetTo(const nsView* aOther) const; /** - * Get the offset between the origin of |this| and the origin of aWidget. - * Adding the return value to a point in the coordinate system of |this| - * will transform the point to the coordinate system of aWidget. - * - * The offset is expressed in appunits of |this|. - */ - nsPoint GetOffsetToWidget(nsIWidget* aWidget) const; - - /** * Called to query the visibility state of a view. * @result current visibility state */ @@ -340,9 +331,9 @@ class nsView final : public nsIWidgetListener { bool IsRoot() const; static LayoutDeviceIntRect CalcWidgetBounds( - const nsRect& aBounds, int32_t aAppUnitsPerDevPixel, nsView* aParentView, - nsIWidget* aThisWidget, mozilla::widget::WindowType, - mozilla::widget::TransparencyMode); + const nsRect& aBounds, int32_t aAppUnitsPerDevPixel, + nsIFrame* aParentFrame, nsIWidget* aThisWidget, + mozilla::widget::WindowType, mozilla::widget::TransparencyMode); LayoutDeviceIntRect CalcWidgetBounds(mozilla::widget::WindowType, mozilla::widget::TransparencyMode); @@ -440,9 +431,6 @@ class nsView final : public nsIWidgetListener { void NotifyEffectiveVisibilityChanged(bool aEffectivelyVisible); - // Update the cached RootViewManager for all view manager descendents. - void InvalidateHierarchy(); - void CallOnAllRemoteChildren( const std::function<mozilla::CallState(mozilla::dom::BrowserParent*)>& aCallback); diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp @@ -69,13 +69,10 @@ nsViewManager::~nsViewManager() { mRootView = nullptr; } - mRootViewManager = nullptr; - MOZ_RELEASE_ASSERT(!mPresShell, "Releasing nsViewManager without having called Destroy on " "the PresShell!"); } - nsView* nsViewManager::CreateView(const nsRect& aBounds, nsView* aParent, ViewVisibility aVisibilityFlag) { auto* v = new nsView(this, aVisibilityFlag); @@ -93,18 +90,6 @@ void nsViewManager::SetRootView(nsView* aView) { // Do NOT destroy the current root view. It's the caller's responsibility // to destroy it mRootView = aView; - - if (mRootView) { - nsView* parent = mRootView->GetParent(); - if (parent) { - // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so - // no need to set mRootViewManager ourselves here. - parent->InsertChild(mRootView, nullptr); - } else { - InvalidateHierarchy(); - } - } - // Else don't touch mRootViewManager } void nsViewManager::GetWindowDimensions(nscoord* aWidth, nscoord* aHeight) { @@ -214,6 +199,25 @@ nsView* nsViewManager::GetDisplayRootFor(nsView* aView) { } } +nsViewManager* nsViewManager::RootViewManager() const { + const auto* cur = this; + while (auto* parent = cur->GetParentViewManager()) { + cur = parent; + } + return const_cast<nsViewManager*>(cur); +} + +nsViewManager* nsViewManager::GetParentViewManager() const { + if (!mPresShell) { + return nullptr; + } + auto* pc = mPresShell->GetPresContext(); + if (auto* parent = pc->GetParentPresContext()) { + return parent->PresShell()->GetViewManager(); + } + return nullptr; +} + /** aRegion is given in device coordinates!! aContext may be null, in which case layers should be used for @@ -529,7 +533,6 @@ bool nsViewManager::PaintWindow(nsIWidget* aWidget, if (!aWidget) { return false; } - // Get the view pointer here since NS_WILL_PAINT might have // destroyed it during CallWillPaintOnObservers (bug 378273). nsView* view = nsView::GetViewFor(aWidget); @@ -706,19 +709,6 @@ bool nsViewManager::IsViewInserted(nsView* aView) { return false; } -nsIWidget* nsViewManager::GetRootWidget() const { - if (!mRootView) { - return nullptr; - } - if (mRootView->HasWidget()) { - return mRootView->GetWidget(); - } - if (mRootView->GetParent()) { - return mRootView->GetParent()->GetViewManager()->GetRootWidget(); - } - return nullptr; -} - LayoutDeviceIntRect nsViewManager::ViewToWidget(nsView* aView, const nsRect& aRect) const { NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager"); @@ -795,16 +785,3 @@ void nsViewManager::CallWillPaintOnObservers() { } } } - -void nsViewManager::InvalidateHierarchy() { - if (mRootView) { - mRootViewManager = nullptr; - nsView* parent = mRootView->GetParent(); - if (parent) { - mRootViewManager = parent->GetViewManager()->RootViewManager(); - NS_ASSERTION(mRootViewManager != this, - "Root view had a parent, but it has the same view manager"); - } - // else, we are implicitly our own root view manager. - } -} diff --git a/view/nsViewManager.h b/view/nsViewManager.h @@ -204,12 +204,6 @@ class nsViewManager final { public: /** - * Retrieve the widget at the root of the nearest enclosing - * view manager whose root view has a widget. - */ - nsIWidget* GetRootWidget() const; - - /** * Indicate whether the viewmanager is currently painting * * @param aPainting true if the viewmanager is painting @@ -248,8 +242,6 @@ class nsViewManager final { private: static uint32_t gLastUserEventTime; - /* Update the cached RootViewManager pointer on this view manager. */ - void InvalidateHierarchy(); void FlushPendingInvalidates(); MOZ_CAN_RUN_SCRIPT @@ -296,11 +288,9 @@ class nsViewManager final { void SetPainting(bool aPainting) { RootViewManager()->mPainting = aPainting; } - nsViewManager* RootViewManager() const { - return mRootViewManager ? mRootViewManager.get() - : const_cast<nsViewManager*>(this); - } - bool IsRootVM() const { return !mRootViewManager; } + nsViewManager* RootViewManager() const; + nsViewManager* GetParentViewManager() const; + bool IsRootVM() const { return !GetParentViewManager(); } MOZ_CAN_RUN_SCRIPT void WillPaintWindow(nsIWidget* aWidget); MOZ_CAN_RUN_SCRIPT @@ -320,12 +310,6 @@ class nsViewManager final { nsView* mRootView; - // mRootViewManager is a strong reference to the root view manager, unless - // |this| is the root, in which case mRootViewManager is null. Callers - // should use RootViewManager() (which handles that case) rather than using - // mRootViewManager directly. - RefPtr<nsViewManager> mRootViewManager; - // The following members should not be accessed directly except by // the root view manager. Some have accessor functions to enforce // this, as noted. diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp @@ -26,9 +26,9 @@ #include "mozilla/TextEvents.h" #include "PuppetWidget.h" #include "nsContentUtils.h" +#include "nsView.h" #include "nsIWidgetListener.h" #include "imgIContainer.h" -#include "nsView.h" #include "nsXPLookAndFeel.h" #include "nsPrintfCString.h"