css: Refactor StyleSheetInDocument owner (#38136)

Refactor `documentotshadowroot::StyleSheetInDocument`, renaming it into
`ServoStylesheetInDocument` to avoid confusion with Stylo's
`StylesheetInDocument` trait.

To support constructed stylesheet. The `ServoStylesheetInDocument.owner`
would contains enum of:
- `Dom<Element>` - for stylesheet parsed from an element.
- `Dom<CSSStylesheet>` - for constructed stylesheet.

Testing: No WPT regression.
Fixes: #38133

---------

Signed-off-by: Jo Steven Novaryo <jo.steven.novaryo@huawei.com>
This commit is contained in:
Jo Steven Novaryo 2025-07-18 13:39:09 +08:00 committed by GitHub
parent d671f58078
commit bbed6cddcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 112 additions and 57 deletions

View file

@ -134,7 +134,9 @@ use crate::dom::customelementregistry::CustomElementDefinition;
use crate::dom::customevent::CustomEvent;
use crate::dom::datatransfer::DataTransfer;
use crate::dom::documentfragment::DocumentFragment;
use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument};
use crate::dom::documentorshadowroot::{
DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
};
use crate::dom::documenttype::DocumentType;
use crate::dom::domimplementation::DOMImplementation;
use crate::dom::element::{
@ -332,7 +334,7 @@ pub(crate) struct Document {
style_shared_lock: StyleSharedRwLock,
/// List of stylesheets associated with nodes in this document. |None| if the list needs to be refreshed.
#[custom_trace]
stylesheets: DomRefCell<DocumentStylesheetSet<StyleSheetInDocument>>,
stylesheets: DomRefCell<DocumentStylesheetSet<ServoStylesheetInDocument>>,
stylesheet_list: MutNullableDom<StyleSheetList>,
ready_state: Cell<DocumentReadyState>,
/// Whether the DOMContentLoaded event has already been dispatched.
@ -4889,23 +4891,29 @@ impl Document {
stylesheets
.get(Origin::Author, index)
.and_then(|s| s.owner.upcast::<Node>().get_cssom_stylesheet())
.and_then(|s| s.owner.get_cssom_object())
}
/// Add a stylesheet owned by `owner` to the list of document sheets, in the
/// correct tree position.
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn add_stylesheet(&self, owner: &Element, sheet: Arc<Stylesheet>) {
pub(crate) fn add_stylesheet(&self, owner: StylesheetSource, sheet: Arc<Stylesheet>) {
let stylesheets = &mut *self.stylesheets.borrow_mut();
let insertion_point = stylesheets
.iter()
.map(|(sheet, _origin)| sheet)
.find(|sheet_in_doc| {
owner
.upcast::<Node>()
.is_before(sheet_in_doc.owner.upcast())
})
.cloned();
// TODO(stevennovayo): support constructed stylesheet for adopted stylesheet and its ordering
let insertion_point = match &owner {
StylesheetSource::Element(owner_elem) => stylesheets
.iter()
.map(|(sheet, _origin)| sheet)
.find(|sheet_in_doc| match sheet_in_doc.owner {
StylesheetSource::Element(ref other_elem) => {
owner_elem.upcast::<Node>().is_before(other_elem.upcast())
},
StylesheetSource::Constructed(_) => unreachable!(),
})
.cloned(),
StylesheetSource::Constructed(_) => unreachable!(),
};
if self.has_browsing_context() {
self.window.layout_mut().add_stylesheet(
@ -4932,7 +4940,7 @@ impl Document {
/// Remove a stylesheet owned by `owner` from the list of document sheets.
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn remove_stylesheet(&self, owner: &Element, stylesheet: &Arc<Stylesheet>) {
pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, stylesheet: &Arc<Stylesheet>) {
if self.has_browsing_context() {
self.window
.layout_mut()

View file

@ -26,46 +26,77 @@ use crate::dom::element::Element;
use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::{self, Node, VecPreOrderInsertionHelper};
use crate::dom::shadowroot::ShadowRoot;
use crate::dom::types::CSSStyleSheet;
use crate::dom::window::Window;
use crate::script_runtime::CanGc;
use crate::stylesheet_set::StylesheetSetRef;
/// Stylesheet could be constructed by a CSSOM object CSSStylesheet or parsed
/// from HTML element such as `<style>` or `<link>`.
#[derive(Clone, JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct StyleSheetInDocument {
pub(crate) enum StylesheetSource {
Element(Dom<Element>),
// TODO(stevennovaryo): This type of enum would not be used until we implement adopted stylesheet
#[allow(dead_code)]
Constructed(Dom<CSSStyleSheet>),
}
impl StylesheetSource {
pub(crate) fn get_cssom_object(&self) -> Option<DomRoot<CSSStyleSheet>> {
match self {
StylesheetSource::Element(el) => el.upcast::<Node>().get_cssom_stylesheet(),
StylesheetSource::Constructed(ss) => Some(ss.as_rooted()),
}
}
pub(crate) fn is_a_valid_owner(&self) -> bool {
match self {
StylesheetSource::Element(el) => el.as_stylesheet_owner().is_some(),
StylesheetSource::Constructed(ss) => ss.is_constructed(),
}
}
}
#[derive(Clone, JSTraceable, MallocSizeOf)]
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub(crate) struct ServoStylesheetInDocument {
#[ignore_malloc_size_of = "Arc"]
#[no_trace]
pub(crate) sheet: Arc<Stylesheet>,
pub(crate) owner: Dom<Element>,
/// The object that owns this stylesheet. For constructed stylesheet, it would be the
/// CSSOM object itself, and for stylesheet generated by an element, it would be the
/// html element. This is used to get the CSSOM Stylesheet within a DocumentOrShadowDOM.
pub(crate) owner: StylesheetSource,
}
// This is necessary because this type is contained within a Stylo type which needs
// Stylo's version of MallocSizeOf.
impl stylo_malloc_size_of::MallocSizeOf for StyleSheetInDocument {
impl stylo_malloc_size_of::MallocSizeOf for ServoStylesheetInDocument {
fn size_of(&self, ops: &mut stylo_malloc_size_of::MallocSizeOfOps) -> usize {
<StyleSheetInDocument as malloc_size_of::MallocSizeOf>::size_of(self, ops)
<ServoStylesheetInDocument as malloc_size_of::MallocSizeOf>::size_of(self, ops)
}
}
impl fmt::Debug for StyleSheetInDocument {
impl fmt::Debug for ServoStylesheetInDocument {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.sheet.fmt(formatter)
}
}
impl PartialEq for StyleSheetInDocument {
impl PartialEq for ServoStylesheetInDocument {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.sheet, &other.sheet)
}
}
impl ToMediaListKey for StyleSheetInDocument {
impl ToMediaListKey for ServoStylesheetInDocument {
fn to_media_list_key(&self) -> MediaListKey {
self.sheet.contents.to_media_list_key()
}
}
impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
impl ::style::stylesheets::StylesheetInDocument for ServoStylesheetInDocument {
fn enabled(&self) -> bool {
self.sheet.enabled()
}
@ -85,7 +116,7 @@ impl ::style::stylesheets::StylesheetInDocument for StyleSheetInDocument {
// https://w3c.github.io/webcomponents/spec/shadow/#extensions-to-the-documentorshadowroot-mixin
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
#[derive(JSTraceable, MallocSizeOf)]
#[derive(Clone, JSTraceable, MallocSizeOf)]
pub(crate) struct DocumentOrShadowRoot {
window: Dom<Window>,
}
@ -225,18 +256,18 @@ impl DocumentOrShadowRoot {
/// Remove a stylesheet owned by `owner` from the list of document sheets.
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn remove_stylesheet(
owner: &Element,
owner: StylesheetSource,
s: &Arc<Stylesheet>,
mut stylesheets: StylesheetSetRef<StyleSheetInDocument>,
mut stylesheets: StylesheetSetRef<ServoStylesheetInDocument>,
) {
let guard = s.shared_lock.read();
// FIXME(emilio): Would be nice to remove the clone, etc.
stylesheets.remove_stylesheet(
None,
StyleSheetInDocument {
ServoStylesheetInDocument {
sheet: s.clone(),
owner: Dom::from_ref(owner),
owner,
},
&guard,
);
@ -246,18 +277,15 @@ impl DocumentOrShadowRoot {
/// correct tree position.
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn add_stylesheet(
owner: &Element,
mut stylesheets: StylesheetSetRef<StyleSheetInDocument>,
owner: StylesheetSource,
mut stylesheets: StylesheetSetRef<ServoStylesheetInDocument>,
sheet: Arc<Stylesheet>,
insertion_point: Option<StyleSheetInDocument>,
insertion_point: Option<ServoStylesheetInDocument>,
style_shared_lock: &StyleSharedRwLock,
) {
debug_assert!(owner.as_stylesheet_owner().is_some(), "Wat");
debug_assert!(owner.is_a_valid_owner(), "Wat");
let sheet = StyleSheetInDocument {
sheet,
owner: Dom::from_ref(owner),
};
let sheet = ServoStylesheetInDocument { sheet, owner };
let guard = style_shared_lock.read();

View file

@ -23,6 +23,7 @@ use net_traits::{
FetchMetadata, FetchResponseListener, NetworkError, ReferrerPolicy, ResourceFetchTiming,
ResourceTimingType,
};
use script_bindings::root::Dom;
use servo_arc::Arc;
use servo_url::{ImmutableOrigin, ServoUrl};
use style::attr::AttrValue;
@ -41,6 +42,7 @@ use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::csp::{GlobalCspReporting, Violation};
use crate::dom::cssstylesheet::CSSStyleSheet;
use crate::dom::document::Document;
use crate::dom::documentorshadowroot::StylesheetSource;
use crate::dom::domtokenlist::DOMTokenList;
use crate::dom::element::{
AttributeMutation, Element, ElementCreator, cors_setting_for_element,
@ -178,11 +180,13 @@ impl HTMLLinkElement {
pub(crate) fn set_stylesheet(&self, s: Arc<Stylesheet>) {
let stylesheets_owner = self.stylesheet_list_owner();
if let Some(ref s) = *self.stylesheet.borrow() {
stylesheets_owner.remove_stylesheet(self.upcast(), s)
stylesheets_owner
.remove_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), s)
}
*self.stylesheet.borrow_mut() = Some(s.clone());
self.clean_stylesheet_ownership();
stylesheets_owner.add_stylesheet(self.upcast(), s);
stylesheets_owner
.add_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), s);
}
pub(crate) fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
@ -416,7 +420,7 @@ impl VirtualMethods for HTMLLinkElement {
if let Some(s) = self.stylesheet.borrow_mut().take() {
self.clean_stylesheet_ownership();
self.stylesheet_list_owner()
.remove_stylesheet(self.upcast(), &s);
.remove_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), &s);
}
}
}

View file

@ -8,6 +8,7 @@ use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix};
use js::rust::HandleObject;
use net_traits::ReferrerPolicy;
use script_bindings::root::Dom;
use servo_arc::Arc;
use style::media_queries::MediaList as StyleMediaList;
use style::stylesheets::{AllowImportRules, Origin, Stylesheet, UrlExtraData};
@ -22,6 +23,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::csp::{CspReporting, InlineCheckType};
use crate::dom::cssstylesheet::CSSStyleSheet;
use crate::dom::document::Document;
use crate::dom::documentorshadowroot::StylesheetSource;
use crate::dom::element::{AttributeMutation, Element, ElementCreator};
use crate::dom::htmlelement::HTMLElement;
use crate::dom::medialist::MediaList;
@ -153,11 +155,13 @@ impl HTMLStyleElement {
pub(crate) fn set_stylesheet(&self, s: Arc<Stylesheet>) {
let stylesheets_owner = self.stylesheet_list_owner();
if let Some(ref s) = *self.stylesheet.borrow() {
stylesheets_owner.remove_stylesheet(self.upcast(), s)
stylesheets_owner
.remove_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), s)
}
*self.stylesheet.borrow_mut() = Some(s.clone());
self.clean_stylesheet_ownership();
stylesheets_owner.add_stylesheet(self.upcast(), s);
stylesheets_owner
.add_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), s);
}
pub(crate) fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
@ -192,7 +196,7 @@ impl HTMLStyleElement {
if let Some(s) = self.stylesheet.borrow_mut().take() {
self.clean_stylesheet_ownership();
self.stylesheet_list_owner()
.remove_stylesheet(self.upcast(), &s)
.remove_stylesheet(StylesheetSource::Element(Dom::from_ref(self.upcast())), &s)
}
}
}

View file

@ -32,7 +32,9 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::cssstylesheet::CSSStyleSheet;
use crate::dom::document::Document;
use crate::dom::documentfragment::DocumentFragment;
use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument};
use crate::dom::documentorshadowroot::{
DocumentOrShadowRoot, ServoStylesheetInDocument, StylesheetSource,
};
use crate::dom::element::Element;
use crate::dom::htmlslotelement::HTMLSlotElement;
use crate::dom::node::{
@ -62,7 +64,7 @@ pub(crate) struct ShadowRoot {
host: MutNullableDom<Element>,
/// List of author styles associated with nodes in this shadow tree.
#[custom_trace]
author_styles: DomRefCell<AuthorStyles<StyleSheetInDocument>>,
author_styles: DomRefCell<AuthorStyles<ServoStylesheetInDocument>>,
stylesheet_list: MutNullableDom<StyleSheetList>,
window: Dom<Window>,
@ -175,22 +177,29 @@ impl ShadowRoot {
stylesheets
.get(index)
.and_then(|s| s.owner.upcast::<Node>().get_cssom_stylesheet())
.and_then(|s| s.owner.get_cssom_object())
}
/// Add a stylesheet owned by `owner` to the list of shadow root sheets, in the
/// correct tree position.
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn add_stylesheet(&self, owner: &Element, sheet: Arc<Stylesheet>) {
pub(crate) fn add_stylesheet(&self, owner: StylesheetSource, sheet: Arc<Stylesheet>) {
let stylesheets = &mut self.author_styles.borrow_mut().stylesheets;
let insertion_point = stylesheets
.iter()
.find(|sheet_in_shadow| {
owner
.upcast::<Node>()
.is_before(sheet_in_shadow.owner.upcast())
})
.cloned();
// TODO(stevennovayo): support constructed stylesheet for adopted stylesheet and its ordering
let insertion_point = match &owner {
StylesheetSource::Element(owner_elem) => stylesheets
.iter()
.find(|sheet_in_shadow| match sheet_in_shadow.owner {
StylesheetSource::Element(ref other_elem) => {
owner_elem.upcast::<Node>().is_before(other_elem.upcast())
},
StylesheetSource::Constructed(_) => unreachable!(),
})
.cloned(),
StylesheetSource::Constructed(_) => unreachable!(),
};
DocumentOrShadowRoot::add_stylesheet(
owner,
StylesheetSetRef::Author(stylesheets),
@ -202,7 +211,7 @@ impl ShadowRoot {
/// Remove a stylesheet owned by `owner` from the list of shadow root sheets.
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn remove_stylesheet(&self, owner: &Element, s: &Arc<Stylesheet>) {
pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, s: &Arc<Stylesheet>) {
DocumentOrShadowRoot::remove_stylesheet(
owner,
s,

View file

@ -11,7 +11,7 @@ use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::cssstylesheet::CSSStyleSheet;
use crate::dom::document::Document;
use crate::dom::element::Element;
use crate::dom::documentorshadowroot::StylesheetSource;
use crate::dom::shadowroot::ShadowRoot;
use crate::dom::stylesheet::StyleSheet;
use crate::dom::window::Window;
@ -39,7 +39,8 @@ impl StyleSheetListOwner {
}
}
pub(crate) fn add_stylesheet(&self, owner: &Element, sheet: Arc<Stylesheet>) {
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn add_stylesheet(&self, owner: StylesheetSource, sheet: Arc<Stylesheet>) {
match *self {
StyleSheetListOwner::Document(ref doc) => doc.add_stylesheet(owner, sheet),
StyleSheetListOwner::ShadowRoot(ref shadow_root) => {
@ -48,7 +49,8 @@ impl StyleSheetListOwner {
}
}
pub(crate) fn remove_stylesheet(&self, owner: &Element, s: &Arc<Stylesheet>) {
#[cfg_attr(crown, allow(crown::unrooted_must_root))] // Owner needs to be rooted already necessarily.
pub(crate) fn remove_stylesheet(&self, owner: StylesheetSource, s: &Arc<Stylesheet>) {
match *self {
StyleSheetListOwner::Document(ref doc) => doc.remove_stylesheet(owner, s),
StyleSheetListOwner::ShadowRoot(ref shadow_root) => {