commit 8cdcc8296e7e243555779297728a29376c1f7816
parent ea28b263ac2b83315a92b2af5111ab1edadd3193
Author: David Shin <dshin@mozilla.com>
Date: Mon, 10 Nov 2025 23:39:53 +0000
Bug 1998436: Don't parse anchor functions in flex-basis. r=layout-anchor-positioning-reviewers,firefox-style-system-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D271489
Diffstat:
6 files changed, 89 insertions(+), 7 deletions(-)
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
@@ -10311,6 +10311,9 @@ var gCSSProperties = {
"calc(3em / 100% * 3em)",
"calc(3em * (3em / 100%))",
"calc(3em * 3em / 100%)",
+ "anchor-size()",
+ "anchor-size(--a width)",
+ "anchor-size(--a width, 10px)",
],
},
"flex-direction": {
diff --git a/servo/components/style/values/generics/flex.rs b/servo/components/style/values/generics/flex.rs
@@ -12,7 +12,6 @@
Copy,
Debug,
MallocSizeOf,
- Parse,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
diff --git a/servo/components/style/values/specified/flex.rs b/servo/components/style/values/specified/flex.rs
@@ -4,8 +4,11 @@
//! Specified types for CSS values related to flexbox.
+use crate::parser::{Parse, ParserContext};
use crate::values::generics::flex::FlexBasis as GenericFlexBasis;
use crate::values::specified::Size;
+use cssparser::Parser;
+use style_traits::ParseError;
/// A specified value for the `flex-basis` property.
pub type FlexBasis = GenericFlexBasis<Size>;
@@ -23,3 +26,20 @@ impl FlexBasis {
GenericFlexBasis::Size(Size::zero_percent())
}
}
+
+impl Parse for FlexBasis {
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let v = input.try_parse(|i| {
+ Ok(try_match_ident_ignore_ascii_case! {i, "content" => Self::Content, })
+ });
+ if v.is_ok() {
+ return v;
+ }
+ Ok(Self::Size(Size::parse_size_for_flex_basis_width(
+ context, input,
+ )?))
+ }
+}
diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs
@@ -2103,6 +2103,12 @@ macro_rules! parse_fit_content_function {
};
}
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum ParseAnchorFunctions {
+ Yes,
+ No,
+}
+
impl Size {
/// Parses, with quirks.
pub fn parse_quirky<'i, 't>(
@@ -2111,7 +2117,27 @@ impl Size {
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_all_size_properties();
- Self::parse_quirky_internal(context, input, allow_quirks, allow_webkit_fill_available)
+ Self::parse_quirky_internal(
+ context,
+ input,
+ allow_quirks,
+ allow_webkit_fill_available,
+ ParseAnchorFunctions::Yes,
+ )
+ }
+
+ /// Parses for flex-basis: <width>
+ pub fn parse_size_for_flex_basis_width<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ Self::parse_quirky_internal(
+ context,
+ input,
+ AllowQuirks::No,
+ true,
+ ParseAnchorFunctions::No,
+ )
}
/// Parses, with quirks and configurable support for
@@ -2123,18 +2149,19 @@ impl Size {
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
allow_webkit_fill_available: bool,
+ allow_anchor_functions: ParseAnchorFunctions,
) -> Result<Self, ParseError<'i>> {
parse_size_non_length!(Size, input, allow_webkit_fill_available,
"auto" => Auto);
parse_fit_content_function!(Size, input, context, allow_quirks);
+ let allow_anchor = allow_anchor_functions == ParseAnchorFunctions::Yes
+ && static_prefs::pref!("layout.css.anchor-positioning.enabled");
match input
.try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
{
Ok(length) => return Ok(GenericSize::LengthPercentage(length)),
- Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
- return Err(e.into())
- },
+ Err(e) if !allow_anchor => return Err(e.into()),
Err(_) => (),
};
if let Ok(length) = input.try_parse(|i| {
@@ -2162,7 +2189,13 @@ impl Size {
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_width_and_height();
- Self::parse_quirky_internal(context, input, allow_quirks, allow_webkit_fill_available)
+ Self::parse_quirky_internal(
+ context,
+ input,
+ allow_quirks,
+ allow_webkit_fill_available,
+ ParseAnchorFunctions::Yes,
+ )
}
/// Parse a size for width or height, where -webkit-fill-available
@@ -2175,7 +2208,13 @@ impl Size {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_width_and_height();
- Self::parse_quirky_internal(context, input, AllowQuirks::No, allow_webkit_fill_available)
+ Self::parse_quirky_internal(
+ context,
+ input,
+ AllowQuirks::No,
+ allow_webkit_fill_available,
+ ParseAnchorFunctions::Yes,
+ )
}
/// Returns `0%`.
diff --git a/testing/web-platform/tests/css/css-anchor-position/anchor-size-in-flex-basis-crash.html b/testing/web-platform/tests/css/css-anchor-position/anchor-size-in-flex-basis-crash.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>CSS Anchor Positioning: Crash with anchor functions flex-basis</title>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1998436">
+<style>
+#dut1 {
+ display: flex;
+}
+#dut2 {
+ flex-basis: anchor-size(--a width, 10px);
+}
+#dut3 {
+ flex-basis: auto;
+ width: anchor-size(--a width, 10px);
+}
+</style>
+<div id=dut1>
+ <div id=dut2></div>
+ <div id=dut3></div>
+</div>
diff --git a/testing/web-platform/tests/css/css-flexbox/parsing/flex-basis-invalid.html b/testing/web-platform/tests/css/css-flexbox/parsing/flex-basis-invalid.html
@@ -17,6 +17,8 @@ test_invalid_value("flex-basis", "auto content");
test_invalid_value("flex-basis", "-1px");
test_invalid_value("flex-basis", "-2%");
test_invalid_value("flex-basis", "3px 4%");
+test_invalid_value("flex-basis", "anchor-size(--a width)");
+test_invalid_value("flex-basis", "anchor-size(--a width, 10px)");
</script>
</body>
</html>