Bug 1486971 - Test for dynamically change of the prefers-reduced-motion setting on MacOSX. r=froydnj,mstange

The framework to simulate the setting change works as following;

 - nsIDOMWindowUtils.setPrefersReducedMotion() calls an IPC function which ends
   up calling nsChildView::SetPrefersReducedMotion() in the parent process

 - nsChildView::SetPrefersReducedMotion() sets the given value into
   nsLookAndFeel::mPrefersReducedMotionCached just like we set the value queried
   via NSWorkspace.accessibilityDisplayShouldReduceMotion in the parent process
   and send a notification which is the same notification MacOSX sends when the
   system setting changed

 - Normally the cached value is cleared before quering new values since the
   cache value is stale, but in this case the value is up-to-date one, so
   nsChildView::SetPrefersReducedMotion() tells that we don't need to clear the
   cache, and nsIDOMWindowUtils.resetPrefersReducedMotion() resets that state
   of 'we don't need to clear the cache'

There are two test cases with the framework in this commit, one is just setting
the value and checking the value queried by window.matchMedia.  The other one is
receiving 'change' event and checking the value of the event target.

Note that to make this test works the patch for bug 1478212 is necessary since
the test runs in an iframe.

Depends on D5003

Differential Revision: https://phabricator.services.mozilla.com/D5004

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Hiroyuki Ikezoe 2018-09-15 01:00:07 +00:00
Родитель 1683335036
Коммит 5f958f80c7
17 изменённых файлов: 250 добавлений и 1 удалений

Просмотреть файл

@ -4361,6 +4361,28 @@ nsDOMWindowUtils::EnsureDirtyRootFrame()
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetPrefersReducedMotionOverrideForTest(bool aValue)
{
nsIWidget* widget = GetWidget();
if (!widget) {
return NS_OK;
}
return widget->SetPrefersReducedMotionOverrideForTest(aValue);
}
NS_IMETHODIMP
nsDOMWindowUtils::ResetPrefersReducedMotionOverrideForTest()
{
nsIWidget* widget = GetWidget();
if (!widget) {
return NS_OK;
}
return widget->ResetPrefersReducedMotionOverrideForTest();
}
NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)

Просмотреть файл

@ -1940,6 +1940,19 @@ interface nsIDOMWindowUtils : nsISupports {
*/
attribute ACString systemFont;
/**
* Simulate the system setting corresponding to 'prefers-reduced-motion'
* media queries feature is changed to 'on' or 'off'.
*
* Currently this function is available only on MacOSX.
*/
void setPrefersReducedMotionOverrideForTest(in boolean aValue);
/**
* Reset the internal state to be used for above setPrefersReducedMotion.
*/
void resetPrefersReducedMotionOverrideForTest();
// These consts are only for testing purposes.
const long DEFAULT_MOUSE_POINTER_ID = 0;
const long DEFAULT_PEN_POINTER_ID = 1;

Просмотреть файл

@ -579,6 +579,9 @@ parent:
sync SetSystemFont(nsCString aFontName);
sync GetSystemFont() returns (nsCString retval);
sync SetPrefersReducedMotionOverrideForTest(bool aValue);
sync ResetPrefersReducedMotionOverrideForTest();
child:
/**
* Notify the remote browser that it has been Show()n on this

Просмотреть файл

@ -1567,6 +1567,26 @@ TabParent::RecvClearNativeTouchSequence(const uint64_t& aObserverId)
return IPC_OK();
}
mozilla::ipc::IPCResult
TabParent::RecvSetPrefersReducedMotionOverrideForTest(const bool& aValue)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->SetPrefersReducedMotionOverrideForTest(aValue);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
TabParent::RecvResetPrefersReducedMotionOverrideForTest()
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
widget->ResetPrefersReducedMotionOverrideForTest();
}
return IPC_OK();
}
void
TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
{

Просмотреть файл

@ -417,6 +417,11 @@ public:
virtual mozilla::ipc::IPCResult
RecvClearNativeTouchSequence(const uint64_t& aObserverId) override;
virtual mozilla::ipc::IPCResult
RecvSetPrefersReducedMotionOverrideForTest(const bool& aValue) override;
virtual mozilla::ipc::IPCResult
RecvResetPrefersReducedMotionOverrideForTest() override;
void SendMouseEvent(const nsAString& aType, float aX, float aY,
int32_t aButton, int32_t aClickCount,
int32_t aModifiers, bool aIgnoreRootScrollFrame);

Просмотреть файл

@ -842,6 +842,10 @@ description =
description = test only
[PBrowser::GetSystemFont]
description = test only
[PBrowser::SetPrefersReducedMotionOverrideForTest]
description = test only
[PBrowser::ResetPrefersReducedMotionOverrideForTest]
description = test only
[PContent::SyncMessage]
description =
[PContent::CreateChildProcess]

Просмотреть файл

@ -259,6 +259,8 @@ skip-if = android_version == '18' #debug-only failure; timed out #Android 4.3 aw
[test_media_query_serialization.html]
[test_mq_any_hover_and_any_pointer.html]
[test_mq_hover_and_pointer.html]
[test_mq_prefers_reduced_motion_dynamic.html]
run-if = os == 'mac' # Currently the test works on only MacOSX
[test_moz_device_pixel_ratio.html]
[test_namespace_rule.html]
[test_non_content_accessible_properties.html]

Просмотреть файл

@ -0,0 +1,81 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1486971
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1478519</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/AddTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1486971">Mozilla Bug 1486971</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script>
'use strict';
async function waitForFrame() {
return new Promise(resolve => {
window.requestAnimationFrame(resolve);
});
}
// Returns a Promise which will be resolved when the 'change' event is received
// for the given media query string.
async function promiseForChange(mediaQuery) {
return new Promise(resolve => {
window.matchMedia(mediaQuery).addEventListener('change', event => {
resolve(event.matches);
}, { once: true });
});
}
add_task(async () => {
SpecialPowers.DOMWindowUtils.setPrefersReducedMotionOverrideForTest(false);
// Need to wait a frame since MediaQuery changes are asynchronously processed.
await waitForFrame();
ok(!window.matchMedia('(prefers-reduced-motion: reduce)').matches,
'Does not matches prefers-reduced-motion: reduced) when the system sets ' +
'prefers-reduced-motion false');
ok(!window.matchMedia('(prefers-reduced-motion)').matches,
'Does not matches (prefers-reduced-motion) when the system sets ' +
'prefers-reduced-motion false');
ok(window.matchMedia('(prefers-reduced-motion: no-preference)').matches,
'Matches (prefers-reduced-motion: no-preference) when the system sets ' +
'prefers-reduced-motion false');
});
add_task(async () => {
const reduce = promiseForChange('(prefers-reduced-motion: reduce)');
const booleanContext = promiseForChange('(prefers-reduced-motion)');
const noPreference = promiseForChange('(prefers-reduced-motion: no-preference)');
SpecialPowers.DOMWindowUtils.setPrefersReducedMotionOverrideForTest(true);
const [ reduceResult, booleanContextResult, noPreferenceResult ] =
await Promise.all([ reduce, booleanContext, noPreference ]);
ok(reduceResult,
'Matches (prefers-reduced-motion: reduced) when the system sets ' +
'prefers-reduced-motion true');
ok(booleanContextResult,
'Matches (prefers-reduced-motion) when the system sets ' +
'prefers-reduced-motion true');
ok(!noPreferenceResult,
'Does not matches (prefers-reduced-motion: no-preference) when the ' +
'system sets prefers-reduced-motion true');
SpecialPowers.DOMWindowUtils.resetPrefersReducedMotionOverrideForTest();
});
</script>
</body>
</html>

Просмотреть файл

@ -687,6 +687,11 @@ public:
*/
static nsTArray<LookAndFeelInt> GetIntCache();
static void SetIntCache(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache);
/**
* Set a flag indicating whether the cache should be cleared in RefreshImpl()
* or not.
*/
static void SetShouldRetainCacheForTest(bool aValue);
};
} // namespace mozilla

Просмотреть файл

@ -1568,5 +1568,27 @@ PuppetWidget::GetSystemFont(nsCString& aFontName)
return NS_OK;
}
nsresult
PuppetWidget::SetPrefersReducedMotionOverrideForTest(bool aValue)
{
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendSetPrefersReducedMotionOverrideForTest(aValue);
return NS_OK;
}
nsresult
PuppetWidget::ResetPrefersReducedMotionOverrideForTest()
{
if (!mTabChild) {
return NS_ERROR_FAILURE;
}
mTabChild->SendResetPrefersReducedMotionOverrideForTest();
return NS_OK;
}
} // namespace widget
} // namespace mozilla

Просмотреть файл

@ -314,6 +314,9 @@ public:
nsresult SetSystemFont(const nsCString& aFontName) override;
nsresult GetSystemFont(nsCString& aFontName) override;
nsresult SetPrefersReducedMotionOverrideForTest(bool aValue) override;
nsresult ResetPrefersReducedMotionOverrideForTest() override;
// TextEventDispatcherListener
using nsBaseWidget::NotifyIME;
NS_IMETHOD NotifyIME(TextEventDispatcher* aTextEventDispatcher,

Просмотреть файл

@ -549,6 +549,9 @@ public:
void SwipeFinished();
nsresult SetPrefersReducedMotionOverrideForTest(bool aValue) override;
nsresult ResetPrefersReducedMotionOverrideForTest() override;
protected:
virtual ~nsChildView();

Просмотреть файл

@ -3097,6 +3097,42 @@ nsChildView::LookUpDictionary(
NS_OBJC_END_TRY_ABORT_BLOCK;
}
nsresult
nsChildView::SetPrefersReducedMotionOverrideForTest(bool aValue)
{
// Tell that the cache value we are going to set isn't cleared via
// nsPresContext::ThemeChangedInternal which is called right before
// we queue the media feature value change for this prefers-reduced-motion
// change.
LookAndFeel::SetShouldRetainCacheForTest(true);
LookAndFeelInt prefersReducedMotion;
prefersReducedMotion.id = LookAndFeel::eIntID_PrefersReducedMotion;
prefersReducedMotion.value = aValue ? 1 : 0;
AutoTArray<LookAndFeelInt, 1> lookAndFeelCache;
lookAndFeelCache.AppendElement(prefersReducedMotion);
// If we could have a way to modify
// NSWorkspace.accessibilityDisplayShouldReduceMotion, we could use it, but
// unfortunately there is no way, so we change the cache value instead as if
// it's set in the parent process.
LookAndFeel::SetIntCache(lookAndFeelCache);
[[NSNotificationCenter defaultCenter]
postNotificationName: NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
object:nil];
return NS_OK;
}
nsresult
nsChildView::ResetPrefersReducedMotionOverrideForTest()
{
LookAndFeel::SetShouldRetainCacheForTest(false);
return NS_OK;
}
#ifdef ACCESSIBILITY
already_AddRefed<a11y::Accessible>
nsChildView::GetDocumentAccessible()

Просмотреть файл

@ -113,6 +113,10 @@ nsLookAndFeel::NativeInit()
void
nsLookAndFeel::RefreshImpl()
{
if (mShouldRetainCacheForTest) {
return;
}
nsXPLookAndFeel::RefreshImpl();
// We should only clear the cache if we're in the main browser process.

Просмотреть файл

@ -1713,6 +1713,15 @@ class nsIWidget : public nsISupports
return NS_ERROR_NOT_IMPLEMENTED;
}
virtual nsresult SetPrefersReducedMotionOverrideForTest(bool aValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
virtual nsresult ResetPrefersReducedMotionOverrideForTest()
{
return NS_ERROR_NOT_IMPLEMENTED;
}
private:
class LongTapInfo
{

Просмотреть файл

@ -317,7 +317,9 @@ nsXPLookAndFeel::Shutdown()
sInstance = nullptr;
}
nsXPLookAndFeel::nsXPLookAndFeel() : LookAndFeel()
nsXPLookAndFeel::nsXPLookAndFeel()
: LookAndFeel()
, mShouldRetainCacheForTest(false)
{
}
@ -1063,4 +1065,11 @@ LookAndFeel::SetIntCache(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache)
return nsLookAndFeel::GetInstance()->SetIntCacheImpl(aLookAndFeelIntCache);
}
// static
void
LookAndFeel::SetShouldRetainCacheForTest(bool aValue)
{
nsLookAndFeel::GetInstance()->SetShouldRetainCacheImplForTest(aValue);
}
} // namespace mozilla

Просмотреть файл

@ -83,6 +83,10 @@ public:
virtual nsTArray<LookAndFeelInt> GetIntCacheImpl();
virtual void SetIntCacheImpl(const nsTArray<LookAndFeelInt>& aLookAndFeelIntCache) {}
void SetShouldRetainCacheImplForTest(bool aValue)
{
mShouldRetainCacheForTest = aValue;
}
virtual void NativeInit() = 0;
@ -117,6 +121,10 @@ protected:
static nsXPLookAndFeel* sInstance;
static bool sShutdown;
// True if we shouldn't clear the cache value in RefreshImpl().
// NOTE: This should be used only for testing.
bool mShouldRetainCacheForTest;
};
#endif