Bug 1484459: Port servo to the new media query system. r=me
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 18 Aug 2018 18:19:34 +0200
changeset 487376 1e83c797f33992fa9ff267aee33bc5ea29eeba21
parent 487375 41afb719058905f95d939032df62e2b358032c24
child 487377 ce1d36b823758c979517fde4201c627188104113
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1484459
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1484459: Port servo to the new media query system. r=me Port `width`, and also add the `scan` media feature so I don't need to add ugliness just to workaround the unused keyword_evaluator macro. This is not part of the Gecko build in any case.
servo/components/style/gecko/media_features.rs
servo/components/style/media_queries/media_feature.rs
servo/components/style/servo/media_queries.rs
--- a/servo/components/style/gecko/media_features.rs
+++ b/servo/components/style/gecko/media_features.rs
@@ -11,27 +11,16 @@ use gecko_bindings::bindings;
 use values::computed::CSSPixelLength;
 use values::computed::Resolution;
 
 use media_queries::Device;
 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<Au> {
     let pc = device.pres_context();
     if pc.mIsRootPaginatedDocument() != 0 {
         // We want the page size, including unprintable areas and margins.
         // FIXME(emilio, bug 1414600): Not quite!
         let area = &pc.mPageSize;
         return Size2D::new(Au(area.width), Au(area.height))
     }
--- a/servo/components/style/media_queries/media_feature.rs
+++ b/servo/components/style/media_queries/media_feature.rs
@@ -156,16 +156,28 @@ pub struct MediaFeatureDescription {
 impl MediaFeatureDescription {
     /// Whether this media feature allows ranges.
     #[inline]
     pub fn allows_ranges(&self) -> bool {
         self.allows_ranges == AllowsRanges::Yes
     }
 }
 
+/// 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")
             .field("name", &self.name)
             .field("allows_ranges", &self.allows_ranges)
             .field("requirements", &self.requirements)
             .finish()
     }
--- a/servo/components/style/servo/media_queries.rs
+++ b/servo/components/style/servo/media_queries.rs
@@ -1,30 +1,30 @@
 /* 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/. */
 
 //! 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.
 ///
 /// This is the struct against which media queries are evaluated.
 #[derive(Debug, MallocSizeOf)]
 pub struct Device {
     /// The current media type used by de device.
     media_type: MediaType,
@@ -150,130 +150,52 @@ impl Device {
     }
 
     /// Returns the default background color.
     pub fn default_background_color(&self) -> RGBA {
         RGBA::new(255, 255, 255, 255)
     }
 }
 
-/// 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 {
-    /// <http://dev.w3.org/csswg/mediaqueries-3/#width>
-    Width(Range<specified::Length>),
+/// https://drafts.csswg.org/mediaqueries-4/#width
+fn eval_width(
+    device: &Device,
+    value: Option<CSSPixelLength>,
+    range_or_operator: Option<RangeOrOperator>,
+) -> bool {
+    RangeOrOperator::evaluate(
+        range_or_operator,
+        value.map(Au::from),
+        device.au_viewport_size().width,
+    )
+}
+
+#[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)]
+#[repr(u8)]
+enum Scan {
+    Progressive,
+    Interlace,
 }
 
-/// A single expression a per:
-///
-/// <http://dev.w3.org/csswg/mediaqueries-3/#media1>
-#[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<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
-        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,
-                }
-            },
-        }
-    }
+/// https://drafts.csswg.org/mediaqueries-4/#scan
+fn eval_scan(_: &Device, _: Option<Scan>) -> bool {
+    // Since we doesn't support the 'tv' media type, the 'scan' feature never
+    // matches.
+    false
 }
 
-impl ToCss for MediaFeatureExpression {
-    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> 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(')')
-    }
+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(),
+        ),
+    ];
 }
-
-/// 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<T> {
-    /// At least the inner value.
-    Min(T),
-    /// At most the inner value.
-    Max(T),
-    /// Exactly the inner value.
-    Eq(T),
-}
-
-impl Range<specified::Length> {
-    fn to_computed_range(&self, device: &Device, quirks_mode: QuirksMode) -> Range<Au> {
-        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))),
-        })
-    }
-}