Bug 1357880 - Add a telemetry probe for non-passive keyboard event listeners r?smaug
This commit adds a telemetry probe to track the percentage of pages that ever
have a non-passive 'keydown' or 'keypress' event that could preventDefault()
APZ key scrolling of the root of a page.
A flag is added to each EventListenerManager to track whether it ever had
a qualifying event listener, and then in nsGlobalWindow::FreeInnerObjects()
the event targets that could preventDefault() a scroll are checked for this
flag. This check is done at nsGlobalWindow::FreeInnerObjects() so that the
DOM is still alive.
MozReview-Commit-ID: EkK3vxehZA5
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -98,16 +98,17 @@
#include "nsIWidget.h"
#include "nsIWidgetListener.h"
#include "nsIBaseWindow.h"
#include "nsIDeviceSensors.h"
#include "nsIContent.h"
#include "nsIDocShell.h"
#include "nsIDocCharset.h"
#include "nsIDocument.h"
+#include "nsIDocumentInlines.h"
#include "Crypto.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsDOMString.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsThreadUtils.h"
@@ -2028,16 +2029,30 @@ nsGlobalWindow::ClearControllers()
}
}
void
nsGlobalWindow::FreeInnerObjects()
{
NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window");
+ if (mDoc && !nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) {
+ EventTarget* win = this;
+ EventTarget* html = mDoc->GetHtmlElement();
+ EventTarget* body = mDoc->GetBodyElement();
+
+ bool keyboardAware = win->MayHaveAPZAwareKeyEventListener() ||
+ mDoc->MayHaveAPZAwareKeyEventListener() ||
+ (html && html->MayHaveAPZAwareKeyEventListener()) ||
+ (body && body->MayHaveAPZAwareKeyEventListener());
+
+ Telemetry::Accumulate(Telemetry::APZ_AWARE_KEY_LISTENERS,
+ keyboardAware ? 1 : 0);
+ }
+
// Make sure that this is called before we null out the document and
// other members that the window destroyed observers could
// re-create.
NotifyDOMWindowDestroyed(this);
if (auto* reporter = nsWindowMemoryReporter::Get()) {
reporter->ObserveDOMWindowDetached(this);
}
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -124,16 +124,17 @@ EventListenerManagerBase::EventListenerM
: mNoListenerForEvent(eVoidEvent)
, mMayHavePaintEventListener(false)
, mMayHaveMutationListeners(false)
, mMayHaveCapturingListeners(false)
, mMayHaveSystemGroupListeners(false)
, mMayHaveTouchEventListener(false)
, mMayHaveMouseEnterLeaveEventListener(false)
, mMayHavePointerEnterLeaveEventListener(false)
+ , mMayHaveAPZAwareKeyEventListener(false)
, mMayHaveKeyEventListener(false)
, mMayHaveInputOrCompositionEventListener(false)
, mClearingListeners(false)
, mIsMainThreadELM(NS_IsMainThread())
{
static_assert(sizeof(EventListenerManagerBase) == sizeof(uint32_t),
"Keep the size of EventListenerManagerBase size compact!");
}
@@ -406,16 +407,19 @@ EventListenerManager::AddEventListenerIn
window->SetHasGamepadEventListener();
}
} else if (aTypeAtom == nsGkAtoms::onkeydown ||
aTypeAtom == nsGkAtoms::onkeypress ||
aTypeAtom == nsGkAtoms::onkeyup) {
if (!aFlags.mInSystemGroup) {
mMayHaveKeyEventListener = true;
}
+ if (!aFlags.mPassive && aTypeAtom != nsGkAtoms::onkeyup) {
+ mMayHaveAPZAwareKeyEventListener = true;
+ }
} else if (aTypeAtom == nsGkAtoms::oncompositionend ||
aTypeAtom == nsGkAtoms::oncompositionstart ||
aTypeAtom == nsGkAtoms::oncompositionupdate ||
aTypeAtom == nsGkAtoms::oninput) {
if (!aFlags.mInSystemGroup) {
mMayHaveInputOrCompositionEventListener = true;
}
}
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -158,21 +158,22 @@ protected:
EventMessage mNoListenerForEvent;
uint16_t mMayHavePaintEventListener : 1;
uint16_t mMayHaveMutationListeners : 1;
uint16_t mMayHaveCapturingListeners : 1;
uint16_t mMayHaveSystemGroupListeners : 1;
uint16_t mMayHaveTouchEventListener : 1;
uint16_t mMayHaveMouseEnterLeaveEventListener : 1;
uint16_t mMayHavePointerEnterLeaveEventListener : 1;
+ uint16_t mMayHaveAPZAwareKeyEventListener : 1;
uint16_t mMayHaveKeyEventListener : 1;
uint16_t mMayHaveInputOrCompositionEventListener : 1;
uint16_t mClearingListeners : 1;
uint16_t mIsMainThreadELM : 1;
- // uint16_t mUnused : 5;
+ // uint16_t mUnused : 4;
};
/*
* Event listener manager
*/
class EventListenerManager final : public EventListenerManagerBase
{
@@ -437,16 +438,18 @@ public:
* Returns true if there may be a touch event listener registered,
* false if there definitely isn't.
*/
bool MayHaveTouchEventListener() { return mMayHaveTouchEventListener; }
bool MayHaveMouseEnterLeaveEventListener() { return mMayHaveMouseEnterLeaveEventListener; }
bool MayHavePointerEnterLeaveEventListener() { return mMayHavePointerEnterLeaveEventListener; }
+ bool MayHaveAPZAwareKeyEventListener() const { return mMayHaveAPZAwareKeyEventListener; }
+
/**
* Returns true if there may be a key event listener (keydown, keypress,
* or keyup) registered, or false if there definitely isn't.
*/
bool MayHaveKeyEventListener() { return mMayHaveKeyEventListener; }
/**
* Returns true if there may be an advanced input event listener (input,
--- a/dom/events/EventTarget.cpp
+++ b/dom/events/EventTarget.cpp
@@ -60,16 +60,23 @@ EventTarget::SetEventHandler(nsIAtom* aT
bool
EventTarget::IsApzAware() const
{
EventListenerManager* elm = GetExistingListenerManager();
return elm && elm->HasApzAwareListeners();
}
bool
+EventTarget::MayHaveAPZAwareKeyEventListener() const
+{
+ EventListenerManager* elm = GetExistingListenerManager();
+ return elm && elm->MayHaveAPZAwareKeyEventListener();
+}
+
+bool
EventTarget::DispatchEvent(Event& aEvent,
CallerType aCallerType,
ErrorResult& aRv)
{
bool result = false;
aRv = DispatchEvent(&aEvent, &result);
return !aEvent.DefaultPrevented(aCallerType);
}
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -95,16 +95,17 @@ public:
* exist.
*/
virtual EventListenerManager* GetExistingListenerManager() const = 0;
// Called from AsyncEventDispatcher to notify it is running.
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) {}
virtual bool IsApzAware() const;
+ bool MayHaveAPZAwareKeyEventListener() const;
protected:
EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
const nsAString& aTypeString);
void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
EventHandlerNonNull* aHandler);
};
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -10423,16 +10423,23 @@
},
"GFX_CRASH": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"releaseChannelCollection": "opt-out",
"description": "Graphics Crash Reason (...)"
},
+ "APZ_AWARE_KEY_LISTENERS": {
+ "alert_emails": ["rhunt@mozilla.com"],
+ "bug_numbers": [1352654],
+ "expires_in_version": "58",
+ "kind": "boolean",
+ "description": "The percentage of pages with a non-passive key event on the path to the root scrolling element that would disable APZ key scrolling."
+ },
"SCROLL_INPUT_METHODS": {
"alert_emails": ["botond@mozilla.com"],
"bug_numbers": [1238137],
"expires_in_version": "60",
"kind": "enumerated",
"n_values": 64,
"description": "Count of scroll actions triggered by different input methods. See gfx/layers/apz/util/ScrollInputMethods.h for a list of possible values and their meanings."
},