perf(style): share inline source text backing

This commit is contained in:
ldm0
2026-09-05 03:58:34 +08:00
parent 376d62ae28
commit 7002abca3c
7 changed files with 90 additions and 23 deletions
@@ -544,6 +544,11 @@ impl DomHost {
self.dom.text_content(handle)
}
pub fn shared_text_content(&self, handle: DomHandle) -> Option<std::sync::Arc<str>> {
self.node(handle)
.map(|node| node.shared_text_content(&self.dom))
}
pub fn inner_html(&self, handle: DomHandle) -> Option<String> {
self.dom.inner_html(handle)
}
@@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::{collections::HashSet, sync::Arc};
use super::{
JsContextHost,
@@ -873,13 +873,13 @@ impl JsContextHost {
}
pub(crate) fn sync_owner_style_sheet_text(&mut self, owner: DomHandle) {
let css_text = self.dom_host().text_content(owner).unwrap_or_default();
let css_text = self
.dom_host()
.shared_text_content(owner)
.unwrap_or_else(|| Arc::from(""));
let dom_host = self.dom_host() as *const _;
self.style_engine.sync_owner_style_sheet_text_with_host(
unsafe { &*dom_host },
owner,
css_text,
);
self.style_engine
.sync_owner_style_sheet_text_backing_with_host(unsafe { &*dom_host }, owner, css_text);
self.install_owner_live_stylesheet(owner);
}
@@ -1,4 +1,4 @@
use std::collections::HashSet;
use std::{collections::HashSet, sync::Arc};
pub(super) mod adopted;
pub(super) mod imports;
@@ -160,21 +160,31 @@ impl MoliStyleEngine {
.tracks_document(document)
}
#[cfg(test)]
pub(crate) fn set_owner_style_sheet_text_with_host(
&mut self,
host: &DomHost,
owner: DomHandle,
css_text: String,
) {
self.set_owner_style_sheet_text_backing_with_host(host, owner, css_text.into());
}
fn set_owner_style_sheet_text_backing_with_host(
&mut self,
host: &DomHost,
owner: DomHandle,
css_text: Arc<str>,
) {
let parser_base = stylesheet_source_base_url(host, owner);
self.set_owner_style_sheet_source_with_parser_base(host, owner, css_text, parser_base);
}
pub(crate) fn sync_owner_style_sheet_text_with_host(
pub(crate) fn sync_owner_style_sheet_text_backing_with_host(
&mut self,
host: &DomHost,
owner: DomHandle,
css_text: String,
css_text: Arc<str>,
) {
if self.owner_document_world(host, owner).is_some_and(|world| {
world
@@ -184,14 +194,14 @@ impl MoliStyleEngine {
}) {
return;
}
self.set_owner_style_sheet_text_with_host(host, owner, css_text);
self.set_owner_style_sheet_text_backing_with_host(host, owner, css_text);
}
fn process_owner_style_sheet_text_with_host(
&mut self,
host: &DomHost,
owner: DomHandle,
css_text: String,
css_text: Arc<str>,
) {
let Some(document) = owner_document_for_source_owner(host, owner) else {
return;
@@ -214,7 +224,7 @@ impl MoliStyleEngine {
&mut self,
host: &DomHost,
owner: DomHandle,
css_text: String,
css_text: Arc<str>,
parser_base: url::Url,
) {
let Some(document) = owner_document_for_source_owner(host, owner) else {
@@ -518,7 +528,8 @@ impl MoliStyleEngine {
self.process_owner_style_sheet_text_with_host(
host,
owner,
host.text_content(owner).unwrap_or_default(),
host.shared_text_content(owner)
.unwrap_or_else(|| Arc::from("")),
);
} else if matches!(
change.kind(),
@@ -49,13 +49,19 @@ struct SharedStyleSourceCache {
pub(super) fn shared_style_source_contents(
css_text: String,
base_url: url::Url,
) -> Arc<SharedStyleSourceContents> {
shared_style_source_contents_from_shared(css_text.into(), base_url)
}
pub(super) fn shared_style_source_contents_from_shared(
css_text: Arc<str>,
base_url: url::Url,
) -> Arc<SharedStyleSourceContents> {
let key = SharedStyleSourceCacheKey::new(&css_text, &base_url);
if let Some(cached) = CACHE.lock().lookup(&key, &css_text, &base_url) {
return cached;
}
let css_text = Arc::<str>::from(css_text);
let metadata = style_source_metadata_for_css_text(&css_text, &base_url);
let source = Arc::new(SharedStyleSourceContents {
source_metadata: SharedStyleSourceMetadata::from_metadata(
@@ -288,6 +294,17 @@ mod tests {
assert_eq!(cache.retained_bytes, 0);
}
#[test]
fn shared_input_becomes_the_retained_css_text_backing() {
let css_text = Arc::<str>::from(".shared-input { color: green; }");
let source = shared_style_source_contents_from_shared(
Arc::clone(&css_text),
url::Url::parse("https://shared-input.test/style.css").expect("valid base URL"),
);
assert!(Arc::ptr_eq(&css_text, &source.css_text_handle()));
}
#[test]
fn weak_cache_evicts_oldest_index_to_byte_budget() {
let mut cache = SharedStyleSourceCache::with_retained_bytes_limit(2 * ENTRY_RETAINED_BYTES);
@@ -13,7 +13,10 @@ use super::super::{
source_key::{StyleSourceKey, StyleSourceSetKey},
};
use super::imports::stylesheet_top_level_import_urls;
use super::shared_cache::{SharedStyleSourceContents, shared_style_source_contents};
use super::shared_cache::{
SharedStyleSourceContents, shared_style_source_contents,
shared_style_source_contents_from_shared,
};
use crate::{
document_runtime::DomHandle, protocol_types::EmulatedMediaOverrides,
style_engine::StyleViewport,
@@ -92,6 +95,15 @@ pub(crate) struct OwnerStyleSheetSource {
impl StyloStylesheetSource {
pub(crate) fn new(css_text: String, base_url: url::Url) -> Self {
let shared = shared_style_source_contents(css_text, base_url);
Self::from_shared_contents(shared)
}
fn from_shared_text(css_text: StdArc<str>, base_url: url::Url) -> Self {
let shared = shared_style_source_contents_from_shared(css_text, base_url);
Self::from_shared_contents(shared)
}
fn from_shared_contents(shared: StdArc<SharedStyleSourceContents>) -> Self {
let cache_key =
StyleSourceKey::from_css_fingerprint(shared.css_fingerprint(), shared.base_url());
let base_url = shared.base_url_handle();
@@ -542,8 +554,22 @@ impl StylesheetFontFaceDescriptor {
}
impl OwnerStyleSheetSource {
#[cfg(test)]
pub(crate) fn new(owner: DomHandle, css_text: String, parser_base: url::Url) -> Self {
let source = StyloStylesheetSource::new(css_text, parser_base);
Self::from_source(owner, source)
}
pub(crate) fn from_shared_text(
owner: DomHandle,
css_text: StdArc<str>,
parser_base: url::Url,
) -> Self {
let source = StyloStylesheetSource::from_shared_text(css_text, parser_base);
Self::from_source(owner, source)
}
fn from_source(owner: DomHandle, source: StyloStylesheetSource) -> Self {
let processing_contents = source
.processing_contents()
.expect("owner processing source must remain text-backed");
@@ -94,7 +94,7 @@ impl OwnerStyleSheetSources {
pub(super) fn set_source(
&mut self,
owner: DomHandle,
css_text: String,
css_text: Arc<str>,
parser_base: url::Url,
) -> bool {
self.cssom_authoritative_owners.remove(&owner);
@@ -105,7 +105,11 @@ impl OwnerStyleSheetSources {
}) {
return false;
}
let processing_source = Arc::new(OwnerStyleSheetSource::new(owner, css_text, parser_base));
let processing_source = Arc::new(OwnerStyleSheetSource::from_shared_text(
owner,
css_text,
parser_base,
));
self.sources_by_owner.insert(
owner,
InstalledOwnerStyleSheet::from_processing_source(processing_source),
@@ -116,11 +120,15 @@ impl OwnerStyleSheetSources {
pub(super) fn replace_processed_source(
&mut self,
owner: DomHandle,
css_text: String,
css_text: Arc<str>,
parser_base: url::Url,
) {
self.cssom_authoritative_owners.remove(&owner);
let processing_source = Arc::new(OwnerStyleSheetSource::new(owner, css_text, parser_base));
let processing_source = Arc::new(OwnerStyleSheetSource::from_shared_text(
owner,
css_text,
parser_base,
));
self.sources_by_owner.insert(
owner,
InstalledOwnerStyleSheet::from_processing_source(processing_source),
@@ -1770,8 +1770,8 @@ fn owner_style_sheet_sources_share_one_cached_text_allocation() {
let mut owner_sources = super::source_owner_text::OwnerStyleSheetSources::default();
let base_url = url::Url::parse("https://example.test/").expect("valid test url");
let css_text = ".card:has(.item) { color: red; }";
owner_sources.set_source(first_owner, css_text.to_owned(), base_url.clone());
owner_sources.set_source(second_owner, css_text.to_owned(), base_url);
owner_sources.set_source(first_owner, css_text.into(), base_url.clone());
owner_sources.set_source(second_owner, css_text.into(), base_url);
let first = owner_sources
.source(first_owner)
@@ -1867,7 +1867,7 @@ fn linked_source_store_lifecycle_records_drive_retained_record_construction() {
let mut owner_sources = super::source_owner_text::OwnerStyleSheetSources::default();
owner_sources.set_source(
style,
".owner { color: green; }".to_owned(),
".owner { color: green; }".into(),
url::Url::parse("https://example.test/").unwrap(),
);
let linked_url = url::Url::parse("https://example.test/linked.css").unwrap();