Bug 1460655: Make resolutions more like the rest of the CSS values. r=xidorn
MozReview-Commit-ID: 3Gt8VX1KhjC
--- 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())
+ )),
+ }
+ }
+}