Bug 1409113 - Add nsIPresShell::HasHandledUserInput() r=masayuki draft
authorJames Willcox <snorp@snorp.net>
Tue, 21 Nov 2017 16:25:09 -0600
changeset 701998 44f8accc2cba57c4a0386fdb307b252dc81fce62
parent 701594 be242e4fdd19f11735c0c715f593c8d3225fa922
child 701999 b8c9c647f5a7c96646a0853cad8dfcd344a2c382
push id90336
push userbmo:snorp@snorp.net
push dateWed, 22 Nov 2017 15:03:48 +0000
reviewersmasayuki
bugs1409113
milestone59.0a1
Bug 1409113 - Add nsIPresShell::HasHandledUserInput() r=masayuki MozReview-Commit-ID: 3Yr5UmFJx5h
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsIPresShell.h
widget/BasicEvents.h
widget/WidgetEventImpl.cpp
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -798,16 +798,17 @@ PresShell::PresShell()
   , mAsyncResizeTimerIsActive(false)
   , mInResize(false)
   , mApproximateFrameVisibilityVisited(false)
   , mNextPaintCompressed(false)
   , mHasCSSBackgroundColor(false)
   , mScaleToResolution(false)
   , mIsLastChromeOnlyEscapeKeyConsumed(false)
   , mHasReceivedPaintMessage(false)
+  , mHasHandledUserInput(false)
 {
   MOZ_LOG(gLog, LogLevel::Debug, ("PresShell::PresShell this=%p", this));
 
 #ifdef MOZ_REFLOW_PERF
   mReflowCountMgr = new ReflowCountMgr();
   mReflowCountMgr->SetPresContext(mPresContext);
   mReflowCountMgr->SetPresShell(this);
 #endif
@@ -7648,16 +7649,20 @@ PresShell::HandleEventInternal(WidgetEve
       nsFocusManager* fm = nsFocusManager::GetFocusManager();
       if (fm) {
          fm->FlushBeforeEventHandlingIfNeeded(mCurrentEventContent);
       }
     }
 
     // XXX How about IME events and input events for plugins?
     if (aEvent->IsTrusted()) {
+      if (aEvent->IsUserAction()) {
+        mHasHandledUserInput = true;
+      }
+
       switch (aEvent->mMessage) {
       case eKeyPress:
       case eKeyDown:
       case eKeyUp: {
         nsIDocument* doc = GetCurrentEventContent() ?
                            mCurrentEventContent->OwnerDoc() : nullptr;
         auto keyCode = aEvent->AsKeyboardEvent()->mKeyCode;
         if (keyCode == NS_VK_ESCAPE) {
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -404,16 +404,20 @@ public:
 
   void SetNextPaintCompressed() { mNextPaintCompressed = true; }
 
   void NotifyStyleSheetServiceSheetAdded(mozilla::StyleSheet* aSheet,
                                          uint32_t aSheetType) override;
   void NotifyStyleSheetServiceSheetRemoved(mozilla::StyleSheet* aSheet,
                                            uint32_t aSheetType) override;
 
+  virtual bool HasHandledUserInput() const override {
+    return mHasHandledUserInput;
+  }
+
 protected:
   virtual ~PresShell();
 
   void HandlePostedReflowCallbacks(bool aInterruptible);
   void CancelPostedReflowCallbacks();
 
   void ScheduleBeforeFirstPaint();
   void UnsuppressAndInvalidate();
@@ -888,16 +892,19 @@ protected:
   // Whether the last chrome-only escape key event is consumed.
   bool                      mIsLastChromeOnlyEscapeKeyConsumed : 1;
 
   // Whether the widget has received a paint message yet.
   bool                      mHasReceivedPaintMessage : 1;
 
   bool                      mIsLastKeyDownCanceled : 1;
 
+  // Whether we have ever handled a user input event
+  bool                      mHasHandledUserInput : 1;
+
   static bool               sDisableNonTestMouseEvents;
 
   mozilla::TimeStamp        mLastOSWake;
 
   static mozilla::TimeStamp sLastInputCreated;
   static mozilla::TimeStamp sLastInputProcessed;
 
   static bool               sProcessInteractable;
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1567,16 +1567,21 @@ public:
    * specified level of the cascade is shared by multiple style sets.
    *
    * @param aSheetType One of the nsIStyleSheetService.*_SHEET constants.
    */
   nsresult HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
                                                    bool* aRetVal);
 
   /**
+   * Returns whether or not the document has ever handled user input
+   */
+  virtual bool HasHandledUserInput() const = 0;
+
+  /**
    * Refresh observer management.
    */
 protected:
   void DoObserveStyleFlushes();
   void DoObserveLayoutFlushes();
 
   /**
    * Does the actual work of figuring out the current state of font size
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -995,16 +995,18 @@ public:
     // nsVideoFrame may create anonymous image element which fires eLoad,
     // eLoadStart, eLoadEnd, eLoadError. We don't want these events cross
     // the boundary of NAC
     mFlags.mComposedInNativeAnonymousContent = mMessage != eLoad &&
                                                mMessage != eLoadStart &&
                                                mMessage != eLoadEnd &&
                                                mMessage != eLoadError;
   }
+
+  bool IsUserAction() const;
 };
 
 /******************************************************************************
  * mozilla::NativeEventData
  *
  * WidgetGUIEvent's mPluginEvent member used to be a void* pointer,
  * used to reference external, OS-specific data structures.
  *
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -536,16 +536,45 @@ WidgetEvent::PreventDefault(bool aCalled
         // Ignore the case that it's called by a web extension.
         return;
       }
     }
   }
   mFlags.PreventDefault(aCalledByDefaultHandler);
 }
 
+bool
+WidgetEvent::IsUserAction() const
+{
+  if (!IsTrusted()) {
+    return false;
+  }
+  // FYI: eMouseScrollEventClass and ePointerEventClass represent
+  //      user action but they are synthesized events.
+  switch (mClass) {
+    case eKeyboardEventClass:
+    case eCompositionEventClass:
+    case eMouseScrollEventClass:
+    case eWheelEventClass:
+    case eGestureNotifyEventClass:
+    case eSimpleGestureEventClass:
+    case eTouchEventClass:
+    case eCommandEventClass:
+    case eContentCommandEventClass:
+    case ePluginEventClass:
+      return true;
+    case eMouseEventClass:
+    case eDragEventClass:
+    case ePointerEventClass:
+      return AsMouseEvent()->IsReal();
+    default:
+      return false;
+  }
+}
+
 /******************************************************************************
  * mozilla::WidgetInputEvent
  ******************************************************************************/
 
 /* static */
 Modifier
 WidgetInputEvent::GetModifier(const nsAString& aDOMKeyName)
 {