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
This commit is contained in:
Emily McDonough 2022-11-02 22:30:19 +00:00
Родитель 624091d13e
Коммит f697f06790
3 изменённых файлов: 55 добавлений и 14 удалений

Просмотреть файл

@ -515,7 +515,7 @@ ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType,
if (!style) { if (!style) {
style = Servo_ComputedValues_GetForAnonymousBox(aParentStyle, aType, style = Servo_ComputedValues_GetForAnonymousBox(aParentStyle, aType,
mRawSet.get()) mRawSet.get(), nullptr)
.Consume(); .Consume();
MOZ_ASSERT(style); MOZ_ASSERT(style);
if (aParentStyle) { if (aParentStyle) {
@ -527,14 +527,29 @@ ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType,
} }
already_AddRefed<ComputedStyle> already_AddRefed<ComputedStyle>
ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) { ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType,
const nsAtom* aPageName) {
MOZ_ASSERT(PseudoStyle::IsNonInheritingAnonBox(aType)); MOZ_ASSERT(PseudoStyle::IsNonInheritingAnonBox(aType));
MOZ_ASSERT(!aPageName || aType == PseudoStyleType::pageContent,
"page name should only be specified for pageContent");
nsCSSAnonBoxes::NonInheriting type = nsCSSAnonBoxes::NonInheriting type =
nsCSSAnonBoxes::NonInheritingTypeForPseudoType(aType); nsCSSAnonBoxes::NonInheritingTypeForPseudoType(aType);
RefPtr<ComputedStyle>& cache = mNonInheritingComputedStyles[type];
if (cache) { // The empty atom is used to indicate no specified page name, and is not
RefPtr<ComputedStyle> retval = cache; // usable as a page-rule selector. Changing this to null is a slight
return retval.forget(); // 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<ComputedStyle>* cache = nullptr;
if (!aPageName) {
cache = &mNonInheritingComputedStyles[type];
if (*cache) {
RefPtr<ComputedStyle> retval = *cache;
return retval.forget();
}
} }
UpdateStylistIfNeeded(); UpdateStylistIfNeeded();
@ -547,11 +562,14 @@ ServoStyleSet::ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType aType) {
"viewport needs fixup to handle blockifying it"); "viewport needs fixup to handle blockifying it");
RefPtr<ComputedStyle> computedValues = RefPtr<ComputedStyle> computedValues =
Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawSet.get()) Servo_ComputedValues_GetForAnonymousBox(nullptr, aType, mRawSet.get(),
aPageName)
.Consume(); .Consume();
MOZ_ASSERT(computedValues); MOZ_ASSERT(computedValues);
cache = computedValues; if (cache) {
*cache = computedValues;
}
return computedValues.forget(); return computedValues.forget();
} }

Просмотреть файл

@ -236,7 +236,15 @@ class ServoStyleSet {
// Get a ComputedStyle for an anonymous box. The pseudo type must be // Get a ComputedStyle for an anonymous box. The pseudo type must be
// a non-inheriting anon box. // a non-inheriting anon box.
already_AddRefed<ComputedStyle> ResolveNonInheritingAnonymousBoxStyle( already_AddRefed<ComputedStyle> ResolveNonInheritingAnonymousBoxStyle(
PseudoStyleType); PseudoStyleType aType) {
return ResolveNonInheritingAnonymousBoxStyle(aType, nullptr);
}
already_AddRefed<ComputedStyle> ResolvePageContentStyle(
const nsAtom* aPageName) {
return ResolveNonInheritingAnonymousBoxStyle(PseudoStyleType::pageContent,
aPageName);
}
already_AddRefed<ComputedStyle> ResolveXULTreePseudoStyle( already_AddRefed<ComputedStyle> ResolveXULTreePseudoStyle(
dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag, dom::Element* aParentElement, nsCSSAnonBoxPseudoStaticAtom* aPseudoTag,
@ -587,6 +595,9 @@ class ServoStyleSet {
nsCSSAnonBoxes::NonInheriting::_Count, RefPtr<ComputedStyle>> nsCSSAnonBoxes::NonInheriting::_Count, RefPtr<ComputedStyle>>
mNonInheritingComputedStyles; mNonInheritingComputedStyles;
already_AddRefed<ComputedStyle> ResolveNonInheritingAnonymousBoxStyle(
PseudoStyleType aType, const nsAtom* aPageName);
public: public:
void PutCachedAnonymousContentStyles( void PutCachedAnonymousContentStyles(
AnonymousContentKey aKey, nsTArray<RefPtr<ComputedStyle>>&& aStyles) { AnonymousContentKey aKey, nsTArray<RefPtr<ComputedStyle>>&& aStyles) {

Просмотреть файл

@ -3902,6 +3902,7 @@ pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
parent_style_or_null: Option<&ComputedValues>, parent_style_or_null: Option<&ComputedValues>,
pseudo: PseudoStyleType, pseudo: PseudoStyleType,
raw_data: &RawServoStyleSet, raw_data: &RawServoStyleSet,
page_name: *const nsAtom,
) -> Strong<ComputedValues> { ) -> Strong<ComputedValues> {
let global_style_data = &*GLOBAL_STYLE_DATA; let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read(); 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 // If the pseudo element is PageContent, we should append @page rules to the
// precomputed pseudo. // precomputed pseudo.
//
// TODO(emilio): We'll need a separate code path or extra arguments for
// named pages, etc.
let mut extra_declarations = vec![]; let mut extra_declarations = vec![];
if pseudo == PseudoElement::PageContent { if pseudo == PseudoElement::PageContent {
let iter = data.stylist.iter_extra_data_origins_rev(); 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::User => CascadeLevel::UserNormal,
Origin::Author => CascadeLevel::same_tree_author_normal(), 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<Locked<PageRule>>| {
extra_declarations.push(ApplicableDeclarationBlock::from_declarations( extra_declarations.push(ApplicableDeclarationBlock::from_declarations(
rule.0.read_with(level.guard(&guards)).block.clone(), rule.read_with(level.guard(&guards)).block.clone(),
level, level,
LayerOrder::root(), 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 = let rule_node =