diff --git a/dom/ipc/BrowserBridgeChild.cpp b/dom/ipc/BrowserBridgeChild.cpp index ddd68d09cc51..c8fd9f564e1e 100644 --- a/dom/ipc/BrowserBridgeChild.cpp +++ b/dom/ipc/BrowserBridgeChild.cpp @@ -13,8 +13,10 @@ #include "nsFocusManager.h" #include "nsFrameLoader.h" #include "nsFrameLoaderOwner.h" -#include "nsQueryObject.h" #include "nsIDocShellTreeOwner.h" +#include "nsQueryObject.h" +#include "nsSubDocumentFrame.h" +#include "nsView.h" using namespace mozilla::ipc; @@ -159,6 +161,38 @@ mozilla::ipc::IPCResult BrowserBridgeChild::RecvFireFrameLoadEvent( return IPC_OK(); } +mozilla::ipc::IPCResult BrowserBridgeChild::RecvScrollRectIntoView( + const nsRect& aRect, const ScrollAxis& aVertical, + const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags, + const int32_t& aAppUnitsPerDevPixel) { + RefPtr owner = mFrameLoader->GetOwnerContent(); + if (!owner) { + return IPC_OK(); + } + + nsIFrame* frame = owner->GetPrimaryFrame(); + if (!frame) { + return IPC_OK(); + } + + nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(frame); + if (!subdocumentFrame) { + return IPC_OK(); + } + + nsPoint extraOffset = subdocumentFrame->GetExtraOffset(); + + int32_t parentAPD = frame->PresContext()->AppUnitsPerDevPixel(); + nsRect rect = + aRect.ScaleToOtherAppUnitsRoundOut(aAppUnitsPerDevPixel, parentAPD); + rect += extraOffset; + RefPtr presShell = frame->PresShell(); + presShell->ScrollFrameRectIntoView(frame, rect, aVertical, aHorizontal, + aScrollFlags); + + return IPC_OK(); +} + void BrowserBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { mIPCOpen = false; } diff --git a/dom/ipc/BrowserBridgeChild.h b/dom/ipc/BrowserBridgeChild.h index a9a22db4eebe..191f698003bf 100644 --- a/dom/ipc/BrowserBridgeChild.h +++ b/dom/ipc/BrowserBridgeChild.h @@ -85,6 +85,12 @@ class BrowserBridgeChild : public PBrowserBridgeChild { mozilla::ipc::IPCResult RecvFireFrameLoadEvent(bool aIsTrusted); + MOZ_CAN_RUN_SCRIPT_BOUNDARY + mozilla::ipc::IPCResult RecvScrollRectIntoView( + const nsRect& aRect, const ScrollAxis& aVertical, + const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags, + const int32_t& aAppUnitsPerDevPixel); + void ActorDestroy(ActorDestroyReason aWhy) override; private: diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp index 715589452f14..3943b92fdb19 100644 --- a/dom/ipc/BrowserParent.cpp +++ b/dom/ipc/BrowserParent.cpp @@ -3797,6 +3797,20 @@ mozilla::ipc::IPCResult BrowserParent::RecvFireFrameLoadEvent(bool aIsTrusted) { return IPC_OK(); } +mozilla::ipc::IPCResult BrowserParent::RecvScrollRectIntoView( + const nsRect& aRect, const ScrollAxis& aVertical, + const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags, + const int32_t& aAppUnitsPerDevPixel) { + BrowserBridgeParent* bridge = GetBrowserBridgeParent(); + if (!bridge || !bridge->CanSend()) { + return IPC_OK(); + } + + Unused << bridge->SendScrollRectIntoView(aRect, aVertical, aHorizontal, + aScrollFlags, aAppUnitsPerDevPixel); + return IPC_OK(); +} + NS_IMETHODIMP FakeChannel::OnAuthAvailable(nsISupports* aContext, nsIAuthInformation* aAuthInfo) { diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h index eab66389ce60..d5fa4d17ea9b 100644 --- a/dom/ipc/BrowserParent.h +++ b/dom/ipc/BrowserParent.h @@ -447,6 +447,11 @@ class BrowserParent final : public PBrowserParent, mozilla::ipc::IPCResult RecvDispatchKeyboardEvent( const mozilla::WidgetKeyboardEvent& aEvent); + mozilla::ipc::IPCResult RecvScrollRectIntoView( + const nsRect& aRect, const ScrollAxis& aVertical, + const ScrollAxis& aHorizontal, const ScrollFlags& aScrollFlags, + const int32_t& aAppUnitsPerDevPixel); + PColorPickerParent* AllocPColorPickerParent(const nsString& aTitle, const nsString& aInitialColor); diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index c4551bf80e2e..701a0c9a3d6c 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -89,6 +89,8 @@ using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h"; using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h"; using mozilla::dom::EffectsInfo from "mozilla/dom/TabMessageUtils.h"; using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h"; +using mozilla::ScrollAxis from "mozilla/PresShellForwards.h"; +using mozilla::ScrollFlags from "mozilla/PresShellForwards.h"; namespace mozilla { namespace dom { @@ -693,6 +695,10 @@ parent: */ async FireFrameLoadEvent(bool aIsTrusted); + async ScrollRectIntoView(nsRect aRect, ScrollAxis aVertical, + ScrollAxis aHorizontal, ScrollFlags aScrollFlags, + int32_t aAppUnitsPerDevPixel); + child: /** * Notify the remote browser that it has been Show()n on this diff --git a/dom/ipc/PBrowserBridge.ipdl b/dom/ipc/PBrowserBridge.ipdl index fe03f489c1c4..b6d011b077b3 100644 --- a/dom/ipc/PBrowserBridge.ipdl +++ b/dom/ipc/PBrowserBridge.ipdl @@ -16,6 +16,9 @@ using mozilla::layers::LayersId from "mozilla/layers/LayersTypes.h"; using mozilla::WidgetMouseEvent from "ipc/nsGUIEventIPC.h"; using mozilla::a11y::IDispatchHolder from "mozilla/a11y/IPCTypes.h"; using mozilla::dom::EffectsInfo from "mozilla/dom/TabMessageUtils.h"; +using mozilla::ScrollAxis from "mozilla/PresShellForwards.h"; +using mozilla::ScrollFlags from "mozilla/PresShellForwards.h"; +using struct nsRect from "nsRect.h"; namespace mozilla { namespace dom { @@ -56,6 +59,10 @@ child: */ async FireFrameLoadEvent(bool aIsTrusted); + async ScrollRectIntoView(nsRect aRect, ScrollAxis aVertical, + ScrollAxis aHorizontal, ScrollFlags aScrollFlags, + int32_t aAppUnitsPerDevPixel); + parent: // Destroy the remote web browser due to the nsFrameLoader going away. async __delete__(); diff --git a/dom/ipc/TabMessageUtils.h b/dom/ipc/TabMessageUtils.h index f058c1ce13eb..1e4dc59756df 100644 --- a/dom/ipc/TabMessageUtils.h +++ b/dom/ipc/TabMessageUtils.h @@ -17,6 +17,7 @@ #include "mozilla/dom/EffectsInfo.h" #include "mozilla/layers/LayersMessageUtils.h" #include "ipc/IPCMessageUtils.h" +#include "X11UndefineNone.h" namespace mozilla { namespace dom { @@ -94,6 +95,48 @@ struct ParamTraits { } }; +template <> +struct ParamTraits + : public ContiguousEnumSerializerInclusive< + mozilla::WhenToScroll, mozilla::WhenToScroll::Always, + mozilla::WhenToScroll::IfNotFullyVisible> {}; + +template <> +struct ParamTraits + : public BitFlagsEnumSerializer {}; + +template <> +struct ParamTraits { + typedef mozilla::ScrollAxis paramType; + + static void Write(Message* aMsg, const paramType& aParam) { + WriteParam(aMsg, aParam.mWhereToScroll); + WriteParam(aMsg, aParam.mWhenToScroll); + WriteParam(aMsg, aParam.mOnlyIfPerceivedScrollableDirection); + } + + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + if (!ReadParam(aMsg, aIter, &aResult->mWhereToScroll)) { + return false; + } + if (!ReadParam(aMsg, aIter, &aResult->mWhenToScroll)) { + return false; + } + + // We can't set mOnlyIfPerceivedScrollableDirection directly since it's + // a bitfield. + bool value; + if (!ReadParam(aMsg, aIter, &value)) { + return false; + } + aResult->mOnlyIfPerceivedScrollableDirection = value; + + return true; + } +}; + } // namespace IPC #endif // TABMESSAGE_UTILS_H diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index c47536479e69..664527f68876 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -3616,12 +3616,20 @@ bool PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame, const nsRect& aRect, } if (!parent && !(aScrollFlags & ScrollFlags::ScrollNoParentFrames)) { nsPoint extraOffset(0, 0); + int32_t APD = container->PresContext()->AppUnitsPerDevPixel(); parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset); if (parent) { - int32_t APD = container->PresContext()->AppUnitsPerDevPixel(); int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel(); rect = rect.ScaleToOtherAppUnitsRoundOut(APD, parentAPD); rect += extraOffset; + } else { + nsCOMPtr docShell = + container->PresContext()->GetDocShell(); + if (BrowserChild* browserChild = BrowserChild::GetFrom(docShell)) { + // Defer to the parent document if this is an out-of-process iframe. + Unused << browserChild->SendScrollRectIntoView( + rect, aVertical, aHorizontal, aScrollFlags, APD); + } } } container = parent; diff --git a/layout/base/PresShellForwards.h b/layout/base/PresShellForwards.h index 089d8f710252..2c4252684e69 100644 --- a/layout/base/PresShellForwards.h +++ b/layout/base/PresShellForwards.h @@ -151,6 +151,7 @@ enum class ScrollFlags { IgnoreMarginAndPadding = 1 << 6, // ScrollOverflowHidden | ScrollNoParentFrames AnchorScrollFlags = (1 << 1) | (1 << 2), + ALL_BITS = (1 << 7) - 1, }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ScrollFlags) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index a08d7b4380cc..2221f477d35e 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1600,17 +1600,31 @@ nsIFrame* nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) { nsIFrame* nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame, nsPoint* aExtraOffset) { nsIFrame* p = aFrame->GetParent(); - if (p) return p; + if (p) { + return p; + } nsView* v = aFrame->GetView(); - if (!v) return nullptr; + if (!v) { + return nullptr; + } v = v->GetParent(); // anonymous inner view - if (!v) return nullptr; - if (aExtraOffset) { - *aExtraOffset += v->GetPosition(); + if (!v) { + return nullptr; } v = v->GetParent(); // subdocumentframe's view - return v ? v->GetFrame() : nullptr; + if (!v) { + return nullptr; + } + + p = v->GetFrame(); + if (p && aExtraOffset) { + nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(p); + MOZ_ASSERT(subdocumentFrame); + *aExtraOffset += subdocumentFrame->GetExtraOffset(); + } + + return p; } // static diff --git a/layout/generic/moz.build b/layout/generic/moz.build index 5f655b62afa2..9635e02955cc 100644 --- a/layout/generic/moz.build +++ b/layout/generic/moz.build @@ -92,6 +92,7 @@ with Files('nsVideoFrame.*'): BUG_COMPONENT = ('Core', 'Audio/Video') EXPORTS += [ + 'nsAtomicContainerFrame.h', 'nsCanvasFrame.h', 'nsContainerFrame.h', 'nsDirection.h', diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 8b6df641675d..aa6115dc8b2d 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -1285,6 +1285,11 @@ nsView* nsSubDocumentFrame::EnsureInnerView() { return mInnerView; } +nsPoint nsSubDocumentFrame::GetExtraOffset() const { + MOZ_ASSERT(mInnerView); + return mInnerView->GetPosition(); +} + nsIFrame* nsSubDocumentFrame::ObtainIntrinsicSizeFrame() { if (StyleDisplay()->IsContainSize()) { // Intrinsic size of 'contain:size' replaced elements is 0,0. So, don't use diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h index dc43097d4feb..139b10250806 100644 --- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -96,6 +96,7 @@ class nsSubDocumentFrame final : public nsAtomicContainerFrame, nsresult BeginSwapDocShells(nsIFrame* aOther); void EndSwapDocShells(nsIFrame* aOther); nsView* EnsureInnerView(); + nsPoint GetExtraOffset() const; nsIFrame* GetSubdocumentRootFrame(); enum { IGNORE_PAINT_SUPPRESSION = 0x1 }; mozilla::PresShell* GetSubdocumentPresShellForPainting(uint32_t aFlags);