forked from mirrors/gecko-dev
		
	Bug 1897405 p1. Implement parsing of CSS 'anchor-name'. r=emilio,devtools-reviewers,firefox-style-system-reviewers,nchevobbe
Differential Revision: https://phabricator.services.mozilla.com/D210787
This commit is contained in:
		
							parent
							
								
									12a4e6fb6e
								
							
						
					
					
						commit
						aac256321a
					
				
					 14 changed files with 177 additions and 11 deletions
				
			
		|  | @ -9,6 +9,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [ | |||
|   [ | ||||
|     "discrete", | ||||
|     new Set([ | ||||
|       "anchor-name", | ||||
|       "align-content", | ||||
|       "align-items", | ||||
|       "align-self", | ||||
|  |  | |||
|  | @ -107,7 +107,7 @@ use.counter: | |||
|     send_in_pings: | ||||
|       - use-counters | ||||
| 
 | ||||
| # Total of 2301 use counter metrics (excludes denominators). | ||||
| # Total of 2303 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 697 'CSS (page)' use counters. | ||||
| # Total of 698 'CSS (page)' use counters. | ||||
| use.counter.css.page: | ||||
|   css_align_content: | ||||
|     type: counter | ||||
|  | @ -18586,6 +18586,23 @@ use.counter.css.page: | |||
|     send_in_pings: | ||||
|       - use-counters | ||||
| 
 | ||||
|   css_anchor_name: | ||||
|     type: counter | ||||
|     description: > | ||||
|       Whether a page used the CSS property anchor-name. | ||||
|       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: > | ||||
|  | @ -27392,7 +27409,7 @@ use.counter.css.page: | |||
|     send_in_pings: | ||||
|       - use-counters | ||||
| 
 | ||||
| # Total of 697 'CSS (document)' use counters. | ||||
| # Total of 698 'CSS (document)' use counters. | ||||
| use.counter.css.doc: | ||||
|   css_align_content: | ||||
|     type: counter | ||||
|  | @ -30437,6 +30454,23 @@ use.counter.css.doc: | |||
|     send_in_pings: | ||||
|       - use-counters | ||||
| 
 | ||||
|   css_anchor_name: | ||||
|     type: counter | ||||
|     description: > | ||||
|       Whether a document used the CSS property anchor-name. | ||||
|       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: > | ||||
|  |  | |||
|  | @ -620,6 +620,7 @@ cbindgen-types = [ | |||
|     { gecko = "StyleLockedFontFaceRule", servo = "crate::gecko::arc_types::LockedFontFaceRule" }, | ||||
|     { gecko = "StyleBaselineSource", servo = "crate::values::computed::BaselineSource" }, | ||||
|     { gecko = "StyleAu", servo = "app_units::Au" }, | ||||
|     { gecko = "StyleAnchorName", servo = "crate::values::computed::position::AnchorName" }, | ||||
| ] | ||||
| 
 | ||||
| mapped-generic-types = [ | ||||
|  |  | |||
|  | @ -2151,7 +2151,8 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource) | |||
|       mWebkitLineClamp(aSource.mWebkitLineClamp), | ||||
|       mShapeImageThreshold(aSource.mShapeImageThreshold), | ||||
|       mShapeMargin(aSource.mShapeMargin), | ||||
|       mShapeOutside(aSource.mShapeOutside) { | ||||
|       mShapeOutside(aSource.mShapeOutside), | ||||
|       mAnchorName(aSource.mAnchorName) { | ||||
|   MOZ_COUNT_CTOR(nsStyleDisplay); | ||||
| } | ||||
| 
 | ||||
|  | @ -2522,7 +2523,8 @@ nsChangeHint nsStyleDisplay::CalcDifference( | |||
|                 mContentVisibility != aNewData.mContentVisibility || | ||||
|                 mContainerType != aNewData.mContainerType || | ||||
|                 mContain != aNewData.mContain || | ||||
|                 mContainerName != aNewData.mContainerName)) { | ||||
|                 mContainerName != aNewData.mContainerName || | ||||
|                 mAnchorName != aNewData.mAnchorName)) { | ||||
|     hint |= nsChangeHint_NeutralChange; | ||||
|   } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1316,6 +1316,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay { | |||
| 
 | ||||
|   mozilla::StyleShapeOutside mShapeOutside; | ||||
| 
 | ||||
|   // 'none', 'all', or a list of one or more `<dashed-ident>` identifiers that
 | ||||
|   // anchor positioned elements may reference.
 | ||||
|   mozilla::StyleAnchorName mAnchorName; | ||||
| 
 | ||||
|   mozilla::Maybe<mozilla::WindowButtonType> GetWindowButtonType() const { | ||||
|     if (MOZ_LIKELY(mDefaultAppearance == mozilla::StyleAppearance::None)) { | ||||
|       return mozilla::Nothing(); | ||||
|  |  | |||
|  | @ -13295,6 +13295,25 @@ if (IsCSSPropertyPrefEnabled("layout.css.contain-intrinsic-size.enabled")) { | |||
|   }; | ||||
| } | ||||
| 
 | ||||
| if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { | ||||
|   gCSSProperties["anchor-name"] = { | ||||
|     domProp: "anchorName", | ||||
|     inherited: false, | ||||
|     type: CSS_TYPE_LONGHAND, | ||||
|     initial_values: ["none"], | ||||
|     other_values: ["--foo", "--foo, --baz", "--foo,--baz", "--foo ,--baz"], | ||||
|     invalid_values: [ | ||||
|       "--foo --bar", | ||||
|       "foo", | ||||
|       "none bar", | ||||
|       "none --baz", | ||||
|       "--foo bar", | ||||
|       ",--foo", | ||||
|       "--foo,", | ||||
|     ], | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| if (false) { | ||||
|   // TODO These properties are chrome-only, and are not exposed via CSSOM.
 | ||||
|   // We may still want to find a way to test them. See bug 1206999.
 | ||||
|  |  | |||
|  | @ -8436,6 +8436,14 @@ | |||
|   value: false | ||||
|   mirror: always | ||||
| 
 | ||||
| # Whether to enable CSS Anchor Positioning support. | ||||
| # https://drafts.csswg.org/css-anchor-position-1/ | ||||
| - name: layout.css.anchor-positioning.enabled | ||||
|   type: RelaxedAtomicBool | ||||
|   value: false | ||||
|   mirror: always | ||||
|   rust: true | ||||
| 
 | ||||
| # Override DPI. A value of -1 means use the maximum of 96 and the system DPI. | ||||
| # A value of 0 means use the system DPI. A positive value is used as the DPI. | ||||
| # This sets the physical size of a device pixel and thus controls the | ||||
|  |  | |||
|  | @ -61,6 +61,19 @@ impl computed_value::T { | |||
| } | ||||
| </%helpers:single_keyword> | ||||
| 
 | ||||
| // Changes do not invalidate our element. We handle notify/invalidating
 | ||||
| // elements that reference anchor-name elsewhere.
 | ||||
| ${helpers.predefined_type( | ||||
|     "anchor-name", | ||||
|     "AnchorName", | ||||
|     "computed::AnchorName::none()", | ||||
|     engines="gecko", | ||||
|     animation_value_type="discrete", | ||||
|     gecko_pref="layout.css.anchor-positioning.enabled", | ||||
|     spec="https://drafts.csswg.org/css-anchor-position-1/#propdef-anchor-name", | ||||
|     affects="", | ||||
| )} | ||||
| 
 | ||||
| ${helpers.predefined_type( | ||||
|     "float", | ||||
|     "Float", | ||||
|  |  | |||
|  | @ -88,6 +88,7 @@ pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate}; | |||
| 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::AspectRatio; | ||||
| pub use self::position::{ | ||||
|     GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex, | ||||
|  |  | |||
|  | @ -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::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow}; | ||||
| pub use crate::values::specified::position::{AnchorName, GridAutoFlow, GridTemplateAreas, MasonryAutoFlow}; | ||||
| use crate::Zero; | ||||
| use std::fmt::{self, Write}; | ||||
| use style_traits::{CssWriter, ToCss}; | ||||
|  |  | |||
|  | @ -592,6 +592,21 @@ impl ToCss for CustomIdent { | |||
| )] | ||||
| pub struct DashedIdent(pub Atom); | ||||
| 
 | ||||
| impl DashedIdent { | ||||
|     /// Parse an already-tokenizer identifier
 | ||||
|     pub fn from_ident<'i>( | ||||
|         location: SourceLocation, | ||||
|         ident: &CowRcStr<'i>, | ||||
|     ) -> Result<Self, ParseError<'i>> { | ||||
|         if !ident.starts_with("--") { | ||||
|             return Err( | ||||
|                 location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) | ||||
|             ); | ||||
|         } | ||||
|         Ok(Self(Atom::from(ident.as_ref()))) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Parse for DashedIdent { | ||||
|     fn parse<'i, 't>( | ||||
|         _: &ParserContext, | ||||
|  | @ -599,11 +614,7 @@ impl Parse for DashedIdent { | |||
|     ) -> Result<Self, ParseError<'i>> { | ||||
|         let location = input.current_source_location(); | ||||
|         let ident = input.expect_ident()?; | ||||
|         if ident.starts_with("--") { | ||||
|             Ok(Self(Atom::from(ident.as_ref()))) | ||||
|         } else { | ||||
|             Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))) | ||||
|         } | ||||
|         Self::from_ident(location, ident) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -81,6 +81,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::AspectRatio; | ||||
| pub use self::position::AnchorName; | ||||
| pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, PositionOrAuto}; | ||||
| pub use self::position::{MasonryAutoFlow, MasonryItemOrder, MasonryPlacement}; | ||||
| pub use self::position::{PositionComponent, ZIndex}; | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| use crate::parser::{Parse, ParserContext}; | ||||
| use crate::selector_map::PrecomputedHashMap; | ||||
| use crate::str::HTML_SPACE_CHARACTERS; | ||||
| use crate::values::DashedIdent; | ||||
| use crate::values::computed::LengthPercentage as ComputedLengthPercentage; | ||||
| use crate::values::computed::{Context, Percentage, ToComputedValue}; | ||||
| use crate::values::generics::position::AspectRatio as GenericAspectRatio; | ||||
|  | @ -22,10 +23,12 @@ use crate::{Atom, Zero}; | |||
| use cssparser::Parser; | ||||
| use selectors::parser::SelectorParseErrorKind; | ||||
| use servo_arc::Arc; | ||||
| use smallvec::{smallvec, SmallVec}; | ||||
| 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::arc_slice::ArcSlice; | ||||
| 
 | ||||
| /// The specified value of a CSS `<position>`
 | ||||
| pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>; | ||||
|  | @ -337,6 +340,73 @@ impl<S: Side> PositionComponent<S> { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /// https://drafts.csswg.org/css-anchor-position-1/#propdef-anchor-name
 | ||||
| #[repr(transparent)] | ||||
| #[derive(
 | ||||
|     Clone, | ||||
|     Debug, | ||||
|     MallocSizeOf, | ||||
|     PartialEq, | ||||
|     SpecifiedValueInfo, | ||||
|     ToComputedValue, | ||||
|     ToResolvedValue, | ||||
|     ToShmem, | ||||
| )] | ||||
| pub struct AnchorName(#[css(iterable, if_empty = "none")] #[ignore_malloc_size_of = "Arc"] pub crate::ArcSlice<DashedIdent>); | ||||
| 
 | ||||
| impl AnchorName { | ||||
|     /// 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 AnchorName { | ||||
|     fn parse<'i, 't>( | ||||
|         context: &ParserContext, | ||||
|         input: &mut Parser<'i, 't>, | ||||
|     ) -> Result<Self, ParseError<'i>> { | ||||
|         let location = input.current_source_location(); | ||||
|         let first = input.expect_ident()?; | ||||
|         if first.eq_ignore_ascii_case("none") { | ||||
|             return Ok(Self::none()); | ||||
|         } | ||||
|         // The common case is probably just to have a single anchor name, so
 | ||||
|         // space for four on the stack should be plenty.
 | ||||
|         let mut idents: SmallVec<[DashedIdent; 4]> = smallvec![DashedIdent::from_ident( | ||||
|             location, | ||||
|             first, | ||||
|         )?]; | ||||
|         while input.try_parse(|input| input.expect_comma()).is_ok() { | ||||
|             idents.push(DashedIdent::parse(context, input)?); | ||||
|         } | ||||
|         Ok(AnchorName(ArcSlice::from_iter(idents.drain(..)))) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ToCss for AnchorName { | ||||
|     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result | ||||
|     where | ||||
|         W: fmt::Write, | ||||
|     { | ||||
|         let mut iter = self.0.iter(); | ||||
|         match iter.next() { | ||||
|             None => return dest.write_str("none"), | ||||
|             Some(f) => f.to_css(dest)?, | ||||
|         } | ||||
|         for name in iter { | ||||
|             dest.write_str(", ")?; | ||||
|             name.to_css(dest)?; | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Represents a side, either horizontal or vertical, of a CSS position.
 | ||||
| pub trait Side { | ||||
|     /// Returns the start side.
 | ||||
|  |  | |||
|  | @ -82,6 +82,7 @@ exclude = [ | |||
|   "AuthorStyles", | ||||
| ] | ||||
| include = [ | ||||
|   "AnchorName", | ||||
|   "AnimationTimeline", | ||||
|   "AnimationIterationCount", | ||||
|   "AnimationDirection", | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jonathan Watt
						Jonathan Watt