Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
style: Move MediaList to its own module.
And move the parsing from a free function to MediaList::parse. Bug: 1468846 Reviewed-by: xidorn MozReview-Commit-ID: 75ES6I2EEOE
- Loading branch information
Showing
3 changed files
with
159 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* 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 list: | ||
//! | ||
//! https://drafts.csswg.org/mediaqueries/#typedef-media-query-list | ||
|
||
use cssparser::{Delimiter, Parser}; | ||
use cssparser::{ParserInput, Token}; | ||
use context::QuirksMode; | ||
use error_reporting::{ContextualParseError, ParseErrorReporter}; | ||
use parser::{ParserContext, ParserErrorContext}; | ||
use super::{Device, MediaQuery, Qualifier}; | ||
|
||
/// A type that encapsulates a media query list. | ||
#[css(comma)] | ||
#[derive(Clone, Debug, MallocSizeOf, ToCss)] | ||
pub struct MediaList { | ||
/// The list of media queries. | ||
#[css(iterable)] | ||
pub media_queries: Vec<MediaQuery>, | ||
} | ||
|
||
impl MediaList { | ||
/// Parse a media query list from CSS. | ||
/// | ||
/// Always returns a media query list. If any invalid media query is | ||
/// found, the media query list is only filled with the equivalent of | ||
/// "not all", see: | ||
/// | ||
/// <https://drafts.csswg.org/mediaqueries/#error-handling> | ||
pub fn parse<R>( | ||
context: &ParserContext, | ||
input: &mut Parser, | ||
error_reporter: &R, | ||
) -> MediaList | ||
where | ||
R: ParseErrorReporter, | ||
{ | ||
if input.is_exhausted() { | ||
return Self::empty(); | ||
} | ||
|
||
let mut media_queries = vec![]; | ||
loop { | ||
let start_position = input.position(); | ||
match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i)) { | ||
Ok(mq) => { | ||
media_queries.push(mq); | ||
}, | ||
Err(err) => { | ||
media_queries.push(MediaQuery::never_matching()); | ||
let location = err.location; | ||
let error = | ||
ContextualParseError::InvalidMediaRule(input.slice_from(start_position), err); | ||
let error_context = ParserErrorContext { error_reporter }; | ||
context.log_css_error(&error_context, location, error); | ||
}, | ||
} | ||
|
||
match input.next() { | ||
Ok(&Token::Comma) => {}, | ||
Ok(_) => unreachable!(), | ||
Err(_) => break, | ||
} | ||
} | ||
|
||
MediaList { media_queries } | ||
} | ||
|
||
/// Create an empty MediaList. | ||
pub fn empty() -> Self { | ||
MediaList { | ||
media_queries: vec![], | ||
} | ||
} | ||
|
||
/// Evaluate a whole `MediaList` against `Device`. | ||
pub fn evaluate(&self, device: &Device, quirks_mode: QuirksMode) -> bool { | ||
// Check if it is an empty media query list or any queries match (OR condition) | ||
// https://drafts.csswg.org/mediaqueries-4/#mq-list | ||
self.media_queries.is_empty() || self.media_queries.iter().any(|mq| { | ||
let media_match = mq.media_type.matches(device.media_type()); | ||
|
||
// Check if all conditions match (AND condition) | ||
let query_match = media_match && | ||
mq.expressions | ||
.iter() | ||
.all(|expression| expression.matches(&device, quirks_mode)); | ||
|
||
// Apply the logical NOT qualifier to the result | ||
match mq.qualifier { | ||
Some(Qualifier::Not) => !query_match, | ||
_ => query_match, | ||
} | ||
}) | ||
} | ||
|
||
/// Whether this `MediaList` contains no media queries. | ||
pub fn is_empty(&self) -> bool { | ||
self.media_queries.is_empty() | ||
} | ||
|
||
/// Append a new media query item to the media list. | ||
/// <https://drafts.csswg.org/cssom/#dom-medialist-appendmedium> | ||
/// | ||
/// Returns true if added, false if fail to parse the medium string. | ||
pub fn append_medium(&mut self, context: &ParserContext, new_medium: &str) -> bool { | ||
let mut input = ParserInput::new(new_medium); | ||
let mut parser = Parser::new(&mut input); | ||
let new_query = match MediaQuery::parse(&context, &mut parser) { | ||
Ok(query) => query, | ||
Err(_) => { | ||
return false; | ||
}, | ||
}; | ||
// This algorithm doesn't actually matches the current spec, | ||
// but it matches the behavior of Gecko and Edge. | ||
// See https://github.com/w3c/csswg-drafts/issues/697 | ||
self.media_queries.retain(|query| query != &new_query); | ||
self.media_queries.push(new_query); | ||
true | ||
} | ||
|
||
/// Delete a media query from the media list. | ||
/// <https://drafts.csswg.org/cssom/#dom-medialist-deletemedium> | ||
/// | ||
/// Returns true if found and deleted, false otherwise. | ||
pub fn delete_medium(&mut self, context: &ParserContext, old_medium: &str) -> bool { | ||
let mut input = ParserInput::new(old_medium); | ||
let mut parser = Parser::new(&mut input); | ||
let old_query = match MediaQuery::parse(context, &mut parser) { | ||
Ok(query) => query, | ||
Err(_) => { | ||
return false; | ||
}, | ||
}; | ||
let old_len = self.media_queries.len(); | ||
self.media_queries.retain(|query| query != &old_query); | ||
old_len != self.media_queries.len() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters