diff options
-rw-r--r-- | components/style/properties/data.py | 1 | ||||
-rw-r--r-- | components/style/properties/longhands/box.mako.rs | 20 | ||||
-rw-r--r-- | components/style/properties/shorthands/box.mako.rs | 39 | ||||
-rw-r--r-- | components/style/values/computed/box.rs | 7 | ||||
-rw-r--r-- | components/style/values/computed/mod.rs | 2 | ||||
-rw-r--r-- | components/style/values/specified/box.rs | 55 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 2 | ||||
-rw-r--r-- | components/style_derive/to_css.rs | 38 | ||||
-rw-r--r-- | components/style_traits/values.rs | 13 |
9 files changed, 161 insertions, 16 deletions
diff --git a/components/style/properties/data.py b/components/style/properties/data.py index 84e0b482569..426b03276d0 100644 --- a/components/style/properties/data.py +++ b/components/style/properties/data.py @@ -444,6 +444,7 @@ class Longhand(Property): "ColumnCount", "Contain", "ContentVisibility", + "ContainerType", "Display", "FillRule", "Float", diff --git a/components/style/properties/longhands/box.mako.rs b/components/style/properties/longhands/box.mako.rs index 1fccedcc652..f534617e5bc 100644 --- a/components/style/properties/longhands/box.mako.rs +++ b/components/style/properties/longhands/box.mako.rs @@ -624,6 +624,26 @@ ${helpers.predefined_type( )} ${helpers.predefined_type( + "container-type", + "ContainerType", + "computed::ContainerType::NONE", + engines="gecko", + animation_value_type="none", + gecko_pref="layout.css.container-queries.enabled", + spec="https://drafts.csswg.org/css-contain-3/#container-type", +)} + +${helpers.predefined_type( + "container-name", + "ContainerName", + "computed::ContainerName::none()", + engines="gecko", + animation_value_type="none", + gecko_pref="layout.css.container-queries.enabled", + spec="https://drafts.csswg.org/css-contain-3/#container-name", +)} + +${helpers.predefined_type( "appearance", "Appearance", "computed::Appearance::None", diff --git a/components/style/properties/shorthands/box.mako.rs b/components/style/properties/shorthands/box.mako.rs index a0bc082caeb..c52ae420683 100644 --- a/components/style/properties/shorthands/box.mako.rs +++ b/components/style/properties/shorthands/box.mako.rs @@ -347,6 +347,45 @@ ${helpers.two_properties_shorthand( <%helpers:shorthand engines="gecko" + name="container" + sub_properties="container-type container-name" + gecko_pref="layout.css.container-queries.enabled", + spec="https://drafts.csswg.org/css-contain-3/#container-shorthand" +> + pub fn parse_value<'i>( + context: &ParserContext, + input: &mut Parser<'i, '_>, + ) -> Result<Longhands, ParseError<'i>> { + use crate::parser::Parse; + use crate::values::specified::box_::{ContainerName, ContainerType}; + // See https://github.com/w3c/csswg-drafts/issues/7180 for why we don't + // match the spec. + let container_type = ContainerType::parse(context, input)?; + let container_name = if input.try_parse(|input| input.expect_delim('/')).is_ok() { + ContainerName::parse(context, input)? + } else { + ContainerName::none() + }; + Ok(expanded! { + container_type: container_type, + container_name: container_name, + }) + } + + impl<'a> ToCss for LonghandsToSerialize<'a> { + fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write { + self.container_type.to_css(dest)?; + if !self.container_name.is_none() { + dest.write_str(" / ")?; + self.container_name.to_css(dest)?; + } + Ok(()) + } + } +</%helpers:shorthand> + +<%helpers:shorthand + engines="gecko" name="page-break-before" flags="SHORTHAND_IN_GETCS IS_LEGACY_SHORTHAND" sub_properties="break-before" diff --git a/components/style/values/computed/box.rs b/components/style/values/computed/box.rs index dd1e4900672..f4d3a4f5a35 100644 --- a/components/style/values/computed/box.rs +++ b/components/style/values/computed/box.rs @@ -13,9 +13,10 @@ use crate::values::specified::box_ as specified; pub use crate::values::specified::box_::{ AnimationName, AnimationTimeline, Appearance, BreakBetween, BreakWithin, - Clear as SpecifiedClear, Contain, ContentVisibility, Display, Float as SpecifiedFloat, Overflow, - OverflowAnchor, OverflowClipBox, OverscrollBehavior, ScrollSnapAlign, ScrollSnapAxis, - ScrollSnapStrictness, ScrollSnapType, ScrollbarGutter, TouchAction, TransitionProperty, WillChange, + Clear as SpecifiedClear, Contain, ContainerName, ContainerType, ContentVisibility, Display, + Float as SpecifiedFloat, Overflow, OverflowAnchor, OverflowClipBox, + OverscrollBehavior, ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, + ScrollSnapType, ScrollbarGutter, TouchAction, TransitionProperty, 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 68194eb733a..ef1c88a43e5 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -44,7 +44,7 @@ pub use self::basic_shape::FillRule; pub use self::border::{BorderCornerRadius, BorderRadius, BorderSpacing}; pub use self::border::{BorderImageRepeat, BorderImageSideWidth}; pub use self::border::{BorderImageSlice, BorderImageWidth}; -pub use self::box_::{AnimationIterationCount, AnimationName, AnimationTimeline, Contain}; +pub use self::box_::{AnimationIterationCount, AnimationName, AnimationTimeline, Contain, ContainerName, ContainerType}; pub use self::box_::{Appearance, BreakBetween, BreakWithin, Clear, ContentVisibility, Float}; pub use self::box_::{Display, Overflow, OverflowAnchor, TransitionProperty}; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize, ScrollbarGutter}; diff --git a/components/style/values/specified/box.rs b/components/style/values/specified/box.rs index 6157bfab6c8..cebcaa74dda 100644 --- a/components/style/values/specified/box.rs +++ b/components/style/values/specified/box.rs @@ -1288,6 +1288,61 @@ pub enum ContentVisibility { Visible, } +bitflags! { + #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToCss, Parse, ToResolvedValue, ToShmem)] + #[repr(C)] + #[allow(missing_docs)] + #[css(bitflags(single="none", mixed="style,size,inline-size", overlapping_bits))] + /// https://drafts.csswg.org/css-contain-3/#container-type + /// + /// TODO: block-size is on the spec but it seems it was removed? WPTs don't + /// support it, see https://github.com/w3c/csswg-drafts/issues/7179. + pub struct ContainerType: u8 { + /// The `none` variant. + const NONE = 0; + /// The `style` variant. + const STYLE = 1 << 0; + /// The `inline-size` variant. + const INLINE_SIZE = 1 << 1; + /// The `size` variant, exclusive with `inline-size` (they sharing bits + /// guarantees this). + const SIZE = 1 << 2 | Self::INLINE_SIZE.bits; + } +} + +/// https://drafts.csswg.org/css-contain-3/#container-name +#[repr(transparent)] +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)] +pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>); + +impl ContainerName { + /// Return the `none` value. + pub fn none() -> Self { + Self(Default::default()) + } + + /// Returns whether this is the `none` value. + pub fn is_none(&self) -> bool { + self.0.is_empty() + } +} + +impl Parse for ContainerName { + fn parse<'i, 't>( _: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> { + let mut idents = vec![]; + let location = input.current_source_location(); + let first = input.expect_ident()?; + if first.eq_ignore_ascii_case("none") { + return Ok(Self::none()) + } + idents.push(CustomIdent::from_ident(location, first, &["none"])?); + while let Ok(ident) = input.try_parse(|input| input.expect_ident_cloned()) { + idents.push(CustomIdent::from_ident(location, &ident, &["none"])?); + } + Ok(ContainerName(idents.into())) + } +} + /// A specified value for the `perspective` property. pub type Perspective = GenericPerspective<NonNegativeLength>; diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index ac622961642..7292088920d 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -37,7 +37,7 @@ pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth}; pub use self::border::{BorderImageRepeat, BorderImageSideWidth}; pub use self::border::{BorderRadius, BorderSideWidth, BorderSpacing, BorderStyle}; pub use self::box_::{AnimationIterationCount, AnimationName, AnimationTimeline, Contain, Display}; -pub use self::box_::{Appearance, BreakBetween, BreakWithin}; +pub use self::box_::{Appearance, BreakBetween, BreakWithin, ContainerName, ContainerType}; pub use self::box_::{Clear, ContentVisibility, Float, Overflow, OverflowAnchor}; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize, ScrollbarGutter}; pub use self::box_::{ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStrictness, ScrollSnapType}; diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 25fc4e86be4..af729f91459 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -31,17 +31,35 @@ fn derive_bitflags(input: &syn::DeriveInput, bitflags: &CssBitflagAttrs) -> Toke let mut has_any = false; }); + if bitflags.overlapping_bits { + body.append_all(quote! { + let mut serialized = Self::empty(); + }); + } + for (rust_name, css_name) in bitflags.mixed_flags() { let rust_ident = Ident::new(&rust_name, Span::call_site()); - body.append_all(quote! { - if self.intersects(Self::#rust_ident) { - if has_any { - dest.write_char(' ')?; - } - has_any = true; - dest.write_str(#css_name)?; + let serialize = quote! { + if has_any { + dest.write_char(' ')?; } - }); + has_any = true; + dest.write_str(#css_name)?; + }; + if bitflags.overlapping_bits { + body.append_all(quote! { + if self.contains(Self::#rust_ident) && !serialized.intersects(Self::#rust_ident) { + #serialize + serialized.insert(Self::#rust_ident); + } + }); + } else { + body.append_all(quote! { + if self.intersects(Self::#rust_ident) { + #serialize + } + }); + } } body.append_all(quote! { @@ -319,6 +337,10 @@ pub struct CssBitflagAttrs { /// Extra validation of the resulting mixed flags. #[darling(default)] pub validate_mixed: Option<Path>, + /// Whether there are overlapping bits we need to take care of when + /// serializing. + #[darling(default)] + pub overlapping_bits: bool, } impl CssBitflagAttrs { diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 1677629d1a9..d04485790f8 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -44,9 +44,9 @@ use std::fmt::{self, Write}; /// * `#[css(represents_keyword)]` can be used on bool fields in order to /// serialize the field name if the field is true, or nothing otherwise. It /// also collects those keywords for `SpecifiedValueInfo`. -/// * `#[css(bitflags(single="", mixed="", validate="")]` can be used to derive -/// parse / serialize / etc on bitflags. The rules for parsing bitflags are -/// the following: +/// * `#[css(bitflags(single="", mixed="", validate="", overlapping_bits)]` can +/// be used to derive parse / serialize / etc on bitflags. The rules for parsing +/// bitflags are the following: /// /// * `single` flags can only appear on their own. It's common that bitflags /// properties at least have one such value like `none` or `auto`. @@ -66,6 +66,13 @@ use std::fmt::{self, Write}; /// /// But `bar baz` will be valid, as they don't share bits, and so would /// `foo` with any other flag, or `bazz` on its own. +/// * `overlapping_bits` enables some tracking during serialization of mixed +/// flags to avoid serializing variants that can subsume other variants. +/// In the example above, you could do: +/// mixed="foo,bazz,bar,baz", overlapping_bits +/// to ensure that if bazz is serialized, bar and baz aren't, even though +/// their bits are set. Note that the serialization order is canonical, +/// and thus depends on the order you specify the flags in. /// /// * finally, one can put `#[css(derive_debug)]` on the whole type, to /// implement `Debug` by a single call to `ToCss::to_css`. |