mirror of
https://github.com/servo/servo.git
synced 2025-09-30 08:39:16 +01:00
Reuse StylesheetContent
for inline style sheets with identical content (#38540)
For duplicate style sheets with identical content, `StylesheetContents` can be reused to avoid redundant parsing of the inline style sheets. Since duplicate stylesheets is a common case with web components, this change will significantly improve performance. Additionally, the cache hit rate of stylo's `CascadeDataCache` can now be significantly improved. When shared `StylesheetContents` is modified, copy-on-write will occur to avoid affecting other sharers. And then updates the references to `CssRule` or `PropertyDeclarationBlock` stored in the CSSOMs to ensure that modifications are made only on the new copy. Signed-off-by: sharpshooter_pt <ibluegalaxy_taoj@163.com>
This commit is contained in:
parent
f6b77f94e2
commit
6e6ef513a9
25 changed files with 711 additions and 125 deletions
|
@ -4,9 +4,13 @@
|
|||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use itertools::izip;
|
||||
use script_bindings::inheritance::Castable;
|
||||
use servo_arc::Arc;
|
||||
use style::shared_lock::Locked;
|
||||
use style::shared_lock::{Locked, SharedRwLockReadGuard};
|
||||
use style::stylesheets::{
|
||||
AllowImportRules, CssRuleType, CssRuleTypes, CssRules, CssRulesHelpers, KeyframesRule,
|
||||
RulesMutateError, StylesheetLoader as StyleStylesheetLoader,
|
||||
|
@ -44,7 +48,7 @@ pub(crate) struct CSSRuleList {
|
|||
reflector_: Reflector,
|
||||
parent_stylesheet: Dom<CSSStyleSheet>,
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
rules: RulesSource,
|
||||
rules: RefCell<RulesSource>,
|
||||
dom_rules: DomRefCell<Vec<MutNullableDom<CSSRule>>>,
|
||||
}
|
||||
|
||||
|
@ -78,7 +82,7 @@ impl CSSRuleList {
|
|||
CSSRuleList {
|
||||
reflector_: Reflector::new(),
|
||||
parent_stylesheet: Dom::from_ref(parent_stylesheet),
|
||||
rules,
|
||||
rules: RefCell::new(rules),
|
||||
dom_rules: DomRefCell::new(dom_rules),
|
||||
}
|
||||
}
|
||||
|
@ -107,8 +111,9 @@ impl CSSRuleList {
|
|||
parse_relative_rule_type: Option<CssRuleType>,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<u32> {
|
||||
let css_rules = if let RulesSource::Rules(ref rules) = self.rules {
|
||||
rules
|
||||
self.parent_stylesheet.will_modify();
|
||||
let css_rules = if let RulesSource::Rules(rules) = &*self.rules.borrow() {
|
||||
rules.clone()
|
||||
} else {
|
||||
panic!("Called insert_rule on non-CssRule-backed CSSRuleList");
|
||||
};
|
||||
|
@ -144,6 +149,7 @@ impl CSSRuleList {
|
|||
.map_err(Convert::convert)?;
|
||||
|
||||
let parent_stylesheet = &*self.parent_stylesheet;
|
||||
parent_stylesheet.will_modify();
|
||||
let dom_rule = CSSRule::new_specific(window, parent_stylesheet, new_rule, can_gc);
|
||||
self.dom_rules
|
||||
.borrow_mut()
|
||||
|
@ -154,10 +160,12 @@ impl CSSRuleList {
|
|||
|
||||
/// In case of a keyframe rule, index must be valid.
|
||||
pub(crate) fn remove_rule(&self, index: u32) -> ErrorResult {
|
||||
self.parent_stylesheet.will_modify();
|
||||
|
||||
let index = index as usize;
|
||||
let mut guard = self.parent_stylesheet.shared_lock().write();
|
||||
|
||||
match self.rules {
|
||||
match *self.rules.borrow() {
|
||||
RulesSource::Rules(ref css_rules) => {
|
||||
css_rules
|
||||
.write_with(&mut guard)
|
||||
|
@ -199,7 +207,7 @@ impl CSSRuleList {
|
|||
rule.or_init(|| {
|
||||
let parent_stylesheet = &self.parent_stylesheet;
|
||||
let lock = parent_stylesheet.shared_lock();
|
||||
match self.rules {
|
||||
match *self.rules.borrow() {
|
||||
RulesSource::Rules(ref rules) => {
|
||||
let rule = {
|
||||
let guard = lock.read();
|
||||
|
@ -235,11 +243,48 @@ impl CSSRuleList {
|
|||
/// Should only be called for keyframes-backed rules, use insert_rule
|
||||
/// for CssRules-backed rules
|
||||
pub(crate) fn append_lazy_dom_rule(&self) {
|
||||
if let RulesSource::Rules(..) = self.rules {
|
||||
if let RulesSource::Rules(..) = &*self.rules.borrow() {
|
||||
panic!("Can only call append_lazy_rule with keyframes-backed CSSRules");
|
||||
}
|
||||
self.dom_rules.borrow_mut().push(MutNullableDom::new(None));
|
||||
}
|
||||
|
||||
pub(super) fn update_rules(&self, rules: RulesSource, guard: &SharedRwLockReadGuard) {
|
||||
let dom_rules = self.dom_rules.borrow();
|
||||
match rules {
|
||||
RulesSource::Rules(ref css_rules) => {
|
||||
if let RulesSource::Keyframes(..) = &*self.rules.borrow() {
|
||||
panic!("Called update_rules on non-CssRule-backed CSSRuleList with CssRules");
|
||||
}
|
||||
|
||||
let css_rules_iter = css_rules.read_with(guard).0.iter();
|
||||
for (dom_rule, css_rule) in izip!(dom_rules.iter(), css_rules_iter) {
|
||||
let Some(dom_rule) = dom_rule.get() else {
|
||||
continue;
|
||||
};
|
||||
dom_rule.update_rule(css_rule, guard);
|
||||
}
|
||||
},
|
||||
RulesSource::Keyframes(ref keyframesrule) => {
|
||||
if let RulesSource::Rules(..) = &*self.rules.borrow() {
|
||||
panic!("Called update_rules on CssRule-backed CSSRuleList with non-CssRules");
|
||||
}
|
||||
|
||||
let keyframerules_iter = keyframesrule.read_with(guard).keyframes.iter();
|
||||
for (dom_rule, keyframerule) in izip!(dom_rules.iter(), keyframerules_iter) {
|
||||
let Some(dom_rule) = dom_rule.get() else {
|
||||
continue;
|
||||
};
|
||||
let Some(dom_rule) = dom_rule.downcast::<CSSKeyframeRule>() else {
|
||||
continue;
|
||||
};
|
||||
dom_rule.update_rule(keyframerule.clone(), guard);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
*self.rules.borrow_mut() = rules;
|
||||
}
|
||||
}
|
||||
|
||||
impl CSSRuleListMethods<crate::DomTypeHolder> for CSSRuleList {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue