diff --git a/components/style/gecko/media_queries.rs b/components/style/gecko/media_queries.rs index f27d78fd937..2ea4229133a 100644 --- a/components/style/gecko/media_queries.rs +++ b/components/style/gecko/media_queries.rs @@ -26,7 +26,6 @@ use euclid::{Scale, SideOffsets2D}; use servo_arc::Arc; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::{cmp, fmt}; -use style_traits::viewport::ViewportConstraints; use style_traits::{CSSPixel, DevicePixel}; /// The `Device` in Gecko wraps a pres context, has a default values computed, @@ -135,12 +134,6 @@ impl Device { NonNegativeLength::new(au.to_f32_px()) } - /// Tells the device that a new viewport rule has been found, and stores the - /// relevant viewport constraints. - pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) { - unreachable!("Gecko doesn't support @viewport"); - } - /// Whether any animation name may be referenced from the style of any /// element. pub fn animation_name_may_be_referenced(&self, name: &KeyframesName) -> bool { diff --git a/components/style/invalidation/stylesheets.rs b/components/style/invalidation/stylesheets.rs index 5fc8ec4b764..6326a15e61a 100644 --- a/components/style/invalidation/stylesheets.rs +++ b/components/style/invalidation/stylesheets.rs @@ -551,7 +551,6 @@ impl StylesheetInvalidationSet { CounterStyle(..) | Page(..) | Property(..) | - Viewport(..) | FontFeatureValues(..) | FontPaletteValues(..) | LayerStatement(..) | @@ -637,13 +636,9 @@ impl StylesheetInvalidationSet { CounterStyle(..) | Page(..) | Property(..) | - Viewport(..) | FontFeatureValues(..) | FontPaletteValues(..) => { - debug!( - " > Found unsupported rule, marking the whole subtree \ - invalid." - ); + debug!(" > Found unsupported rule, marking the whole subtree invalid."); // TODO(emilio): Can we do better here? // diff --git a/components/style/servo/media_queries.rs b/components/style/servo/media_queries.rs index 11f3550a311..7ee7e1cfe5f 100644 --- a/components/style/servo/media_queries.rs +++ b/components/style/servo/media_queries.rs @@ -22,7 +22,6 @@ use euclid::default::Size2D as UntypedSize2D; use euclid::{Scale, SideOffsets2D, Size2D}; use mime::Mime; use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; -use style_traits::viewport::ViewportConstraints; use style_traits::{CSSPixel, DevicePixel}; /// A device is a structure that represents the current media a given document @@ -191,11 +190,6 @@ impl Device { Default::default() } - /// Take into account a viewport rule taken from the stylesheets. - pub fn account_for_viewport_rule(&mut self, constraints: &ViewportConstraints) { - self.viewport_size = constraints.size; - } - /// Return the media type of the current device. pub fn media_type(&self) -> MediaType { self.media_type.clone() diff --git a/components/style/stylesheets/cascading_at_rule.rs b/components/style/stylesheets/cascading_at_rule.rs deleted file mode 100644 index b23b0720fed..00000000000 --- a/components/style/stylesheets/cascading_at_rule.rs +++ /dev/null @@ -1,70 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -//! Cascading at-rule types and traits - -use crate::stylesheets::Origin; -use std::fmt::{self, Write}; -use style_traits::{CssWriter, ToCss}; - -/// Computes the cascade precedence as according to -/// -#[inline] -fn cascade_precendence(origin: Origin, important: bool) -> u8 { - match (origin, important) { - (Origin::UserAgent, true) => 1, - (Origin::User, true) => 2, - (Origin::Author, true) => 3, - (Origin::Author, false) => 4, - (Origin::User, false) => 5, - (Origin::UserAgent, false) => 6, - } -} - -/// Cascading rule descriptor implementation. -/// This is only used for at-rules which can cascade. These are @viewport and -/// @page, although we don't currently implement @page as such. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] -pub struct DescriptorDeclaration { - /// Origin of the declaration - pub origin: Origin, - /// Declaration value - pub descriptor: T, - /// Indicates the presence of a !important property. - pub important: bool, -} - -impl DescriptorDeclaration { - #[allow(missing_docs)] - pub fn new(origin: Origin, descriptor: T, important: bool) -> Self { - Self { - origin, - descriptor, - important, - } - } - /// Returns true iff self is equal or higher precedence to the other. - pub fn higher_or_equal_precendence(&self, other: &Self) -> bool { - let self_precedence = cascade_precendence(self.origin, self.important); - let other_precedence = cascade_precendence(other.origin, other.important); - - self_precedence <= other_precedence - } -} - -impl ToCss for DescriptorDeclaration -where - T: ToCss, -{ - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - self.descriptor.to_css(dest)?; - if self.important { - dest.write_str(" !important")?; - } - dest.write_char(';') - } -} diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index 800ebee12ff..b9a0ec98311 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -4,7 +4,6 @@ //! Style sheets and their CSS rules. -mod cascading_at_rule; pub mod container_rule; mod counter_style_rule; mod document_rule; @@ -26,7 +25,6 @@ mod rules_iterator; mod style_rule; mod stylesheet; pub mod supports_rule; -pub mod viewport_rule; #[cfg(feature = "gecko")] use crate::gecko_bindings::sugar::refptr::RefCounted; @@ -74,7 +72,6 @@ pub use self::stylesheet::{AllowImportRules, SanitizationData, SanitizationKind} pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet}; pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets}; pub use self::supports_rule::SupportsRule; -pub use self::viewport_rule::ViewportRule; /// The CORS mode used for a CSS load. #[repr(u8)] @@ -256,7 +253,6 @@ pub enum CssRule { FontFeatureValues(Arc), FontPaletteValues(Arc), CounterStyle(Arc>), - Viewport(Arc), Keyframes(Arc>), Supports(Arc), Page(Arc>), @@ -292,7 +288,6 @@ impl CssRule { CssRule::FontFeatureValues(_) => 0, CssRule::FontPaletteValues(_) => 0, CssRule::CounterStyle(_) => 0, - CssRule::Viewport(_) => 0, CssRule::Keyframes(_) => 0, CssRule::Supports(ref arc) => { arc.unconditional_shallow_size_of(ops) + arc.size_of(guard, ops) @@ -338,8 +333,6 @@ pub enum CssRuleType { Document = 13, // https://drafts.csswg.org/css-fonts/#om-fontfeaturevalues FontFeatureValues = 14, - // https://drafts.csswg.org/css-device-adapt/#css-rule-interface - Viewport = 15, // After viewport, all rules should return 0 from the API, but we still need // a constant somewhere. LayerBlock = 16, @@ -408,7 +401,6 @@ impl CssRule { CssRule::CounterStyle(_) => CssRuleType::CounterStyle, CssRule::Keyframes(_) => CssRuleType::Keyframes, CssRule::Namespace(_) => CssRuleType::Namespace, - CssRule::Viewport(_) => CssRuleType::Viewport, CssRule::Supports(_) => CssRuleType::Supports, CssRule::Page(_) => CssRuleType::Page, CssRule::Property(_) => CssRuleType::Property, @@ -507,7 +499,6 @@ impl DeepCloneWithLock for CssRule { let rule = arc.read_with(guard); CssRule::CounterStyle(Arc::new(lock.wrap(rule.clone()))) }, - CssRule::Viewport(ref arc) => CssRule::Viewport(arc.clone()), CssRule::Keyframes(ref arc) => { let rule = arc.read_with(guard); CssRule::Keyframes(Arc::new( @@ -550,7 +541,6 @@ impl ToCssWithGuard for CssRule { CssRule::FontFeatureValues(ref rule) => rule.to_css(guard, dest), CssRule::FontPaletteValues(ref rule) => rule.to_css(guard, dest), CssRule::CounterStyle(ref lock) => lock.read_with(guard).to_css(guard, dest), - CssRule::Viewport(ref rule) => rule.to_css(guard, dest), CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest), CssRule::Media(ref rule) => rule.to_css(guard, dest), CssRule::Supports(ref rule) => rule.to_css(guard, dest), diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index b601f607e85..cb3fa862c25 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -26,10 +26,9 @@ use crate::stylesheets::keyframes_rule::parse_keyframe_list; use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule}; use crate::stylesheets::supports_rule::SupportsCondition; use crate::stylesheets::{ - viewport_rule, AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule, + AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule, FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MediaRule, NamespaceRule, PageRule, PageSelectors, RulesMutateError, StyleRule, StylesheetLoader, SupportsRule, - ViewportRule, }; use crate::values::computed::font::FamilyName; use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName}; @@ -200,8 +199,6 @@ pub enum AtRulePrelude { Container(Arc), /// An @supports rule, with its conditional Supports(SupportsCondition), - /// A @viewport rule prelude. - Viewport, /// A @keyframes rule, with its animation name and vendor prefix if exists. Keyframes(KeyframesName, Option), /// A @page rule prelude, with its page name if it exists. @@ -584,9 +581,6 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> { let name = parse_counter_style_name_definition(input)?; AtRulePrelude::CounterStyle(name) }, - "viewport" if viewport_rule::enabled() => { - AtRulePrelude::Viewport - }, "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => { let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") { Some(VendorPrefix::WebKit) @@ -685,12 +679,6 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b, 'i> { source_location, })) }, - AtRulePrelude::Viewport => { - let body = self.nest_for_rule(CssRuleType::Viewport, |p| { - ViewportRule::parse(&p.context, input) - })?; - CssRule::Viewport(Arc::new(body)) - }, AtRulePrelude::Keyframes(name, vendor_prefix) => { self.nest_for_rule(CssRuleType::Keyframe, |p| { CssRule::Keyframes(Arc::new(p.shared_lock.wrap(KeyframesRule { diff --git a/components/style/stylesheets/rules_iterator.rs b/components/style/stylesheets/rules_iterator.rs index 950bcd238eb..0ab2b42c0bc 100644 --- a/components/style/stylesheets/rules_iterator.rs +++ b/components/style/stylesheets/rules_iterator.rs @@ -65,7 +65,6 @@ where CssRule::Namespace(_) | CssRule::FontFace(_) | CssRule::CounterStyle(_) | - CssRule::Viewport(_) | CssRule::Keyframes(_) | CssRule::Page(_) | CssRule::Property(_) | diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index ece2c4a6060..6c205e03c66 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -228,25 +228,6 @@ macro_rules! rule_filter { } } -macro_rules! rule_filter_for_non_locked { - ($( $method: ident($variant:ident => $rule_type: ident), )+) => { - $( - #[allow(missing_docs)] - fn $method(&self, device: &Device, guard: &SharedRwLockReadGuard, mut f: F) - where F: FnMut(&crate::stylesheets::$rule_type), - { - use crate::stylesheets::CssRule; - - for rule in self.effective_rules(device, guard) { - if let CssRule::$variant(ref rule) = *rule { - f(&rule) - } - } - } - )+ - } -} - /// A trait to represent a given stylesheet in a document. pub trait StylesheetInDocument: ::std::fmt::Debug { /// Get whether this stylesheet is enabled. @@ -304,10 +285,6 @@ pub trait StylesheetInDocument: ::std::fmt::Debug { rule_filter! { effective_font_face_rules(FontFace => FontFaceRule), } - - rule_filter_for_non_locked! { - effective_viewport_rules(Viewport => ViewportRule), - } } impl StylesheetInDocument for Stylesheet { @@ -401,7 +378,6 @@ impl SanitizationKind { CssRule::Property(..) | CssRule::FontFeatureValues(..) | CssRule::FontPaletteValues(..) | - CssRule::Viewport(..) | CssRule::CounterStyle(..) => !is_standard, } } diff --git a/components/style/stylesheets/viewport_rule.rs b/components/style/stylesheets/viewport_rule.rs deleted file mode 100644 index 13480fd5621..00000000000 --- a/components/style/stylesheets/viewport_rule.rs +++ /dev/null @@ -1,802 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -//! The [`@viewport`][at] at-rule and [`meta`][meta] element. -//! -//! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule -//! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta - -use crate::context::QuirksMode; -use crate::error_reporting::ContextualParseError; -use crate::media_queries::Device; -use crate::parser::{Parse, ParserContext}; -use crate::properties::StyleBuilder; -use crate::rule_cache::RuleCacheConditions; -use crate::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard}; -use crate::str::CssStringWriter; -use crate::stylesheets::cascading_at_rule::DescriptorDeclaration; -use crate::stylesheets::container_rule::ContainerSizeQuery; -use crate::stylesheets::{Origin, StylesheetInDocument}; -use crate::values::computed::{Context, ToComputedValue}; -use crate::values::generics::length::LengthPercentageOrAuto; -use crate::values::generics::NonNegative; -use crate::values::specified::{self, NoCalcLength}; -use crate::values::specified::{NonNegativeLengthPercentageOrAuto, ViewportPercentageLength}; -use app_units::Au; -use cssparser::{ - parse_important, AtRuleParser, CowRcStr, DeclarationParser, Parser, QualifiedRuleParser, - RuleBodyItemParser, RuleBodyParser, -}; -use euclid::Size2D; -use selectors::parser::SelectorParseErrorKind; -use std::borrow::Cow; -use std::fmt::{self, Write}; -use std::iter::Enumerate; -use std::str::Chars; -use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom}; -use style_traits::{CssWriter, ParseError, PinchZoomFactor, StyleParseErrorKind, ToCss}; - -/// Whether parsing and processing of `@viewport` rules is enabled. -pub fn enabled() -> bool { - false -} - -macro_rules! declare_viewport_descriptor { - ( $( $variant_name: expr => $variant: ident($data: ident), )+ ) => { - declare_viewport_descriptor_inner!([] [ $( $variant_name => $variant($data), )+ ] 0); - }; -} - -macro_rules! declare_viewport_descriptor_inner { - ( - [ $( $assigned_variant_name: expr => - $assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ] - [ - $next_variant_name: expr => $next_variant: ident($next_data: ident), - $( $variant_name: expr => $variant: ident($data: ident), )* - ] - $next_discriminant: expr - ) => { - declare_viewport_descriptor_inner! { - [ - $( $assigned_variant_name => $assigned_variant($assigned_data) = $assigned_discriminant, )* - $next_variant_name => $next_variant($next_data) = $next_discriminant, - ] - [ $( $variant_name => $variant($data), )* ] - $next_discriminant + 1 - } - }; - - ( - [ $( $assigned_variant_name: expr => - $assigned_variant: ident($assigned_data: ident) = $assigned_discriminant: expr, )* ] - [ ] - $number_of_variants: expr - ) => { - #[derive(Clone, Debug, PartialEq, ToShmem)] - #[cfg_attr(feature = "servo", derive(MallocSizeOf))] - #[allow(missing_docs)] - pub enum ViewportDescriptor { - $( - $assigned_variant($assigned_data), - )+ - } - - const VIEWPORT_DESCRIPTOR_VARIANTS: usize = $number_of_variants; - - impl ViewportDescriptor { - #[allow(missing_docs)] - pub fn discriminant_value(&self) -> usize { - match *self { - $( - ViewportDescriptor::$assigned_variant(..) => $assigned_discriminant, - )* - } - } - } - - impl ToCss for ViewportDescriptor { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - match *self { - $( - ViewportDescriptor::$assigned_variant(ref val) => { - dest.write_str($assigned_variant_name)?; - dest.write_str(": ")?; - val.to_css(dest)?; - }, - )* - } - dest.write_char(';') - } - } - }; -} - -declare_viewport_descriptor! { - "min-width" => MinWidth(ViewportLength), - "max-width" => MaxWidth(ViewportLength), - - "min-height" => MinHeight(ViewportLength), - "max-height" => MaxHeight(ViewportLength), - - "zoom" => Zoom(Zoom), - "min-zoom" => MinZoom(Zoom), - "max-zoom" => MaxZoom(Zoom), - - "user-zoom" => UserZoom(UserZoom), - "orientation" => Orientation(Orientation), -} - -trait FromMeta: Sized { - fn from_meta(value: &str) -> Option; -} - -/// ViewportLength is a length | percentage | auto | extend-to-zoom -/// See: -/// * http://dev.w3.org/csswg/css-device-adapt/#min-max-width-desc -/// * http://dev.w3.org/csswg/css-device-adapt/#extend-to-zoom -#[allow(missing_docs)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -#[derive(Clone, Debug, PartialEq, ToCss, ToShmem)] -pub enum ViewportLength { - Specified(NonNegativeLengthPercentageOrAuto), - ExtendToZoom, -} - -impl FromMeta for ViewportLength { - fn from_meta(value: &str) -> Option { - macro_rules! specified { - ($value:expr) => { - ViewportLength::Specified(LengthPercentageOrAuto::LengthPercentage(NonNegative( - specified::LengthPercentage::Length($value), - ))) - }; - } - - Some(match value { - v if v.eq_ignore_ascii_case("device-width") => specified!( - NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.)) - ), - v if v.eq_ignore_ascii_case("device-height") => specified!( - NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vh(100.)) - ), - _ => match value.parse::() { - Ok(n) if n >= 0. => specified!(NoCalcLength::from_px(n.max(1.).min(10000.))), - Ok(_) => return None, - Err(_) => specified!(NoCalcLength::from_px(1.)), - }, - }) - } -} - -impl ViewportLength { - fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - // we explicitly do not accept 'extend-to-zoom', since it is a UA - // internal value for viewport translation - NonNegativeLengthPercentageOrAuto::parse(context, input).map(ViewportLength::Specified) - } -} - -impl FromMeta for Zoom { - fn from_meta(value: &str) -> Option { - Some(match value { - v if v.eq_ignore_ascii_case("yes") => Zoom::Number(1.), - v if v.eq_ignore_ascii_case("no") => Zoom::Number(0.1), - v if v.eq_ignore_ascii_case("device-width") => Zoom::Number(10.), - v if v.eq_ignore_ascii_case("device-height") => Zoom::Number(10.), - _ => match value.parse::() { - Ok(n) if n >= 0. => Zoom::Number(n.max(0.1).min(10.)), - Ok(_) => return None, - Err(_) => Zoom::Number(0.1), - }, - }) - } -} - -impl FromMeta for UserZoom { - fn from_meta(value: &str) -> Option { - Some(match value { - v if v.eq_ignore_ascii_case("yes") => UserZoom::Zoom, - v if v.eq_ignore_ascii_case("no") => UserZoom::Fixed, - v if v.eq_ignore_ascii_case("device-width") => UserZoom::Zoom, - v if v.eq_ignore_ascii_case("device-height") => UserZoom::Zoom, - _ => match value.parse::() { - Ok(n) if n >= 1. || n <= -1. => UserZoom::Zoom, - _ => UserZoom::Fixed, - }, - }) - } -} - -struct ViewportRuleParser<'a, 'b: 'a> { - context: &'a ParserContext<'b>, -} - -#[allow(missing_docs)] -pub type ViewportDescriptorDeclaration = DescriptorDeclaration; - -fn parse_shorthand<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, -) -> Result<(ViewportLength, ViewportLength), ParseError<'i>> { - let min = ViewportLength::parse(context, input)?; - match input.try_parse(|i| ViewportLength::parse(context, i)) { - Err(_) => Ok((min.clone(), min)), - Ok(max) => Ok((min, max)), - } -} - -type ViewportDeclarations = Vec; - -impl<'a, 'b, 'i> AtRuleParser<'i> for ViewportRuleParser<'a, 'b> { - type Prelude = (); - type AtRule = ViewportDeclarations; - type Error = StyleParseErrorKind<'i>; -} - -impl<'a, 'b, 'i> QualifiedRuleParser<'i> for ViewportRuleParser<'a, 'b> { - type Prelude = (); - type QualifiedRule = ViewportDeclarations; - type Error = StyleParseErrorKind<'i>; -} - -impl<'a, 'b, 'i> DeclarationParser<'i> for ViewportRuleParser<'a, 'b> { - type Declaration = Vec; - type Error = StyleParseErrorKind<'i>; - - fn parse_value<'t>( - &mut self, - name: CowRcStr<'i>, - input: &mut Parser<'i, 't>, - ) -> Result, ParseError<'i>> { - macro_rules! declaration { - ($declaration:ident($parse:expr)) => { - declaration!($declaration { - value: $parse(input)?, - important: input.try_parse(parse_important).is_ok(), - }) - }; - ($declaration:ident { value: $value:expr, important: $important:expr, }) => { - ViewportDescriptorDeclaration::new( - self.context.stylesheet_origin, - ViewportDescriptor::$declaration($value), - $important, - ) - }; - } - - macro_rules! ok { - ($declaration:ident($parse:expr)) => { - Ok(vec![declaration!($declaration($parse))]) - }; - (shorthand -> [$min:ident, $max:ident]) => {{ - let shorthand = parse_shorthand(self.context, input)?; - let important = input.try_parse(parse_important).is_ok(); - - Ok(vec![ - declaration!($min { - value: shorthand.0, - important: important, - }), - declaration!($max { - value: shorthand.1, - important: important, - }), - ]) - }}; - } - - match_ignore_ascii_case! { &*name, - "min-width" => ok!(MinWidth(|i| ViewportLength::parse(self.context, i))), - "max-width" => ok!(MaxWidth(|i| ViewportLength::parse(self.context, i))), - "width" => ok!(shorthand -> [MinWidth, MaxWidth]), - "min-height" => ok!(MinHeight(|i| ViewportLength::parse(self.context, i))), - "max-height" => ok!(MaxHeight(|i| ViewportLength::parse(self.context, i))), - "height" => ok!(shorthand -> [MinHeight, MaxHeight]), - "zoom" => ok!(Zoom(Zoom::parse)), - "min-zoom" => ok!(MinZoom(Zoom::parse)), - "max-zoom" => ok!(MaxZoom(Zoom::parse)), - "user-zoom" => ok!(UserZoom(UserZoom::parse)), - "orientation" => ok!(Orientation(Orientation::parse)), - _ => Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))), - } - } -} - -impl<'a, 'b, 'i> RuleBodyItemParser<'i, ViewportDeclarations, StyleParseErrorKind<'i>> - for ViewportRuleParser<'a, 'b> -{ - fn parse_declarations(&self) -> bool { - true - } - fn parse_qualified(&self) -> bool { - false - } -} - -/// A `@viewport` rule. -#[derive(Clone, Debug, PartialEq, ToShmem)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -pub struct ViewportRule { - /// The declarations contained in this @viewport rule. - pub declarations: Vec, -} - -/// Whitespace as defined by DEVICE-ADAPT § 9.2 -// TODO: should we just use whitespace as defined by HTML5? -const WHITESPACE: &'static [char] = &['\t', '\n', '\r', ' ']; - -/// Separators as defined by DEVICE-ADAPT § 9.2 -// need to use \x2c instead of ',' due to test-tidy -const SEPARATOR: &'static [char] = &['\x2c', ';']; - -#[inline] -fn is_whitespace_separator_or_equals(c: &char) -> bool { - WHITESPACE.contains(c) || SEPARATOR.contains(c) || *c == '=' -} - -impl ViewportRule { - /// Parse a single @viewport rule. - /// - /// TODO(emilio): This could use the `Parse` trait now. - pub fn parse<'i, 't>( - context: &ParserContext, - input: &mut Parser<'i, 't>, - ) -> Result> { - let mut parser = ViewportRuleParser { context }; - - let mut cascade = Cascade::new(); - let mut parser = RuleBodyParser::new(input, &mut parser); - while let Some(result) = parser.next() { - match result { - Ok(declarations) => { - for declarations in declarations { - cascade.add(Cow::Owned(declarations)) - } - }, - Err((error, slice)) => { - let location = error.location; - let error = ContextualParseError::UnsupportedViewportDescriptorDeclaration( - slice, error, - ); - context.log_css_error(location, error); - }, - } - } - Ok(ViewportRule { - declarations: cascade.finish(), - }) - } -} - -impl ViewportRule { - #[allow(missing_docs)] - pub fn from_meta(content: &str) -> Option { - let mut declarations = vec![None; VIEWPORT_DESCRIPTOR_VARIANTS]; - macro_rules! push_descriptor { - ($descriptor:ident($value:expr)) => {{ - let descriptor = ViewportDescriptor::$descriptor($value); - let discriminant = descriptor.discriminant_value(); - declarations[discriminant] = Some(ViewportDescriptorDeclaration::new( - Origin::Author, - descriptor, - false, - )); - }}; - } - - let mut has_width = false; - let mut has_height = false; - let mut has_zoom = false; - - let mut iter = content.chars().enumerate(); - - macro_rules! start_of_name { - ($iter:ident) => { - $iter - .by_ref() - .skip_while(|&(_, c)| is_whitespace_separator_or_equals(&c)) - .next() - }; - } - - while let Some((start, _)) = start_of_name!(iter) { - let property = ViewportRule::parse_meta_property(content, &mut iter, start); - - if let Some((name, value)) = property { - macro_rules! push { - ($descriptor:ident($translate:path)) => { - if let Some(value) = $translate(value) { - push_descriptor!($descriptor(value)); - } - }; - } - - match name { - n if n.eq_ignore_ascii_case("width") => { - if let Some(value) = ViewportLength::from_meta(value) { - push_descriptor!(MinWidth(ViewportLength::ExtendToZoom)); - push_descriptor!(MaxWidth(value)); - has_width = true; - } - }, - n if n.eq_ignore_ascii_case("height") => { - if let Some(value) = ViewportLength::from_meta(value) { - push_descriptor!(MinHeight(ViewportLength::ExtendToZoom)); - push_descriptor!(MaxHeight(value)); - has_height = true; - } - }, - n if n.eq_ignore_ascii_case("initial-scale") => { - if let Some(value) = Zoom::from_meta(value) { - push_descriptor!(Zoom(value)); - has_zoom = true; - } - }, - n if n.eq_ignore_ascii_case("minimum-scale") => push!(MinZoom(Zoom::from_meta)), - n if n.eq_ignore_ascii_case("maximum-scale") => push!(MaxZoom(Zoom::from_meta)), - n if n.eq_ignore_ascii_case("user-scalable") => { - push!(UserZoom(UserZoom::from_meta)) - }, - _ => {}, - } - } - } - - // DEVICE-ADAPT § 9.4 - The 'width' and 'height' properties - // http://dev.w3.org/csswg/css-device-adapt/#width-and-height-properties - if !has_width && has_zoom { - if has_height { - push_descriptor!(MinWidth(ViewportLength::Specified( - LengthPercentageOrAuto::Auto - ))); - push_descriptor!(MaxWidth(ViewportLength::Specified( - LengthPercentageOrAuto::Auto - ))); - } else { - push_descriptor!(MinWidth(ViewportLength::ExtendToZoom)); - push_descriptor!(MaxWidth(ViewportLength::ExtendToZoom)); - } - } - - let declarations: Vec<_> = declarations.into_iter().filter_map(|entry| entry).collect(); - if !declarations.is_empty() { - Some(ViewportRule { declarations }) - } else { - None - } - } - - fn parse_meta_property<'a>( - content: &'a str, - iter: &mut Enumerate>, - start: usize, - ) -> Option<(&'a str, &'a str)> { - fn end_of_token(iter: &mut Enumerate) -> Option<(usize, char)> { - iter.by_ref() - .skip_while(|&(_, c)| !is_whitespace_separator_or_equals(&c)) - .next() - } - - fn skip_whitespace(iter: &mut Enumerate) -> Option<(usize, char)> { - iter.by_ref() - .skip_while(|&(_, c)| WHITESPACE.contains(&c)) - .next() - } - - // * '=' - let end = match end_of_token(iter) { - Some((end, c)) if WHITESPACE.contains(&c) => match skip_whitespace(iter) { - Some((_, c)) if c == '=' => end, - _ => return None, - }, - Some((end, c)) if c == '=' => end, - _ => return None, - }; - let name = &content[start..end]; - - // * - let start = match skip_whitespace(iter) { - Some((start, c)) if !SEPARATOR.contains(&c) => start, - _ => return None, - }; - let value = match end_of_token(iter) { - Some((end, _)) => &content[start..end], - _ => &content[start..], - }; - - Some((name, value)) - } -} - -impl ToCssWithGuard for ViewportRule { - // Serialization of ViewportRule is not specced. - fn to_css(&self, _guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result { - dest.write_str("@viewport { ")?; - let mut iter = self.declarations.iter(); - iter.next().unwrap().to_css(&mut CssWriter::new(dest))?; - for declaration in iter { - dest.write_char(' ')?; - declaration.to_css(&mut CssWriter::new(dest))?; - } - dest.write_str(" }") - } -} - -#[allow(missing_docs)] -pub struct Cascade { - declarations: Vec>, - count_so_far: usize, -} - -#[allow(missing_docs)] -impl Cascade { - pub fn new() -> Self { - Cascade { - declarations: vec![None; VIEWPORT_DESCRIPTOR_VARIANTS], - count_so_far: 0, - } - } - - pub fn from_stylesheets<'a, I, S>( - stylesheets: I, - guards: &StylesheetGuards, - device: &Device, - ) -> Self - where - I: Iterator, - S: StylesheetInDocument + 'static, - { - let mut cascade = Self::new(); - for (stylesheet, origin) in stylesheets { - stylesheet.effective_viewport_rules(device, guards.for_origin(origin), |rule| { - for declaration in &rule.declarations { - cascade.add(Cow::Borrowed(declaration)) - } - }) - } - cascade - } - - pub fn add(&mut self, declaration: Cow) { - let descriptor = declaration.descriptor.discriminant_value(); - - match self.declarations[descriptor] { - Some((ref mut order_of_appearance, ref mut entry_declaration)) => { - if declaration.higher_or_equal_precendence(entry_declaration) { - *entry_declaration = declaration.into_owned(); - *order_of_appearance = self.count_so_far; - } - }, - ref mut entry @ None => { - *entry = Some((self.count_so_far, declaration.into_owned())); - }, - } - self.count_so_far += 1; - } - - pub fn finish(mut self) -> Vec { - // sort the descriptors by order of appearance - self.declarations - .sort_by_key(|entry| entry.as_ref().map(|&(index, _)| index)); - self.declarations - .into_iter() - .filter_map(|entry| entry.map(|(_, decl)| decl)) - .collect() - } -} - -/// Just a helper trait to be able to implement methods on ViewportConstraints. -pub trait MaybeNew { - /// Create a ViewportConstraints from a viewport size and a `@viewport` - /// rule. - fn maybe_new( - device: &Device, - rule: &ViewportRule, - quirks_mode: QuirksMode, - ) -> Option; -} - -impl MaybeNew for ViewportConstraints { - fn maybe_new( - device: &Device, - rule: &ViewportRule, - quirks_mode: QuirksMode, - ) -> Option { - use std::cmp; - - if rule.declarations.is_empty() { - return None; - } - - let mut min_width = None; - let mut max_width = None; - - let mut min_height = None; - let mut max_height = None; - - let mut initial_zoom = None; - let mut min_zoom = None; - let mut max_zoom = None; - - let mut user_zoom = UserZoom::Zoom; - let mut orientation = Orientation::Auto; - - // collapse the list of declarations into descriptor values - for declaration in &rule.declarations { - match declaration.descriptor { - ViewportDescriptor::MinWidth(ref value) => min_width = Some(value), - ViewportDescriptor::MaxWidth(ref value) => max_width = Some(value), - - ViewportDescriptor::MinHeight(ref value) => min_height = Some(value), - ViewportDescriptor::MaxHeight(ref value) => max_height = Some(value), - - ViewportDescriptor::Zoom(value) => initial_zoom = value.to_f32(), - ViewportDescriptor::MinZoom(value) => min_zoom = value.to_f32(), - ViewportDescriptor::MaxZoom(value) => max_zoom = value.to_f32(), - - ViewportDescriptor::UserZoom(value) => user_zoom = value, - ViewportDescriptor::Orientation(value) => orientation = value, - } - } - - // TODO: return `None` if all descriptors are either absent or initial value - - macro_rules! choose { - ($op:ident, $opta:expr, $optb:expr) => { - match ($opta, $optb) { - (None, None) => None, - (a, None) => a, - (None, b) => b, - (Some(a), Some(b)) => Some(a.$op(b)), - } - }; - } - macro_rules! min { - ($opta:expr, $optb:expr) => { - choose!(min, $opta, $optb) - }; - } - macro_rules! max { - ($opta:expr, $optb:expr) => { - choose!(max, $opta, $optb) - }; - } - - // DEVICE-ADAPT § 6.2.1 Resolve min-zoom and max-zoom values - if min_zoom.is_some() && max_zoom.is_some() { - max_zoom = Some(min_zoom.unwrap().max(max_zoom.unwrap())) - } - - // DEVICE-ADAPT § 6.2.2 Constrain zoom value to the [min-zoom, max-zoom] range - if initial_zoom.is_some() { - initial_zoom = max!(min_zoom, min!(max_zoom, initial_zoom)); - } - - // DEVICE-ADAPT § 6.2.3 Resolve non-auto lengths to pixel lengths - let initial_viewport = device.au_viewport_size(); - - let mut conditions = RuleCacheConditions::default(); - let context = Context::new( - // Note: DEVICE-ADAPT § 5. states that relative length values are - // resolved against initial values - StyleBuilder::for_inheritance(device, None, None), - quirks_mode, - &mut conditions, - ContainerSizeQuery::none(), - ); - - // DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom' - let extend_width; - let extend_height; - if let Some(extend_zoom) = max!(initial_zoom, max_zoom) { - let scale_factor = 1. / extend_zoom; - extend_width = Some(initial_viewport.width.scale_by(scale_factor)); - extend_height = Some(initial_viewport.height.scale_by(scale_factor)); - } else { - extend_width = None; - extend_height = None; - } - - macro_rules! to_pixel_length { - ($value:ident, $dimension:ident, $extend_to:ident => $auto_extend_to:expr) => { - if let Some($value) = $value { - match *$value { - ViewportLength::Specified(ref length) => match *length { - LengthPercentageOrAuto::Auto => None, - LengthPercentageOrAuto::LengthPercentage(ref lop) => Some( - lop.to_computed_value(&context) - .to_used_value(initial_viewport.$dimension), - ), - }, - ViewportLength::ExtendToZoom => { - // $extend_to will be 'None' if 'extend-to-zoom' is 'auto' - match ($extend_to, $auto_extend_to) { - (None, None) => None, - (a, None) => a, - (None, b) => b, - (a, b) => cmp::max(a, b), - } - }, - } - } else { - None - } - }; - } - - // DEVICE-ADAPT § 9.3 states that max-descriptors need to be resolved - // before min-descriptors. - // http://dev.w3.org/csswg/css-device-adapt/#resolve-extend-to-zoom - let max_width = to_pixel_length!(max_width, width, extend_width => None); - let max_height = to_pixel_length!(max_height, height, extend_height => None); - - let min_width = to_pixel_length!(min_width, width, extend_width => max_width); - let min_height = to_pixel_length!(min_height, height, extend_height => max_height); - - // DEVICE-ADAPT § 6.2.4 Resolve initial width and height from min/max descriptors - macro_rules! resolve { - ($min:ident, $max:ident, $initial:expr) => { - if $min.is_some() || $max.is_some() { - let max = match $max { - Some(max) => cmp::min(max, $initial), - None => $initial, - }; - - Some(match $min { - Some(min) => cmp::max(min, max), - None => max, - }) - } else { - None - } - }; - } - - let width = resolve!(min_width, max_width, initial_viewport.width); - let height = resolve!(min_height, max_height, initial_viewport.height); - - // DEVICE-ADAPT § 6.2.5 Resolve width value - let width = if width.is_none() && height.is_none() { - Some(initial_viewport.width) - } else { - width - }; - - let width = width.unwrap_or_else(|| match initial_viewport.height { - Au(0) => initial_viewport.width, - initial_height => { - let ratio = initial_viewport.width.to_f32_px() / initial_height.to_f32_px(); - Au::from_f32_px(height.unwrap().to_f32_px() * ratio) - }, - }); - - // DEVICE-ADAPT § 6.2.6 Resolve height value - let height = height.unwrap_or_else(|| match initial_viewport.width { - Au(0) => initial_viewport.height, - initial_width => { - let ratio = initial_viewport.height.to_f32_px() / initial_width.to_f32_px(); - Au::from_f32_px(width.to_f32_px() * ratio) - }, - }); - - Some(ViewportConstraints { - size: Size2D::new(width.to_f32_px(), height.to_f32_px()), - - // TODO: compute a zoom factor for 'auto' as suggested by DEVICE-ADAPT § 10. - initial_zoom: PinchZoomFactor::new(initial_zoom.unwrap_or(1.)), - min_zoom: min_zoom.map(PinchZoomFactor::new), - max_zoom: max_zoom.map(PinchZoomFactor::new), - - user_zoom, - orientation, - }) - } -} diff --git a/components/style/stylist.rs b/components/style/stylist.rs index 92adee56457..b4fd4e3a64b 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -31,7 +31,6 @@ use crate::stylesheets::container_rule::ContainerCondition; use crate::stylesheets::import_rule::ImportLayer; use crate::stylesheets::keyframes_rule::KeyframesAnimation; use crate::stylesheets::layer_rule::{LayerName, LayerOrder}; -use crate::stylesheets::viewport_rule::{self, MaybeNew, ViewportRule}; #[cfg(feature = "gecko")] use crate::stylesheets::{ CounterStyleRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, PageRule, @@ -64,7 +63,6 @@ use std::hash::{Hash, Hasher}; use std::sync::Mutex; use std::{mem, ops}; use style_traits::dom::{DocumentState, ElementState}; -use style_traits::viewport::ViewportConstraints; /// The type of the stylesheets that the stylist contains. #[cfg(feature = "servo")] @@ -503,9 +501,6 @@ pub struct Stylist { /// `set_device`. device: Device, - /// Viewport constraints based on the current device. - viewport_constraints: Option, - /// The list of stylesheets. stylesheets: StylistStylesheetSet, @@ -610,7 +605,6 @@ impl Stylist { #[inline] pub fn new(device: Device, quirks_mode: QuirksMode) -> Self { Self { - viewport_constraints: None, device, quirks_mode, stylesheets: StylistStylesheetSet::new(), @@ -734,37 +728,6 @@ impl Stylist { self.num_rebuilds += 1; - // Update viewport_constraints regardless of which origins' - // `CascadeData` we're updating. - self.viewport_constraints = None; - if viewport_rule::enabled() { - // TODO(emilio): This doesn't look so efficient. - // - // Presumably when we properly implement this we can at least have a - // bit on the stylesheet that says whether it contains viewport - // rules to skip it entirely? - // - // Processing it with the rest of rules seems tricky since it - // overrides the viewport size which may change the evaluation of - // media queries (or may not? how are viewport units in media - // queries defined?) - let cascaded_rule = ViewportRule { - declarations: viewport_rule::Cascade::from_stylesheets( - self.stylesheets.iter(), - guards, - &self.device, - ) - .finish(), - }; - - self.viewport_constraints = - ViewportConstraints::maybe_new(&self.device, &cascaded_rule, self.quirks_mode); - - if let Some(ref constraints) = self.viewport_constraints { - self.device.account_for_viewport_rule(constraints); - } - } - let flusher = self.stylesheets.flush(document_element, snapshots); let had_invalidations = flusher.had_invalidations(); @@ -1230,29 +1193,7 @@ impl Stylist { /// /// Also, the device that arrives here may need to take the viewport rules /// into account. - pub fn set_device(&mut self, mut device: Device, guards: &StylesheetGuards) -> OriginSet { - if viewport_rule::enabled() { - let cascaded_rule = { - let stylesheets = self.stylesheets.iter(); - - ViewportRule { - declarations: viewport_rule::Cascade::from_stylesheets( - stylesheets, - guards, - &device, - ) - .finish(), - } - }; - - self.viewport_constraints = - ViewportConstraints::maybe_new(&device, &cascaded_rule, self.quirks_mode); - - if let Some(ref constraints) = self.viewport_constraints { - device.account_for_viewport_rule(constraints); - } - } - + pub fn set_device(&mut self, device: Device, guards: &StylesheetGuards) -> OriginSet { self.device = device; self.media_features_change_changed_style(guards, &self.device) } @@ -1293,12 +1234,6 @@ impl Stylist { origins } - /// Returns the viewport constraints that apply to this document because of - /// a @viewport rule. - pub fn viewport_constraints(&self) -> Option<&ViewportConstraints> { - self.viewport_constraints.as_ref() - } - /// Returns the Quirks Mode of the document. pub fn quirks_mode(&self) -> QuirksMode { self.quirks_mode @@ -2844,8 +2779,6 @@ impl CascadeData { self.extra_data .add_page(guard, rule, containing_rule_state.layer_id)?; }, - // TODO: Handle CssRule::Property - CssRule::Viewport(..) => {}, _ => { handled = false; }, @@ -3088,7 +3021,6 @@ impl CascadeData { CssRule::Keyframes(..) | CssRule::Page(..) | CssRule::Property(..) | - CssRule::Viewport(..) | CssRule::Document(..) | CssRule::LayerBlock(..) | CssRule::LayerStatement(..) | diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 7087558375a..2c64e399ca5 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -68,8 +68,6 @@ pub mod dom; pub mod specified_value_info; #[macro_use] pub mod values; -#[macro_use] -pub mod viewport; pub mod owned_slice; pub mod owned_str; diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 4e5d3bc3483..3c9f0acacd0 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -504,62 +504,6 @@ impl_to_css_for_predefined_type!(u32); impl_to_css_for_predefined_type!(::cssparser::Token<'a>); impl_to_css_for_predefined_type!(::cssparser::UnicodeRange); -/// Define an enum type with unit variants that each correspond to a CSS keyword. -macro_rules! define_css_keyword_enum { - (pub enum $name:ident { $($variant:ident = $css:expr,)+ }) => { - #[allow(missing_docs)] - #[cfg_attr(feature = "servo", derive(serde::Deserialize, serde::Serialize))] - #[derive(Clone, Copy, Debug, Eq, Hash, - malloc_size_of_derive::MallocSizeOf, PartialEq, to_shmem_derive::ToShmem)] - pub enum $name { - $($variant),+ - } - - impl $name { - /// Parse this property from a CSS input stream. - pub fn parse<'i, 't>(input: &mut ::cssparser::Parser<'i, 't>) - -> Result<$name, $crate::ParseError<'i>> { - use cssparser::Token; - let location = input.current_source_location(); - match *input.next()? { - Token::Ident(ref ident) => { - Self::from_ident(ident).map_err(|()| { - location.new_unexpected_token_error( - Token::Ident(ident.clone()), - ) - }) - } - ref token => { - Err(location.new_unexpected_token_error(token.clone())) - } - } - } - - /// Parse this property from an already-tokenized identifier. - pub fn from_ident(ident: &str) -> Result<$name, ()> { - cssparser::match_ignore_ascii_case! { ident, - $($css => Ok($name::$variant),)+ - _ => Err(()) - } - } - } - - impl $crate::ToCss for $name { - fn to_css( - &self, - dest: &mut $crate::CssWriter, - ) -> ::std::fmt::Result - where - W: ::std::fmt::Write, - { - match *self { - $( $name::$variant => ::std::fmt::Write::write_str(dest, $css) ),+ - } - } - } - }; -} - /// Helper types for the handling of specified values. pub mod specified { use malloc_size_of_derive::MallocSizeOf; diff --git a/components/style_traits/viewport.rs b/components/style_traits/viewport.rs deleted file mode 100644 index c5b25293188..00000000000 --- a/components/style_traits/viewport.rs +++ /dev/null @@ -1,152 +0,0 @@ -/* 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 https://mozilla.org/MPL/2.0/. */ - -//! Helper types for the `@viewport` rule. - -use std::fmt::{self, Write}; - -use cssparser::*; -use euclid::Size2D; -use malloc_size_of_derive::MallocSizeOf; -use serde::{Deserialize, Serialize}; -use to_shmem_derive::ToShmem; - -use crate::{CSSPixel, CssWriter, ParseError, PinchZoomFactor, ToCss}; - -define_css_keyword_enum! { - pub enum UserZoom { - Zoom = "zoom", - Fixed = "fixed", - } -} - -define_css_keyword_enum! { - pub enum Orientation { - Auto = "auto", - Portrait = "portrait", - Landscape = "landscape", - } -} - -/// A set of viewport descriptors: -/// -/// -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, MallocSizeOf))] -pub struct ViewportConstraints { - /// Width and height: - /// * https://drafts.csswg.org/css-device-adapt/#width-desc - /// * https://drafts.csswg.org/css-device-adapt/#height-desc - pub size: Size2D, - /// - pub initial_zoom: PinchZoomFactor, - /// - pub min_zoom: Option, - /// - pub max_zoom: Option, - /// - pub user_zoom: UserZoom, - /// - pub orientation: Orientation, -} - -impl ToCss for ViewportConstraints { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: Write, - { - dest.write_str("@viewport { width: ")?; - self.size.width.to_css(dest)?; - - dest.write_str("px; height: ")?; - self.size.height.to_css(dest)?; - - dest.write_str("px; zoom: ")?; - self.initial_zoom.get().to_css(dest)?; - - if let Some(min_zoom) = self.min_zoom { - dest.write_str("; min-zoom: ")?; - min_zoom.get().to_css(dest)?; - } - - if let Some(max_zoom) = self.max_zoom { - dest.write_str("; max-zoom: ")?; - max_zoom.get().to_css(dest)?; - } - - dest.write_str("; user-zoom: ")?; - self.user_zoom.to_css(dest)?; - - dest.write_str("; orientation: ")?; - self.orientation.to_css(dest)?; - dest.write_str("; }") - } -} - -/// -#[derive(Clone, Copy, Debug, PartialEq, ToShmem)] -#[cfg_attr(feature = "servo", derive(MallocSizeOf))] -pub enum Zoom { - /// A number value. - Number(f32), - /// A percentage value. - Percentage(f32), - /// The `auto` keyword. - Auto, -} - -impl ToCss for Zoom { - fn to_css(&self, dest: &mut CssWriter) -> fmt::Result - where - W: fmt::Write, - { - match *self { - Zoom::Number(number) => number.to_css(dest), - Zoom::Auto => dest.write_str("auto"), - Zoom::Percentage(percentage) => { - (percentage * 100.).to_css(dest)?; - dest.write_char('%') - }, - } - } -} - -impl Zoom { - /// Parse a zoom value per: - /// - /// - pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result> { - use crate::values::specified::AllowedNumericType::NonNegative; - use crate::ParsingMode; - - let location = input.current_source_location(); - match *input.next()? { - // TODO: This parse() method should take ParserContext as an - // argument, and pass ParsingMode owned by the ParserContext to - // is_ok() instead of using ParsingMode::DEFAULT directly. - // In order to do so, we might want to move these stuff into style::stylesheets::viewport_rule. - Token::Percentage { unit_value, .. } - if NonNegative.is_ok(ParsingMode::DEFAULT, unit_value) => - { - Ok(Zoom::Percentage(unit_value)) - }, - Token::Number { value, .. } if NonNegative.is_ok(ParsingMode::DEFAULT, value) => { - Ok(Zoom::Number(value)) - }, - Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") => Ok(Zoom::Auto), - ref t => Err(location.new_unexpected_token_error(t.clone())), - } - } - - /// Get this zoom value as a float value. Returns `None` if the value is the - /// `auto` keyword. - #[inline] - pub fn to_f32(&self) -> Option { - match *self { - Zoom::Number(number) => Some(number as f32), - Zoom::Percentage(percentage) => Some(percentage as f32), - Zoom::Auto => None, - } - } -}