mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
style: Add code to parse media conditions.
Still unused. Bug: 1422225 Reviewed-by: xidorn MozReview-Commit-ID: IQfxObw9BV5
This commit is contained in:
parent
e7cc548c35
commit
0b49a3701a
4 changed files with 267 additions and 138 deletions
|
@ -651,6 +651,16 @@ impl MediaFeatureExpression {
|
|||
})?;
|
||||
|
||||
input.parse_nested_block(|input| {
|
||||
Self::parse_in_parenthesis_block(context, input)
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a media range expression where we've already consumed the
|
||||
/// parenthesis.
|
||||
pub fn parse_in_parenthesis_block<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
// FIXME: remove extra indented block when lifetimes are non-lexical
|
||||
let feature;
|
||||
let range;
|
||||
|
@ -785,7 +795,6 @@ impl MediaFeatureExpression {
|
|||
})?;
|
||||
|
||||
Ok(Self::new(feature, Some(value), range_or_operator))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns whether this media query evaluates to true for the given device.
|
||||
|
|
109
components/style/media_queries/media_condition.rs
Normal file
109
components/style/media_queries/media_condition.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! A media query condition:
|
||||
//!
|
||||
//! https://drafts.csswg.org/mediaqueries-4/#typedef-media-condition
|
||||
|
||||
use cssparser::{Parser, Token};
|
||||
use parser::ParserContext;
|
||||
use style_traits::ParseError;
|
||||
|
||||
use super::MediaFeatureExpression;
|
||||
|
||||
|
||||
/// A binary `and` or `or` operator.
|
||||
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum Operator {
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
/// Represents a media condition.
|
||||
pub enum MediaCondition {
|
||||
/// A simple media feature expression, implicitly parenthesized.
|
||||
Feature(MediaFeatureExpression),
|
||||
/// A negation of a condition.
|
||||
Not(Box<MediaCondition>),
|
||||
/// A set of joint operations.
|
||||
Operation(Box<[MediaCondition]>, Operator),
|
||||
/// A condition wrapped in parenthesis.
|
||||
InParens(Box<MediaCondition>),
|
||||
}
|
||||
|
||||
impl MediaCondition {
|
||||
/// Parse a single media condition.
|
||||
pub fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
|
||||
// FIXME(emilio): This can be cleaner with nll.
|
||||
let is_negation = match *input.next()? {
|
||||
Token::ParenthesisBlock => false,
|
||||
Token::Ident(ref ident) if ident.eq_ignore_ascii_case("not") => true,
|
||||
ref t => {
|
||||
return Err(location.new_unexpected_token_error(t.clone()))
|
||||
}
|
||||
};
|
||||
|
||||
if is_negation {
|
||||
let inner_condition = Self::parse_in_parens(context, input)?;
|
||||
return Ok(MediaCondition::Not(Box::new(inner_condition)))
|
||||
}
|
||||
|
||||
// ParenthesisBlock.
|
||||
let first_condition = Self::parse_paren_block(context, input)?;
|
||||
let operator = match input.try(Operator::parse) {
|
||||
Ok(op) => op,
|
||||
Err(..) => return Ok(first_condition),
|
||||
};
|
||||
|
||||
let mut conditions = vec![];
|
||||
conditions.push(first_condition);
|
||||
conditions.push(Self::parse_in_parens(context, input)?);
|
||||
|
||||
let delim = match operator {
|
||||
Operator::And => "and",
|
||||
Operator::Or => "or",
|
||||
};
|
||||
|
||||
loop {
|
||||
if input.try(|i| i.expect_ident_matching(delim)).is_err() {
|
||||
return Ok(MediaCondition::Operation(
|
||||
conditions.into_boxed_slice(),
|
||||
operator,
|
||||
));
|
||||
}
|
||||
|
||||
conditions.push(Self::parse_in_parens(context, input)?);
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a media condition in parentheses.
|
||||
pub fn parse_in_parens<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.expect_parenthesis_block()?;
|
||||
Self::parse_paren_block(context, input)
|
||||
}
|
||||
|
||||
fn parse_paren_block<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.parse_nested_block(|input| {
|
||||
// Base case.
|
||||
if let Ok(expr) = input.try(|i| MediaFeatureExpression::parse_in_parenthesis_block(context, i)) {
|
||||
return Ok(MediaCondition::Feature(expr));
|
||||
}
|
||||
|
||||
let inner = Self::parse(context, input)?;
|
||||
Ok(MediaCondition::InParens(Box::new(inner)))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -6,9 +6,11 @@
|
|||
//!
|
||||
//! [mq]: https://drafts.csswg.org/mediaqueries/
|
||||
|
||||
mod media_condition;
|
||||
mod media_list;
|
||||
mod media_query;
|
||||
|
||||
pub use self::media_condition::MediaCondition;
|
||||
pub use self::media_list::MediaList;
|
||||
pub use self::media_query::{MediaQuery, MediaQueryType, MediaType, Qualifier};
|
||||
|
||||
|
|
|
@ -183,16 +183,26 @@ impl MediaFeatureExpression {
|
|||
/// Parse a media expression of the form:
|
||||
///
|
||||
/// ```
|
||||
/// (media-feature: media-value)
|
||||
/// media-feature: media-value
|
||||
/// ```
|
||||
///
|
||||
/// Only supports width and width ranges for now.
|
||||
/// Only supports width ranges for now.
|
||||
pub fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
input.expect_parenthesis_block()?;
|
||||
input.parse_nested_block(|input| {
|
||||
Self::parse_in_parenthesis_block(context, input)
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse a media range expression where we've already consumed the
|
||||
/// parenthesis.
|
||||
pub fn parse_in_parenthesis_block<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let name = input.expect_ident_cloned()?;
|
||||
input.expect_colon()?;
|
||||
// TODO: Handle other media features
|
||||
|
@ -208,7 +218,6 @@ impl MediaFeatureExpression {
|
|||
},
|
||||
_ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name)))
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// Evaluate this expression and return whether it matches the current
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue