Add runtime setting to force passive event listeners.
Add the ability to set the default value for the 'passive' field
in AddEventListenerOptions.
The value can take on 4 values; 'false', 'true', 'documentonlytrue',
'forcetrue'. It can be set from the command line or by adjusting
the chrome://flags.
BUG=599611
Review-Url: https://codereview.chromium.org/1965493002
Cr-Commit-Position: refs/heads/master@{#393565}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index f421c6e..4346326b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5628,6 +5628,21 @@
<message name="IDS_FLAGS_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK_DESCRIPTION" desc="Description for the flag for gesture requiment for media playback">
User gesture requirement for playing media elements. Disabling this will allow autoplay to work.
</message>
+ <message name="IDS_FLAGS_PASSIVE_EVENT_LISTENER_DOCUMENT_TRUE" desc="Choice for passive listeners to default to true on document level nodes.">
+ Document Level True (when unspecified)
+ </message>
+ <message name="IDS_FLAGS_PASSIVE_EVENT_LISTENER_TRUE" desc="Choice for passive listeners to default to true on all nodes not explicitly set.">
+ True (when unspecified)
+ </message>
+ <message name="IDS_FLAGS_PASSIVE_EVENT_LISTENER_FORCE_ALL_TRUE" desc="Choice for passive listeners to default to true on all nodes.">
+ Force All True
+ </message>
+ <message name="IDS_FLAGS_PASSIVE_EVENT_LISTENER_DEFAULT_NAME" desc="Name for the flag to adjust the default behaviour for passive event listeners.">
+ Passive Event Listener Override
+ </message>
+ <message name="IDS_FLAGS_PASSIVE_EVENT_LISTENER_DEFAULT_DESCRIPTION" desc="Description for the flag to adjust default behaviour for passive event listeners.">
+ Forces touchstart, touchmove, mousewheel and wheel event listeners (which haven't requested otherwise) to be treated as passive. This will break touch/wheel behavior on some websites but is useful for demonstrating the potential performance benefits of adopting passive event listeners.
+ </message>
<if expr="is_android">
<message name="IDS_FLAGS_MEDIA_STYLE_NOTIFICATION_NAME" desc="Title for the flag for using Android MediaStyle notification">
Android MediaStyle notification
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0e2e88d3..539da28 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -185,6 +185,16 @@
};
#endif
+const FeatureEntry::Choice kPassiveListenersChoices[] = {
+ {IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
+ {IDS_FLAGS_PASSIVE_EVENT_LISTENER_DOCUMENT_TRUE,
+ switches::kPassiveListenersDefault, "documentonlytrue"},
+ {IDS_FLAGS_PASSIVE_EVENT_LISTENER_TRUE, switches::kPassiveListenersDefault,
+ "true"},
+ {IDS_FLAGS_PASSIVE_EVENT_LISTENER_FORCE_ALL_TRUE,
+ switches::kPassiveListenersDefault, "forcealltrue"},
+};
+
const FeatureEntry::Choice kMarkNonSecureAsChoices[] = {
{IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
{IDS_MARK_NON_SECURE_AS_NEUTRAL, security_state::switches::kMarkNonSecureAs,
@@ -1866,6 +1876,11 @@
IDS_FLAGS_EXPERIMENTAL_POINTER_EVENT_NAME,
IDS_FLAGS_EXPERIMENTAL_POINTER_EVENT_DESCRIPTION, kOsAll,
FEATURE_VALUE_TYPE(features::kPointerEvents)},
+ {"passive-listener-default", // FLAGS:RECORD_UMA
+ IDS_FLAGS_PASSIVE_EVENT_LISTENER_DEFAULT_NAME,
+ IDS_FLAGS_PASSIVE_EVENT_LISTENER_DEFAULT_DESCRIPTION, kOsAll,
+ MULTI_VALUE_TYPE(kPassiveListenersChoices)},
+
// NOTE: Adding new command-line switches requires adding corresponding
// entries to enum "LoginCustomFlags" in histograms.xml. See note in
// histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 18c53677..557b67d3 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1437,6 +1437,7 @@
switches::kNoReferrers,
switches::kNoSandbox,
switches::kOverridePluginPowerSaverForTesting,
+ switches::kPassiveListenersDefault,
switches::kPpapiInProcess,
switches::kProfilerTiming,
switches::kReducedReferrerGranularity,
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index f95921d..244e371 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -675,6 +675,13 @@
const char kOverscrollHistoryNavigation[] =
"overscroll-history-navigation";
+// Override the default value for the 'passive' field in javascript
+// addEventListener calls. Values are defined as:
+// 'documentonlytrue' to set the default be true only for document level nodes.
+// 'true' to set the default to be true on all nodes (when not specified).
+// 'forcealltrue' to force the value on all nodes.
+const char kPassiveListenersDefault[] = "passive-listeners-default";
+
// Argument to the process type that indicates a PPAPI broker process type.
const char kPpapiBrokerProcess[] = "ppapi-broker";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 2ebf9c8..be5cc9e 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -195,6 +195,7 @@
CONTENT_EXPORT extern const char kNumRasterThreads[];
CONTENT_EXPORT extern const char kOverridePluginPowerSaverForTesting[];
CONTENT_EXPORT extern const char kOverscrollHistoryNavigation[];
+CONTENT_EXPORT extern const char kPassiveListenersDefault[];
CONTENT_EXPORT extern const char kPpapiBrokerProcess[];
CONTENT_EXPORT extern const char kPpapiFlashArgs[];
CONTENT_EXPORT extern const char kPpapiInProcess[];
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 3990452..df3decf8 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -723,6 +723,20 @@
selection_strategy = WebSettings::SelectionStrategyType::Direction;
webview()->settings()->setSelectionStrategy(selection_strategy);
+ std::string passiveListenersDefault =
+ command_line.GetSwitchValueASCII(switches::kPassiveListenersDefault);
+ if (!passiveListenersDefault.empty()) {
+ WebSettings::PassiveEventListenerDefault passiveDefault =
+ WebSettings::PassiveEventListenerDefault::False;
+ if (passiveListenersDefault == "documentonlytrue")
+ passiveDefault = WebSettings::PassiveEventListenerDefault::DocumentTrue;
+ else if (passiveListenersDefault == "true")
+ passiveDefault = WebSettings::PassiveEventListenerDefault::True;
+ else if (passiveListenersDefault == "forcealltrue")
+ passiveDefault = WebSettings::PassiveEventListenerDefault::ForceAllTrue;
+ webview()->settings()->setPassiveEventListenerDefault(passiveDefault);
+ }
+
ApplyBlinkSettings(command_line, webview()->settings());
if (params.main_frame_routing_id != MSG_ROUTING_NONE) {
diff --git a/third_party/WebKit/Source/core/events/AddEventListenerOptionsDefaults.h b/third_party/WebKit/Source/core/events/AddEventListenerOptionsDefaults.h
new file mode 100644
index 0000000..8887c1e
--- /dev/null
+++ b/third_party/WebKit/Source/core/events/AddEventListenerOptionsDefaults.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AddEventListenerOptionsDefaults_h
+#define AddEventListenerOptionsDefaults_h
+
+namespace blink {
+
+// Defines the default for 'passive' field used in the AddEventListenerOptions interface
+// when javascript calls addEventListener.
+// |False| is the default specified in
+// https://dom.spec.whatwg.org/#dictdef-addeventlisteneroptions. However
+// specifying a different default value is useful in demonstrating the
+// power of passive event listeners.
+enum class PassiveListenerDefault {
+ False, // Default of false.
+ True, // Default of true.
+ DocumentTrue, // Default of true for document level elements, false otherwise.
+ ForceAllTrue // Force all values to be true even when specified.
+};
+
+} // namespace blink
+
+#endif // AddEventListenerOptionsDefaults_h
diff --git a/third_party/WebKit/Source/core/events/EventTarget.cpp b/third_party/WebKit/Source/core/events/EventTarget.cpp
index c8caf6c..7781288b 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.cpp
+++ b/third_party/WebKit/Source/core/events/EventTarget.cpp
@@ -54,21 +54,14 @@
namespace blink {
namespace {
-void setDefaultEventListenerOptionsLegacy(EventListenerOptions& options, bool useCapture)
+Settings* windowSettings(LocalDOMWindow* executingWindow)
{
- options.setCapture(useCapture);
-}
-
-void setDefaultAddEventListenerOptionsLegacy(AddEventListenerOptions& options, bool useCapture)
-{
- setDefaultEventListenerOptionsLegacy(options, useCapture);
- options.setPassive(false);
-}
-
-void setDefaultAddEventListenerOptions(AddEventListenerOptions& options)
-{
- if (!options.hasPassive())
- options.setPassive(false);
+ if (executingWindow) {
+ if (LocalFrame* frame = executingWindow->frame()) {
+ return frame->settings();
+ }
+ }
+ return nullptr;
}
double blockedEventsWarningThreshold(const ExecutionContext* context, const Event* event)
@@ -189,10 +182,44 @@
return nullptr;
}
+void EventTarget::setDefaultAddEventListenerOptions(AddEventListenerOptions& options)
+{
+ if (Settings* settings = windowSettings(executingWindow())) {
+ switch (settings->passiveListenerDefault()) {
+ case PassiveListenerDefault::False:
+ if (!options.hasPassive())
+ options.setPassive(false);
+ break;
+ case PassiveListenerDefault::True:
+ if (!options.hasPassive())
+ options.setPassive(true);
+ break;
+ case PassiveListenerDefault::ForceAllTrue:
+ options.setPassive(true);
+ break;
+ case PassiveListenerDefault::DocumentTrue:
+ if (!options.hasPassive()) {
+ if (Node* node = toNode()) {
+ if (node->isDocumentNode() || node->document().documentElement() == node || node->document().body() == node) {
+ options.setPassive(true);
+ }
+ } else if (toLocalDOMWindow()) {
+ options.setPassive(true);
+ }
+ }
+ break;
+ }
+ } else {
+ if (!options.hasPassive())
+ options.setPassive(false);
+ }
+}
+
bool EventTarget::addEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
{
AddEventListenerOptions options;
- setDefaultAddEventListenerOptionsLegacy(options, useCapture);
+ options.setCapture(useCapture);
+ setDefaultAddEventListenerOptions(options);
return addEventListenerInternal(eventType, listener, options);
}
@@ -245,7 +272,7 @@
bool EventTarget::removeEventListener(const AtomicString& eventType, const EventListener* listener, bool useCapture)
{
EventListenerOptions options;
- setDefaultEventListenerOptionsLegacy(options, useCapture);
+ options.setCapture(useCapture);
return removeEventListenerInternal(eventType, listener, options);
}
diff --git a/third_party/WebKit/Source/core/events/EventTarget.h b/third_party/WebKit/Source/core/events/EventTarget.h
index eba60f8..cac244aa 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.h
+++ b/third_party/WebKit/Source/core/events/EventTarget.h
@@ -171,6 +171,7 @@
private:
LocalDOMWindow* executingWindow();
+ void setDefaultAddEventListenerOptions(AddEventListenerOptions&);
void fireEventListeners(Event*, EventTargetData*, EventListenerVector&);
void countLegacyEvents(const AtomicString& legacyTypeName, EventListenerVector*, EventListenerVector*);
diff --git a/third_party/WebKit/Source/core/frame/Settings.h b/third_party/WebKit/Source/core/frame/Settings.h
index 91dafef..6ab18c6 100644
--- a/third_party/WebKit/Source/core/frame/Settings.h
+++ b/third_party/WebKit/Source/core/frame/Settings.h
@@ -33,6 +33,7 @@
#include "core/SettingsMacros.h"
#include "core/editing/EditingBehaviorTypes.h"
#include "core/editing/SelectionStrategy.h"
+#include "core/events/AddEventListenerOptionsDefaults.h"
#include "core/frame/SettingsDelegate.h"
#include "core/html/track/TextTrackKindUserPreference.h"
#include "platform/Timer.h"
diff --git a/third_party/WebKit/Source/core/frame/Settings.in b/third_party/WebKit/Source/core/frame/Settings.in
index 09969f1..a21b4ff 100644
--- a/third_party/WebKit/Source/core/frame/Settings.in
+++ b/third_party/WebKit/Source/core/frame/Settings.in
@@ -408,3 +408,9 @@
# event listener that caused an event to be dispatched to main thread and
# delayed by more than the specified time (in seconds).
blockedMainThreadEventsWarningThreshold type=double, initial=0
+
+# Ability to override the default 'passive' value in AddEventListenerOptions. This
+# is useful to demonstrate the power of passive event listeners. This can be removed
+# when there is greater adoption, interventions to force it on and associated devtools
+# to enable it have been shipped.
+passiveListenerDefault type=PassiveListenerDefault, initial=PassiveListenerDefault::False
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
index 7479b00..d9212b9b 100644
--- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
+++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -535,6 +535,11 @@
STATIC_ASSERT_ENUM(WebSettings::EditingBehaviorUnix, EditingUnixBehavior);
STATIC_ASSERT_ENUM(WebSettings::EditingBehaviorAndroid, EditingAndroidBehavior);
+STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::False, PassiveListenerDefault::False);
+STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::True, PassiveListenerDefault::True);
+STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::DocumentTrue, PassiveListenerDefault::DocumentTrue);
+STATIC_ASSERT_ENUM(WebSettings::PassiveEventListenerDefault::ForceAllTrue, PassiveListenerDefault::ForceAllTrue);
+
STATIC_ASSERT_ENUM(WebIDBDatabaseExceptionUnknownError, UnknownError);
STATIC_ASSERT_ENUM(WebIDBDatabaseExceptionConstraintError, ConstraintError);
STATIC_ASSERT_ENUM(WebIDBDatabaseExceptionDataError, DataError);
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
index da9e03d..54d06cb 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
@@ -627,6 +627,11 @@
m_settings->setStrictlyBlockBlockableMixedContent(enabled);
}
+void WebSettingsImpl::setPassiveEventListenerDefault(PassiveEventListenerDefault defaultValue)
+{
+ m_settings->setPassiveListenerDefault(static_cast<PassiveListenerDefault>(defaultValue));
+}
+
void WebSettingsImpl::setPasswordEchoEnabled(bool flag)
{
m_settings->setPasswordEchoEnabled(flag);
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.h b/third_party/WebKit/Source/web/WebSettingsImpl.h
index f2190939..3ba0a70 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.h
@@ -123,6 +123,7 @@
void setMinimumLogicalFontSize(int) override;
void setMockScrollbarsEnabled(bool) override;
void setOfflineWebApplicationCacheEnabled(bool) override;
+ void setPassiveEventListenerDefault(PassiveEventListenerDefault) override;
void setPasswordEchoDurationInSeconds(double) override;
void setPasswordEchoEnabled(bool) override;
void setPerTilePaintingEnabled(bool) override;
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index f215571..f905fd0 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -95,6 +95,15 @@
Subtitles
};
+ // Defines the default for 'passive' field used in the AddEventListenerOptions interface
+ // when javascript calls addEventListener.
+ enum class PassiveEventListenerDefault {
+ False, // Default of false.
+ True, // Default of true.
+ DocumentTrue, // Default of true for document level elements, false otherwise.
+ ForceAllTrue // Force all values to be true even when specified.
+ };
+
// Sets value of a setting by its string identifier from Settings.in and
// string representation of value. An enum's string representation is the
// string representation of the integer value of the enum.
@@ -184,6 +193,7 @@
virtual void setMinimumLogicalFontSize(int) = 0;
virtual void setMockScrollbarsEnabled(bool) = 0;
virtual void setOfflineWebApplicationCacheEnabled(bool) = 0;
+ virtual void setPassiveEventListenerDefault(PassiveEventListenerDefault) = 0;
virtual void setPasswordEchoDurationInSeconds(double) = 0;
virtual void setPasswordEchoEnabled(bool) = 0;
virtual void setPerTilePaintingEnabled(bool) = 0;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 989a968d..f99682b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -77488,6 +77488,7 @@
<int value="157217034" label="enable-tab-for-desktop-share"/>
<int value="178337215" label="enable-md-history"/>
<int value="180074362" label="memory-pressure-thresholds"/>
+ <int value="194895489" label="passive-listeners-default"/>
<int value="203776499" label="enable-virtual-keyboard-overscroll"/>
<int value="244697230" label="enable-theme-color-in-tabbed-mode"/>
<int value="266702296" label="disable-plugin-power-saver"/>