Bug 1371395 Part 2: Servo-side allow emulation of supported media types. draft
authorBrad Werth <bwerth@mozilla.com>
Mon, 31 Jul 2017 17:26:47 -0700
changeset 642257 a7e85f85dd4767c9eaa46773b95a32d3ac541d54
parent 642256 f6cd03c8d42b0cc189a632ef175c6c372c4ab6c0
child 642258 1bfe8d3770300e564b2e37840410c62a3818a469
push id72694
push userbwerth@mozilla.com
push dateTue, 08 Aug 2017 00:28:48 +0000
bugs1371395
milestone57.0a1
Bug 1371395 Part 2: Servo-side allow emulation of supported media types. MozReview-Commit-ID: kn3rDbQmn5
servo/components/style/gecko/media_queries.rs
servo/components/style/media_queries.rs
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -13,30 +13,31 @@ use euclid::Size2D;
 use font_metrics::get_metrics_provider_for_product;
 use gecko::values::convert_nscolor_to_rgba;
 use gecko_bindings::bindings;
 use gecko_bindings::structs;
 use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSValue, nsCSSUnit, nsStringBuffer};
 use gecko_bindings::structs::{nsMediaExpression_Range, nsMediaFeature};
 use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType, nsMediaFeature_RequirementFlags};
 use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned};
+use gecko_bindings::structs::nsIAtom;
 use media_queries::MediaType;
 use parser::ParserContext;
 use properties::{ComputedValues, StyleBuilder};
 use properties::longhands::font_size;
 use selectors::parser::SelectorParseError;
 use servo_arc::Arc;
 use std::fmt::{self, Write};
 use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
 use str::starts_with_ignore_ascii_case;
 use string_cache::Atom;
 use style_traits::{CSSPixel, DevicePixel};
 use style_traits::{ToCss, ParseError, StyleParseError};
 use style_traits::viewport::ViewportConstraints;
-use values::{CSSFloat, specified};
+use values::{CSSFloat, specified, CustomIdent};
 use values::computed::{self, ToComputedValue};
 
 /// The `Device` in Gecko wraps a pres context, has a default values computed,
 /// and contains all the viewport rule state.
 pub struct Device {
     /// NB: The pres context lifetime is tied to the styleset, who owns the
     /// stylist, and thus the `Device`, so having a raw pres context pointer
     /// here is fine.
@@ -134,25 +135,26 @@ impl Device {
     /// default computed values.
     pub fn reset(&mut self) {
         self.reset_computed_values();
     }
 
     /// Returns the current media type of the device.
     pub fn media_type(&self) -> MediaType {
         unsafe {
-            // FIXME(emilio): Gecko allows emulating random media with
-            // mIsEmulatingMedia / mMediaEmulated . Refactor both sides so that
-            // is supported (probably just making MediaType an Atom).
-            if self.pres_context().mMedium == atom!("screen").as_ptr() {
-                MediaType::Screen
+            // Gecko allows emulating random media with mIsEmulatingMedia and
+            // mMediaEmulated.
+            let context = self.pres_context();
+            let medium_to_use = if context.mIsEmulatingMedia() != 0 {
+                context.mMediaEmulated.raw::<nsIAtom>()
             } else {
-                debug_assert!(self.pres_context().mMedium == atom!("print").as_ptr());
-                MediaType::Print
-            }
+                context.mMedium
+            };
+
+            MediaType(CustomIdent(Atom::from(medium_to_use)))
         }
     }
 
     /// Returns the current viewport size in app units.
     pub fn au_viewport_size(&self) -> Size2D<Au> {
         self.used_viewport_size.store(true, Ordering::Relaxed);
         unsafe {
             // TODO(emilio): Need to take into account scrollbars.
--- a/servo/components/style/media_queries.rs
+++ b/servo/components/style/media_queries.rs
@@ -1,24 +1,26 @@
 /* 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 context::QuirksMode;
 use cssparser::{Delimiter, Parser, Token, ParserInput};
 use parser::ParserContext;
 use selectors::parser::SelectorParseError;
 use serialize_comma_separated_list;
 use std::fmt;
 use style_traits::{ToCss, ParseError, StyleParseError};
+use values::CustomIdent;
+use string_cache::Atom;
+use str::string_as_ascii_lowercase;
 
 #[cfg(feature = "servo")]
 pub use servo::media_queries::{Device, Expression};
 #[cfg(feature = "gecko")]
 pub use gecko::media_queries::{Device, Expression};
 
 /// A type that encapsulates a media query list.
 #[derive(Debug, Clone)]
@@ -103,19 +105,17 @@ impl ToCss for MediaQuery {
                 // 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() {
                     write!(dest, "all")?;
                 }
             },
-            MediaQueryType::Known(MediaType::Screen) => write!(dest, "screen")?,
-            MediaQueryType::Known(MediaType::Print) => write!(dest, "print")?,
-            MediaQueryType::Unknown(ref desc) => write!(dest, "{}", desc)?,
+            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() {
             write!(dest, " and ")?;
@@ -132,66 +132,56 @@ impl ToCss for MediaQuery {
 }
 
 /// http://dev.w3.org/csswg/mediaqueries-3/#media0
 #[derive(PartialEq, Eq, Clone, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub enum MediaQueryType {
     /// A media type that matches every device.
     All,
-    /// A known media type, that we parse and understand.
-    Known(MediaType),
-    /// An unknown media type.
-    Unknown(Atom),
+    /// A specific media type.
+    Concrete(MediaType),
 }
 
 impl MediaQueryType {
     fn parse(ident: &str) -> Result<Self, ()> {
         match_ignore_ascii_case! { ident,
             "all" => return Ok(MediaQueryType::All),
-            // From https://drafts.csswg.org/mediaqueries/#mq-syntax:
-            //
-            //   The <media-type> production does not include the keywords only,
-            //   not, and, and or.
-            "not" | "or" | "and" | "only" => return Err(()),
             _ => (),
         };
 
-        Ok(match MediaType::parse(ident) {
-            Some(media_type) => MediaQueryType::Known(media_type),
-            None => MediaQueryType::Unknown(Atom::from(ident)),
-        })
+        // 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::Known(ref known_type) => *known_type == other,
-            MediaQueryType::Unknown(..) => false,
+            MediaQueryType::Concrete(ref known_type) => *known_type == other,
         }
     }
 }
 
 /// https://drafts.csswg.org/mediaqueries/#media-types
 #[derive(PartialEq, Eq, Clone, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum MediaType {
-    /// The "screen" media type.
-    Screen,
-    /// The "print" media type.
-    Print,
-}
+pub struct MediaType(pub CustomIdent);
 
 impl MediaType {
-    fn parse(name: &str) -> Option<Self> {
-        Some(match_ignore_ascii_case! { name,
-            "screen" => MediaType::Screen,
-            "print" => MediaType::Print,
-            _ => return None
-        })
+    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>> {