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
|
@ -2,16 +2,17 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cell::{Cell, Ref};
|
||||
use std::rc::Rc;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::rust::HandleObject;
|
||||
use script_bindings::inheritance::Castable;
|
||||
use script_bindings::realms::InRealm;
|
||||
use script_bindings::root::Dom;
|
||||
use servo_arc::Arc;
|
||||
use style::media_queries::MediaList as StyleMediaList;
|
||||
use style::shared_lock::SharedRwLock;
|
||||
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard};
|
||||
use style::stylesheets::{
|
||||
AllowImportRules, CssRuleTypes, Origin, Stylesheet as StyleStyleSheet, UrlExtraData,
|
||||
};
|
||||
|
@ -33,6 +34,7 @@ use crate::dom::bindings::str::{DOMString, USVString};
|
|||
use crate::dom::cssrulelist::{CSSRuleList, RulesSource};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::htmlstyleelement::HTMLStyleElement;
|
||||
use crate::dom::medialist::MediaList;
|
||||
use crate::dom::node::NodeTraits;
|
||||
use crate::dom::stylesheet::StyleSheet;
|
||||
|
@ -55,7 +57,12 @@ pub(crate) struct CSSStyleSheet {
|
|||
/// The inner Stylo's [Stylesheet].
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
#[no_trace]
|
||||
style_stylesheet: Arc<StyleStyleSheet>,
|
||||
style_stylesheet: DomRefCell<Arc<StyleStyleSheet>>,
|
||||
|
||||
/// The inner Stylo's [SharedRwLock], stored at here to avoid referencing
|
||||
/// temporary variables.
|
||||
#[no_trace]
|
||||
style_shared_lock: SharedRwLock,
|
||||
|
||||
/// <https://drafts.csswg.org/cssom/#concept-css-style-sheet-origin-clean-flag>
|
||||
origin_clean: Cell<bool>,
|
||||
|
@ -86,7 +93,8 @@ impl CSSStyleSheet {
|
|||
stylesheet: StyleSheet::new_inherited(type_, href, title),
|
||||
owner_node: MutNullableDom::new(owner),
|
||||
rulelist: MutNullableDom::new(None),
|
||||
style_stylesheet: stylesheet,
|
||||
style_shared_lock: stylesheet.shared_lock.clone(),
|
||||
style_stylesheet: DomRefCell::new(stylesheet),
|
||||
origin_clean: Cell::new(true),
|
||||
constructor_document: constructor_document.map(Dom::from_ref),
|
||||
adopters: Default::default(),
|
||||
|
@ -150,7 +158,7 @@ impl CSSStyleSheet {
|
|||
|
||||
fn rulelist(&self, can_gc: CanGc) -> DomRoot<CSSRuleList> {
|
||||
self.rulelist.or_init(|| {
|
||||
let rules = self.style_stylesheet.contents.rules.clone();
|
||||
let rules = self.style_stylesheet.borrow().contents.rules.clone();
|
||||
CSSRuleList::new(
|
||||
self.global().as_window(),
|
||||
self,
|
||||
|
@ -161,7 +169,7 @@ impl CSSStyleSheet {
|
|||
}
|
||||
|
||||
pub(crate) fn disabled(&self) -> bool {
|
||||
self.style_stylesheet.disabled()
|
||||
self.style_stylesheet.borrow().disabled()
|
||||
}
|
||||
|
||||
pub(crate) fn owner_node(&self) -> Option<DomRoot<Element>> {
|
||||
|
@ -169,7 +177,7 @@ impl CSSStyleSheet {
|
|||
}
|
||||
|
||||
pub(crate) fn set_disabled(&self, disabled: bool) {
|
||||
if self.style_stylesheet.set_disabled(disabled) {
|
||||
if self.style_stylesheet.borrow().set_disabled(disabled) {
|
||||
self.notify_invalidations();
|
||||
}
|
||||
}
|
||||
|
@ -179,15 +187,11 @@ impl CSSStyleSheet {
|
|||
}
|
||||
|
||||
pub(crate) fn shared_lock(&self) -> &SharedRwLock {
|
||||
&self.style_stylesheet.shared_lock
|
||||
&self.style_shared_lock
|
||||
}
|
||||
|
||||
pub(crate) fn style_stylesheet(&self) -> &StyleStyleSheet {
|
||||
&self.style_stylesheet
|
||||
}
|
||||
|
||||
pub(crate) fn style_stylesheet_arc(&self) -> &Arc<StyleStyleSheet> {
|
||||
&self.style_stylesheet
|
||||
pub(crate) fn style_stylesheet(&self) -> Ref<'_, Arc<StyleStyleSheet>> {
|
||||
self.style_stylesheet.borrow()
|
||||
}
|
||||
|
||||
pub(crate) fn set_origin_clean(&self, origin_clean: bool) {
|
||||
|
@ -231,6 +235,36 @@ impl CSSStyleSheet {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn will_modify(&self) {
|
||||
let Some(node) = self.owner_node.get() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(node) = node.downcast::<HTMLStyleElement>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
node.will_modify_stylesheet();
|
||||
}
|
||||
|
||||
pub(crate) fn update_style_stylesheet(
|
||||
&self,
|
||||
style_stylesheet: &Arc<StyleStyleSheet>,
|
||||
guard: &SharedRwLockReadGuard,
|
||||
) {
|
||||
// When the shared `StylesheetContents` is about to be modified,
|
||||
// `CSSStyleSheet::owner_node` performs a copy-on-write to avoid
|
||||
// affecting other sharers, see `CSSStyleSheet::will_modify`. And
|
||||
// then updates the references to `CssRule` or `PropertyDeclarationBlock`
|
||||
// stored in the CSSOMs to ensure that modifications are made only
|
||||
// on the new copy.
|
||||
*self.style_stylesheet.borrow_mut() = style_stylesheet.clone();
|
||||
if let Some(rulelist) = self.rulelist.get() {
|
||||
let rules = style_stylesheet.contents.rules.clone();
|
||||
rulelist.update_rules(RulesSource::Rules(rules), guard);
|
||||
}
|
||||
}
|
||||
|
||||
/// Invalidate all stylesheet set this stylesheet is a part on.
|
||||
pub(crate) fn notify_invalidations(&self) {
|
||||
if let Some(owner) = self.owner_node() {
|
||||
|
@ -402,8 +436,12 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
let global = sheet.global();
|
||||
let window = global.as_window();
|
||||
|
||||
sheet.will_modify();
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
let _span = tracing::trace_span!("ParseStylesheet", servo_profiling = true).entered();
|
||||
StyleStyleSheet::update_from_str(
|
||||
&sheet.style_stylesheet,
|
||||
&sheet.style_stylesheet(),
|
||||
&text,
|
||||
UrlExtraData(window.get_url().get_arc()),
|
||||
None,
|
||||
|
@ -441,8 +479,12 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
|
|||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
|
||||
self.will_modify();
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
let _span = tracing::trace_span!("ParseStylesheet", servo_profiling = true).entered();
|
||||
StyleStyleSheet::update_from_str(
|
||||
&self.style_stylesheet,
|
||||
&self.style_stylesheet(),
|
||||
&text,
|
||||
UrlExtraData(window.get_url().get_arc()),
|
||||
None,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue