diff --git a/components/style/gecko/media_features.rs b/components/style/gecko/media_features.rs index 3595133f55c..8d7147f6ad2 100644 --- a/components/style/gecko/media_features.rs +++ b/components/style/gecko/media_features.rs @@ -16,17 +16,6 @@ use media_queries::media_feature::{MediaFeatureDescription, Evaluator}; use media_queries::media_feature::{AllowsRanges, ParsingRequirements}; use media_queries::media_feature_expression::{AspectRatio, RangeOrOperator}; -macro_rules! feature { - ($name:expr, $allows_ranges:expr, $evaluator:expr, $reqs:expr,) => { - MediaFeatureDescription { - name: $name, - allows_ranges: $allows_ranges, - evaluator: $evaluator, - requirements: $reqs, - } - } -} - fn viewport_size(device: &Device) -> Size2D { let pc = device.pres_context(); if pc.mIsRootPaginatedDocument() != 0 { diff --git a/components/style/media_queries/media_feature.rs b/components/style/media_queries/media_feature.rs index 7c0bfc12bef..fc486f0e627 100644 --- a/components/style/media_queries/media_feature.rs +++ b/components/style/media_queries/media_feature.rs @@ -161,6 +161,18 @@ impl MediaFeatureDescription { } } +/// A simple helper to construct a `MediaFeatureDescription`. +macro_rules! feature { + ($name:expr, $allows_ranges:expr, $evaluator:expr, $reqs:expr,) => { + $crate::media_queries::media_feature::MediaFeatureDescription { + name: $name, + allows_ranges: $allows_ranges, + evaluator: $evaluator, + requirements: $reqs, + } + } +} + impl fmt::Debug for MediaFeatureDescription { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MediaFeatureExpression") diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index ba31cfcaf4b..ab4240815b4 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -5,21 +5,21 @@ //! Servo's media-query device and expression representation. use app_units::Au; -use context::QuirksMode; -use cssparser::{Parser, RGBA}; +use cssparser::RGBA; use euclid::{Size2D, TypedScale, TypedSize2D}; use media_queries::MediaType; -use parser::ParserContext; use properties::ComputedValues; -use selectors::parser::SelectorParseErrorKind; -use std::fmt::{self, Write}; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; -use style_traits::{CSSPixel, CssWriter, DevicePixel, ParseError, ToCss}; +use style_traits::{CSSPixel, DevicePixel}; use style_traits::viewport::ViewportConstraints; -use values::{specified, KeyframesName}; -use values::computed::{self, ToComputedValue}; +use values::KeyframesName; +use values::computed::CSSPixelLength; use values::computed::font::FontSize; +use media_queries::media_feature::{MediaFeatureDescription, Evaluator}; +use media_queries::media_feature::{AllowsRanges, ParsingRequirements}; +use media_queries::media_feature_expression::RangeOrOperator; + /// A device is a structure that represents the current media a given document /// is displayed in. /// @@ -155,125 +155,47 @@ impl Device { } } -/// A expression kind servo understands and parses. -/// -/// Only `pub` for unit testing, please don't use it directly! -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -pub enum ExpressionKind { - /// - Width(Range), +/// https://drafts.csswg.org/mediaqueries-4/#width +fn eval_width( + device: &Device, + value: Option, + range_or_operator: Option, +) -> bool { + RangeOrOperator::evaluate( + range_or_operator, + value.map(Au::from), + device.au_viewport_size().width, + ) } -/// A single expression a per: -/// -/// -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -pub struct MediaFeatureExpression(pub ExpressionKind); - -impl MediaFeatureExpression { - /// The kind of expression we're, just for unit testing. - /// - /// Eventually this will become servo-only. - pub fn kind_for_testing(&self) -> &ExpressionKind { - &self.0 - } - - /// Parse a media expression of the form: - /// - /// ``` - /// media-feature: media-value - /// ``` - /// - /// Only supports width ranges for now. - pub fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - 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> { - let name = input.expect_ident_cloned()?; - input.expect_colon()?; - // TODO: Handle other media features - Ok(MediaFeatureExpression(match_ignore_ascii_case! { &name, - "min-width" => { - ExpressionKind::Width(Range::Min(specified::Length::parse_non_negative(context, input)?)) - }, - "max-width" => { - ExpressionKind::Width(Range::Max(specified::Length::parse_non_negative(context, input)?)) - }, - "width" => { - ExpressionKind::Width(Range::Eq(specified::Length::parse_non_negative(context, input)?)) - }, - _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))) - })) - } - - /// Evaluate this expression and return whether it matches the current - /// device. - pub fn matches(&self, device: &Device, quirks_mode: QuirksMode) -> bool { - let viewport_size = device.au_viewport_size(); - let value = viewport_size.width; - match self.0 { - ExpressionKind::Width(ref range) => { - match range.to_computed_range(device, quirks_mode) { - Range::Min(ref width) => value >= *width, - Range::Max(ref width) => value <= *width, - Range::Eq(ref width) => value == *width, - } - }, - } - } +#[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)] +#[repr(u8)] +enum Scan { + Progressive, + Interlace, } -impl ToCss for MediaFeatureExpression { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - let (s, l) = match self.0 { - ExpressionKind::Width(Range::Min(ref l)) => ("(min-width: ", l), - ExpressionKind::Width(Range::Max(ref l)) => ("(max-width: ", l), - ExpressionKind::Width(Range::Eq(ref l)) => ("(width: ", l), - }; - dest.write_str(s)?; - l.to_css(dest)?; - dest.write_char(')') - } +/// https://drafts.csswg.org/mediaqueries-4/#scan +fn eval_scan(_: &Device, _: Option) -> bool { + // Since we doesn't support the 'tv' media type, the 'scan' feature never + // matches. + false } -/// An enumeration that represents a ranged value. -/// -/// Only public for testing, implementation details of `MediaFeatureExpression` -/// may change for Stylo. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -pub enum Range { - /// At least the inner value. - Min(T), - /// At most the inner value. - Max(T), - /// Exactly the inner value. - Eq(T), -} - -impl Range { - fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range { - computed::Context::for_media_query_evaluation(device, quirks_mode, |context| match *self { - Range::Min(ref width) => Range::Min(Au::from(width.to_computed_value(&context))), - Range::Max(ref width) => Range::Max(Au::from(width.to_computed_value(&context))), - Range::Eq(ref width) => Range::Eq(Au::from(width.to_computed_value(&context))), - }) - } +lazy_static! { + /// A list with all the media features that Servo supports. + pub static ref MEDIA_FEATURES: [MediaFeatureDescription; 2] = [ + feature!( + atom!("width"), + AllowsRanges::Yes, + Evaluator::Length(eval_width), + ParsingRequirements::empty(), + ), + feature!( + atom!("scan"), + AllowsRanges::No, + keyword_evaluator!(eval_scan, Scan), + ParsingRequirements::empty(), + ), + ]; }