Use resources stylesheet for details element.

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
stevennovaryo 2025-05-06 14:36:04 +08:00
parent 871630606f
commit d7ec3635e6
7 changed files with 114 additions and 64 deletions

1
Cargo.lock generated
View file

@ -6551,6 +6551,7 @@ dependencies = [
"servo_malloc_size_of",
"servo_url",
"stylo",
"url",
"webrender_api",
]

View file

@ -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<UserAgentStylesheets, &'static str> {
fn parse_ua_stylesheet(
shared_lock: &SharedRwLock,
filename: &str,
content: &[u8],
) -> Result<DocumentStyleSheet, &'static str> {
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.

View file

@ -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::<Element>().set_attribute(
&local_name!("rel"),
AttrValue::String("stylesheet".to_owned()),
can_gc,
);
root.upcast::<Node>()
.AppendChild(link_element.upcast::<Node>(), can_gc)
.unwrap();
let details_stylesheet = parse_resource_stylesheet(
link_element
.upcast::<Node>()
.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::<Element>().set_attribute(
&local_name!("name"),
AttrValue::from_atomic("internal-main-summary".to_owned()),
can_gc,
);
root.upcast::<Node>()
.AppendChild(summary.upcast::<Node>(), can_gc)
.unwrap();
let fallback_summary =
HTMLElement::new(local_name!("summary"), None, &document, None, can_gc);
fallback_summary.upcast::<Element>().set_attribute(
&local_name!("name"),
AttrValue::from_atomic("internal-fallback-summary".to_owned()),
can_gc,
);
fallback_summary
.upcast::<Node>()
.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::<Element>()
.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::<Element>()
.set_string_attribute(&local_name!("style"), implicit_summary_style.into(), can_gc);
}
}
impl HTMLDetailsElementMethods<crate::DomTypeHolder> 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());
}
}

View file

@ -66,6 +66,7 @@ pub fn sandbox_access_files_dirs() -> Vec<PathBuf> {
.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 <details> element UA Shadow Tree.
/// It can be empty but then <details> 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<dyn ResourceReaderMethods + Sync + Send> {
Resource::AboutMemoryHTML => {
&include_bytes!("../../../resources/about-memory.html")[..]
},
Resource::DetailsCSS => &include_bytes!("../../../resources/details.css")[..],
}
.to_owned()
}

View file

@ -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 }

View file

@ -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<ServoArc<Stylesheet>, &'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<DocumentStyleSheet, &'static str> {
parse_stylesheet_as_origin(shared_lock, filename, content, Origin::UserAgent)
.map(DocumentStyleSheet)
}
pub fn parse_resource_stylesheet(
shared_lock: &SharedRwLock,
resources: Resource,
) -> Result<ServoArc<Stylesheet>, &'static str> {
let content = &resources::read_bytes(resources.clone());
parse_stylesheet_as_origin(shared_lock, resources.filename(), content, Origin::Author)
}

18
resources/details.css Normal file
View file

@ -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;
}