diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index a24c3cb036b..5a026ae0632 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -543,100 +543,14 @@ ${helpers.predefined_type("transform-origin", boxed=True, spec="https://drafts.csswg.org/css-transforms/#transform-origin-property")} -// FIXME: `size` and `content` values are not implemented and `strict` is implemented -// like `content`(layout style paint) in gecko. We should implement `size` and `content`, -// also update the glue once they are implemented in gecko. -<%helpers:longhand name="contain" animation_value_type="discrete" products="gecko" - flags="FIXPOS_CB" - gecko_pref="layout.css.contain.enabled", - spec="https://drafts.csswg.org/css-contain/#contain-property"> - use std::fmt; - use style_traits::ToCss; - - pub mod computed_value { - pub type T = super::SpecifiedValue; - } - - bitflags! { - #[derive(MallocSizeOf, ToComputedValue)] - pub struct SpecifiedValue: u8 { - const LAYOUT = 0x01; - const STYLE = 0x02; - const PAINT = 0x04; - const STRICT = 0x8; - const STRICT_BITS = SpecifiedValue::LAYOUT.bits | SpecifiedValue::STYLE.bits | SpecifiedValue::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(SpecifiedValue::STRICT) { - return dest.write_str("strict") - } - - let mut has_any = false; - macro_rules! maybe_write_value { - ($ident:path => $str:expr) => { - if self.contains($ident) { - if has_any { - dest.write_str(" ")?; - } - has_any = true; - dest.write_str($str)?; - } - } - } - maybe_write_value!(SpecifiedValue::LAYOUT => "layout"); - maybe_write_value!(SpecifiedValue::STYLE => "style"); - maybe_write_value!(SpecifiedValue::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<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) - -> 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(SpecifiedValue::STRICT | SpecifiedValue::STRICT_BITS); - return Ok(result) - } - - while let Ok(name) = input.try(|i| i.expect_ident_cloned()) { - let flag = match_ignore_ascii_case! { &name, - "layout" => Some(SpecifiedValue::LAYOUT), - "style" => Some(SpecifiedValue::STYLE), - "paint" => Some(SpecifiedValue::PAINT), - _ => None - }; - let flag = match flag { - Some(flag) if !result.contains(flag) => flag, - _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name.clone()))) - }; - result.insert(flag); - } - - if !result.is_empty() { - Ok(result) - } else { - Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) - } - } - +${helpers.predefined_type("contain", + "Contain", + "specified::Contain::empty()", + animation_value_type="discrete", + products="gecko", + flags="FIXPOS_CB", + gecko_pref="layout.css.contain.enabled", + spec="https://drafts.csswg.org/css-contain/#contain-property")} // Non-standard ${helpers.single_keyword("-moz-appearance", diff --git a/components/style/values/computed/box.rs b/components/style/values/computed/box.rs index 2916b3a9695..eeeede9c33a 100644 --- a/components/style/values/computed/box.rs +++ b/components/style/values/computed/box.rs @@ -9,7 +9,7 @@ use values::computed::length::LengthOrPercentage; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; use values::generics::box_::VerticalAlign as GenericVerticalAlign; -pub use values::specified::box_::{AnimationName, Display, OverflowClipBox}; +pub use values::specified::box_::{AnimationName, Display, OverflowClipBox, Contain}; pub use values::specified::box_::{OverscrollBehavior, ScrollSnapType, TouchAction, WillChange}; /// A computed value for the `vertical-align` property. diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 08095d8628c..7141dba4e12 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -40,7 +40,7 @@ pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVa pub use self::font::{FontFamily, FontLanguageOverride, FontVariantSettings, FontVariantEastAsian}; pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang}; -pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior}; +pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain}; pub use self::box_::{OverflowClipBox, ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 9a17db7a480..f4b55446aa1 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -9,8 +9,9 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; #[cfg(feature = "servo")] use properties::{longhands, PropertyDeclaration}; +use selectors::parser::SelectorParseErrorKind; use std::fmt; -use style_traits::{ParseError, ToCss}; +use style_traits::{ParseError, ToCss, StyleParseErrorKind}; use values::CustomIdent; use values::KeyframesName; #[cfg(feature = "servo")] @@ -492,3 +493,92 @@ pub fn assert_touch_action_matches() { NS_STYLE_TOUCH_ACTION_MANIPULATION => TouchAction::TOUCH_ACTION_MANIPULATION, } } + +bitflags! { + #[derive(MallocSizeOf, ToComputedValue)] + /// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property + pub struct Contain: u8 { + /// `layout` variant, turns on layout containment + const LAYOUT = 0x01; + /// `style` variant, turns on style containment + const STYLE = 0x02; + /// `paint` variant, turns on paint containment + const PAINT = 0x04; + /// `strict` variant, turns on all types of containment + const STRICT = 0x8; + /// variant with all the bits that contain: strict turns on + const STRICT_BITS = Contain::LAYOUT.bits | Contain::STYLE.bits | Contain::PAINT.bits; + } +} + +impl ToCss for Contain { + 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(Contain::STRICT) { + return dest.write_str("strict") + } + + let mut has_any = false; + macro_rules! maybe_write_value { + ($ident:path => $str:expr) => { + if self.contains($ident) { + if has_any { + dest.write_str(" ")?; + } + has_any = true; + dest.write_str($str)?; + } + } + } + maybe_write_value!(Contain::LAYOUT => "layout"); + maybe_write_value!(Contain::STYLE => "style"); + maybe_write_value!(Contain::PAINT => "paint"); + + debug_assert!(has_any); + Ok(()) + } +} + +impl Parse for Contain { + /// none | strict | content | [ size || layout || style || paint ] + fn parse<'i, 't>( + _context: &ParserContext, + input: &mut Parser<'i, 't> + ) -> Result> { + let mut result = Contain::empty(); + while let Ok(name) = input.try(|i| i.expect_ident_cloned()) { + let flag = match_ignore_ascii_case! { &name, + "layout" => Some(Contain::LAYOUT), + "style" => Some(Contain::STYLE), + "paint" => Some(Contain::PAINT), + "strict" => { + if result.is_empty() { + return Ok(Contain::STRICT | Contain::STRICT_BITS) + } + None + }, + "none" => { + if result.is_empty() { + return Ok(result) + } + None + }, + _ => None + }; + + let flag = match flag { + Some(flag) if !result.contains(flag) => flag, + _ => return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name))) + }; + result.insert(flag); + } + + if !result.is_empty() { + Ok(result) + } else { + Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) + } + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index a750dcab486..d5c93a1fc1c 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -34,7 +34,7 @@ pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVa pub use self::font::{FontFamily, FontLanguageOverride, FontVariantSettings, FontVariantEastAsian}; pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang}; -pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior}; +pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain}; pub use self::box_::{OverflowClipBox, ScrollSnapType, TouchAction, VerticalAlign, WillChange}; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; pub use self::effects::{BoxShadow, Filter, SimpleShadow};