tor-browser

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

commit 50e9eff04372c3cb6504b9e876bed2721fdeed0e
parent 59187fbc73b5de73905cf534cc3cfb0e9ecbc1d0
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date:   Thu,  2 Oct 2025 08:34:18 +0000

Bug 1991989 - Implement @position-try style resolution. r=firefox-style-system-reviewers,layout-anchor-positioning-reviewers,layout-reviewers,dshin

Unfortunately, only a couple tests start passing, because I'm only
applying the fallback style to position-area so far, and most tests use
width/height plus the inset properties.

However, the styles are correct, and those should be fixable in
follow-ups. This seems worth landing on its own.

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

Diffstat:
Mlayout/generic/AbsoluteContainingBlock.cpp | 18+++++++++++++++---
Mlayout/style/ServoStyleSet.cpp | 8++++++++
Mlayout/style/ServoStyleSet.h | 4++++
Mservo/components/servo_arc/lib.rs | 2+-
Mservo/components/style/gecko_bindings/sugar/ownership.rs | 9+++++++++
Mservo/components/style/style_resolver.rs | 2+-
Mservo/components/style/stylist.rs | 49++++++++++++++++++++++++++++++++++++++++++++++++-
Mservo/ports/geckolib/glue.rs | 24++++++++++++++++++++++++
Dtesting/web-platform/meta/css/css-anchor-position/anchor-center-fallback-transition-behavior.html.ini | 3---
Mtesting/web-platform/meta/css/css-anchor-position/last-successful-change-try-rule.html.ini | 4++--
Mtesting/web-platform/meta/css/css-anchor-position/position-try-order-position-area.html.ini | 44++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 156 insertions(+), 11 deletions(-)

diff --git a/layout/generic/AbsoluteContainingBlock.cpp b/layout/generic/AbsoluteContainingBlock.cpp @@ -26,6 +26,7 @@ #include "nsIFrameInlines.h" #include "nsPlaceholderFrame.h" #include "nsPresContext.h" +#include "nsPresContextInlines.h" #ifdef DEBUG # include "nsBlockFrame.h" @@ -894,6 +895,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( } do { const StylePositionTryFallbacksItem* currentFallback = nullptr; + RefPtr<ComputedStyle> currentFallbackStyle; if (currentFallbackIndex) { currentFallback = &fallbacks[*currentFallbackIndex]; } @@ -907,11 +909,21 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( auto positionArea = stylePos->mPositionArea; const StylePositionTryFallbacksTryTactic* tactic = nullptr; if (currentFallback) { - if (currentFallback->IsPositionArea()) { - positionArea = currentFallback->AsPositionArea(); - } else if (currentFallback->IsIdentAndOrTactic()) { + if (currentFallback->IsIdentAndOrTactic()) { const auto& item = currentFallback->AsIdentAndOrTactic(); + if (!item.ident.AsAtom()->IsEmpty()) { + currentFallbackStyle = aPresContext->StyleSet()->ResolvePositionTry( + *aKidFrame->GetContent()->AsElement(), *aKidFrame->Style(), + item.ident.AsAtom()); + if (currentFallbackStyle) { + positionArea = + currentFallbackStyle->StylePosition()->mPositionArea; + } + } tactic = &item.try_tactic; + } else { + MOZ_ASSERT(currentFallback->IsPositionArea()); + positionArea = currentFallback->AsPositionArea(); } } diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp @@ -608,6 +608,14 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStartingStyle( .Consume(); } +already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePositionTry( + dom::Element& aElement, ComputedStyle& aStyle, nsAtom* aName) { + MOZ_ASSERT(aName); + return Servo_ComputedValues_GetForPositionTry(mRawData.get(), &aStyle, + &aElement, aName) + .Consume(); +} + // manage the set of style sheets in the style set void ServoStyleSet::AppendStyleSheet(StyleSheet& aSheet) { MOZ_ASSERT(aSheet.IsApplicable()); diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h @@ -262,6 +262,10 @@ class ServoStyleSet { // function after checking if it may have rules inside @starting-style. already_AddRefed<ComputedStyle> ResolveStartingStyle(dom::Element& aElement); + already_AddRefed<ComputedStyle> ResolvePositionTry(dom::Element& aElement, + ComputedStyle& aStyle, + nsAtom* aName); + size_t SheetCount(Origin) const; StyleSheet* SheetAt(Origin, size_t aIndex) const; diff --git a/servo/components/servo_arc/lib.rs b/servo/components/servo_arc/lib.rs @@ -1064,7 +1064,7 @@ impl<A, B> ArcUnion<A, B> { /// Returns an enum representing a borrow of either A or B. #[inline] - pub fn borrow(&self) -> ArcUnionBorrow<A, B> { + pub fn borrow(&self) -> ArcUnionBorrow<'_, A, B> { if self.is_first() { let ptr = self.p.as_ptr() as *const ArcInner<A>; let borrow = unsafe { ArcBorrow::from_ref(&(*ptr).data) }; diff --git a/servo/components/style/gecko_bindings/sugar/ownership.rs b/servo/components/style/gecko_bindings/sugar/ownership.rs @@ -30,6 +30,15 @@ impl<T> From<Arc<T>> for Strong<T> { } } +impl<T> From<Option<Arc<T>>> for Strong<T> { + fn from(arc: Option<Arc<T>>) -> Self { + match arc { + Some(arc) => arc.into(), + None => Self::null(), + } + } +} + impl<GeckoType> Strong<GeckoType> { #[inline] /// Returns whether this reference is null. diff --git a/servo/components/style/style_resolver.rs b/servo/components/style/style_resolver.rs @@ -119,7 +119,7 @@ impl From<ResolvedElementStyles> for ElementStyles { } } -fn with_default_parent_styles<E, F, R>(element: E, f: F) -> R +pub(crate) fn with_default_parent_styles<E, F, R>(element: E, f: F) -> R where E: TElement, F: FnOnce(Option<&ComputedValues>, Option<&ComputedValues>) -> R, diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs @@ -1209,6 +1209,53 @@ impl Stylist { ) } + /// Computes a fallback style lazily given the current and parent styles, and name. + pub fn resolve_position_try<E>( + &self, + style: &ComputedValues, + guards: &StylesheetGuards, + element: E, + name: &Atom, + ) -> Option<Arc<ComputedValues>> + where + E: TElement, + { + let fallback_rule = self.lookup_position_try(name, element)?; + let fallback_block = &fallback_rule.read_with(guards.author).block; + let pseudo = style + .pseudo() + .or_else(|| element.implemented_pseudo_element()); + let inputs = { + let mut inputs = CascadeInputs::new_from_style(style); + // @position-try doesn't care about any :visited-dependent property. + inputs.visited_rules = None; + let rules = inputs.rules.as_ref().unwrap_or(self.rule_tree.root()); + let mut important_rules_changed = false; + inputs.rules = self.rule_tree.update_rule_at_level( + CascadeLevel::PositionFallback, + LayerOrder::root(), + Some(fallback_block.borrow_arc()), + rules, + guards, + &mut important_rules_changed, + ); + inputs + }; + crate::style_resolver::with_default_parent_styles(element, |parent_style, layout_parent_style| { + Some(self.cascade_style_and_visited( + Some(element), + pseudo.as_ref(), + inputs, + guards, + parent_style, + layout_parent_style, + FirstLineReparenting::No, + /* rule_cache = */ None, + &mut RuleCacheConditions::default(), + )) + }) + } + /// Computes a style using the given CascadeInputs. This can be used to /// compute a style any time we know what rules apply and just need to use /// the given parent styles. @@ -1564,7 +1611,7 @@ impl Stylist { /// Returns the registered `@position-try-rule` animation for the specified name. #[inline] - pub fn lookup_position_try<'a, E>( + fn lookup_position_try<'a, E>( &'a self, name: &Atom, element: E, diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs @@ -4383,6 +4383,30 @@ pub unsafe extern "C" fn Servo_ComputedValues_GetForPageContent( } #[no_mangle] +pub unsafe extern "C" fn Servo_ComputedValues_GetForPositionTry( + raw_data: &PerDocumentStyleData, + style: &ComputedValues, + element: &RawGeckoElement, + name: *const nsAtom, +) -> Strong<ComputedValues> { + debug_assert!(!name.is_null()); + let global_style_data = &*GLOBAL_STYLE_DATA; + let guard = global_style_data.shared_lock.read(); + let guards = StylesheetGuards::same(&guard); + let element = GeckoElement(element); + let data = raw_data.borrow(); + Atom::with(name, |name| { + data.stylist.resolve_position_try( + style, + &guards, + element, + name, + ) + }) + .into() +} + +#[no_mangle] pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox( parent_style_or_null: Option<&ComputedValues>, pseudo: PseudoStyleType, diff --git a/testing/web-platform/meta/css/css-anchor-position/anchor-center-fallback-transition-behavior.html.ini b/testing/web-platform/meta/css/css-anchor-position/anchor-center-fallback-transition-behavior.html.ini @@ -1,3 +0,0 @@ -[anchor-center-fallback-transition-behavior.html] - [anchor-center aligned bottom anchored element overflowing IMCB] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-anchor-position/last-successful-change-try-rule.html.ini b/testing/web-platform/meta/css/css-anchor-position/last-successful-change-try-rule.html.ini @@ -1,6 +1,6 @@ [last-successful-change-try-rule.html] - [Starts rendering with --try] + [No successful position, keep --try] expected: FAIL - [No successful position, keep --try] + [No successful position, last successful invalidated by @position-try change] expected: FAIL diff --git a/testing/web-platform/meta/css/css-anchor-position/position-try-order-position-area.html.ini b/testing/web-platform/meta/css/css-anchor-position/position-try-order-position-area.html.ini @@ -1,3 +1,47 @@ [position-try-order-position-area.html] expected: if (processor == "x86") and (os == "linux"): [OK, CRASH] + [--right, --left, --bottom, --top | --right] + expected: FAIL + + [normal --right, --left, --bottom, --top | --right] + expected: FAIL + + [normal --top, --left, --bottom, --right | --top] + expected: FAIL + + [most-block-size --right, --left | --right] + expected: FAIL + + [most-height --right, --left | --right] + expected: FAIL + + [most-inline-size --bottom, --top | --bottom] + expected: FAIL + + [most-width --bottom, --top | --bottom] + expected: FAIL + + [most-inline-size --right, --left, --bottom, --top | --bottom] + expected: FAIL + + [most-inline-size --right, --left, --top, --bottom | --top] + expected: FAIL + + [most-block-size --bottom, --top, --right, --left | --right] + expected: FAIL + + [most-block-size --bottom, --top, --left, --right | --left] + expected: FAIL + + [most-inline-size --left-sweep, --bottom-sweep | --left-sweep] + expected: FAIL + + [most-inline-size --bottom-sweep, --left-sweep | --bottom-sweep] + expected: FAIL + + [most-block-size --left-sweep, --bottom-sweep | --left-sweep] + expected: FAIL + + [most-inline-size --right-sweep, --left-sweep, --bottom-sweep, --top-sweep | --left-sweep] + expected: FAIL