From f697f067901dc4292261394c509f65c168198352 Mon Sep 17 00:00:00 2001 From: Emily McDonough Date: Wed, 2 Nov 2022 22:30:19 +0000 Subject: [PATCH] Bug 1798581 - Add optional page name argument to Servo_ComputedValues_GetForAnonymousBox and ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle r=emilio This needs to bypass the cache on ServoStyleSet when looking up styles with named pages. We could possibly cache the last used named page style, which would avoid extra style calculations for multiple sequential pages with the same page name, but for now the cache is just ignored. Differential Revision: https://phabricator.services.mozilla.com/D160976 --- layout/style/ServoStyleSet.cpp | 34 ++++++++++++++++++++++++++-------- layout/style/ServoStyleSet.h | 13 ++++++++++++- servo/ports/geckolib/glue.rs | 22 +++++++++++++++++----- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index 0ee424eea4b9..b4f4f6e22f68 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -515,7 +515,7 @@ ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType, if (!style) { style = Servo_ComputedValues_GetForAnonymousBox(aParentStyle, aType, - mRawSet.get()) + mRawSet.get(), nullptr) .Consume(); MOZ_ASSERT(style); if (aParentStyle) { @@ -527,14 +527,29 @@ ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType, } already_AddRefed -ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) { +ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType, + const nsAtom* aPageName) { MOZ_ASSERT(PseudoStyle::IsNonInheritingAnonBox(aType)); + MOZ_ASSERT(!aPageName || aType == PseudoStyleType::pageContent, + "page name should only be specified for pageContent"); nsCSSAnonBoxes::NonInheriting type = nsCSSAnonBoxes::NonInheritingTypeForPseudoType(aType); - RefPtr& cache = mNonInheritingComputedStyles[type]; - if (cache) { - RefPtr retval = cache; - return retval.forget(); + + // The empty atom is used to indicate no specified page name, and is not + // usable as a page-rule selector. Changing this to null is a slight + // optimization to avoid the Servo code from doing an unnecessary hashtable + // lookup, and still use the style cache in this case. + if (aPageName == nsGkAtoms::_empty) { + aPageName = nullptr; + } + // Only use the cache if we are not doing a lookup for a named page style. + RefPtr* cache = nullptr; + if (!aPageName) { + cache = &mNonInheritingComputedStyles[type]; + if (*cache) { + RefPtr retval = *cache; + return retval.forget(); + } } UpdateStylistIfNeeded(); @@ -547,11 +562,14 @@ ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) { "viewport needs fixup to handle blockifying it"); RefPtr computedValues = - Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawSet.get()) + Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawSet.get(), + aPageName) .Consume(); MOZ_ASSERT(computedValues); - cache = computedValues; + if (cache) { + *cache = computedValues; + } return computedValues.forget(); } diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index fc2d44e59f38..07d729e5a07a 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -236,7 +236,15 @@ class ServoStyleSet { // Get a ComputedStyle for an anonymous box. The pseudo type must be // a non-inheriting anon box. already_AddRefed ResolveNonInheritingAnonymousBoxStyle( - PseudoStyleType); + PseudoStyleType aType) { + return ResolveNonInheritingAnonymousBoxStyle(aType, nullptr); + } + + already_AddRefed ResolvePageContentStyle( + const nsAtom* aPageName) { + return ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType::pageContent, + aPageName); + } already_AddRefed ResolveXULTreePseudoStyle( dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag, @@ -587,6 +595,9 @@ class ServoStyleSet { nsCSSAnonBoxes::NonInheriting::_Count, RefPtr> mNonInheritingComputedStyles; + already_AddRefed ResolveNonInheritingAnonymousBoxStyle( + PseudoStyleType aType, const nsAtom* aPageName); + public: void PutCachedAnonymousContentStyles( AnonymousContentKey aKey, nsTArray>&& aStyles) { diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index fc4009f22492..67d10b6ec2c5 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -3902,6 +3902,7 @@ pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox( parent_style_or_null: Option<&ComputedValues>, pseudo: PseudoStyleType, raw_data: &RawServoStyleSet, + page_name: *const nsAtom, ) -> Strong { let global_style_data = &*GLOBAL_STYLE_DATA; let guard = global_style_data.shared_lock.read(); @@ -3912,9 +3913,6 @@ pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox( // If the pseudo element is PageContent, we should append @page rules to the // precomputed pseudo. - // - // TODO(emilio): We'll need a separate code path or extra arguments for - // named pages, etc. let mut extra_declarations = vec![]; if pseudo == PseudoElement::PageContent { let iter = data.stylist.iter_extra_data_origins_rev(); @@ -3924,14 +3922,28 @@ pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox( Origin::User => CascadeLevel::UserNormal, Origin::Author => CascadeLevel::same_tree_author_normal(), }; - for &(ref rule, _layer_id) in data.pages.global.iter() { + extra_declarations.reserve(data.pages.global.len()); + let mut add_rule = |rule: &Arc>| { extra_declarations.push(ApplicableDeclarationBlock::from_declarations( - rule.0.read_with(level.guard(&guards)).block.clone(), + rule.read_with(level.guard(&guards)).block.clone(), level, LayerOrder::root(), )); + }; + for &(ref rule, _layer_id) in data.pages.global.iter() { + add_rule(&rule.0); + } + if !page_name.is_null() { + Atom::with(page_name, |name| { + if let Some(rules) = data.pages.named.get(name) { + // Rules are already sorted by source order. + rules.iter().for_each(|d| add_rule(&d.rule)); + } + }); } } + } else { + debug_assert!(page_name_or_null.is_null()); } let rule_node =