Commit 73ebda83 authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Update CSS prefers-reduced-motion dynamically on Mac and Windows

Previously the content-side support for reduced motion for a frame was
static and would not react to changes in the system settings until you
created a new frame. This CL listens for notifications and recomputes
the webkit preferences when that happens (which then causes the new
prefers-reduced-motion value to be calculated).

This CL also introduces a caching mechanism for the system setting, to
avoid potentially expensive recomputation.

Test: Tested manually on MacOS and Windows devices.
Bug: 722548
Change-Id: I6be0822cc40a697a4373fbf53888d2219e5890f2
Reviewed-on: https://chromium-review.googlesource.com/c/1418498
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Reviewed-by: default avatarStephen McGruer <smcgruer@chromium.org>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#628406}
parent b76ea80f
...@@ -10,10 +10,16 @@ ...@@ -10,10 +10,16 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "build/build_config.h"
#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_accessibility_state.h"
#include "ui/accessibility/ax_mode.h" #include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/ax_mode_observer.h" #include "ui/accessibility/ax_mode_observer.h"
#if defined(OS_WIN)
#include <memory>
#include "ui/gfx/win/singleton_hwnd_observer.h"
#endif
namespace content { namespace content {
// The BrowserAccessibilityState class is used to determine if Chrome should be // The BrowserAccessibilityState class is used to determine if Chrome should be
...@@ -93,6 +99,11 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl ...@@ -93,6 +99,11 @@ class CONTENT_EXPORT BrowserAccessibilityStateImpl
bool disable_hot_tracking_; bool disable_hot_tracking_;
#if defined(OS_WIN)
// Only used on Windows
std::unique_ptr<gfx::SingletonHwndObserver> singleton_hwnd_observer_;
#endif
DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityStateImpl); DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityStateImpl);
}; };
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "ui/gfx/animation/animation.h"
@interface NSWorkspace (Partials) @interface NSWorkspace (Partials)
...@@ -23,7 +25,39 @@ ...@@ -23,7 +25,39 @@
namespace content { namespace content {
void BrowserAccessibilityStateImpl::PlatformInitialize() {} namespace {
void SetupAccessibilityDisplayOptionsNotifier() {
// We need to call into gfx::Animation and WebContentsImpl on the UI thread,
// so ensure that we setup the notification on the correct thread.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (@available(macOS 10.10, *)) {
// Listen to accessibility display options changing, so that we can update
// the renderer for the prefers reduced motion settings.
//
// BrowserAccessibilityStateImpl is a deliberately leaked singleton, so we
// don't need to record the notification token for later cleanup.
[[[NSWorkspace sharedWorkspace] notificationCenter]
addObserverForName:
NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
object:nil
queue:nil
usingBlock:^(NSNotification* notification) {
gfx::Animation::UpdatePrefersReducedMotion();
for (WebContentsImpl* wc :
WebContentsImpl::GetAllWebContents()) {
wc->GetRenderViewHost()->OnWebkitPreferencesChanged();
}
}];
}
}
} // namespace
void BrowserAccessibilityStateImpl::PlatformInitialize() {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&SetupAccessibilityDisplayOptionsNotifier));
}
void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() { void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
// NOTE: This function is running on the file thread. // NOTE: This function is running on the file thread.
......
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "ui/accessibility/platform/ax_platform_node_win.h" #include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/gfx/animation/animation.h"
namespace content { namespace content {
...@@ -67,11 +69,24 @@ class WindowsAccessibilityEnabler : public ui::IAccessible2UsageObserver { ...@@ -67,11 +69,24 @@ class WindowsAccessibilityEnabler : public ui::IAccessible2UsageObserver {
bool acc_name_called_ = false; bool acc_name_called_ = false;
}; };
void OnWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (message == WM_SETTINGCHANGE && wparam == SPI_SETCLIENTAREAANIMATION) {
gfx::Animation::UpdatePrefersReducedMotion();
for (WebContentsImpl* wc : WebContentsImpl::GetAllWebContents()) {
wc->GetRenderViewHost()->OnWebkitPreferencesChanged();
}
}
}
} // namespace } // namespace
void BrowserAccessibilityStateImpl::PlatformInitialize() { void BrowserAccessibilityStateImpl::PlatformInitialize() {
ui::GetIAccessible2UsageObserverList().AddObserver( ui::GetIAccessible2UsageObserverList().AddObserver(
new WindowsAccessibilityEnabler()); new WindowsAccessibilityEnabler());
singleton_hwnd_observer_.reset(
new gfx::SingletonHwndObserver(base::BindRepeating(&OnWndProc)));
} }
void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() { void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "ui/gfx/animation/animation.h" #include "ui/gfx/animation/animation.h"
#include "base/message_loop/message_loop.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "ui/gfx/animation/animation_container.h" #include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/animation_delegate.h" #include "ui/gfx/animation/animation_delegate.h"
...@@ -16,6 +17,9 @@ namespace gfx { ...@@ -16,6 +17,9 @@ namespace gfx {
Animation::RichAnimationRenderMode Animation::rich_animation_rendering_mode_ = Animation::RichAnimationRenderMode Animation::rich_animation_rendering_mode_ =
RichAnimationRenderMode::PLATFORM; RichAnimationRenderMode::PLATFORM;
// static
base::Optional<bool> Animation::prefers_reduced_motion_;
Animation::Animation(base::TimeDelta timer_interval) Animation::Animation(base::TimeDelta timer_interval)
: timer_interval_(timer_interval), : timer_interval_(timer_interval),
is_animating_(false), is_animating_(false),
...@@ -107,20 +111,31 @@ bool Animation::ShouldRenderRichAnimationImpl() { ...@@ -107,20 +111,31 @@ bool Animation::ShouldRenderRichAnimationImpl() {
} }
#endif #endif
#if !defined(OS_WIN) && !defined(OS_MACOSX) #if !defined(OS_WIN) && (!defined(OS_MACOSX) || defined(OS_IOS))
// static // static
bool Animation::ScrollAnimationsEnabledBySystem() { bool Animation::ScrollAnimationsEnabledBySystem() {
// Defined in platform specific files for Windows and OSX. // Defined in platform specific files for Windows and OSX.
return true; return true;
} }
bool Animation::PrefersReducedMotion() { // static
void Animation::UpdatePrefersReducedMotion() {
// prefers_reduced_motion_ should only be modified on the UI thread.
// TODO(crbug.com/927163): DCHECK this assertion once tests are well-behaved.
// By default, we assume that animations are enabled, to avoid impacting the // By default, we assume that animations are enabled, to avoid impacting the
// experience for users on systems that don't have APIs for reduced motion. // experience for users on systems that don't have APIs for reduced motion.
return false; prefers_reduced_motion_ = false;
} }
#endif #endif
// static
bool Animation::PrefersReducedMotion() {
if (!prefers_reduced_motion_)
UpdatePrefersReducedMotion();
return *prefers_reduced_motion_;
}
bool Animation::ShouldSendCanceledFromStop() { bool Animation::ShouldSendCanceledFromStop() {
return false; return false;
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "ui/gfx/animation/animation_container_element.h" #include "ui/gfx/animation/animation_container_element.h"
#include "ui/gfx/animation/animation_export.h" #include "ui/gfx/animation/animation_export.h"
...@@ -80,8 +81,9 @@ class ANIMATION_EXPORT Animation : public AnimationContainerElement { ...@@ -80,8 +81,9 @@ class ANIMATION_EXPORT Animation : public AnimationContainerElement {
static bool ScrollAnimationsEnabledBySystem(); static bool ScrollAnimationsEnabledBySystem();
// Determines whether the user desires reduced motion based on platform APIs. // Determines whether the user desires reduced motion based on platform APIs.
// Should only be called from the browser process. // Should only be called from the browser process, on the UI thread.
static bool PrefersReducedMotion(); static bool PrefersReducedMotion();
static void UpdatePrefersReducedMotion();
protected: protected:
// Invoked from Start to allow subclasses to prepare for the animation. // Invoked from Start to allow subclasses to prepare for the animation.
...@@ -128,6 +130,10 @@ class ANIMATION_EXPORT Animation : public AnimationContainerElement { ...@@ -128,6 +130,10 @@ class ANIMATION_EXPORT Animation : public AnimationContainerElement {
// Time we started at. // Time we started at.
base::TimeTicks start_time_; base::TimeTicks start_time_;
// Obtaining the PrefersReducedMotion system setting can be expensive, so it
// is cached in this boolean.
static base::Optional<bool> prefers_reduced_motion_;
DISALLOW_COPY_AND_ASSIGN(Animation); DISALLOW_COPY_AND_ASSIGN(Animation);
}; };
......
...@@ -33,21 +33,18 @@ bool Animation::ScrollAnimationsEnabledBySystem() { ...@@ -33,21 +33,18 @@ bool Animation::ScrollAnimationsEnabledBySystem() {
} }
// static // static
bool Animation::PrefersReducedMotion() { void Animation::UpdatePrefersReducedMotion() {
// Because of sandboxing, OS settings should only be queried from the browser // prefers_reduced_motion_ should only be modified on the UI thread.
// process. // TODO(crbug.com/927163): DCHECK this assertion once tests are well-behaved.
DCHECK(base::MessageLoopCurrentForUI::IsSet() ||
base::MessageLoopCurrentForIO::IsSet());
// We default to assuming that animations are enabled, to avoid impacting the // We default to assuming that animations are enabled, to avoid impacting the
// experience for users on pre-10.12 systems. // experience for users on pre-10.12 systems.
bool prefers_reduced_motion = false; prefers_reduced_motion_ = false;
SEL sel = @selector(accessibilityDisplayShouldReduceMotion); SEL sel = @selector(accessibilityDisplayShouldReduceMotion);
if ([[NSWorkspace sharedWorkspace] respondsToSelector:sel]) { if ([[NSWorkspace sharedWorkspace] respondsToSelector:sel]) {
prefers_reduced_motion = prefers_reduced_motion_ =
[[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion]; [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
} }
return prefers_reduced_motion;
} }
} // namespace gfx } // namespace gfx
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <windows.h> #include <windows.h>
#include "base/message_loop/message_loop.h"
namespace gfx { namespace gfx {
// static // static
...@@ -24,12 +26,15 @@ bool Animation::ScrollAnimationsEnabledBySystem() { ...@@ -24,12 +26,15 @@ bool Animation::ScrollAnimationsEnabledBySystem() {
} }
// static // static
bool Animation::PrefersReducedMotion() { void Animation::UpdatePrefersReducedMotion() {
// prefers_reduced_motion_ should only be modified on the UI thread.
// TODO(crbug.com/927163): DCHECK this assertion once tests are well-behaved.
// We default to assuming that animations are enabled, to avoid impacting the // We default to assuming that animations are enabled, to avoid impacting the
// experience for users on systems that don't have SPI_GETCLIENTAREAANIMATION. // experience for users on systems that don't have SPI_GETCLIENTAREAANIMATION.
BOOL win_anim_enabled = true; BOOL win_anim_enabled = true;
SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &win_anim_enabled, 0); SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &win_anim_enabled, 0);
return !win_anim_enabled; prefers_reduced_motion_ = !win_anim_enabled;
} }
} // namespace gfx } // namespace gfx
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment