зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1035774 - Add media feature keys for hover and pointer. r=heycam,emilio
Summary: https://drafts.csswg.org/mediaqueries-4/#hover https://drafts.csswg.org/mediaqueries-4/#pointer In this patch series, we don't introduce any-hover and any-pointer media features yet, but functionalities for them on each platform backends will be introduced in this patch series, so eIntID_AllPointerCapabilities and relevant stuff is added in this patch for the convenience that each platform backends can be reviewed at once. Differential Revision: https://phabricator.services.mozilla.com/D3296
This commit is contained in:
Родитель
2b08d1333b
Коммит
ef03e2a299
|
@ -56,6 +56,7 @@ namespace mozilla {
|
|||
class ComputedStyle;
|
||||
class StyleSheet;
|
||||
class ServoElementSnapshotTable;
|
||||
enum class PointerCapabilities : uint8_t;
|
||||
}
|
||||
using mozilla::FontFamilyList;
|
||||
using mozilla::FontFamilyName;
|
||||
|
@ -750,6 +751,7 @@ uint32_t Gecko_MediaFeatures_GetColorDepth(nsIDocument*);
|
|||
void Gecko_MediaFeatures_GetDeviceSize(nsIDocument*, nscoord* width, nscoord* height);
|
||||
float Gecko_MediaFeatures_GetResolution(nsIDocument*);
|
||||
bool Gecko_MediaFeatures_PrefersReducedMotion(nsIDocument*);
|
||||
mozilla::PointerCapabilities Gecko_MediaFeatures_PrimaryPointerCapabilities(nsIDocument*);
|
||||
float Gecko_MediaFeatures_GetDevicePixelRatio(nsIDocument*);
|
||||
bool Gecko_MediaFeatures_HasSystemMetric(nsIDocument*,
|
||||
nsAtom* metric,
|
||||
|
|
|
@ -257,6 +257,7 @@ whitelist-types = [
|
|||
"mozilla::StyleShapeRadius",
|
||||
"mozilla::StyleGrid.*",
|
||||
"mozilla::UpdateAnimationsTasks",
|
||||
"mozilla::PointerCapabilities",
|
||||
"mozilla::LookAndFeel",
|
||||
"mozilla::gfx::Float",
|
||||
"mozilla::gfx::FontVariation",
|
||||
|
@ -620,6 +621,7 @@ structs-types = [
|
|||
"ComputedStyleStrong",
|
||||
"EffectCompositor_CascadeLevel",
|
||||
"UpdateAnimationsTasks",
|
||||
"PointerCapabilities",
|
||||
"ParsingMode",
|
||||
"InheritTarget",
|
||||
"DocumentMatchingFunction",
|
||||
|
|
|
@ -125,6 +125,17 @@ enum class InheritTarget {
|
|||
PlaceholderFrame,
|
||||
};
|
||||
|
||||
// Represents values for interaction media features.
|
||||
// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
|
||||
enum class PointerCapabilities : uint8_t {
|
||||
None = 0,
|
||||
Coarse = 1 << 0,
|
||||
Fine = 1 << 1,
|
||||
Hover = 1 << 2,
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PointerCapabilities)
|
||||
|
||||
// These measurements are obtained for both the UA cache and the Stylist, but
|
||||
// not all the fields are used in both cases.
|
||||
class ServoStyleSetSizes
|
||||
|
|
|
@ -262,6 +262,28 @@ Gecko_MediaFeatures_PrefersReducedMotion(nsIDocument* aDocument)
|
|||
return LookAndFeel::GetInt(LookAndFeel::eIntID_PrefersReducedMotion, 0) == 1;
|
||||
}
|
||||
|
||||
PointerCapabilities
|
||||
Gecko_MediaFeatures_PrimaryPointerCapabilities(nsIDocument* aDocument)
|
||||
{
|
||||
// The default value is mouse-type pointer.
|
||||
const PointerCapabilities kDefaultCapabilities =
|
||||
PointerCapabilities::Fine | PointerCapabilities::Hover;
|
||||
|
||||
if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
|
||||
return kDefaultCapabilities;
|
||||
}
|
||||
|
||||
int32_t intValue;
|
||||
nsresult rv =
|
||||
LookAndFeel::GetInt(LookAndFeel::eIntID_PrimaryPointerCapabilities,
|
||||
&intValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
return kDefaultCapabilities;
|
||||
}
|
||||
|
||||
return static_cast<PointerCapabilities>(intValue);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsMediaFeatures::InitSystemMetrics()
|
||||
{
|
||||
|
|
|
@ -257,6 +257,7 @@ skip-if = android_version == '18' #debug-only failure; timed out #Android 4.3 aw
|
|||
[test_media_queries_dynamic_xbl.html]
|
||||
[test_media_query_list.html]
|
||||
[test_media_query_serialization.html]
|
||||
[test_mq_hover_and_pointer.html]
|
||||
[test_moz_device_pixel_ratio.html]
|
||||
[test_namespace_rule.html]
|
||||
[test_non_content_accessible_properties.html]
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1035774
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1035774</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=1035774">Mozilla Bug 1035774</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
<script>
|
||||
|
||||
const NO_POINTER = 0x00;
|
||||
const COARSE_POINTER = 0x01;
|
||||
const FINE_POINTER = 0x02;
|
||||
const HOVER_CAPABLE_POINTER = 0x04;
|
||||
|
||||
add_task(async () => {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [ ['privacy.resistFingerprinting', true] ]
|
||||
});
|
||||
|
||||
// When resistFingerprinting is enabled, we pretend that the system has a
|
||||
// mouse pointer.
|
||||
ok(!matchMedia("(pointer: none)").matches,
|
||||
"Doesn't match (pointer: none)");
|
||||
ok(!matchMedia("(pointer: coarse)").matches,
|
||||
"Doesn't match (pointer: coarse)");
|
||||
ok(matchMedia("(pointer: fine)").matches, "Matches (pointer: fine)");
|
||||
ok(matchMedia("(pointer)").matches, "Matches (pointer)");
|
||||
|
||||
ok(!matchMedia("(hover: none)").matches, "Doesn't match (hover: none)");
|
||||
ok(matchMedia("(hover: hover)").matches, "Matches (hover: hover)");
|
||||
ok(matchMedia("(hover)").matches, "Matches (hover)");
|
||||
|
||||
await SpecialPowers.flushPrefEnv();
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
// No pointer.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [ ['ui.primaryPointerCapabilities', NO_POINTER] ]
|
||||
});
|
||||
|
||||
ok(matchMedia("(pointer: none)").matches, "Matches (pointer: none)");
|
||||
ok(!matchMedia("(pointer: coarse)").matches,
|
||||
"Doesn't match (pointer: coarse)");
|
||||
ok(!matchMedia("(pointer: fine)").matches, "Doesn't match (pointer: fine)");
|
||||
ok(!matchMedia("(pointer)").matches, "Matches (pointer)");
|
||||
|
||||
ok(matchMedia("(hover: none)").matches, "Matches (hover: none)");
|
||||
ok(!matchMedia("(hover: hover)").matches, "Doesn't match (hover: hover)");
|
||||
ok(!matchMedia("(hover)").matches, "Doesn't match (hover)");
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
// Mouse type pointer.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [ ['ui.primaryPointerCapabilities', FINE_POINTER | HOVER_CAPABLE_POINTER] ]
|
||||
});
|
||||
|
||||
ok(!matchMedia("(pointer: none)").matches,
|
||||
"Doesn't match (pointer: none)");
|
||||
ok(!matchMedia("(pointer: coarse)").matches,
|
||||
"Doesn't match (pointer: coarse)");
|
||||
ok(matchMedia("(pointer: fine)").matches, "Matches (pointer: fine)");
|
||||
ok(matchMedia("(pointer)").matches, "Matches (pointer)");
|
||||
|
||||
ok(!matchMedia("(hover: none)").matches, "Doesn't match (hover: none)");
|
||||
ok(matchMedia("(hover: hover)").matches, "Matches (hover: hover)");
|
||||
ok(matchMedia("(hover)").matches, "Matches (hover)");
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
// Mouse type pointer.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [ ['ui.primaryPointerCapabilities',
|
||||
FINE_POINTER |
|
||||
HOVER_CAPABLE_POINTER] ]
|
||||
});
|
||||
|
||||
ok(!matchMedia("(pointer: none)").matches,
|
||||
"Doesn't match (pointer: none)");
|
||||
ok(!matchMedia("(pointer: coarse)").matches,
|
||||
"Doesn't match (pointer: coarse)");
|
||||
ok(matchMedia("(pointer: fine)").matches, "Matches (pointer: fine)");
|
||||
ok(matchMedia("(pointer)").matches, "Matches (pointer)");
|
||||
|
||||
ok(!matchMedia("(hover: none)").matches, "Doesn't match (hover: none)");
|
||||
ok(matchMedia("(hover: hover)").matches, "Matches (hover: hover)");
|
||||
ok(matchMedia("(hover)").matches, "Matches (hover)");
|
||||
});
|
||||
|
||||
add_task(async () => {
|
||||
// Touch screen.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [ ['ui.primaryPointerCapabilities', COARSE_POINTER] ]
|
||||
});
|
||||
|
||||
ok(!matchMedia("(pointer: none)").matches, "Doesn't match (pointer: none)");
|
||||
ok(matchMedia("(pointer: coarse)").matches, "Matches (pointer: coarse)");
|
||||
ok(!matchMedia("(pointer: fine)").matches, "Doesn't match (pointer: fine)");
|
||||
ok(matchMedia("(pointer)").matches, "Matches (pointer)");
|
||||
|
||||
ok(matchMedia("(hover: none)").matches, "Match (hover: none)");
|
||||
ok(!matchMedia("(hover: hover)").matches, "Doesn't match (hover: hover)");
|
||||
ok(!matchMedia("(hover)").matches, "Doesn't match (hover)");
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -8,6 +8,7 @@ use Atom;
|
|||
use app_units::Au;
|
||||
use euclid::Size2D;
|
||||
use gecko_bindings::bindings;
|
||||
use gecko_bindings::structs;
|
||||
use media_queries::Device;
|
||||
use media_queries::media_feature::{AllowsRanges, ParsingRequirements};
|
||||
use media_queries::media_feature::{MediaFeatureDescription, Evaluator};
|
||||
|
@ -300,6 +301,66 @@ fn eval_prefers_reduced_motion(device: &Device, query_value: Option<PrefersReduc
|
|||
}
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/mediaqueries-4/#mf-interaction
|
||||
bitflags! {
|
||||
struct PointerCapabilities: u8 {
|
||||
const COARSE = structs::PointerCapabilities_Coarse;
|
||||
const FINE = structs::PointerCapabilities_Fine;
|
||||
const HOVER = structs::PointerCapabilities_Hover;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)]
|
||||
#[repr(u8)]
|
||||
enum Pointer {
|
||||
None,
|
||||
Coarse,
|
||||
Fine,
|
||||
}
|
||||
|
||||
fn primary_pointer_capabilities(device: &Device) -> PointerCapabilities {
|
||||
PointerCapabilities::from_bits_truncate(
|
||||
unsafe { bindings::Gecko_MediaFeatures_PrimaryPointerCapabilities(device.document()) }
|
||||
)
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/mediaqueries-4/#pointer
|
||||
fn eval_pointer(device: &Device, query_value: Option<Pointer>) -> bool {
|
||||
let pointer_capabilities = primary_pointer_capabilities(device);
|
||||
let query_value = match query_value {
|
||||
Some(v) => v,
|
||||
None => return !pointer_capabilities.is_empty(),
|
||||
};
|
||||
|
||||
match query_value {
|
||||
Pointer::None => pointer_capabilities.is_empty(),
|
||||
Pointer::Coarse => pointer_capabilities.intersects(PointerCapabilities::COARSE),
|
||||
Pointer::Fine => pointer_capabilities.intersects(PointerCapabilities::FINE),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)]
|
||||
#[repr(u8)]
|
||||
enum Hover {
|
||||
None,
|
||||
Hover,
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/mediaqueries-4/#hover
|
||||
fn eval_hover(device: &Device, query_value: Option<Hover>) -> bool {
|
||||
let pointer_capabilities = primary_pointer_capabilities(device);
|
||||
let can_hover = pointer_capabilities.intersects(PointerCapabilities::HOVER);
|
||||
let query_value = match query_value {
|
||||
Some(v) => v,
|
||||
None => return can_hover,
|
||||
};
|
||||
|
||||
match query_value {
|
||||
Hover::None => !can_hover,
|
||||
Hover::Hover => can_hover,
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_moz_is_glyph(
|
||||
device: &Device,
|
||||
query_value: Option<bool>,
|
||||
|
@ -390,7 +451,7 @@ lazy_static! {
|
|||
/// to support new types in these entries and (2) ensuring that either
|
||||
/// nsPresContext::MediaFeatureValuesChanged is called when the value that
|
||||
/// would be returned by the evaluator function could change.
|
||||
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 43] = [
|
||||
pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 45] = [
|
||||
feature!(
|
||||
atom!("width"),
|
||||
AllowsRanges::Yes,
|
||||
|
@ -509,6 +570,18 @@ lazy_static! {
|
|||
keyword_evaluator!(eval_prefers_reduced_motion, PrefersReducedMotion),
|
||||
ParsingRequirements::empty(),
|
||||
),
|
||||
feature!(
|
||||
atom!("pointer"),
|
||||
AllowsRanges::No,
|
||||
keyword_evaluator!(eval_pointer, Pointer),
|
||||
ParsingRequirements::empty(),
|
||||
),
|
||||
feature!(
|
||||
atom!("hover"),
|
||||
AllowsRanges::No,
|
||||
keyword_evaluator!(eval_hover, Hover),
|
||||
ParsingRequirements::empty(),
|
||||
),
|
||||
|
||||
// Internal -moz-is-glyph media feature: applies only inside SVG glyphs.
|
||||
// Internal because it is really only useful in the user agent anyway
|
||||
|
|
|
@ -447,7 +447,22 @@ public:
|
|||
* 0: no-preference
|
||||
* 1: reduce
|
||||
*/
|
||||
|
||||
eIntID_PrefersReducedMotion,
|
||||
/**
|
||||
* Corresponding to PointerCapabilities in ServoTypes.h
|
||||
* 0: None
|
||||
* 1: Coarse
|
||||
* 2: Fine
|
||||
* 4: Hover
|
||||
*/
|
||||
eIntID_PrimaryPointerCapabilities,
|
||||
/**
|
||||
* Corresponding to union of PointerCapabilities values in ServoTypes.h
|
||||
* E.g. if there is a mouse and a digitizer, the value will be
|
||||
* 'Coarse | Fine | Hover'.
|
||||
*/
|
||||
eIntID_AllPointerCapabilities,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -141,6 +141,12 @@ nsLookAndFeelIntPref nsXPLookAndFeel::sIntPrefs[] =
|
|||
{ "ui.prefersReducedMotion",
|
||||
eIntID_PrefersReducedMotion,
|
||||
false, 0 },
|
||||
{ "ui.primaryPointerCapabilities",
|
||||
eIntID_PrimaryPointerCapabilities,
|
||||
false, 6 /* fine and hover-capable pointer, i.e. mouse-type */ },
|
||||
{ "ui.allPointerCapabilities",
|
||||
eIntID_AllPointerCapabilities,
|
||||
false, 6 /* fine and hover-capable pointer, i.e. mouse-type */ },
|
||||
};
|
||||
|
||||
nsLookAndFeelFloatPref nsXPLookAndFeel::sFloatPrefs[] =
|
||||
|
|
|
@ -1383,6 +1383,7 @@ STATIC_ATOMS = [
|
|||
Atom("patternTransform", "patternTransform"),
|
||||
Atom("patternUnits", "patternUnits"),
|
||||
Atom("pc", "pc"),
|
||||
Atom("pointer", "pointer"),
|
||||
Atom("pointer_events", "pointer-events"),
|
||||
Atom("points", "points"),
|
||||
Atom("pointsAtX", "pointsAtX"),
|
||||
|
|
Загрузка…
Ссылка в новой задаче