Bug 1460655: Make resolutions more like the rest of the CSS values. r=xidorn draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Thu, 10 May 2018 18:06:27 +0200
changeset 794248 6a99802f307ad0a331272bac80029d334987a88b
parent 794226 60ab8ccf7a641c4edd7fa05fa826490090c28649
child 794249 dc1cdb8f98e6aaf62ed46bfcf7b2c7fdaebdc189
push id109629
push userbmo:emilio@crisal.io
push dateFri, 11 May 2018 16:31:53 +0000
reviewersxidorn
bugs1460655
milestone62.0a1
Bug 1460655: Make resolutions more like the rest of the CSS values. r=xidorn MozReview-Commit-ID: 3Gt8VX1KhjC
servo/components/style/gecko/media_queries.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/computed/resolution.rs
servo/components/style/values/specified/mod.rs
servo/components/style/values/specified/resolution.rs
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -2,17 +2,17 @@
  * 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/. */
 
 //! Gecko's media-query device and expression representation.
 
 use app_units::AU_PER_PX;
 use app_units::Au;
 use context::QuirksMode;
-use cssparser::{BasicParseErrorKind, Parser, Token, RGBA};
+use cssparser::{BasicParseErrorKind, Parser, RGBA};
 use euclid::Size2D;
 use euclid::TypedScale;
 use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
 use gecko_bindings::bindings;
 use gecko_bindings::structs;
 use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue};
 use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
 use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
@@ -27,17 +27,17 @@ use str::starts_with_ignore_ascii_case;
 use string_cache::Atom;
 use style_traits::{CSSPixel, CssWriter, DevicePixel};
 use style_traits::{ParseError, StyleParseErrorKind, ToCss};
 use style_traits::viewport::ViewportConstraints;
 use stylesheets::Origin;
 use values::{serialize_atom_identifier, CSSFloat, CustomIdent, KeyframesName};
 use values::computed::{self, ToComputedValue};
 use values::computed::font::FontSize;
-use values::specified::{Integer, Length, Number};
+use values::specified::{Integer, Length, Number, Resolution};
 
 /// 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.
     pres_context: RawGeckoPresContextOwned,
@@ -281,63 +281,16 @@ impl ToCss for Expression {
 
 impl PartialEq for Expression {
     fn eq(&self, other: &Expression) -> bool {
         self.feature.mName == other.feature.mName && self.value == other.value &&
             self.range == other.range
     }
 }
 
-/// A resolution.
-#[derive(Clone, Debug, PartialEq, ToCss)]
-pub enum Resolution {
-    /// Dots per inch.
-    #[css(dimension)]
-    Dpi(CSSFloat),
-    /// Dots per pixel.
-    #[css(dimension)]
-    Dppx(CSSFloat),
-    /// Dots per centimeter.
-    #[css(dimension)]
-    Dpcm(CSSFloat),
-}
-
-impl Resolution {
-    fn to_dpi(&self) -> CSSFloat {
-        match *self {
-            Resolution::Dpi(f) => f,
-            Resolution::Dppx(f) => f * 96.0,
-            Resolution::Dpcm(f) => f * 2.54,
-        }
-    }
-
-    fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
-        let location = input.current_source_location();
-        let (value, unit) = match *input.next()? {
-            Token::Dimension {
-                value, ref unit, ..
-            } => (value, unit),
-            ref t => return Err(location.new_unexpected_token_error(t.clone())),
-        };
-
-        if value <= 0. {
-            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
-        }
-
-        (match_ignore_ascii_case! { &unit,
-            "dpi" => Ok(Resolution::Dpi(value)),
-            "dppx" => Ok(Resolution::Dppx(value)),
-            "dpcm" => Ok(Resolution::Dpcm(value)),
-            _ => Err(())
-        }).map_err(|()| {
-            location.new_custom_error(StyleParseErrorKind::UnexpectedDimension(unit.clone()))
-        })
-    }
-}
-
 /// A value found or expected in a media expression.
 ///
 /// FIXME(emilio): How should calc() serialize in the Number / Integer /
 /// BoolInteger / IntRatio case, as computed or as specified value?
 ///
 /// If the first, this would need to store the relevant values.
 ///
 /// See: https://github.com/w3c/csswg-drafts/issues/1968
@@ -530,17 +483,17 @@ fn parse_feature_value<'i, 't>(
         },
         nsMediaFeature_ValueType::eIntRatio => {
             let a = Integer::parse_positive(context, input)?;
             input.expect_delim('/')?;
             let b = Integer::parse_positive(context, input)?;
             MediaExpressionValue::IntRatio(a.value() as u32, b.value() as u32)
         },
         nsMediaFeature_ValueType::eResolution => {
-            MediaExpressionValue::Resolution(Resolution::parse(input)?)
+            MediaExpressionValue::Resolution(Resolution::parse(context, input)?)
         },
         nsMediaFeature_ValueType::eEnumerated => {
             let location = input.current_source_location();
             let keyword = input.expect_ident()?;
             let keyword = unsafe {
                 bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
             };
 
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -51,16 +51,17 @@ pub use self::column::ColumnCount;
 pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
 pub use self::effects::{BoxShadow, Filter, SimpleShadow};
 pub use self::flex::FlexBasis;
 pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
 pub use self::inherited_box::{ImageOrientation, Orientation};
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
 pub use self::rect::LengthOrNumberRect;
+pub use self::resolution::Resolution;
 pub use super::{Auto, Either, None_};
 pub use super::specified::{BorderStyle, TextDecorationLine};
 pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage};
 pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength};
 pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
 pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto};
 pub use self::list::Quotes;
 #[cfg(feature = "gecko")]
@@ -100,16 +101,17 @@ pub mod gecko;
 pub mod image;
 pub mod inherited_box;
 pub mod length;
 pub mod list;
 pub mod outline;
 pub mod percentage;
 pub mod position;
 pub mod rect;
+pub mod resolution;
 pub mod svg;
 pub mod table;
 pub mod text;
 pub mod time;
 pub mod transform;
 pub mod ui;
 pub mod url;
 
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/computed/resolution.rs
@@ -0,0 +1,48 @@
+/* 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/. */
+
+//! Resolution values:
+//!
+//! https://drafts.csswg.org/css-values/#resolution
+
+use std::fmt::{self, Write};
+use style_traits::{CssWriter, ToCss};
+use values::computed::{Context, ToComputedValue};
+use values::specified;
+use values::CSSFloat;
+
+/// A computed `<resolution>`.
+pub struct Resolution(CSSFloat);
+
+impl Resolution {
+    /// Returns this resolution value as dppx.
+    #[inline]
+    pub fn dppx(&self) -> CSSFloat {
+        self.0
+    }
+}
+
+impl ToComputedValue for specified::Resolution {
+    type ComputedValue = Resolution;
+
+    #[inline]
+    fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
+        Resolution(self.to_dppx())
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        specified::Resolution::Dppx(computed.dppx())
+    }
+}
+
+impl ToCss for Resolution {
+    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+    where
+        W: fmt::Write,
+    {
+        self.dppx().to_css(dest)?;
+        dest.write_str("dppx")
+    }
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -56,16 +56,17 @@ pub use self::length::{LengthOrPercentag
 pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength};
 pub use self::length::{NoCalcLength, ViewportPercentageLength};
 pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto};
 pub use self::list::Quotes;
 #[cfg(feature = "gecko")]
 pub use self::list::ListStyleType;
 pub use self::outline::OutlineStyle;
 pub use self::rect::LengthOrNumberRect;
+pub use self::resolution::Resolution;
 pub use self::percentage::Percentage;
 pub use self::position::{GridAutoFlow, GridTemplateAreas, Position};
 pub use self::position::{PositionComponent, ZIndex};
 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
 pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth};
 pub use self::svg::MozContextProperties;
 pub use self::table::XSpan;
 pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign};
@@ -100,16 +101,17 @@ pub mod grid;
 pub mod image;
 pub mod inherited_box;
 pub mod length;
 pub mod list;
 pub mod outline;
 pub mod percentage;
 pub mod position;
 pub mod rect;
+pub mod resolution;
 pub mod source_size_list;
 pub mod svg;
 pub mod table;
 pub mod text;
 pub mod time;
 pub mod transform;
 pub mod ui;
 pub mod url;
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/specified/resolution.rs
@@ -0,0 +1,73 @@
+/* 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/. */
+
+//! Resolution values:
+//!
+//! https://drafts.csswg.org/css-values/#resolution
+
+use cssparser::{Parser, Token};
+use parser::{Parse, ParserContext};
+use style_traits::{ParseError, StyleParseErrorKind};
+use values::CSSFloat;
+
+/// A specified resolution.
+#[derive(Clone, Debug, PartialEq, ToCss)]
+pub enum Resolution {
+    /// Dots per inch.
+    #[css(dimension)]
+    Dpi(CSSFloat),
+    /// Dots per pixel.
+    #[css(dimension)]
+    Dppx(CSSFloat),
+    /// Dots per centimeter.
+    #[css(dimension)]
+    Dpcm(CSSFloat),
+}
+
+impl Resolution {
+    /// Convert this resolution value to dppx units.
+    pub fn to_dppx(&self) -> CSSFloat {
+        match *self {
+            Resolution::Dppx(f) => f,
+            _ => self.to_dpi() / 96.0,
+        }
+    }
+
+    /// Convert this resolution value to dpi units.
+    pub fn to_dpi(&self) -> CSSFloat {
+        match *self {
+            Resolution::Dpi(f) => f,
+            Resolution::Dppx(f) => f * 96.0,
+            Resolution::Dpcm(f) => f * 2.54,
+        }
+    }
+}
+
+impl Parse for Resolution {
+    fn parse<'i, 't>(
+        _: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        let location = input.current_source_location();
+        let (value, unit) = match *input.next()? {
+            Token::Dimension {
+                value, ref unit, ..
+            } => (value, unit),
+            ref t => return Err(location.new_unexpected_token_error(t.clone())),
+        };
+
+        if value <= 0. {
+            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+        }
+
+        match_ignore_ascii_case! { &unit,
+            "dpi" => Ok(Resolution::Dpi(value)),
+            "dppx" => Ok(Resolution::Dppx(value)),
+            "dpcm" => Ok(Resolution::Dpcm(value)),
+            _ => Err(location.new_custom_error(
+                StyleParseErrorKind::UnexpectedDimension(unit.clone())
+            )),
+        }
+    }
+}