Bug 1385071 - Allow keyboard APZ with passive listeners, behind a pref. r?kats draft
authorRyan Hunt <rhunt@eqrion.net>
Thu, 27 Jul 2017 19:53:57 -0400
changeset 617124 179769747c8fe8e1c04234884628df2c56352134
parent 617123 eaeac18e6d0cab5d6c686dd78b1db25c8a4ad272
child 639707 1aac7f791d59b59db1fe9262b8bb7eccf0e2ea89
push id70932
push userbmo:rhunt@eqrion.net
push dateThu, 27 Jul 2017 23:57:43 +0000
reviewerskats
bugs1385071
milestone56.0a1
Bug 1385071 - Allow keyboard APZ with passive listeners, behind a pref. r?kats This commit adds the pref, 'apz.keyboard.passive-listeners', to allow web content to have passive key event listeners and use keyboard APZ. When we are allowing passive listeners, we need to dispatch the input to content and can no longer consume the event. So we use mHandledByAPZ in nsXBLWindowKeyHandler to determine whether we still need to do the default action, or whether it has been done by APZ. MozReview-Commit-ID: 2HAC6DjDyPZ
dom/xbl/nsXBLWindowKeyHandler.cpp
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/FocusTarget.cpp
gfx/thebes/gfxPrefs.h
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -489,16 +489,21 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDO
     }
 
     // If the event is untrusted event or was already consumed, do nothing.
     if (!widgetKeyboardEvent->IsTrusted() ||
         widgetKeyboardEvent->DefaultPrevented()) {
       return NS_OK;
     }
 
+    // If this event was handled by APZ then don't do the default action
+    if (widgetKeyboardEvent->mFlags.mHandledByAPZ) {
+      return NS_OK;
+    }
+
     // XXX Don't check isReserved here because even if the handler in this
     //     instance isn't reserved but another instance reserves the key
     //     combination, it will be executed when the event is normal keyboard
     //     events...
     bool isReserved = false;
     if (!HasHandlerForEvent(keyEvent, &isReserved)) {
       return NS_OK;
     }
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1333,17 +1333,18 @@ APZCTreeManager::ReceiveInputEvent(Input
       // Dispatch the event to the input queue.
       result = mInputQueue->ReceiveInputEvent(
           targetApzc,
           /* aTargetConfirmed = */ true,
           keyInput, aOutInputBlockId);
 
       // Any keyboard event that is dispatched to the input queue at this point
       // should have been consumed
-      MOZ_ASSERT(result == nsEventStatus_eConsumeNoDefault);
+      MOZ_ASSERT(result == nsEventStatus_eConsumeDoDefault ||
+                 result == nsEventStatus_eConsumeNoDefault);
 
       keyInput.mHandledByAPZ = true;
       focusSetter.MarkAsNonFocusChanging();
 
       break;
     }
   }
   return result;
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1738,17 +1738,20 @@ AsyncPanZoomController::OnKeyboard(const
 
   KeyboardScrollAnimation* animation = mAnimation->AsKeyboardScrollAnimation();
   MOZ_ASSERT(animation);
 
   animation->UpdateDestination(aEvent.mTimeStamp,
                                CSSPixel::ToAppUnits(destination),
                                nsSize(velocity.x, velocity.y));
 
-  return nsEventStatus_eConsumeNoDefault;
+  // If we are allowing passive event listeners then we need to dispatch
+  // this event to content
+  return gfxPrefs::APZKeyboardPassiveListeners() ? nsEventStatus_eConsumeDoDefault
+                                                 : nsEventStatus_eConsumeNoDefault;
 }
 
 CSSPoint
 AsyncPanZoomController::GetKeyboardDestination(const KeyboardScrollAction& aAction) const
 {
   CSSSize lineScrollSize;
   CSSSize pageScrollSize;
   CSSPoint scrollOffset;
--- a/gfx/layers/apz/src/FocusTarget.cpp
+++ b/gfx/layers/apz/src/FocusTarget.cpp
@@ -59,17 +59,37 @@ HasListenersForKeyEvents(nsIContent* aCo
   }
 
   WidgetEvent event(true, eVoidEvent);
   nsTArray<EventTarget*> targets;
   nsresult rv = EventDispatcher::Dispatch(aContent, nullptr, &event, nullptr,
       nullptr, nullptr, &targets);
   NS_ENSURE_SUCCESS(rv, false);
   for (size_t i = 0; i < targets.Length(); i++) {
-    if (targets[i]->HasUntrustedOrNonSystemGroupKeyEventListeners()) {
+    if (targets[i]->HasNonSystemGroupListenersForUntrustedKeyEvents()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static bool
+HasListenersForNonPassiveKeyEvents(nsIContent* aContent)
+{
+  if (!aContent) {
+    return false;
+  }
+
+  WidgetEvent event(true, eVoidEvent);
+  nsTArray<EventTarget*> targets;
+  nsresult rv = EventDispatcher::Dispatch(aContent, nullptr, &event, nullptr,
+      nullptr, nullptr, &targets);
+  NS_ENSURE_SUCCESS(rv, false);
+  for (size_t i = 0; i < targets.Length(); i++) {
+    if (targets[i]->HasNonPassiveNonSystemGroupListenersForUntrustedKeyEvents()) {
       return true;
     }
   }
   return false;
 }
 
 static bool
 IsEditableNode(nsINode* aNode)
@@ -114,19 +134,25 @@ FocusTarget::FocusTarget(nsIPresShell* a
 
   // Find the focused content and use it to determine whether there are key event
   // listeners or whether key events will be targeted at a different process
   // through a remote browser.
   nsCOMPtr<nsIContent> focusedContent = presShell->GetFocusedContentInOurWindow();
 
   // Check if there are key event listeners that could prevent default or change
   // the focus or selection of the page.
-  mFocusHasKeyEventListeners =
-    HasListenersForKeyEvents(focusedContent ? focusedContent.get()
-                                            : document->GetUnfocusedKeyEventTarget());
+  if (gfxPrefs::APZKeyboardPassiveListeners()) {
+    mFocusHasKeyEventListeners =
+      HasListenersForNonPassiveKeyEvents(focusedContent ? focusedContent.get()
+                                                        : document->GetUnfocusedKeyEventTarget());
+  } else {
+    mFocusHasKeyEventListeners =
+      HasListenersForKeyEvents(focusedContent ? focusedContent.get()
+                                              : document->GetUnfocusedKeyEventTarget());
+  }
 
   // Check if the focused element is content editable or if the document
   // is in design mode.
   if (IsEditableNode(focusedContent) ||
       IsEditableNode(document)) {
     FT_LOG("Creating nil target with seq=%" PRIu64 ", kl=%d (disabling for editable node)\n",
            aFocusSequenceNumber,
            static_cast<int>(mFocusHasKeyEventListeners));
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -309,16 +309,17 @@ private:
   DECL_GFX_PREF(Live, "apz.fling_curve_threshold_inches_per_ms", APZCurveThreshold, float, -1.0f);
   DECL_GFX_PREF(Live, "apz.fling_friction",                    APZFlingFriction, float, 0.002f);
   DECL_GFX_PREF(Live, "apz.fling_min_velocity_threshold",      APZFlingMinVelocityThreshold, float, 0.5f);
   DECL_GFX_PREF(Live, "apz.fling_stop_on_tap_threshold",       APZFlingStopOnTapThreshold, float, 0.05f);
   DECL_GFX_PREF(Live, "apz.fling_stopped_threshold",           APZFlingStoppedThreshold, float, 0.01f);
   DECL_GFX_PREF(Live, "apz.frame_delay.enabled",               APZFrameDelayEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.highlight_checkerboarded_areas",    APZHighlightCheckerboardedAreas, bool, false);
   DECL_GFX_PREF(Once, "apz.keyboard.enabled",                  APZKeyboardEnabled, bool, false);
+  DECL_GFX_PREF(Live, "apz.keyboard.passive-listeners",        APZKeyboardPassiveListeners, bool, false);
   DECL_GFX_PREF(Live, "apz.max_velocity_inches_per_ms",        APZMaxVelocity, float, -1.0f);
   DECL_GFX_PREF(Once, "apz.max_velocity_queue_size",           APZMaxVelocityQueueSize, uint32_t, 5);
   DECL_GFX_PREF(Live, "apz.min_skate_speed",                   APZMinSkateSpeed, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.minimap.enabled",                   APZMinimap, bool, false);
   DECL_GFX_PREF(Live, "apz.minimap.visibility.enabled",        APZMinimapVisibilityEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.one_touch_pinch.enabled",           APZOneTouchPinchEnabled, bool, true);
   DECL_GFX_PREF(Live, "apz.overscroll.enabled",                APZOverscrollEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);