From 535959f2a5d08923c681bdc7450d4e0c55bab0c8 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Wed, 15 Mar 2017 15:04:43 -0500 Subject: [PATCH] Parsing / serialization for CSS contain --- .../style/properties/longhand/box.mako.rs | 103 ++++++++++++++++++ tests/unit/style/parsing/containment.rs | 26 +++++ tests/unit/style/parsing/mod.rs | 1 + 3 files changed, 130 insertions(+) create mode 100644 tests/unit/style/parsing/containment.rs diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index f4daad8962e..c57eb947535 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -1899,6 +1899,109 @@ ${helpers.single_keyword("transform-style", } +<%helpers:longhand name="contain" animatable="False" products="none" + spec="https://drafts.csswg.org/css-contain/#contain-property"> + use std::fmt; + use style_traits::ToCss; + use values::HasViewportPercentage; + use values::computed::ComputedValueAsSpecified; + + impl ComputedValueAsSpecified for SpecifiedValue {} + no_viewport_percentage!(SpecifiedValue); + + pub mod computed_value { + pub type T = super::SpecifiedValue; + } + + bitflags! { + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub flags SpecifiedValue: u8 { + const SIZE = 0x01, + const LAYOUT = 0x02, + const STYLE = 0x04, + const PAINT = 0x08, + const STRICT = SIZE.bits | LAYOUT.bits | STYLE.bits | PAINT.bits, + const CONTENT = LAYOUT.bits | STYLE.bits | PAINT.bits, + } + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if self.is_empty() { + return dest.write_str("none") + } + if self.contains(STRICT) { + return dest.write_str("strict") + } + if self.contains(CONTENT) { + return dest.write_str("content") + } + + let mut has_any = false; + macro_rules! maybe_write_value { + ($ident:ident => $str:expr) => { + if self.contains($ident) { + if has_any { + try!(dest.write_str(" ")); + } + has_any = true; + try!(dest.write_str($str)); + } + } + } + maybe_write_value!(SIZE => "size"); + maybe_write_value!(LAYOUT => "layout"); + maybe_write_value!(STYLE => "style"); + maybe_write_value!(PAINT => "paint"); + + debug_assert!(has_any); + Ok(()) + } + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T::empty() + } + + /// none | strict | content | [ size || layout || style || paint ] + pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + let mut result = SpecifiedValue::empty(); + + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(result) + } + if input.try(|input| input.expect_ident_matching("strict")).is_ok() { + result.insert(STRICT); + return Ok(result) + } + if input.try(|input| input.expect_ident_matching("content")).is_ok() { + result.insert(CONTENT); + return Ok(result) + } + + while let Ok(name) = input.try(|input| input.expect_ident()) { + let flag = match_ignore_ascii_case! { &name, + "size" => SIZE, + "layout" => LAYOUT, + "style" => STYLE, + "paint" => PAINT, + _ => return Err(()) + }; + if result.contains(flag) { + return Err(()) + } + result.insert(flag); + } + + if !result.is_empty() { + Ok(result) + } else { + Err(()) + } + } + + // Non-standard ${helpers.single_keyword("-moz-appearance", """none button button-arrow-down button-arrow-next button-arrow-previous button-arrow-up diff --git a/tests/unit/style/parsing/containment.rs b/tests/unit/style/parsing/containment.rs new file mode 100644 index 00000000000..de697cb8441 --- /dev/null +++ b/tests/unit/style/parsing/containment.rs @@ -0,0 +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/. */ + +use cssparser::Parser; +use media_queries::CSSErrorReporterTest; +use style::parser::ParserContext; +use style::stylesheets::Origin; + +#[test] +fn contain_longhand_should_parse_correctly() { + use style::properties::longhands::contain; + use style::properties::longhands::contain::SpecifiedValue; + + let none = parse_longhand!(contain, "none"); + assert_eq!(none, SpecifiedValue::empty()); + + let strict = parse_longhand!(contain, "strict"); + assert_eq!(strict, contain::STRICT); + + let style_paint = parse_longhand!(contain, "style paint"); + assert_eq!(style_paint, contain::STYLE | contain::PAINT); + + // Assert that the `2px` is not consumed, which would trigger parsing failure in real use + assert_parser_exhausted!(contain, "layout 2px", false); +} diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index cfa7582eeda..40899ab40c4 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -87,6 +87,7 @@ mod basic_shape; mod border; mod box_; mod column; +mod containment; mod effects; mod font; mod image;