diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index e61c994046c..aae2b58b699 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1743,7 +1743,7 @@ fn static_assert() { scroll-snap-points-x scroll-snap-points-y transform scroll-snap-type-y scroll-snap-coordinate perspective-origin transform-origin -moz-binding will-change - shape-outside""" %> + shape-outside contain""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> // We manually-implement the |display| property until we get general @@ -2364,6 +2364,71 @@ fn static_assert() { } <% impl_shape_source("shape_outside", "mShapeOutside") %> + + pub fn set_contain(&mut self, v: longhands::contain::computed_value::T) { + use gecko_bindings::structs::NS_STYLE_CONTAIN_NONE; + use gecko_bindings::structs::NS_STYLE_CONTAIN_STRICT; + use gecko_bindings::structs::NS_STYLE_CONTAIN_LAYOUT; + use gecko_bindings::structs::NS_STYLE_CONTAIN_STYLE; + use gecko_bindings::structs::NS_STYLE_CONTAIN_PAINT; + use gecko_bindings::structs::NS_STYLE_CONTAIN_ALL_BITS; + use properties::longhands::contain; + + if v.is_empty() { + self.gecko.mContain = NS_STYLE_CONTAIN_NONE as u8; + return; + } + + if v.contains(contain::STRICT) { + self.gecko.mContain = (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS) as u8; + return; + } + + let mut bitfield = 0; + if v.contains(contain::LAYOUT) { + bitfield |= NS_STYLE_CONTAIN_LAYOUT; + } + if v.contains(contain::STYLE) { + bitfield |= NS_STYLE_CONTAIN_STYLE; + } + if v.contains(contain::PAINT) { + bitfield |= NS_STYLE_CONTAIN_PAINT; + } + + self.gecko.mContain = bitfield as u8; + } + + pub fn clone_contain(&self) -> longhands::contain::computed_value::T { + use gecko_bindings::structs::NS_STYLE_CONTAIN_STRICT; + use gecko_bindings::structs::NS_STYLE_CONTAIN_LAYOUT; + use gecko_bindings::structs::NS_STYLE_CONTAIN_STYLE; + use gecko_bindings::structs::NS_STYLE_CONTAIN_PAINT; + use gecko_bindings::structs::NS_STYLE_CONTAIN_ALL_BITS; + use properties::longhands::contain; + + let mut servo_flags = contain::computed_value::T::empty(); + let gecko_flags = self.gecko.mContain; + + if gecko_flags & (NS_STYLE_CONTAIN_STRICT as u8) != 0 && + gecko_flags & (NS_STYLE_CONTAIN_ALL_BITS as u8) != 0 { + servo_flags.insert(contain::STRICT | contain::STRICT_BITS); + return servo_flags; + } + + if gecko_flags & (NS_STYLE_CONTAIN_LAYOUT as u8) != 0 { + servo_flags.insert(contain::LAYOUT); + } + if gecko_flags & (NS_STYLE_CONTAIN_STYLE as u8) != 0{ + servo_flags.insert(contain::STYLE); + } + if gecko_flags & (NS_STYLE_CONTAIN_PAINT as u8) != 0 { + servo_flags.insert(contain::PAINT); + } + + return servo_flags; + } + + ${impl_simple_copy("contain", "mContain")} <%def name="simple_image_array_property(name, shorthand, field_name)"> diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 9bb5193682b..e07e974fe82 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -353,6 +353,7 @@ ${helpers.single_keyword("overflow-clip-box", "padding-box content-box", // FIXME(pcwalton, #2742): Implement scrolling for `scroll` and `auto`. ${helpers.single_keyword("overflow-x", "visible hidden scroll auto", + extra_gecko_values="clip", need_clone=True, animation_type="none", gecko_constant_prefix="NS_STYLE_OVERFLOW", spec="https://drafts.csswg.org/css-overflow/#propdef-overflow-x")} @@ -2316,7 +2317,10 @@ ${helpers.single_keyword("transform-style", } -<%helpers:longhand name="contain" animation_type="none" products="none" +// 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_type="none" products="gecko" need_clone="True" spec="https://drafts.csswg.org/css-contain/#contain-property"> use std::fmt; use style_traits::ToCss; @@ -2333,12 +2337,11 @@ ${helpers.single_keyword("transform-style", 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, + const LAYOUT = 0x01, + const STYLE = 0x02, + const PAINT = 0x04, + const STRICT = 0x8, + const STRICT_BITS = LAYOUT.bits | STYLE.bits | PAINT.bits, } } @@ -2350,9 +2353,6 @@ ${helpers.single_keyword("transform-style", 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 { @@ -2366,7 +2366,6 @@ ${helpers.single_keyword("transform-style", } } } - maybe_write_value!(SIZE => "size"); maybe_write_value!(LAYOUT => "layout"); maybe_write_value!(STYLE => "style"); maybe_write_value!(PAINT => "paint"); @@ -2389,17 +2388,12 @@ ${helpers.single_keyword("transform-style", 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); + result.insert(STRICT | STRICT_BITS); 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, diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index b53c9254659..30ed8e3afc1 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2435,8 +2435,11 @@ pub fn apply_declarations<'a, F, I>(device: &Device, { use computed_values::overflow_x::T as overflow; use computed_values::overflow_y; - match (style.get_box().clone_overflow_x() == longhands::overflow_x::computed_value::T::visible, - style.get_box().clone_overflow_y().0 == longhands::overflow_x::computed_value::T::visible) { + + let overflow_x = style.get_box().clone_overflow_x(); + let overflow_y = style.get_box().clone_overflow_y().0; + match (overflow_x == longhands::overflow_x::computed_value::T::visible, + overflow_y == longhands::overflow_x::computed_value::T::visible) { (true, true) => {} (true, _) => { style.mutate_box().set_overflow_x(overflow::auto); @@ -2446,8 +2449,36 @@ pub fn apply_declarations<'a, F, I>(device: &Device, } _ => {} } + + % if product == "gecko": + use properties::longhands::contain; + // When 'contain: paint', update overflow from 'visible' to 'clip'. + let contain = style.get_box().clone_contain(); + if contain.contains(contain::PAINT) { + if let longhands::overflow_x::computed_value::T::visible = overflow_x { + style.mutate_box().set_overflow_x(overflow::clip); + } + if let longhands::overflow_x::computed_value::T::visible = overflow_y { + style.mutate_box().set_overflow_y(overflow_y::T(overflow::clip)); + } + } + % endif } + % if product == "gecko": + { + use computed_values::display::T as display; + use properties::longhands::contain; + // An element with contain:paint or contain:layout needs to "be a + // formatting context" + let contain = style.get_box().clone_contain(); + if contain.contains(contain::PAINT) && + style.get_box().clone_display() == display::inline { + style.mutate_box().set_adjusted_display(display::inline_block); + } + } + % endif + // CSS 2.1 section 9.7: // // If 'position' has the value 'absolute' or 'fixed', [...] the computed diff --git a/tests/unit/style/parsing/containment.rs b/tests/unit/style/parsing/containment.rs index d4cffe9f1a5..dbd02fd7067 100644 --- a/tests/unit/style/parsing/containment.rs +++ b/tests/unit/style/parsing/containment.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use parsing::parse; +use style_traits::ToCss; #[test] fn contain_longhand_should_parse_correctly() { @@ -13,11 +14,14 @@ fn contain_longhand_should_parse_correctly() { assert_eq!(none, SpecifiedValue::empty()); let strict = parse_longhand!(contain, "strict"); - assert_eq!(strict, contain::STRICT); + assert_eq!(strict, contain::STRICT | contain::STRICT_BITS); let style_paint = parse_longhand!(contain, "style paint"); assert_eq!(style_paint, contain::STYLE | contain::PAINT); + assert_roundtrip_with_context!(contain::parse, "strict"); + assert_roundtrip_with_context!(contain::parse, "layout style paint"); + // Assert that the `2px` is not consumed, which would trigger parsing failure in real use assert_parser_exhausted!(contain::parse, "layout 2px", false); }