From d7ec3635e60842c87f1565b4db6a8665bbc4a50a Mon Sep 17 00:00:00 2001 From: stevennovaryo Date: Tue, 6 May 2025 14:36:04 +0800 Subject: [PATCH] Use resources stylesheet for details element. Signed-off-by: stevennovaryo --- Cargo.lock | 1 + components/layout/layout_impl.rs | 27 +------ components/script/dom/htmldetailselement.rs | 78 +++++++++++---------- components/shared/embedder/resources.rs | 6 ++ components/shared/script_layout/Cargo.toml | 1 + components/shared/script_layout/lib.rs | 47 ++++++++++++- resources/details.css | 18 +++++ 7 files changed, 114 insertions(+), 64 deletions(-) create mode 100644 resources/details.css diff --git a/Cargo.lock b/Cargo.lock index cfc9a0a0abb..0ce8ddebcac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6551,6 +6551,7 @@ dependencies = [ "servo_malloc_size_of", "servo_url", "stylo", + "url", "webrender_api", ] diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 54edc215389..7c8ca09b024 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -36,7 +36,7 @@ use rayon::ThreadPool; use script::layout_dom::{ServoLayoutDocument, ServoLayoutElement, ServoLayoutNode}; use script_layout_interface::{ Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, ReflowGoal, - ReflowRequest, ReflowResult, TrustedNodeAddress, + ReflowRequest, ReflowResult, TrustedNodeAddress, parse_ua_stylesheet, }; use script_traits::{DrawAPaintImageResult, PaintWorkletError, Painter, ScriptThreadMessage}; use servo_arc::Arc as ServoArc; @@ -58,7 +58,7 @@ use style::properties::{ComputedValues, PropertyId}; use style::queries::values::PrefersColorScheme; use style::selector_parser::{PseudoElement, RestyleDamage, SnapshotMap}; use style::servo::media_queries::FontMetricsProvider; -use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards}; +use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards}; use style::stylesheets::{ DocumentStyleSheet, Origin, Stylesheet, StylesheetInDocument, UrlExtraData, UserAgentStylesheets, @@ -72,7 +72,6 @@ use style::values::specified::font::{KeywordInfo, QueryFontMetricsFlags}; use style::{Zero, driver}; use style_traits::{CSSPixel, SpeculativePainter}; use stylo_atoms::Atom; -use url::Url; use webrender_api::units::{DevicePixel, DevicePoint, LayoutPixel, LayoutPoint, LayoutSize}; use webrender_api::{ExternalScrollId, HitTestFlags}; @@ -989,28 +988,6 @@ impl LayoutThread { } fn get_ua_stylesheets() -> Result { - fn parse_ua_stylesheet( - shared_lock: &SharedRwLock, - filename: &str, - content: &[u8], - ) -> Result { - let url = Url::parse(&format!("chrome://resources/{:?}", filename)) - .ok() - .unwrap(); - Ok(DocumentStyleSheet(ServoArc::new(Stylesheet::from_bytes( - content, - url.into(), - None, - None, - Origin::UserAgent, - MediaList::empty(), - shared_lock.clone(), - None, - None, - QuirksMode::NoQuirks, - )))) - } - let shared_lock = &GLOBAL_STYLE_DATA.shared_lock; // FIXME: presentational-hints.css should be at author origin with zero specificity. diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs index 1d48b8e7a97..d6dacac911b 100644 --- a/components/script/dom/htmldetailselement.rs +++ b/components/script/dom/htmldetailselement.rs @@ -5,9 +5,14 @@ use std::cell::{Cell, Ref}; use dom_struct::dom_struct; +use embedder_traits::resources::Resource; use html5ever::{LocalName, Prefix, local_name}; use js::rust::HandleObject; +use script_layout_interface::parse_resource_stylesheet; +use style::attr::AttrValue; +use super::element::ElementCreator; +use super::types::HTMLLinkElement; use crate::dom::attr::Attr; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::HTMLDetailsElementBinding::HTMLDetailsElementMethods; @@ -116,13 +121,49 @@ impl HTMLDetailsElement { ) .expect("Attaching UA shadow root failed"); + let link_element = HTMLLinkElement::new( + local_name!("link"), + None, + &document, + None, + ElementCreator::ScriptCreated, + can_gc, + ); + link_element.upcast::().set_attribute( + &local_name!("rel"), + AttrValue::String("stylesheet".to_owned()), + can_gc, + ); + root.upcast::() + .AppendChild(link_element.upcast::(), can_gc) + .unwrap(); + + let details_stylesheet = parse_resource_stylesheet( + link_element + .upcast::() + .owner_doc() + .style_shared_lock(), + Resource::DetailsCSS, + ); + link_element.set_stylesheet(details_stylesheet.unwrap()); + let summary = HTMLSlotElement::new(local_name!("slot"), None, &document, None, can_gc); + summary.upcast::().set_attribute( + &local_name!("name"), + AttrValue::from_atomic("internal-main-summary".to_owned()), + can_gc, + ); root.upcast::() .AppendChild(summary.upcast::(), can_gc) .unwrap(); let fallback_summary = HTMLElement::new(local_name!("summary"), None, &document, None, can_gc); + fallback_summary.upcast::().set_attribute( + &local_name!("name"), + AttrValue::from_atomic("internal-fallback-summary".to_owned()), + can_gc, + ); fallback_summary .upcast::() .SetTextContent(Some(DEFAULT_SUMMARY.into()), can_gc); @@ -179,40 +220,6 @@ impl HTMLDetailsElement { } shadow_tree.descendants.Assign(slottable_children); } - - fn update_shadow_tree_styles(&self, can_gc: CanGc) { - let shadow_tree = self.shadow_tree(can_gc); - - let value = if self.Open() { - "display: block;" - } else { - // TODO: This should be "display: block; content-visibility: hidden;", - // but servo does not support content-visibility yet - "display: none;" - }; - shadow_tree - .descendants - .upcast::() - .set_string_attribute(&local_name!("style"), value.into(), can_gc); - - // Manually update the list item style of the implicit summary element. - // Unlike the other summaries, this summary is in the shadow tree and - // can't be styled with UA sheets - let implicit_summary_list_item_style = if self.Open() { - "disclosure-open" - } else { - "disclosure-closed" - }; - let implicit_summary_style = format!( - "display: list-item; - counter-increment: list-item 0; - list-style: {implicit_summary_list_item_style} inside;" - ); - shadow_tree - .implicit_summary - .upcast::() - .set_string_attribute(&local_name!("style"), implicit_summary_style.into(), can_gc); - } } impl HTMLDetailsElementMethods for HTMLDetailsElement { @@ -234,8 +241,6 @@ impl VirtualMethods for HTMLDetailsElement { .attribute_mutated(attr, mutation, can_gc); if attr.local_name() == &local_name!("open") { - self.update_shadow_tree_styles(can_gc); - let counter = self.toggle_counter.get() + 1; self.toggle_counter.set(counter); @@ -263,6 +268,5 @@ impl VirtualMethods for HTMLDetailsElement { self.super_type().unwrap().bind_to_tree(context, can_gc); self.update_shadow_tree_contents(CanGc::note()); - self.update_shadow_tree_styles(CanGc::note()); } } diff --git a/components/shared/embedder/resources.rs b/components/shared/embedder/resources.rs index 28464a95d1a..7716fd20c92 100644 --- a/components/shared/embedder/resources.rs +++ b/components/shared/embedder/resources.rs @@ -66,6 +66,7 @@ pub fn sandbox_access_files_dirs() -> Vec { .unwrap_or_default() } +#[derive(Clone)] pub enum Resource { /// A list of GATT services that are blocked from being used by web bluetooth. /// The format of the file is a list of UUIDs, one per line, with an optional second word to specify the @@ -109,6 +110,9 @@ pub enum Resource { DirectoryListingHTML, /// A HTML page that is used for the about:memory url. AboutMemoryHTML, + /// A CSS file to style the elements inside
element UA Shadow Tree. + /// It can be empty but then
element simply wouldn't work. + DetailsCSS, } impl Resource { @@ -123,6 +127,7 @@ impl Resource { Resource::CrashHTML => "crash.html", Resource::DirectoryListingHTML => "directory-listing.html", Resource::AboutMemoryHTML => "about-memory.html", + Resource::DetailsCSS => "details.css", } } } @@ -167,6 +172,7 @@ fn resources_for_tests() -> Box { Resource::AboutMemoryHTML => { &include_bytes!("../../../resources/about-memory.html")[..] }, + Resource::DetailsCSS => &include_bytes!("../../../resources/details.css")[..], } .to_owned() } diff --git a/components/shared/script_layout/Cargo.toml b/components/shared/script_layout/Cargo.toml index 167606f7247..e11ede50155 100644 --- a/components/shared/script_layout/Cargo.toml +++ b/components/shared/script_layout/Cargo.toml @@ -38,4 +38,5 @@ serde = { workspace = true } servo_arc = { workspace = true } servo_url = { path = "../../url" } stylo = { workspace = true } +url = { workspace = true } webrender_api = { workspace = true } diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs index e82ee16e24b..ac521c622c9 100644 --- a/components/shared/script_layout/lib.rs +++ b/components/shared/script_layout/lib.rs @@ -20,6 +20,7 @@ use base::Epoch; use base::id::{BrowsingContextId, PipelineId, WebViewId}; use compositing_traits::CrossProcessCompositorApi; use constellation_traits::{LoadData, ScrollState}; +use embedder_traits::resources::{self, Resource}; use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails}; use euclid::default::{Point2D, Rect}; use fnv::FnvHashMap; @@ -43,11 +44,13 @@ use style::context::QuirksMode; use style::data::ElementData; use style::dom::OpaqueNode; use style::invalidation::element::restyle_hints::RestyleHint; -use style::media_queries::Device; +use style::media_queries::{Device, MediaList}; use style::properties::PropertyId; use style::properties::style_structs::Font; use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot}; -use style::stylesheets::Stylesheet; +use style::shared_lock::SharedRwLock; +use style::stylesheets::{DocumentStyleSheet, Origin, Stylesheet}; +use url::Url; use webrender_api::ImageKey; use webrender_api::units::DeviceIntSize; @@ -635,3 +638,43 @@ mod test { assert_eq!(image_animation_state.last_update_time, 0.101); } } + +pub fn parse_stylesheet_as_origin( + shared_lock: &SharedRwLock, + filename: &str, + content: &[u8], + origin: Origin, +) -> Result, &'static str> { + let url = Url::parse(&format!("chrome://resources/{:?}", filename)) + .ok() + .unwrap(); + Ok(ServoArc::new(Stylesheet::from_bytes( + content, + url.into(), + None, + None, + origin, + MediaList::empty(), + shared_lock.clone(), + None, + None, + QuirksMode::NoQuirks, + ))) +} + +pub fn parse_ua_stylesheet( + shared_lock: &SharedRwLock, + filename: &str, + content: &[u8], +) -> Result { + parse_stylesheet_as_origin(shared_lock, filename, content, Origin::UserAgent) + .map(DocumentStyleSheet) +} + +pub fn parse_resource_stylesheet( + shared_lock: &SharedRwLock, + resources: Resource, +) -> Result, &'static str> { + let content = &resources::read_bytes(resources.clone()); + parse_stylesheet_as_origin(shared_lock, resources.filename(), content, Origin::Author) +} diff --git a/resources/details.css b/resources/details.css new file mode 100644 index 00000000000..81331ae22c2 --- /dev/null +++ b/resources/details.css @@ -0,0 +1,18 @@ +/* We should use `content-visibility` but it is yet to be implemented. + * These rule would not comply with ::details-content and should be removed + * with it's implementation */ +slot:not([name]) { + display: none; +} +:host([open]) slot:not([name]) { + display: block; +} + +summary[name=internal-fallback-summary] { + display: list-item; + counter-increment: list-item 0; + list-style: disclosure-closed inside; +} +:host([open]) summary[name=internal-fallback-summary] { + list-style-type: disclosure-open; +}