Bug 636905 - part 1: add a flag that tracks whether the user has interacted with a given document, r?smaug draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Sat, 26 Sep 2015 14:54:29 +0100
changeset 296581 34dfcd3a8d5ff64cf9e3e5ae4d1af94b9ab0806b
parent 296350 8676dd9dde5fa512acf16d54bf0ef43ac3130509
child 296582 49bb57b9162bfa365e3c07589d107fd764e788a7
push id5861
push usergijskruitbosch@gmail.com
push dateSat, 26 Sep 2015 14:11:25 +0000
reviewerssmaug
bugs636905
milestone44.0a1
Bug 636905 - part 1: add a flag that tracks whether the user has interacted with a given document, r?smaug
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
@@ -1527,17 +1527,18 @@ nsIDocument::nsIDocument()
     // &&-ed in, this is safe.
     mAllowDNSPrefetch(true),
     mIsBeingUsedAsImage(false),
     mHasLinksToUpdate(false),
     mFontFaceSetDirty(true),
     mGetUserFontSetCalled(false),
     mPostedFlushUserFontSet(false),
     mPartID(0),
-    mDidFireDOMContentLoaded(true)
+    mDidFireDOMContentLoaded(true),
+    mUserHasInteracted(false)
 {
   SetInDocument();
 
   PR_INIT_CLIST(&mDOMMediaQueryLists);  
 }
 
 // NOTE! nsDocument::operator new() zeroes out all members, so don't
 // bother initializing members to 0.
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2597,16 +2597,26 @@ public:
   void SetDocumentAndPageUseCounter(mozilla::UseCounter aUseCounter)
   {
     SetDocumentUseCounter(aUseCounter);
     SetPageUseCounter(aUseCounter);
   }
 
   void PropagateUseCounters(nsIDocument* aParentDocument);
 
+  void SetUserHasInteracted(bool aUserHasInteracted)
+  {
+    mUserHasInteracted = aUserHasInteracted;
+  }
+
+  bool UserHasInteracted()
+  {
+    return mUserHasInteracted;
+  }
+
 protected:
   bool GetUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mUseCounters[aUseCounter];
   }
 
   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
@@ -3002,16 +3012,19 @@ protected:
 
   // Flags for use counters used directly by this document.
   std::bitset<mozilla::eUseCounter_Count> mUseCounters;
   // Flags for use counters used by any child documents of this document.
   std::bitset<mozilla::eUseCounter_Count> mChildDocumentUseCounters;
   // Flags for whether we've notified our top-level "page" of a use counter
   // for this child document.
   std::bitset<mozilla::eUseCounter_Count> mNotifiedPageForUseCounter;
+
+  // Whether the user has interacted with the document or not:
+  bool mUserHasInteracted;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -498,26 +498,42 @@ EventStateManager::PreHandleEvent(nsPres
   // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
   // a page when user is not active doesn't change the state to active.
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   if (aEvent->mFlags.mIsTrusted &&
       ((mouseEvent && mouseEvent->IsReal() &&
         mouseEvent->mMessage != eMouseEnterIntoWidget &&
         mouseEvent->mMessage != eMouseExitFromWidget) ||
        aEvent->mClass == eWheelEventClass ||
+       aEvent->mClass == ePointerEventClass ||
+       aEvent->mClass == eTouchEventClass ||
        aEvent->mClass == eKeyboardEventClass)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
         UpdateUserActivityTimer();
       }
     }
     ++gMouseOrKeyboardEventCounter;
+
+
+    nsCOMPtr<nsINode> node = do_QueryInterface(aTargetContent);
+    if (node &&
+        (aEvent->mMessage == eKeyUp || aEvent->mMessage == eMouseUp ||
+         aEvent->mMessage == eWheel || aEvent->mMessage == eTouchEnd ||
+         aEvent->mMessage == ePointerUp)) {
+      nsIDocument* doc = node->OwnerDoc();
+      while (doc && !doc->UserHasInteracted()) {
+        doc->SetUserHasInteracted(true);
+        doc = nsContentUtils::IsChildOfSameType(doc) ?
+          doc->GetParentDocument() : nullptr;
+      }
+    }
   }
 
   WheelTransaction::OnEvent(aEvent);
 
   // Focus events don't necessarily need a frame.
   if (!mCurrentTarget && !aTargetContent) {
     NS_ERROR("mCurrentTarget and aTargetContent are null");
     return NS_ERROR_NULL_POINTER;
--- a/dom/webidl/Document.webidl
+++ b/dom/webidl/Document.webidl
@@ -387,15 +387,21 @@ partial interface Document {
   /**
    * Removes the element inserted into the CanvasFrame given an AnonymousContent
    * instance.
    */
   [ChromeOnly, Throws]
   void removeAnonymousContent(AnonymousContent aContent);
 };
 
+// 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;
+};
+
 Document implements XPathEvaluator;
 Document implements GlobalEventHandlers;
 Document implements TouchEventHandlers;
 Document implements ParentNode;
 Document implements OnErrorEventHandlerForNodes;
 Document implements GeometryUtils;
 Document implements FontFaceSource;