Commit 7e0ecb21 authored by Adam Argyle's avatar Adam Argyle Committed by Commit Bot

Support for the prefers-reduced-data media query feature

Intent to prototype: https://groups.google.com/a/chromium.org/d/msg/blink-dev/oNJTem41LBs/CA4Nx05aAwAJ

Bug: 1051189
Change-Id: I2ff88a70858cf322725f50e40f979c9596f45b0b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2083838
Commit-Queue: Adam Argyle <argyle@chromium.org>
Reviewed-by: default avatarYoav Weiss <yoavweiss@chromium.org>
Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779564}
parent 3357f674
......@@ -1225,6 +1225,7 @@
"only",
// (prefers-reduced-motion:) media feature
// (prefers-reduced-data:) media feature
"reduce",
// (forced-colors:) media feature
......
......@@ -54,6 +54,7 @@
"pointer",
"prefers-color-scheme",
"prefers-reduced-motion",
"prefers-reduced-data",
"resolution",
"-webkit-transform-3d",
"scan",
......
......@@ -736,6 +736,20 @@ static bool PrefersReducedMotionMediaFeatureEval(
media_values.PrefersReducedMotion();
}
static bool PrefersReducedDataMediaFeatureEval(
const MediaQueryExpValue& value,
MediaFeaturePrefix,
const MediaValues& media_values) {
if (!value.IsValid())
return media_values.PrefersReducedData();
if (!value.is_id)
return false;
return (value.id == CSSValueID::kNoPreference) ^
media_values.PrefersReducedData();
}
static bool AnyPointerMediaFeatureEval(const MediaQueryExpValue& value,
MediaFeaturePrefix,
const MediaValues& media_values) {
......
......@@ -82,6 +82,11 @@ static inline bool FeatureWithValidIdent(const String& media_feature,
if (media_feature == media_feature_names::kPrefersReducedMotionMediaFeature)
return ident == CSSValueID::kNoPreference || ident == CSSValueID::kReduce;
if (RuntimeEnabledFeatures::PrefersReducedDataEnabled() &&
media_feature == media_feature_names::kPrefersReducedDataMediaFeature) {
return ident == CSSValueID::kNoPreference || ident == CSSValueID::kReduce;
}
if (RuntimeEnabledFeatures::ForcedColorsEnabled()) {
if (media_feature == media_feature_names::kForcedColorsMediaFeature) {
return ident == CSSValueID::kNone || ident == CSSValueID::kActive;
......@@ -216,6 +221,9 @@ static inline bool FeatureWithoutValue(
media_feature_names::kPrefersColorSchemeMediaFeature ||
media_feature ==
media_feature_names::kPrefersReducedMotionMediaFeature ||
(media_feature ==
media_feature_names::kPrefersReducedDataMediaFeature &&
RuntimeEnabledFeatures::PrefersReducedDataEnabled()) ||
(media_feature == media_feature_names::kForcedColorsMediaFeature &&
RuntimeEnabledFeatures::ForcedColorsEnabled()) ||
(media_feature ==
......
......@@ -22,6 +22,7 @@
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/platform/graphics/color_space_gamut.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/widget/frame_widget.h"
namespace blink {
......@@ -204,6 +205,18 @@ bool MediaValues::CalculatePrefersReducedMotion(LocalFrame* frame) {
return frame->GetSettings()->GetPrefersReducedMotion();
}
bool MediaValues::CalculatePrefersReducedData(LocalFrame* frame) {
DCHECK(frame);
DCHECK(frame->GetSettings());
if (const auto* overrides = frame->GetPage()->GetMediaFeatureOverrides()) {
MediaQueryExpValue value = overrides->GetOverride("prefers-reduced-data");
if (value.IsValid())
return value.id == CSSValueID::kReduce;
}
return (GetNetworkStateNotifier().SaveDataEnabled() &&
!frame->GetSettings()->GetDataSaverHoldbackWebApi());
}
ForcedColors MediaValues::CalculateForcedColors() {
if (Platform::Current() && Platform::Current()->ThemeEngine())
return Platform::Current()->ThemeEngine()->GetForcedColors();
......
......@@ -83,6 +83,7 @@ class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
virtual ColorSpaceGamut ColorGamut() const = 0;
virtual PreferredColorScheme GetPreferredColorScheme() const = 0;
virtual bool PrefersReducedMotion() const = 0;
virtual bool PrefersReducedData() const = 0;
virtual ForcedColors GetForcedColors() const = 0;
virtual NavigationControls GetNavigationControls() const = 0;
virtual ScreenSpanning GetScreenSpanning() const = 0;
......@@ -108,6 +109,7 @@ class CORE_EXPORT MediaValues : public GarbageCollected<MediaValues> {
static ColorSpaceGamut CalculateColorGamut(LocalFrame*);
static PreferredColorScheme CalculatePreferredColorScheme(LocalFrame*);
static bool CalculatePrefersReducedMotion(LocalFrame*);
static bool CalculatePrefersReducedData(LocalFrame*);
static ForcedColors CalculateForcedColors();
static NavigationControls CalculateNavigationControls(LocalFrame*);
static ScreenSpanning CalculateScreenSpanning(LocalFrame*);
......
......@@ -78,6 +78,7 @@ MediaValuesCached::MediaValuesCachedData::MediaValuesCachedData(
color_gamut = MediaValues::CalculateColorGamut(frame);
preferred_color_scheme = MediaValues::CalculatePreferredColorScheme(frame);
prefers_reduced_motion = MediaValues::CalculatePrefersReducedMotion(frame);
prefers_reduced_data = MediaValues::CalculatePrefersReducedData(frame);
forced_colors = MediaValues::CalculateForcedColors();
navigation_controls = MediaValues::CalculateNavigationControls(frame);
screen_spanning = MediaValues::CalculateScreenSpanning(frame);
......@@ -199,6 +200,10 @@ bool MediaValuesCached::PrefersReducedMotion() const {
return data_.prefers_reduced_motion;
}
bool MediaValuesCached::PrefersReducedData() const {
return data_.prefers_reduced_data;
}
ForcedColors MediaValuesCached::GetForcedColors() const {
return data_.forced_colors;
}
......
......@@ -37,6 +37,7 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
ColorSpaceGamut color_gamut;
PreferredColorScheme preferred_color_scheme;
bool prefers_reduced_motion;
bool prefers_reduced_data = false;
ForcedColors forced_colors;
NavigationControls navigation_controls;
ScreenSpanning screen_spanning;
......@@ -66,6 +67,7 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
data.color_gamut = color_gamut;
data.preferred_color_scheme = preferred_color_scheme;
data.prefers_reduced_motion = prefers_reduced_motion;
data.prefers_reduced_data = prefers_reduced_data;
data.forced_colors = forced_colors;
data.navigation_controls = navigation_controls;
data.screen_spanning = screen_spanning;
......@@ -106,6 +108,7 @@ class CORE_EXPORT MediaValuesCached final : public MediaValues {
ColorSpaceGamut ColorGamut() const override;
PreferredColorScheme GetPreferredColorScheme() const override;
bool PrefersReducedMotion() const override;
bool PrefersReducedData() const override;
ForcedColors GetForcedColors() const override;
NavigationControls GetNavigationControls() const override;
ScreenSpanning GetScreenSpanning() const override;
......
......@@ -148,6 +148,10 @@ bool MediaValuesDynamic::PrefersReducedMotion() const {
return CalculatePrefersReducedMotion(frame_);
}
bool MediaValuesDynamic::PrefersReducedData() const {
return CalculatePrefersReducedData(frame_);
}
ForcedColors MediaValuesDynamic::GetForcedColors() const {
return CalculateForcedColors();
}
......
......@@ -49,6 +49,7 @@ class CORE_EXPORT MediaValuesDynamic : public MediaValues {
ColorSpaceGamut ColorGamut() const override;
PreferredColorScheme GetPreferredColorScheme() const override;
bool PrefersReducedMotion() const override;
bool PrefersReducedData() const override;
ForcedColors GetForcedColors() const override;
NavigationControls GetNavigationControls() const override;
ScreenSpanning GetScreenSpanning() const override;
......
......@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/platform/geometry/float_size.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
namespace blink {
......@@ -1575,6 +1576,48 @@ TEST_F(StyleEngineTest, MediaQueriesChangePrefersReducedMotion) {
GetCSSPropertyColor()));
}
TEST_F(StyleEngineTest, MediaQueriesChangePrefersReducedDataOn) {
GetNetworkStateNotifier().SetSaveDataEnabled(true);
GetDocument().body()->setInnerHTML(R"HTML(
<style>
body { color: red }
@media (prefers-reduced-data: reduce) {
body { color: green }
}
</style>
<body></body>
)HTML");
UpdateAllLifecyclePhases();
EXPECT_TRUE(GetNetworkStateNotifier().SaveDataEnabled());
EXPECT_EQ(MakeRGB(0, 128, 0),
GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
GetCSSPropertyColor()));
}
TEST_F(StyleEngineTest, MediaQueriesChangePrefersReducedDataOff) {
GetNetworkStateNotifier().SetSaveDataEnabled(false);
GetDocument().body()->setInnerHTML(R"HTML(
<style>
body { color: red }
@media (prefers-reduced-data: reduce) {
body { color: green }
}
</style>
<body></body>
)HTML");
UpdateAllLifecyclePhases();
EXPECT_FALSE(GetNetworkStateNotifier().SaveDataEnabled());
EXPECT_EQ(MakeRGB(255, 0, 0),
GetDocument().body()->GetComputedStyle()->VisitedDependentColor(
GetCSSPropertyColor()));
}
TEST_F(StyleEngineTest, MediaQueriesChangeForcedColors) {
ScopedForcedColorsForTest scoped_feature(true);
GetDocument().body()->setInnerHTML(R"HTML(
......
......@@ -1455,6 +1455,10 @@
name: "PreferNonCompositedScrolling",
settable_from_internals: true,
},
{
name: 'PrefersReducedData',
status: 'experimental',
},
// This feature is deprecated and we are evangelizing affected sites.
// See https://crbug.com/346236 for current status.
{
......
This is a testharness.js-based test.
FAIL Should be parseable in a CSS stylesheet: '(prefers-reduced-data)' assert_true: expected true got false
FAIL Should be parseable in a CSS stylesheet: '(prefers-reduced-data: no-preference)' assert_true: expected true got false
FAIL Should be parseable in a CSS stylesheet: '(prefers-reduced-data: reduce)' assert_true: expected true got false
PASS Should not be parseable in a CSS stylesheet: '(prefers-reduced-data: 0)'
PASS Should not be parseable in a CSS stylesheet: '(prefers-reduced-data: none)'
PASS Should not be parseable in a CSS stylesheet: '(prefers-reduced-data: 10px)'
PASS Should not be parseable in a CSS stylesheet: '(prefers-reduced-data: no-preference reduce)'
PASS Should not be parseable in a CSS stylesheet: '(prefers-reduced-data: reduced)'
PASS Should not be parseable in a CSS stylesheet: '(prefers-reduced-data: no-preference/reduce)'
FAIL Should be parseable in JS: '(prefers-reduced-data)' assert_true: expected true got false
FAIL Should be parseable in JS: '(prefers-reduced-data: no-preference)' assert_true: expected true got false
FAIL Should be parseable in JS: '(prefers-reduced-data: reduce)' assert_true: expected true got false
PASS Should not be parseable in JS: '(prefers-reduced-data: 0)'
PASS Should not be parseable in JS: '(prefers-reduced-data: none)'
PASS Should not be parseable in JS: '(prefers-reduced-data: 10px)'
PASS Should not be parseable in JS: '(prefers-reduced-data: no-preference reduce)'
PASS Should not be parseable in JS: '(prefers-reduced-data: reduced)'
PASS Should not be parseable in JS: '(prefers-reduced-data: no-preference/reduce)'
FAIL Check that no-preference evaluates to false in the boolean context assert_equals: expected true but got false
Harness: the test ran to completion.
......@@ -28,11 +28,14 @@ query_should_not_be_js_parseable("(prefers-reduced-data: reduced)");
query_should_not_be_js_parseable("(prefers-reduced-data: no-preference/reduce)");
test(() => {
// What this is saying is that 'no-preference' is not the default, so
// irregardless of the current OS settings, (prefers-reduced-data).matches
// should not be equivalent to (prefers-reduced-data: no-preference).matches.
// https://drafts.csswg.org/mediaqueries-5/#boolean-context
let booleanContext = window.matchMedia("(prefers-reduced-data)");
let noPreference = window.matchMedia("(prefers-reduced-data: no-preference)");
assert_equals(booleanContext.matches, !noPreference.matches);
}, "Check that no-preference evaluates to false in the boolean context");
test(() => {
let invalid = window.matchMedia("(prefers-reduced-data: 10px)");
assert_equals(invalid.matches, false);
}, "Check that invalid evaluates to false");
</script>
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