Bug 1468846: Move MediaQuery and friends to its own module. r?xidorn draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 14 Jun 2018 13:54:07 -0700
changeset 807546 7d909a1b1529e29036420e197f1a25db0b90ccc0
parent 807545 2977b2c194690648e569c2d04ba26641e049b118
child 807552 ec583f9ecd863300ee97cfea658dfa4fd75b15cc
push id113143
push userbmo:emilio@crisal.io
push dateThu, 14 Jun 2018 21:16:25 +0000
reviewersxidorn
bugs1468846
milestone62.0a1
Bug 1468846: Move MediaQuery and friends to its own module. r?xidorn MozReview-Commit-ID: 3FRMnIHFwR3
servo/components/style/media_queries/media_query.rs
servo/components/style/media_queries/mod.rs
new file mode 100644
--- /dev/null
+++ b/servo/components/style/media_queries/media_query.rs
@@ -0,0 +1,197 @@
+/* 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:
+//!
+//! https://drafts.csswg.org/mediaqueries/#typedef-media-query
+
+use Atom;
+use cssparser::Parser;
+use parser::ParserContext;
+use selectors::parser::SelectorParseErrorKind;
+use std::fmt::{self, Write};
+use str::string_as_ascii_lowercase;
+use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
+use values::CustomIdent;
+
+use super::Expression;
+
+/// <https://drafts.csswg.org/mediaqueries/#mq-prefix>
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)]
+pub enum Qualifier {
+    /// Hide a media query from legacy UAs:
+    /// <https://drafts.csswg.org/mediaqueries/#mq-only>
+    Only,
+    /// Negate a media query:
+    /// <https://drafts.csswg.org/mediaqueries/#mq-not>
+    Not,
+}
+
+/// <https://drafts.csswg.org/mediaqueries/#media-types>
+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
+pub struct MediaType(pub CustomIdent);
+
+impl MediaType {
+    /// The `screen` media type.
+    pub fn screen() -> Self {
+        MediaType(CustomIdent(atom!("screen")))
+    }
+
+    /// The `print` media type.
+    pub fn print() -> Self {
+        MediaType(CustomIdent(atom!("print")))
+    }
+
+    fn parse(name: &str) -> Result<Self, ()> {
+        // From https://drafts.csswg.org/mediaqueries/#mq-syntax:
+        //
+        //   The <media-type> production does not include the keywords not, or, and, and only.
+        //
+        // Here we also perform the to-ascii-lowercase part of the serialization
+        // algorithm: https://drafts.csswg.org/cssom/#serializing-media-queries
+        match_ignore_ascii_case! { name,
+            "not" | "or" | "and" | "only" => Err(()),
+            _ => Ok(MediaType(CustomIdent(Atom::from(string_as_ascii_lowercase(name))))),
+        }
+    }
+}
+
+/// A [media query][mq].
+///
+/// [mq]: https://drafts.csswg.org/mediaqueries/
+#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
+pub struct MediaQuery {
+    /// The qualifier for this query.
+    pub qualifier: Option<Qualifier>,
+    /// The media type for this query, that can be known, unknown, or "all".
+    pub media_type: MediaQueryType,
+    /// The set of expressions that this media query contains.
+    pub expressions: Vec<Expression>,
+}
+
+impl ToCss for MediaQuery {
+    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+    where
+        W: Write,
+    {
+        if let Some(qual) = self.qualifier {
+            qual.to_css(dest)?;
+            dest.write_char(' ')?;
+        }
+
+        match self.media_type {
+            MediaQueryType::All => {
+                // We need to print "all" if there's a qualifier, or there's
+                // just an empty list of expressions.
+                //
+                // Otherwise, we'd serialize media queries like "(min-width:
+                // 40px)" in "all (min-width: 40px)", which is unexpected.
+                if self.qualifier.is_some() || self.expressions.is_empty() {
+                    dest.write_str("all")?;
+                }
+            },
+            MediaQueryType::Concrete(MediaType(ref desc)) => desc.to_css(dest)?,
+        }
+
+        if self.expressions.is_empty() {
+            return Ok(());
+        }
+
+        if self.media_type != MediaQueryType::All || self.qualifier.is_some() {
+            dest.write_str(" and ")?;
+        }
+
+        self.expressions[0].to_css(dest)?;
+
+        for expr in self.expressions.iter().skip(1) {
+            dest.write_str(" and ")?;
+            expr.to_css(dest)?;
+        }
+        Ok(())
+    }
+}
+
+impl MediaQuery {
+    /// Return a media query that never matches, used for when we fail to parse
+    /// a given media query.
+    pub fn never_matching() -> Self {
+        Self {
+            qualifier: Some(Qualifier::Not),
+            media_type: MediaQueryType::All,
+            expressions: vec![],
+        }
+    }
+
+    /// Parse a media query given css input.
+    ///
+    /// Returns an error if any of the expressions is unknown.
+    pub fn parse<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<MediaQuery, ParseError<'i>> {
+        let mut expressions = vec![];
+
+        let qualifier = input.try(Qualifier::parse).ok();
+        let media_type = match input.try(|i| i.expect_ident_cloned()) {
+            Ok(ident) => MediaQueryType::parse(&*ident).map_err(|()| {
+                input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
+            })?,
+            Err(_) => {
+                // Media type is only optional if qualifier is not specified.
+                if qualifier.is_some() {
+                    return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+                }
+
+                // Without a media type, require at least one expression.
+                expressions.push(Expression::parse(context, input)?);
+
+                MediaQueryType::All
+            },
+        };
+
+        // Parse any subsequent expressions
+        loop {
+            if input
+                .try(|input| input.expect_ident_matching("and"))
+                .is_err()
+            {
+                return Ok(MediaQuery {
+                    qualifier,
+                    media_type,
+                    expressions,
+                });
+            }
+            expressions.push(Expression::parse(context, input)?)
+        }
+    }
+}
+
+/// <http://dev.w3.org/csswg/mediaqueries-3/#media0>
+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
+pub enum MediaQueryType {
+    /// A media type that matches every device.
+    All,
+    /// A specific media type.
+    Concrete(MediaType),
+}
+
+impl MediaQueryType {
+    fn parse(ident: &str) -> Result<Self, ()> {
+        match_ignore_ascii_case! { ident,
+            "all" => return Ok(MediaQueryType::All),
+            _ => (),
+        };
+
+        // If parseable, accept this type as a concrete type.
+        MediaType::parse(ident).map(MediaQueryType::Concrete)
+    }
+
+    /// Returns whether this media query type matches a MediaType.
+    pub fn matches(&self, other: MediaType) -> bool {
+        match *self {
+            MediaQueryType::All => true,
+            MediaQueryType::Concrete(ref known_type) => *known_type == other,
+        }
+    }
+}
--- a/servo/components/style/media_queries/mod.rs
+++ b/servo/components/style/media_queries/mod.rs
@@ -1,204 +1,18 @@
 /* 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/. */
 
 //! [Media queries][mq].
 //!
 //! [mq]: https://drafts.csswg.org/mediaqueries/
 
-use Atom;
-use cssparser::Parser;
-use parser::ParserContext;
-use selectors::parser::SelectorParseErrorKind;
-use std::fmt::{self, Write};
-use str::string_as_ascii_lowercase;
-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
-use values::CustomIdent;
-
 mod media_list;
+mod media_query;
 
 pub use self::media_list::MediaList;
+pub use self::media_query::{MediaQuery, MediaQueryType, MediaType, Qualifier};
+
 #[cfg(feature = "servo")]
 pub use servo::media_queries::{Device, Expression};
 #[cfg(feature = "gecko")]
 pub use gecko::media_queries::{Device, Expression};
-
-/// <https://drafts.csswg.org/mediaqueries/#mq-prefix>
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Parse, ToCss)]
-pub enum Qualifier {
-    /// Hide a media query from legacy UAs:
-    /// <https://drafts.csswg.org/mediaqueries/#mq-only>
-    Only,
-    /// Negate a media query:
-    /// <https://drafts.csswg.org/mediaqueries/#mq-not>
-    Not,
-}
-
-/// A [media query][mq].
-///
-/// [mq]: https://drafts.csswg.org/mediaqueries/
-#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
-pub struct MediaQuery {
-    /// The qualifier for this query.
-    pub qualifier: Option<Qualifier>,
-    /// The media type for this query, that can be known, unknown, or "all".
-    pub media_type: MediaQueryType,
-    /// The set of expressions that this media query contains.
-    pub expressions: Vec<Expression>,
-}
-
-impl MediaQuery {
-    /// Return a media query that never matches, used for when we fail to parse
-    /// a given media query.
-    fn never_matching() -> Self {
-        Self {
-            qualifier: Some(Qualifier::Not),
-            media_type: MediaQueryType::All,
-            expressions: vec![],
-        }
-    }
-}
-
-impl ToCss for MediaQuery {
-    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
-    where
-        W: Write,
-    {
-        if let Some(qual) = self.qualifier {
-            qual.to_css(dest)?;
-            dest.write_char(' ')?;
-        }
-
-        match self.media_type {
-            MediaQueryType::All => {
-                // We need to print "all" if there's a qualifier, or there's
-                // just an empty list of expressions.
-                //
-                // Otherwise, we'd serialize media queries like "(min-width:
-                // 40px)" in "all (min-width: 40px)", which is unexpected.
-                if self.qualifier.is_some() || self.expressions.is_empty() {
-                    dest.write_str("all")?;
-                }
-            },
-            MediaQueryType::Concrete(MediaType(ref desc)) => desc.to_css(dest)?,
-        }
-
-        if self.expressions.is_empty() {
-            return Ok(());
-        }
-
-        if self.media_type != MediaQueryType::All || self.qualifier.is_some() {
-            dest.write_str(" and ")?;
-        }
-
-        self.expressions[0].to_css(dest)?;
-
-        for expr in self.expressions.iter().skip(1) {
-            dest.write_str(" and ")?;
-            expr.to_css(dest)?;
-        }
-        Ok(())
-    }
-}
-
-/// <http://dev.w3.org/csswg/mediaqueries-3/#media0>
-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
-pub enum MediaQueryType {
-    /// A media type that matches every device.
-    All,
-    /// A specific media type.
-    Concrete(MediaType),
-}
-
-impl MediaQueryType {
-    fn parse(ident: &str) -> Result<Self, ()> {
-        match_ignore_ascii_case! { ident,
-            "all" => return Ok(MediaQueryType::All),
-            _ => (),
-        };
-
-        // If parseable, accept this type as a concrete type.
-        MediaType::parse(ident).map(MediaQueryType::Concrete)
-    }
-
-    fn matches(&self, other: MediaType) -> bool {
-        match *self {
-            MediaQueryType::All => true,
-            MediaQueryType::Concrete(ref known_type) => *known_type == other,
-        }
-    }
-}
-
-/// <https://drafts.csswg.org/mediaqueries/#media-types>
-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)]
-pub struct MediaType(pub CustomIdent);
-
-impl MediaType {
-    /// The `screen` media type.
-    pub fn screen() -> Self {
-        MediaType(CustomIdent(atom!("screen")))
-    }
-
-    /// The `print` media type.
-    pub fn print() -> Self {
-        MediaType(CustomIdent(atom!("print")))
-    }
-
-    fn parse(name: &str) -> Result<Self, ()> {
-        // From https://drafts.csswg.org/mediaqueries/#mq-syntax:
-        //
-        //   The <media-type> production does not include the keywords not, or, and, and only.
-        //
-        // Here we also perform the to-ascii-lowercase part of the serialization
-        // algorithm: https://drafts.csswg.org/cssom/#serializing-media-queries
-        match_ignore_ascii_case! { name,
-            "not" | "or" | "and" | "only" => Err(()),
-            _ => Ok(MediaType(CustomIdent(Atom::from(string_as_ascii_lowercase(name))))),
-        }
-    }
-}
-
-impl MediaQuery {
-    /// Parse a media query given css input.
-    ///
-    /// Returns an error if any of the expressions is unknown.
-    pub fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<MediaQuery, ParseError<'i>> {
-        let mut expressions = vec![];
-
-        let qualifier = input.try(Qualifier::parse).ok();
-        let media_type = match input.try(|i| i.expect_ident_cloned()) {
-            Ok(ident) => MediaQueryType::parse(&*ident).map_err(|()| {
-                input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))
-            })?,
-            Err(_) => {
-                // Media type is only optional if qualifier is not specified.
-                if qualifier.is_some() {
-                    return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
-                }
-
-                // Without a media type, require at least one expression.
-                expressions.push(Expression::parse(context, input)?);
-
-                MediaQueryType::All
-            },
-        };
-
-        // Parse any subsequent expressions
-        loop {
-            if input
-                .try(|input| input.expect_ident_matching("and"))
-                .is_err()
-            {
-                return Ok(MediaQuery {
-                    qualifier,
-                    media_type,
-                    expressions,
-                });
-            }
-            expressions.push(Expression::parse(context, input)?)
-        }
-    }
-}