diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 46f300494923c..dbd7b51f89bbb 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -32,6 +32,7 @@ using ScreenIntSize from "Units.h"; using struct mozilla::layers::FrameMetrics from "FrameMetrics.h"; using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h"; using struct mozilla::layers::ZoomConstraints from "FrameMetrics.h"; +using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h"; using FrameMetrics::ViewID from "FrameMetrics.h"; using struct mozilla::void_t from "ipc/IPCMessageUtils.h"; using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h"; @@ -446,8 +447,8 @@ parent: * The zoom controller code lives on the parent side and so this allows it to * have up-to-date zoom constraints. */ - UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId, bool aIsRoot, - ZoomConstraints aConstraints); + UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId, + MaybeZoomConstraints aConstraints); /** * Brings up the auth prompt dialog. diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 2a362f799c1b6..9441ddac0517a 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -321,8 +321,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize) ConvertScaleForRoot(viewportInfo.GetMaxZoom())); DoUpdateZoomConstraints(presShellId, viewId, - /* isRoot = */ true, - constraints); + Some(constraints)); } float screenW = GetInnerSize().width; @@ -484,8 +483,7 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize) ConvertScaleForRoot(viewportInfo.GetMaxZoom())); DoUpdateZoomConstraints(presShellId, viewId, - /* isRoot = */ true, - constraints); + Some(constraints)); } } @@ -1077,12 +1075,20 @@ TabChild::OnSecurityChange(nsIWebProgress* aWebProgress, bool TabChild::DoUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, - const bool& aIsRoot, - const ZoomConstraints& aConstraints) + const Maybe& aConstraints) { + ScrollableLayerGuid newGuid(0, aPresShellId, aViewId); + if (mLastZoomConstraintsGuid && newGuid != mLastZoomConstraintsGuid.value()) { + // The guid has changed, so clear the constraints we sent for the previous + // guid. + SendUpdateZoomConstraints(mLastZoomConstraintsGuid->mPresShellId, + mLastZoomConstraintsGuid->mScrollId, + mozilla::void_t()); + } + mLastZoomConstraintsGuid = Some(newGuid); + return SendUpdateZoomConstraints(aPresShellId, aViewId, - aIsRoot, aConstraints); } @@ -2806,6 +2812,11 @@ TabChild::RecvDestroy() mTabChildGlobal->DispatchTrustedEvent(NS_LITERAL_STRING("unload")); } + if (mLastZoomConstraintsGuid) { + DoUpdateZoomConstraints(mLastZoomConstraintsGuid->mPresShellId, + mLastZoomConstraintsGuid->mScrollId, + Nothing()); + } nsCOMPtr observerService = mozilla::services::GetObserverService(); diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index e960e91f56464..9901c5f6ed479 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -190,8 +190,7 @@ class TabChildBase : public nsISupports, bool HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize); virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId, const mozilla::layers::FrameMetrics::ViewID& aViewId, - const bool& aIsRoot, - const mozilla::layers::ZoomConstraints& aConstraints) = 0; + const Maybe& aConstraints) = 0; virtual ScreenIntSize GetInnerSize() = 0; @@ -311,8 +310,7 @@ class TabChild final : public TabChildBase, nsIPrincipal* aPrincipal) override; virtual bool DoUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, - const bool& aIsRoot, - const ZoomConstraints& aConstraints) override; + const Maybe& aConstraints) override; virtual bool RecvLoadURL(const nsCString& aURI, const BrowserConfiguration& aConfiguration) override; virtual bool RecvCacheFileDescriptor(const nsString& aPath, @@ -660,6 +658,7 @@ class TabChild final : public TabChildBase, bool mParentIsActive; bool mAsyncPanZoomEnabled; CSSSize mUnscaledInnerSize; + Maybe mLastZoomConstraintsGuid; DISALLOW_EVIL_CONSTRUCTORS(TabChild); }; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 6723f96b7d68b..924f945536d02 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2740,11 +2740,10 @@ TabParent::RecvZoomToRect(const uint32_t& aPresShellId, bool TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, - const bool& aIsRoot, - const ZoomConstraints& aConstraints) + const MaybeZoomConstraints& aConstraints) { if (RenderFrameParent* rfp = GetRenderFrame()) { - rfp->UpdateZoomConstraints(aPresShellId, aViewId, aIsRoot, aConstraints); + rfp->UpdateZoomConstraints(aPresShellId, aViewId, aConstraints); } return true; } diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index e4e2d90c27494..ff47eeb32923b 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -222,8 +222,7 @@ class TabParent final : public PBrowserParent const CSSRect& aRect) override; virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId, const ViewID& aViewId, - const bool& aIsRoot, - const ZoomConstraints& aConstraints) override; + const MaybeZoomConstraints& aConstraints) override; virtual bool RecvContentReceivedInputBlock(const ScrollableLayerGuid& aGuid, const uint64_t& aInputBlockId, const bool& aPreventDefault) override; diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index d5cf7af8bbdc0..ef335a4f4d0e6 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -866,6 +866,8 @@ struct ZoomConstraints { } }; +typedef Maybe MaybeZoomConstraints; + } } diff --git a/gfx/layers/LayersLogging.cpp b/gfx/layers/LayersLogging.cpp index 55c2af4db41bb..6f25b08383063 100644 --- a/gfx/layers/LayersLogging.cpp +++ b/gfx/layers/LayersLogging.cpp @@ -217,6 +217,15 @@ AppendToString(std::stringstream& aStream, const ScrollableLayerGuid& s, << sfx; } +void +AppendToString(std::stringstream& aStream, const ZoomConstraints& z, + const char* pfx, const char* sfx) +{ + aStream << pfx + << nsPrintfCString("{ z=%d dt=%d min=%f max=%f }", z.mAllowZoom, z.mAllowDoubleTapZoom, z.mMinZoom.scale, z.mMaxZoom.scale).get() + << sfx; +} + void AppendToString(std::stringstream& aStream, const Matrix& m, const char* pfx, const char* sfx) diff --git a/gfx/layers/LayersLogging.h b/gfx/layers/LayersLogging.h index ba1341669ef7f..648cd3ba412a1 100644 --- a/gfx/layers/LayersLogging.h +++ b/gfx/layers/LayersLogging.h @@ -130,6 +130,10 @@ void AppendToString(std::stringstream& aStream, const ScrollableLayerGuid& s, const char* pfx="", const char* sfx=""); +void +AppendToString(std::stringstream& aStream, const ZoomConstraints& z, + const char* pfx="", const char* sfx=""); + template void AppendToString(std::stringstream& aStream, const mozilla::gfx::MarginTyped& m, diff --git a/gfx/layers/apz/public/GeckoContentController.h b/gfx/layers/apz/public/GeckoContentController.h index 79db6c805d109..bd1e303e8be3f 100644 --- a/gfx/layers/apz/public/GeckoContentController.h +++ b/gfx/layers/apz/public/GeckoContentController.h @@ -90,16 +90,6 @@ class GeckoContentController */ virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0; - /** - * Retrieves the last known zoom constraints for the root scrollable layer - * for this layers tree. This function should return false if there are no - * last known zoom constraints. - */ - virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints) - { - return false; - } - /** * APZ uses |FrameMetrics::mCompositionBounds| for hit testing. Sometimes, * widget code has knowledge of a touch-sensitive region that should diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 1fcd069ab449f..4e549e4b78d11 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -322,6 +322,8 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, HitTestingTreeNode* aNextSibling, TreeBuildingState& aState) { + mTreeLock.AssertCurrentThreadOwns(); + bool needsApzc = true; if (!aMetrics.IsScrollable()) { needsApzc = false; @@ -464,22 +466,18 @@ APZCTreeManager::PrepareNodeForLayer(const LayerMetricsWrapper& aLayer, } if (newApzc) { - if (apzc->IsRootContent()) { - // If we just created a new root-content apzc, then we need to update - // its zoom constraints which might have arrived before it was created. - ZoomConstraints constraints; - if (state->mController->GetRootZoomConstraints(&constraints)) { - apzc->UpdateZoomConstraints(constraints); - } + auto it = mZoomConstraints.find(guid); + if (it != mZoomConstraints.end()) { + // We have a zoomconstraints for this guid, apply it. + apzc->UpdateZoomConstraints(it->second); } else if (!apzc->HasNoParentWithSameLayersId()) { - // Otherwise, an APZC that has a parent in the same layer tree gets - // the same zoom constraints as its parent. This ensures that if e.g. - // user-scalable=no was specified on the root, none of the APZCs allow - // double-tap to zoom. + // This is a sub-APZC, so inherit the zoom constraints from its parent. + // This ensures that if e.g. user-scalable=no was specified, none of the + // APZCs for that subtree allow double-tap to zoom. apzc->UpdateZoomConstraints(apzc->GetParent()->GetZoomConstraints()); } - // Otherwise, if the APZC has no parent in the same layer tree, leave - // it with the existing zoom constraints. + // Otherwise, this is the root of a layers id, but we didn't have a saved + // zoom constraints. Leave it empty for now. } // Add a guid -> APZC mapping for the newly created APZC. @@ -1028,16 +1026,24 @@ APZCTreeManager::SetTargetAPZC(uint64_t aInputBlockId, const ScrollableLayerGuid void APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid, - const ZoomConstraints& aConstraints) + const Maybe& aConstraints) { MonitorAutoLock lock(mTreeLock); nsRefPtr node = GetTargetNode(aGuid, nullptr); MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC - // For a given layers id, non-{root content} APZCs inherit the zoom constraints - // of their root. - if (node && node->GetApzc()->IsRootContent()) { - UpdateZoomConstraintsRecursively(node.get(), aConstraints); + // Propagate the zoom constraints down to the subtree, stopping at APZCs + // which have their own zoom constraints or are in a different layers id. + if (aConstraints) { + APZCTM_LOG("Recording constraints %s for guid %s\n", + Stringify(aConstraints.value()).c_str(), Stringify(aGuid).c_str()); + mZoomConstraints[aGuid] = aConstraints.value(); + } else { + APZCTM_LOG("Removing constraints for guid %s\n", Stringify(aGuid).c_str()); + mZoomConstraints.erase(aGuid); + } + if (node && aConstraints) { + UpdateZoomConstraintsRecursively(node.get(), aConstraints.ref()); } } @@ -1052,9 +1058,13 @@ APZCTreeManager::UpdateZoomConstraintsRecursively(HitTestingTreeNode* aNode, aNode->GetApzc()->UpdateZoomConstraints(aConstraints); } for (HitTestingTreeNode* child = aNode->GetLastChild(); child; child = child->GetPrevSibling()) { - // We can have subtrees with their own layers id - leave those alone. - if (child->GetApzc() && child->GetApzc()->HasNoParentWithSameLayersId()) { - continue; + if (AsyncPanZoomController* childApzc = child->GetApzc()) { + // We can have subtrees with their own zoom constraints or separate layers + // id - leave those alone. + if (childApzc->HasNoParentWithSameLayersId() || + mZoomConstraints.find(childApzc->GetGuid()) != mZoomConstraints.end()) { + continue; + } } UpdateZoomConstraintsRecursively(child, aConstraints); } diff --git a/gfx/layers/apz/src/APZCTreeManager.h b/gfx/layers/apz/src/APZCTreeManager.h index daa569c9aa290..35935f523b90d 100644 --- a/gfx/layers/apz/src/APZCTreeManager.h +++ b/gfx/layers/apz/src/APZCTreeManager.h @@ -236,9 +236,11 @@ class APZCTreeManager { /** * Updates any zoom constraints contained in the tag. + * If the |aConstraints| is Nothing() then previously-provided constraints for + * the given |aGuid| are cleared. */ void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid, - const ZoomConstraints& aConstraints); + const Maybe& aConstraints); /** * Cancels any currently running animation. Note that all this does is set the @@ -487,10 +489,14 @@ class APZCTreeManager { * isolation (that is, if its tree pointers are not being accessed or mutated). The * lock also needs to be held when accessing the mRootNode instance variable, as that * is considered part of the APZC tree management state. - * Finally, the lock needs to be held when accessing mOverscrollHandoffChain. + * Finally, the lock needs to be held when accessing mZoomConstraints. * IMPORTANT: See the note about lock ordering at the top of this file. */ mutable mozilla::Monitor mTreeLock; nsRefPtr mRootNode; + /* Holds the zoom constraints for scrollable layers, as determined by the + * the main-thread gecko code. */ + std::map mZoomConstraints; + /* This tracks the APZC that should receive all inputs for the current input event block. * This allows touch points to move outside the thing they started on, but still have the * touch events delivered to the same initial APZC. This will only ever be touched on the diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index c15e64e53758f..5d0ed9d1aa56e 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -89,7 +89,6 @@ class RemoteContentController : public GeckoContentController { explicit RemoteContentController(RenderFrameParent* aRenderFrame) : mUILoop(MessageLoop::current()) , mRenderFrame(aRenderFrame) - , mHaveZoomConstraints(false) { } virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override @@ -222,14 +221,6 @@ class RemoteContentController : public GeckoContentController { MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs); } - virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints) override - { - if (mHaveZoomConstraints && aOutConstraints) { - *aOutConstraints = mZoomConstraints; - } - return mHaveZoomConstraints; - } - virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) override { if (mTouchSensitiveRegion.IsEmpty()) @@ -272,12 +263,6 @@ class RemoteContentController : public GeckoContentController { // Methods used by RenderFrameParent to set fields stored here. - void SaveZoomConstraints(const ZoomConstraints& aConstraints) - { - mHaveZoomConstraints = true; - mZoomConstraints = aConstraints; - } - void SetTouchSensitiveRegion(const nsRegion& aRegion) { mTouchSensitiveRegion = aRegion; @@ -286,8 +271,6 @@ class RemoteContentController : public GeckoContentController { MessageLoop* mUILoop; RenderFrameParent* mRenderFrame; - bool mHaveZoomConstraints; - ZoomConstraints mZoomConstraints; nsRegion mTouchSensitiveRegion; }; @@ -578,12 +561,8 @@ RenderFrameParent::SetAllowedTouchBehavior(uint64_t aInputBlockId, void RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId, - bool aIsRoot, - const ZoomConstraints& aConstraints) + const Maybe& aConstraints) { - if (mContentController && aIsRoot) { - mContentController->SaveZoomConstraints(aConstraints); - } if (GetApzcTreeManager()) { GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId), aConstraints); diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h index 64abba21db12b..aeee3f573f6c5 100644 --- a/layout/ipc/RenderFrameParent.h +++ b/layout/ipc/RenderFrameParent.h @@ -93,8 +93,7 @@ class RenderFrameParent : public PRenderFrameParent void UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId, - bool aIsRoot, - const ZoomConstraints& aConstraints); + const Maybe& aConstraints); bool HitTest(const nsRect& aRect);