tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4994fbf4b4d95946f81667c6218eaf3e91c90893
parent c4e294aaf9be3773f7b435174b035cc0715c8325
Author: Jonathan Kew <jkew@mozilla.com>
Date:   Thu, 23 Oct 2025 10:40:24 +0000

Bug 1995253 - patch 1 - Add flip-x and flip-y keywords to position-try-fallbacks. r=layout-reviewers,firefox-style-system-reviewers,emilio

(Testcases added to WPT in following patch.)

Differential Revision: https://phabricator.services.mozilla.com/D269493

Diffstat:
Mlayout/base/AnchorPositioningUtils.cpp | 6++++++
Mlayout/style/test/property_database.js | 12++++++++++++
Mservo/components/style/style_adjuster.rs | 24+++++++++++++++++-------
Mservo/components/style/values/specified/position.rs | 41++++++++++++++++++++++++++++++-----------
4 files changed, 65 insertions(+), 18 deletions(-)

diff --git a/layout/base/AnchorPositioningUtils.cpp b/layout/base/AnchorPositioningUtils.cpp @@ -651,6 +651,12 @@ static void ApplyFallbackTactic( case StylePositionTryFallbacksTryTacticKeyword::FlipStart: FlipStartsAndEnds(aPhysicalArea, aWM); return; + case StylePositionTryFallbacksTryTacticKeyword::FlipX: + FlipInAxis(aPhysicalArea, PhysicalAxis::Horizontal); + return; + case StylePositionTryFallbacksTryTacticKeyword::FlipY: + FlipInAxis(aPhysicalArea, PhysicalAxis::Vertical); + return; } } diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js @@ -13430,6 +13430,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "--foo", "flip-block", "flip-inline", + "flip-x", + "flip-y", "flip-start", "left", "span-y-start", @@ -13479,6 +13481,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "--foo", "flip-block", "flip-inline", + "flip-x", + "flip-y", "flip-start", "left", "span-y-start", @@ -13489,6 +13493,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "most-width --foo", "most-width flip-block", "most-width flip-inline", + "most-width flip-x", + "most-width flip-y", "most-width flip-start", "most-width left", "most-width span-y-start", @@ -13499,6 +13505,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "most-height --foo", "most-height flip-block", "most-height flip-inline", + "most-height flip-x", + "most-height flip-y", "most-height flip-start", "most-height left", "most-height span-y-start", @@ -13509,6 +13517,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "most-block-size --foo", "most-block-size flip-block", "most-block-size flip-inline", + "most-block-size flip-x", + "most-block-size flip-y", "most-block-size flip-start", "most-block-size left", "most-block-size span-y-start", @@ -13519,6 +13529,8 @@ if (IsCSSPropertyPrefEnabled("layout.css.anchor-positioning.enabled")) { "most-inline-size --foo", "most-inline-size flip-block", "most-inline-size flip-inline", + "most-inline-size flip-x", + "most-inline-size flip-y", "most-inline-size flip-start", "most-inline-size left", "most-inline-size span-y-start", diff --git a/servo/components/style/style_adjuster.rs b/servo/components/style/style_adjuster.rs @@ -935,20 +935,30 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { /// overkill for now. fn adjust_for_try_tactic(&mut self, tactic: PositionTryFallbacksTryTactic) { debug_assert!(!tactic.is_empty()); - let horizontal = self.style.writing_mode.is_horizontal(); + // TODO: This is supposed to use the containing block's WM (bug 1995256). + let wm = self.style.writing_mode; // TODO: Flip inset / margin / sizes percentages and anchor lookup sides as necessary. for tactic in tactic.into_iter() { + use PositionTryFallbacksTryTacticKeyword::*; match tactic { - PositionTryFallbacksTryTacticKeyword::None => break, - PositionTryFallbacksTryTacticKeyword::FlipBlock => { + None => break, + FlipBlock => { self.flip_self_alignment(/* block = */ true); - self.flip_insets_and_margins(!horizontal); + self.flip_insets_and_margins(/* horizontal = */ wm.is_vertical()); }, - PositionTryFallbacksTryTacticKeyword::FlipInline => { + FlipInline => { self.flip_self_alignment(/* block = */ false); - self.flip_insets_and_margins(horizontal); + self.flip_insets_and_margins(/* horizontal = */ wm.is_horizontal()); + }, + FlipX => { + self.flip_self_alignment(/* block = */ wm.is_vertical()); + self.flip_insets_and_margins(/* horizontal = */ true); + }, + FlipY => { + self.flip_self_alignment(/* block = */ wm.is_horizontal()); + self.flip_insets_and_margins(/* horizontal = */ false); }, - PositionTryFallbacksTryTacticKeyword::FlipStart => { + FlipStart => { self.flip_start(); }, } diff --git a/servo/components/style/values/specified/position.rs b/servo/components/style/values/specified/position.rs @@ -524,6 +524,10 @@ pub enum PositionTryFallbacksTryTacticKeyword { FlipInline, /// Swap the values in the start properties. FlipStart, + /// Swap the values in the X axis. + FlipX, + /// Swap the values in the Y axis. + FlipY, } impl PositionTryFallbacksTryTacticKeyword { @@ -556,6 +560,8 @@ pub struct PositionTryFallbacksTryTactic( pub PositionTryFallbacksTryTacticKeyword, pub PositionTryFallbacksTryTacticKeyword, pub PositionTryFallbacksTryTacticKeyword, + pub PositionTryFallbacksTryTacticKeyword, + pub PositionTryFallbacksTryTacticKeyword, ); impl Parse for PositionTryFallbacksTryTactic { @@ -563,17 +569,30 @@ impl Parse for PositionTryFallbacksTryTactic { _context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - let first = PositionTryFallbacksTryTacticKeyword::parse(input)?; - let second = input - .try_parse(PositionTryFallbacksTryTacticKeyword::parse) - .unwrap_or_default(); - let third = input - .try_parse(PositionTryFallbacksTryTacticKeyword::parse) - .unwrap_or_default(); - if first == second || first == third || (!second.is_none() && second == third) { - return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + let kw = [ + PositionTryFallbacksTryTacticKeyword::parse(input)?, + input + .try_parse(PositionTryFallbacksTryTacticKeyword::parse) + .unwrap_or_default(), + input + .try_parse(PositionTryFallbacksTryTacticKeyword::parse) + .unwrap_or_default(), + input + .try_parse(PositionTryFallbacksTryTacticKeyword::parse) + .unwrap_or_default(), + input + .try_parse(PositionTryFallbacksTryTacticKeyword::parse) + .unwrap_or_default(), + ]; + for i in 0..kw.len() - 1 { + if kw[i].is_none() { + break; + } + if kw[i + 1..].contains(&kw[i]) { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } } - Ok(Self(first, second, third)) + Ok(Self(kw[0], kw[1], kw[2], kw[3], kw[4])) } } @@ -587,7 +606,7 @@ impl PositionTryFallbacksTryTactic { /// Iterates over the fallbacks in order. #[inline] pub fn into_iter(&self) -> impl IntoIterator<Item = PositionTryFallbacksTryTacticKeyword> { - [self.0, self.1, self.2] + [self.0, self.1, self.2, self.3, self.4] } }