aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/style/properties/data.py1
-rw-r--r--components/style/properties/longhands/box.mako.rs20
-rw-r--r--components/style/properties/shorthands/box.mako.rs39
-rw-r--r--components/style/values/computed/box.rs7
-rw-r--r--components/style/values/computed/mod.rs2
-rw-r--r--components/style/values/specified/box.rs55
-rw-r--r--components/style/values/specified/mod.rs2
-rw-r--r--components/style_derive/to_css.rs38
-rw-r--r--components/style_traits/values.rs13
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`.