Bug 1428722 - part2 : move all user-activation implementation details to nsDocument. draft
authorAlastor Wu <alwu@mozilla.com>
Thu, 11 Jan 2018 17:26:30 +0800
changeset 720213 088dfff9856d86b4ec4d41269f21736b3b6cec35
parent 720212 45addc47ae092f06863cfcfc6e6da411ec02c84e
child 720214 7c8f71b8f0ea8854b69ed83f4d76ba4366d32485
push id95482
push userbmo:alwu@mozilla.com
push dateMon, 15 Jan 2018 03:52:14 +0000
bugs1428722
milestone59.0a1
Bug 1428722 - part2 : move all user-activation implementation details to nsDocument. In order to write tests, I would like to create an method that allows chorome js can directly set the user-activation flag. Therefore, I need to move all these details into nsDocument, then we could easily simulate the user activation. MozReview-Commit-ID: 5JrCoQc0vF7
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/events/EventStateManager.cpp
dom/webidl/Document.webidl
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -13271,33 +13271,46 @@ void
 nsIDocument::SetUserHasInteracted(bool aUserHasInteracted)
 {
   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug,
           ("Document %p has been interacted by user.", this));
   mUserHasInteracted = aUserHasInteracted;
 }
 
 void
-nsIDocument::MaybeNotifyUserActivation(nsIPrincipal* aPrincipal)
+nsIDocument::NotifyUserActivation()
+{
+  ActivateByUserGesture();
+  // Activate parent document which has same principle on the parent chain.
+  nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
+  nsCOMPtr<nsIDocument> parent = GetSameTypeParentDocument();
+  while (parent) {
+    parent->MaybeActivateByUserGesture(principal);
+    parent = parent->GetSameTypeParentDocument();
+  }
+}
+
+void
+nsIDocument::MaybeActivateByUserGesture(nsIPrincipal* aPrincipal)
 {
   bool isEqual = false;
   nsresult rv = aPrincipal->Equals(NodePrincipal(), &isEqual);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   // If a child frame is actived, it would always activate the top frame and its
   // parent frames which has same priciple.
   if (isEqual || IsTopLevelContentDocument()) {
-    NotifyUserActivation();
-  }
-}
-
-void
-nsIDocument::NotifyUserActivation()
+    ActivateByUserGesture();
+  }
+}
+
+void
+nsIDocument::ActivateByUserGesture()
 {
   if (mUserHasActivatedInteraction) {
     return;
   }
 
   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug,
           ("Document %p has been activated by user.", this));
   mUserHasActivatedInteraction = true;
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3066,31 +3066,23 @@ public:
   }
 
   void SetUserHasInteracted(bool aUserHasInteracted);
   bool UserHasInteracted()
   {
     return mUserHasInteracted;
   }
 
-  // This would be called when document get activated by specific user gestures.
+  // This would be called when document get activated by specific user gestures
+  // and propagate the user activation flag to its parent.
   void NotifyUserActivation();
 
   // Return true if document has interacted by specific user gestures.
   bool HasBeenUserActivated();
 
-  void MaybeNotifyUserActivation(nsIPrincipal* aPrincipal);
-
-  // Return the same type parent docuement if exists, or return null.
-  nsIDocument* GetSameTypeParentDocument();
-
-  // Return the first parent document with same pricipal, return nullptr if we
-  // can't find it.
-  nsIDocument* GetFirstParentDocumentWithSamePrincipal(nsIPrincipal* aPrincipal);
-
   bool HasScriptsBlockedBySandbox();
 
   bool InlineScriptAllowedByCSP();
 
   void ReportHasScrollLinkedEffect();
   bool HasScrollLinkedEffect() const
   {
     return mHasScrollLinkedEffect;
@@ -3271,16 +3263,27 @@ protected:
   // mFrameRequestCallbacksScheduled.  aOldShell should only be passed when
   // mPresShell is becoming null; in that case it will be used to get hold of
   // the relevant refresh driver.
   void UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell = nullptr);
 
   // Helper for GetScrollingElement/IsScrollingElement.
   bool IsPotentiallyScrollable(mozilla::dom::HTMLBodyElement* aBody);
 
+  // Return the same type parent docuement if exists, or return null.
+  nsIDocument* GetSameTypeParentDocument();
+
+  // Return the first parent document with same pricipal, return nullptr if we
+  // can't find it.
+  nsIDocument* GetFirstParentDocumentWithSamePrincipal(nsIPrincipal* aPrincipal);
+
+  // Activate the flag 'mUserHasActivatedInteraction' by specific user gestures.
+  void ActivateByUserGesture();
+  void MaybeActivateByUserGesture(nsIPrincipal* aPrincipal);
+
   // Helpers for GetElementsByName.
   static bool MatchNameAttribute(mozilla::dom::Element* aElement,
                                  int32_t aNamespaceID,
                                  nsAtom* aAtom, void* aData);
   static void* UseExistingNameString(nsINode* aRootNode, const nsString* aName);
 
   nsCString mReferrer;
   nsString mLastModified;
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -917,24 +917,16 @@ EventStateManager::NotifyTargetUserActiv
   if (!doc || doc->HasBeenUserActivated()) {
     return;
   }
 
   MOZ_ASSERT(aEvent->mMessage == eKeyUp   ||
              aEvent->mMessage == eMouseUp ||
              aEvent->mMessage == eTouchEnd);
   doc->NotifyUserActivation();
-
-  // Activate parent document which has same principle on the parent chain.
-  nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
-  nsCOMPtr<nsIDocument> parent = doc->GetSameTypeParentDocument();
-  while (parent) {
-    parent->MaybeNotifyUserActivation(principal);
-    parent = parent->GetSameTypeParentDocument();
-  }
 }
 
 void
 EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
 {
   switch (aEvent->mMessage) {
     case eQuerySelectedText:
     case eQueryTextContent:
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -440,16 +440,23 @@ partial interface Document {
 };
 
 // Extension to give chrome JS the ability to determine whether
 // the user has interacted with the document or not.
 partial interface Document {
   [ChromeOnly] readonly attribute boolean userHasInteracted;
 };
 
+// Extension to give chrome JS the ability to simulate activate the docuement
+// by user gesture.
+partial interface Document {
+  [ChromeOnly]
+  void notifyUserActivation();
+};
+
 // Extension to give chrome and XBL JS the ability to determine whether
 // the document is sandboxed without permission to run scripts
 // and whether inline scripts are blocked by the document's CSP.
 partial interface Document {
   [Func="IsChromeOrXBL"] readonly attribute boolean hasScriptsBlockedBySandbox;
   [Func="IsChromeOrXBL"] readonly attribute boolean inlineScriptAllowedByCSP;
 };