Bug 1516482 - part3 : reset user gesture activation flag when top level document changes. r=nika
authorAlastor Wu <alwu@mozilla.com>
Mon, 14 Jan 2019 23:21:05 +0000
changeset 513874 ea8b794f04d8a8c6db65be508d2b76bad32fbfad
parent 513873 da7cefd6569a863d4515b70616d0082e3debbfae
child 513875 63c3828351f0ad793bd8e58426ea5dcc1990aa76
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1516482
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1516482 - part3 : reset user gesture activation flag when top level document changes. r=nika As the user gesture activation flag is a flag which is used to reflect whether the corresponding document of browsing context has been activated by user or not, we should reset the flag when the top level window changes its document. Differential Revision: https://phabricator.services.mozilla.com/D16094
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
docshell/base/ChromeBrowsingContext.cpp
docshell/base/ChromeBrowsingContext.h
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/ipc/ContentParent.cpp
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -334,28 +334,52 @@ void BrowsingContext::NotifyUserGestureA
   if (!XRE_IsContentProcess()) {
     return;
   }
   auto cc = ContentChild::GetSingleton();
   MOZ_ASSERT(cc);
   cc->SendSetUserGestureActivation(BrowsingContextId(topLevelBC->Id()), true);
 }
 
+void BrowsingContext::NotifyResetUserGestureActivation() {
+  // We would reset the user gesture activation flag on the top level browsing
+  // context, which would automatically be sync to other top level browsing
+  // contexts which are in the different process.
+  RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
+  USER_ACTIVATION_LOG("Get top level browsing context 0x%08" PRIx64,
+                      topLevelBC->Id());
+  topLevelBC->ResetUserGestureActivation();
+
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
+  auto cc = ContentChild::GetSingleton();
+  MOZ_ASSERT(cc);
+  cc->SendSetUserGestureActivation(BrowsingContextId(topLevelBC->Id()), false);
+}
+
 void BrowsingContext::SetUserGestureActivation() {
   MOZ_ASSERT(!mParent, "Set user activation flag on non top-level context!");
   USER_ACTIVATION_LOG(
       "Set user gesture activation for browsing context 0x%08" PRIx64, Id());
   mIsActivatedByUserGesture = true;
 }
 
 bool BrowsingContext::GetUserGestureActivation() {
   RefPtr<BrowsingContext> topLevelBC = TopLevelBrowsingContext();
   return topLevelBC->mIsActivatedByUserGesture;
 }
 
+void BrowsingContext::ResetUserGestureActivation() {
+  MOZ_ASSERT(!mParent, "Clear user activation flag on non top-level context!");
+  USER_ACTIVATION_LOG(
+      "Reset user gesture activation for browsing context 0x%08" PRIx64, Id());
+  mIsActivatedByUserGesture = false;
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(BrowsingContext)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BrowsingContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell, mChildren, mParent)
   if (XRE_IsParentProcess()) {
     ChromeBrowsingContext::Cast(tmp)->Unlink();
   }
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -140,19 +140,24 @@ class BrowsingContext : public nsWrapper
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
   // This function would be called when its corresponding document is activated
   // by user gesture, and we would set the flag in the top level browsing
   // context.
   void NotifyUserGestureActivation();
 
-  // This function would only be called in the top level browsing context. It
-  // would set the user gesture activation flag.
+  // This function would be called when we want to reset the user gesture
+  // activation flag of the top level browsing context.
+  void NotifyResetUserGestureActivation();
+
+  // These functions would only be called in the top level browsing context.
+  // They would set/reset the user gesture activation flag.
   void SetUserGestureActivation();
+  void ResetUserGestureActivation();
 
   // Return true if it corresponding document is activated by user gesture.
   bool GetUserGestureActivation();
 
   // Return the window proxy object that corresponds to this browsing context.
   inline JSObject* GetWindowProxy() const { return mWindowProxy; }
   // Set the window proxy object that corresponds to this browsing context.
   void SetWindowProxy(JS::Handle<JSObject*> aWindowProxy) {
--- a/docshell/base/ChromeBrowsingContext.cpp
+++ b/docshell/base/ChromeBrowsingContext.cpp
@@ -95,25 +95,31 @@ void ChromeBrowsingContext::SetCurrentWi
   mCurrentWindowGlobal = aGlobal;
 }
 
 JSObject* ChromeBrowsingContext::WrapObject(JSContext* aCx,
                                             JS::Handle<JSObject*> aGivenProto) {
   return ChromeBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);
 }
 
-void ChromeBrowsingContext::NotifyUserGestureActivationFromIPC() {
+void ChromeBrowsingContext::NotifySetUserGestureActivationFromIPC(
+    bool aIsUserGestureActivation) {
   if (!mCurrentWindowGlobal) {
     return;
   }
 
-  SetUserGestureActivation();
+  if (aIsUserGestureActivation) {
+    SetUserGestureActivation();
+  } else {
+    ResetUserGestureActivation();
+  }
+
   USER_ACTIVATION_LOG("Chrome browsing context 0x%08" PRIx64
-                      " would notify other browsing contexts for setting "
-                      "user gesture activation.",
+                      " would notify other browsing contexts for updating "
+                      "user gesture activation flag.",
                       Id());
   // XXX(alwu) : we need to sync the flag to other browsing contexts which are
   // not in the same child process where the flag was set. Will implement that
   // in bug1519229.
 }
 
 void ChromeBrowsingContext::Traverse(nsCycleCollectionTraversalCallback& cb) {
   ChromeBrowsingContext* tmp = this;
--- a/docshell/base/ChromeBrowsingContext.h
+++ b/docshell/base/ChromeBrowsingContext.h
@@ -46,21 +46,23 @@ class ChromeBrowsingContext final : publ
   WindowGlobalParent* GetCurrentWindowGlobal() const {
     return mCurrentWindowGlobal;
   }
   void SetCurrentWindowGlobal(WindowGlobalParent* aGlobal);
 
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
-  // This function would set its user gesture activation flag and then notify
-  // other browsing contexts which are not the one related with the current
-  // window global to set the flag. (the corresponding browsing context of the
-  // current global window has been set before calling this function)
-  void NotifyUserGestureActivationFromIPC();
+  // This functions would set/reset its user gesture activation flag and then
+  // notify other browsing contexts which are not the one related with the
+  // current window global to set/reset the flag. (the corresponding browsing
+  // context of the current global window has been set/reset before calling this
+  // function)
+  void NotifySetUserGestureActivationFromIPC(bool aIsUserGestureActivation);
+
  protected:
   void Traverse(nsCycleCollectionTraversalCallback& cb);
   void Unlink();
 
   using Type = BrowsingContext::Type;
   ChromeBrowsingContext(BrowsingContext* aParent, BrowsingContext* aOpener,
                         const nsAString& aName, uint64_t aBrowsingContextId,
                         uint64_t aProcessId, Type aType = Type::Chrome);
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1594,16 +1594,24 @@ nsIScriptContext* nsGlobalWindowInner::G
 JSObject* nsGlobalWindowInner::GetGlobalJSObject() {
   return FastGetGlobalJSObject();
 }
 
 void nsGlobalWindowInner::TraceGlobalJSObject(JSTracer* aTrc) {
   TraceWrapper(aTrc, "active window global");
 }
 
+bool nsGlobalWindowInner::ShouldResetBrowsingContextUserGestureActivation() {
+  // Reset user gesture activation flag only when the top level document changes
+  // and its corresponding browsing context has been activated by user gesture.
+  return mWindowGlobalChild && GetOuterWindowInternal() &&
+         GetOuterWindowInternal()->IsTopLevelWindow() && Window() &&
+         Window()->GetUserGestureActivation();
+}
+
 nsresult nsGlobalWindowInner::SetNewDocument(Document* aDocument,
                                              nsISupports* aState,
                                              bool aForceReuseInnerWindow) {
   MOZ_ASSERT(mDocumentPrincipal == nullptr,
              "mDocumentPrincipal prematurely set!");
   MOZ_ASSERT(aDocument);
 
   if (!mOuterWindow) {
@@ -1647,16 +1655,20 @@ void nsGlobalWindowInner::InnerSetNewDoc
   // in the content process which does not have a corresponding TabChild actor.
   // This means we have no actor to be our parent. (Bug 1498293)
   MOZ_DIAGNOSTIC_ASSERT(!mWindowGlobalChild,
                         "Shouldn't have created WindowGlobalChild yet!");
   if (XRE_IsParentProcess() || mTabChild) {
     mWindowGlobalChild = WindowGlobalChild::Create(this);
   }
 
+  if (ShouldResetBrowsingContextUserGestureActivation()) {
+    Window()->NotifyResetUserGestureActivation();
+  }
+
 #ifdef DEBUG
   mLastOpenedURI = aDocument->GetDocumentURI();
 #endif
 
   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,
                         mMutationBits ? 1 : 0);
   Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_TEXT_EVENT_LISTENERS,
                         mMayHaveTextEventListenerInDefaultGroup ? 1 : 0);
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -1250,16 +1250,20 @@ class nsGlobalWindowInner final : public
   // checkpoint after that, and adds observer if new mDocumentFlushedResolvers
   // items are added while Promise callbacks inside the checkpoint.
   template <bool call>
   void CallOrCancelDocumentFlushedResolvers();
 
   void CallDocumentFlushedResolvers();
   void CancelDocumentFlushedResolvers();
 
+  // Return true if we need to notify browsing context to reset its user gesture
+  // activation flag.
+  bool ShouldResetBrowsingContextUserGestureActivation();
+
  public:
   // Dispatch a runnable related to the global.
   virtual nsresult Dispatch(mozilla::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsISerialEventTarget* EventTargetFor(
       mozilla::TaskCategory aCategory) const override;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5727,20 +5727,17 @@ mozilla::ipc::IPCResult ContentParent::R
 
   if (!context) {
     MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
             ("ParentIPC: Trying to activate wrong context 0x%08" PRIx64,
              (uint64_t)aContextId));
     return IPC_OK();
   }
 
-  if (aNewValue) {
-    context->NotifyUserGestureActivationFromIPC();
-  }
-
+  context->NotifySetUserGestureActivationFromIPC(aNewValue);
   return IPC_OK();
 }
 
 void ContentParent::RegisterRemoteWorkerActor() { ++mRemoteWorkerActors; }
 
 void ContentParent::UnregisterRemoveWorkerActor() {
   MOZ_ASSERT(NS_IsMainThread());