From 060c48abc90c62a1997a554512fedb303dc760e3 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Sat, 18 May 2024 16:47:28 +0000 Subject: [PATCH] Bug 1897605. Implement parsing of CSS 'anchor-scope'. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D210874 --- .../server/actors/animation-type-longhand.js | 1 + dom/base/use_counter_metrics.yaml | 40 ++++++++- layout/style/ServoBindings.toml | 1 + layout/style/nsStyleStruct.cpp | 9 +- layout/style/nsStyleStruct.h | 4 + layout/style/test/property_database.js | 25 ++++++ .../style/properties/longhands/box.mako.rs | 13 +++ servo/components/style/values/computed/mod.rs | 1 + .../style/values/computed/position.rs | 2 +- .../components/style/values/specified/mod.rs | 1 + .../style/values/specified/position.rs | 89 +++++++++++++++++++ servo/ports/geckolib/cbindgen.toml | 1 + 12 files changed, 180 insertions(+), 7 deletions(-) diff --git a/devtools/server/actors/animation-type-longhand.js b/devtools/server/actors/animation-type-longhand.js index 90d025c1f95d..889a798a156e 100644 --- a/devtools/server/actors/animation-type-longhand.js +++ b/devtools/server/actors/animation-type-longhand.js @@ -10,6 +10,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ "discrete", new Set([ "anchor-name", + "anchor-scope", "align-content", "align-items", "align-self", diff --git a/dom/base/use_counter_metrics.yaml b/dom/base/use_counter_metrics.yaml index 91cedf7d45d0..72074436843a 100644 --- a/dom/base/use_counter_metrics.yaml +++ b/dom/base/use_counter_metrics.yaml @@ -107,7 +107,7 @@ use.counter: send_in_pings: - use-counters -# Total of 2303 use counter metrics (excludes denominators). +# Total of 2305 use counter metrics (excludes denominators). # Total of 354 'page' use counters. use.counter.page: svgsvgelement_getelementbyid: @@ -15541,7 +15541,7 @@ use.counter.deprecated_ops.doc: send_in_pings: - use-counters -# Total of 698 'CSS (page)' use counters. +# Total of 699 'CSS (page)' use counters. use.counter.css.page: css_align_content: type: counter @@ -18603,6 +18603,23 @@ use.counter.css.page: send_in_pings: - use-counters + css_anchor_scope: + type: counter + description: > + Whether a page used the CSS property anchor-scope. + Compare against `use.counter.top_level_content_documents_destroyed` + to calculate the rate. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098 + notification_emails: + - dom-core@mozilla.com + - emilio@mozilla.com + expires: never + send_in_pings: + - use-counters + css_animation_composition: type: counter description: > @@ -27409,7 +27426,7 @@ use.counter.css.page: send_in_pings: - use-counters -# Total of 698 'CSS (document)' use counters. +# Total of 699 'CSS (document)' use counters. use.counter.css.doc: css_align_content: type: counter @@ -30471,6 +30488,23 @@ use.counter.css.doc: send_in_pings: - use-counters + css_anchor_scope: + type: counter + description: > + Whether a document used the CSS property anchor-scope. + Compare against `use.counter.content_documents_destroyed` + to calculate the rate. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1852098 + notification_emails: + - dom-core@mozilla.com + - emilio@mozilla.com + expires: never + send_in_pings: + - use-counters + css_animation_composition: type: counter description: > diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml index d9161b4d2eb4..e02b0cca3e94 100644 --- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -621,6 +621,7 @@ cbindgen-types = [ { gecko = "StyleBaselineSource", servo = "crate::values::computed::BaselineSource" }, { gecko = "StyleAu", servo = "app_units::Au" }, { gecko = "StyleAnchorName", servo = "crate::values::computed::position::AnchorName" }, + { gecko = "StyleAnchorScope", servo = "crate::values::computed::position::AnchorScope" }, ] mapped-generic-types = [ diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 74365fa0023d..e7c86d251143 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2093,7 +2093,8 @@ nsStyleDisplay::nsStyleDisplay() mBaselineSource(StyleBaselineSource::Auto), mWebkitLineClamp(0), mShapeMargin(LengthPercentage::Zero()), - mShapeOutside(StyleShapeOutside::None()) { + mShapeOutside(StyleShapeOutside::None()), + mAnchorScope(StyleAnchorScope::None()) { MOZ_COUNT_CTOR(nsStyleDisplay); } @@ -2152,7 +2153,8 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource) mShapeImageThreshold(aSource.mShapeImageThreshold), mShapeMargin(aSource.mShapeMargin), mShapeOutside(aSource.mShapeOutside), - mAnchorName(aSource.mAnchorName) { + mAnchorName(aSource.mAnchorName), + mAnchorScope(aSource.mAnchorScope) { MOZ_COUNT_CTOR(nsStyleDisplay); } @@ -2524,7 +2526,8 @@ nsChangeHint nsStyleDisplay::CalcDifference( mContainerType != aNewData.mContainerType || mContain != aNewData.mContain || mContainerName != aNewData.mContainerName || - mAnchorName != aNewData.mAnchorName)) { + mAnchorName != aNewData.mAnchorName || + mAnchorScope != aNewData.mAnchorScope)) { hint |= nsChangeHint_NeutralChange; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 251cf996935f..f5671a412fa6 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1320,6 +1320,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay { // anchor positioned elements may reference. mozilla::StyleAnchorName mAnchorName; + // 'none', 'all', or a list of one or more `` identifiers that + // may identify anchor positioning anchor elements. + mozilla::StyleAnchorScope mAnchorScope; + mozilla::Maybe GetWindowButtonType() const { if (MOZ_LIKELY(mDefaultAppearance == mozilla::StyleAppearance::None)) { return mozilla::Nothing(); diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 228b6786bab1..9d14264ca26a 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -13312,6 +13312,31 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "--foo,", ], }; + + gCSSProperties["anchor-scope"] = { + domProp: "anchorScope", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: ["none"], + other_values: [ + "all", + "--foo", + "--foo, --baz", + "--foo,--baz", + "--foo ,--baz", + ], + invalid_values: [ + "all, --foo", + "--foo, all", + "--foo --bar", + "foo", + "none bar", + "none --baz", + "--foo bar", + ",--foo", + "--foo,", + ], + }; } if (false) { diff --git a/servo/components/style/properties/longhands/box.mako.rs b/servo/components/style/properties/longhands/box.mako.rs index fc39675a98f0..f78bdcc2de0f 100644 --- a/servo/components/style/properties/longhands/box.mako.rs +++ b/servo/components/style/properties/longhands/box.mako.rs @@ -74,6 +74,19 @@ ${helpers.predefined_type( affects="", )} +// Changes do not invalidate our element. We handle notify/invalidating +// any affected descendants elsewhere. +${helpers.predefined_type( + "anchor-scope", + "AnchorScope", + "computed::AnchorScope::none()", + engines="gecko", + animation_value_type="discrete", + gecko_pref="layout.css.anchor-positioning.enabled", + spec="https://drafts.csswg.org/css-anchor-position-1/#propdef-scope", + affects="", +)} + ${helpers.predefined_type( "float", "Float", diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs index 59666514190a..1dffb2637a92 100644 --- a/servo/components/style/values/computed/mod.rs +++ b/servo/components/style/values/computed/mod.rs @@ -89,6 +89,7 @@ pub use self::outline::OutlineStyle; pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize}; pub use self::percentage::{NonNegativePercentage, Percentage}; pub use self::position::AnchorName; +pub use self::position::AnchorScope; pub use self::position::AspectRatio; pub use self::position::{ GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex, diff --git a/servo/components/style/values/computed/position.rs b/servo/components/style/values/computed/position.rs index bdd353248af9..1b5dcbb9b0b2 100644 --- a/servo/components/style/values/computed/position.rs +++ b/servo/components/style/values/computed/position.rs @@ -13,7 +13,7 @@ use crate::values::generics::position::Position as GenericPosition; use crate::values::generics::position::PositionComponent as GenericPositionComponent; use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto; use crate::values::generics::position::ZIndex as GenericZIndex; -pub use crate::values::specified::position::{AnchorName, GridAutoFlow, GridTemplateAreas, MasonryAutoFlow}; +pub use crate::values::specified::position::{AnchorName, AnchorScope, GridAutoFlow, GridTemplateAreas, MasonryAutoFlow}; use crate::Zero; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs index 1ed6bd9b5f07..64e66cf92d37 100644 --- a/servo/components/style/values/specified/mod.rs +++ b/servo/components/style/values/specified/mod.rs @@ -82,6 +82,7 @@ pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, P pub use self::percentage::{NonNegativePercentage, Percentage}; pub use self::position::AspectRatio; pub use self::position::AnchorName; +pub use self::position::AnchorScope; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, PositionOrAuto}; pub use self::position::{MasonryAutoFlow, MasonryItemOrder, MasonryPlacement}; pub use self::position::{PositionComponent, ZIndex}; diff --git a/servo/components/style/values/specified/position.rs b/servo/components/style/values/specified/position.rs index 4209cc6df86c..006273163efa 100644 --- a/servo/components/style/values/specified/position.rs +++ b/servo/components/style/values/specified/position.rs @@ -28,6 +28,7 @@ use std::collections::hash_map::Entry; use std::fmt::{self, Write}; use style_traits::values::specified::AllowedNumericType; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; +use style_traits::{KeywordsCollectFn, SpecifiedValueInfo}; use style_traits::arc_slice::ArcSlice; /// The specified value of a CSS `` @@ -407,6 +408,94 @@ impl ToCss for AnchorName { } } +/// https://drafts.csswg.org/css-anchor-position-1/#propdef-scope +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + ToComputedValue, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum AnchorScope { + /// `none` + None, + /// `all` + All, + /// `#` + Idents(#[ignore_malloc_size_of = "Arc"] crate::ArcSlice), +} + +impl AnchorScope { + /// Return the `none` value. + pub fn none() -> Self { + Self::None + } + + /// Returns whether this is the `none` value. + pub fn is_none(&self) -> bool { + *self == Self::None + } +} + +impl Parse for AnchorScope { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + ) -> Result> { + let location = input.current_source_location(); + let first = input.expect_ident()?; + if first.eq_ignore_ascii_case("none") { + return Ok(Self::None); + } + if first.eq_ignore_ascii_case("all") { + return Ok(Self::All); + } + // Authors using more than a handful of anchored elements is likely + // uncommon, so we only pre-allocate for 8 on the stack here. + let mut idents: SmallVec<[DashedIdent; 8]> = smallvec![DashedIdent::from_ident( + location, + first, + )?]; + while input.try_parse(|input| input.expect_comma()).is_ok() { + idents.push(DashedIdent::parse(context, input)?); + } + Ok(AnchorScope::Idents(ArcSlice::from_iter(idents.drain(..)))) + } +} + +impl ToCss for AnchorScope { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + match *self { + Self::None => dest.write_str("none")?, + Self::All => dest.write_str("all")?, + Self::Idents(ref idents) => { + if let Some((ref first, rest)) = idents.split_first() { + first.to_css(dest)?; + for name in rest { + dest.write_str(", ")?; + name.to_css(dest)?; + } + } + }, + } + Ok(()) + } +} + +impl SpecifiedValueInfo for AnchorScope { + fn collect_completion_keywords(f: KeywordsCollectFn) { + // It would be nice if we could also list all the author defined dashed + // idents in the doc, but that's not practical. + f(&["none", "all"]) + } +} + /// Represents a side, either horizontal or vertical, of a CSS position. pub trait Side { /// Returns the start side. diff --git a/servo/ports/geckolib/cbindgen.toml b/servo/ports/geckolib/cbindgen.toml index c7cb91ddebc2..d07926ea4813 100644 --- a/servo/ports/geckolib/cbindgen.toml +++ b/servo/ports/geckolib/cbindgen.toml @@ -83,6 +83,7 @@ exclude = [ ] include = [ "AnchorName", + "AnchorScope", "AnimationTimeline", "AnimationIterationCount", "AnimationDirection",