mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
style: Simplify media query evaluation code a bit
This patch: * Removes generic <ident> support for media features. These were used for some privileged media features but are no longer used. * Simplifies media feature getters by shifting the responsibility of dealing with RangeOrOperator to the caller. This makes it easier to implement container-query / mediaqueries-4 syntax, and also cleans up the code a bunch. There should be no change in behavior. Differential Revision: https://phabricator.services.mozilla.com/D144051
This commit is contained in:
parent
e4fb1377ac
commit
6a6a53930e
3 changed files with 89 additions and 230 deletions
|
@ -4,7 +4,6 @@
|
|||
|
||||
//! Media features.
|
||||
|
||||
use super::media_feature_expression::RangeOrOperator;
|
||||
use super::Device;
|
||||
use crate::parser::ParserContext;
|
||||
use crate::values::computed::Ratio;
|
||||
|
@ -17,12 +16,7 @@ use style_traits::ParseError;
|
|||
/// A generic discriminant for an enum value.
|
||||
pub type KeywordDiscriminant = u8;
|
||||
|
||||
type MediaFeatureEvaluator<T> = fn(
|
||||
device: &Device,
|
||||
// null == no value was given in the query.
|
||||
value: Option<T>,
|
||||
range_or_operator: Option<RangeOrOperator>,
|
||||
) -> bool;
|
||||
type MediaFeatureGetter<T> = fn(device: &Device) -> T;
|
||||
|
||||
/// Serializes a given discriminant.
|
||||
///
|
||||
|
@ -41,14 +35,14 @@ pub type KeywordParser = for<'a, 'i, 't> fn(
|
|||
/// This determines the kind of values that get parsed, too.
|
||||
#[allow(missing_docs)]
|
||||
pub enum Evaluator {
|
||||
Length(MediaFeatureEvaluator<CSSPixelLength>),
|
||||
Integer(MediaFeatureEvaluator<u32>),
|
||||
Float(MediaFeatureEvaluator<f32>),
|
||||
BoolInteger(MediaFeatureEvaluator<bool>),
|
||||
Length(MediaFeatureGetter<CSSPixelLength>),
|
||||
Integer(MediaFeatureGetter<u32>),
|
||||
Float(MediaFeatureGetter<f32>),
|
||||
BoolInteger(MediaFeatureGetter<bool>),
|
||||
/// A non-negative number ratio, such as the one from device-pixel-ratio.
|
||||
NumberRatio(MediaFeatureEvaluator<Ratio>),
|
||||
NumberRatio(MediaFeatureGetter<Ratio>),
|
||||
/// A resolution.
|
||||
Resolution(MediaFeatureEvaluator<Resolution>),
|
||||
Resolution(MediaFeatureGetter<Resolution>),
|
||||
/// A keyword value.
|
||||
Enumerated {
|
||||
/// The parser to get a discriminant given a string.
|
||||
|
@ -60,9 +54,8 @@ pub enum Evaluator {
|
|||
serializer: KeywordSerializer,
|
||||
/// The evaluator itself. This is guaranteed to be called with a
|
||||
/// keyword that `parser` has produced.
|
||||
evaluator: MediaFeatureEvaluator<KeywordDiscriminant>,
|
||||
evaluator: fn(&Device, Option<KeywordDiscriminant>) -> bool,
|
||||
},
|
||||
Ident(MediaFeatureEvaluator<Atom>),
|
||||
}
|
||||
|
||||
/// A simple helper macro to create a keyword evaluator.
|
||||
|
@ -93,14 +86,7 @@ macro_rules! keyword_evaluator {
|
|||
fn __evaluate(
|
||||
device: &$crate::media_queries::Device,
|
||||
value: Option<$crate::media_queries::media_feature::KeywordDiscriminant>,
|
||||
range_or_operator: Option<
|
||||
$crate::media_queries::media_feature_expression::RangeOrOperator,
|
||||
>,
|
||||
) -> bool {
|
||||
debug_assert!(
|
||||
range_or_operator.is_none(),
|
||||
"Since when do keywords accept ranges?"
|
||||
);
|
||||
// This unwrap is ok because the only discriminants that get
|
||||
// back to us is the ones that `parse` produces.
|
||||
let value: Option<$keyword_type> =
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::servo::media_queries::MEDIA_FEATURES;
|
|||
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
|
||||
use crate::values::computed::{self, Ratio, ToComputedValue};
|
||||
use crate::values::specified::{Integer, Length, Number, Resolution};
|
||||
use crate::values::{serialize_atom_identifier, CSSFloat};
|
||||
use crate::values::CSSFloat;
|
||||
use crate::{Atom, Zero};
|
||||
use cssparser::{Parser, Token};
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
|
@ -78,7 +78,7 @@ pub enum RangeOrOperator {
|
|||
impl RangeOrOperator {
|
||||
/// Evaluate a given range given an optional query value and a value from
|
||||
/// the browser.
|
||||
pub fn evaluate<T>(range_or_op: Option<Self>, query_value: Option<T>, value: T) -> bool
|
||||
fn evaluate<T>(range_or_op: Option<Self>, query_value: Option<T>, value: T) -> bool
|
||||
where
|
||||
T: PartialOrd + Zero,
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ impl RangeOrOperator {
|
|||
|
||||
/// Evaluate a given range given a non-optional query value and a value from
|
||||
/// the browser.
|
||||
pub fn evaluate_with_query_value<T>(range_or_op: Option<Self>, query_value: T, value: T) -> bool
|
||||
fn evaluate_with_query_value<T>(range_or_op: Option<Self>, query_value: T, value: T) -> bool
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
|
@ -125,21 +125,13 @@ impl RangeOrOperator {
|
|||
|
||||
/// A feature expression contains a reference to the media feature, the value
|
||||
/// the media query contained, and the range to evaluate.
|
||||
#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
|
||||
#[derive(Clone, Debug, MallocSizeOf, ToShmem, PartialEq)]
|
||||
pub struct MediaFeatureExpression {
|
||||
feature_index: usize,
|
||||
value: Option<MediaExpressionValue>,
|
||||
range_or_operator: Option<RangeOrOperator>,
|
||||
}
|
||||
|
||||
impl PartialEq for MediaFeatureExpression {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.feature_index == other.feature_index &&
|
||||
self.value == other.value &&
|
||||
self.range_or_operator == other.range_or_operator
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for MediaFeatureExpression {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
|
@ -408,34 +400,50 @@ impl MediaFeatureExpression {
|
|||
specified.to_computed_value(context)
|
||||
})
|
||||
});
|
||||
eval(device, computed, self.range_or_operator)
|
||||
let length = eval(device);
|
||||
RangeOrOperator::evaluate(self.range_or_operator, computed, length)
|
||||
},
|
||||
Evaluator::Integer(eval) => {
|
||||
eval(device, expect!(Integer).cloned(), self.range_or_operator)
|
||||
let computed = expect!(Integer).cloned();
|
||||
let integer = eval(device);
|
||||
RangeOrOperator::evaluate(self.range_or_operator, computed, integer)
|
||||
},
|
||||
Evaluator::Float(eval) => {
|
||||
let computed = expect!(Float).cloned();
|
||||
let float = eval(device);
|
||||
RangeOrOperator::evaluate(self.range_or_operator, computed, float)
|
||||
}
|
||||
Evaluator::NumberRatio(eval) => {
|
||||
// A ratio of 0/0 behaves as the ratio 1/0, so we need to call used_value()
|
||||
// to convert it if necessary.
|
||||
// FIXME: we may need to update here once
|
||||
// https://github.com/w3c/csswg-drafts/issues/4954 got resolved.
|
||||
let computed = match expect!(NumberRatio).cloned() {
|
||||
Some(ratio) => ratio.used_value(),
|
||||
None => return true,
|
||||
};
|
||||
let ratio = eval(device);
|
||||
RangeOrOperator::evaluate_with_query_value(self.range_or_operator, computed, ratio)
|
||||
},
|
||||
Evaluator::Float(eval) => eval(device, expect!(Float).cloned(), self.range_or_operator),
|
||||
Evaluator::NumberRatio(eval) => eval(
|
||||
device,
|
||||
expect!(NumberRatio).cloned(),
|
||||
self.range_or_operator,
|
||||
),
|
||||
Evaluator::Resolution(eval) => {
|
||||
let computed = expect!(Resolution).map(|specified| {
|
||||
computed::Context::for_media_query_evaluation(device, quirks_mode, |context| {
|
||||
specified.to_computed_value(context)
|
||||
specified.to_computed_value(context).dppx()
|
||||
})
|
||||
});
|
||||
eval(device, computed, self.range_or_operator)
|
||||
let resolution = eval(device).dppx();
|
||||
RangeOrOperator::evaluate(self.range_or_operator, computed, resolution)
|
||||
},
|
||||
Evaluator::Enumerated { evaluator, .. } => {
|
||||
evaluator(device, expect!(Enumerated).cloned(), self.range_or_operator)
|
||||
debug_assert!(self.range_or_operator.is_none(), "Ranges with keywords?");
|
||||
evaluator(device, expect!(Enumerated).cloned())
|
||||
},
|
||||
Evaluator::BoolInteger(eval) => {
|
||||
debug_assert!(self.range_or_operator.is_none(), "Ranges with bools?");
|
||||
let computed = expect!(BoolInteger).cloned();
|
||||
let boolean = eval(device);
|
||||
computed.map_or(boolean, |v| v == boolean)
|
||||
},
|
||||
Evaluator::Ident(eval) => eval(device, expect!(Ident).cloned(), self.range_or_operator),
|
||||
Evaluator::BoolInteger(eval) => eval(
|
||||
device,
|
||||
expect!(BoolInteger).cloned(),
|
||||
self.range_or_operator,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -466,8 +474,6 @@ pub enum MediaExpressionValue {
|
|||
/// An enumerated value, defined by the variant keyword table in the
|
||||
/// feature's `mData` member.
|
||||
Enumerated(KeywordDiscriminant),
|
||||
/// An identifier.
|
||||
Ident(Atom),
|
||||
}
|
||||
|
||||
impl MediaExpressionValue {
|
||||
|
@ -482,7 +488,6 @@ impl MediaExpressionValue {
|
|||
MediaExpressionValue::BoolInteger(v) => dest.write_str(if v { "1" } else { "0" }),
|
||||
MediaExpressionValue::NumberRatio(ratio) => ratio.to_css(dest),
|
||||
MediaExpressionValue::Resolution(ref r) => r.to_css(dest),
|
||||
MediaExpressionValue::Ident(ref ident) => serialize_atom_identifier(ident, dest),
|
||||
MediaExpressionValue::Enumerated(value) => match for_expr.feature().evaluator {
|
||||
Evaluator::Enumerated { serializer, .. } => dest.write_str(&*serializer(value)),
|
||||
_ => unreachable!(),
|
||||
|
@ -527,9 +532,6 @@ impl MediaExpressionValue {
|
|||
Evaluator::Enumerated { parser, .. } => {
|
||||
MediaExpressionValue::Enumerated(parser(context, input)?)
|
||||
},
|
||||
Evaluator::Ident(..) => {
|
||||
MediaExpressionValue::Ident(Atom::from(input.expect_ident()?.as_ref()))
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue