script/dom/shadowroot/
ua_shadowroot.rs1use std::cell::Ref;
6
7use html5ever::{LocalName, QualName, ns};
8use js::context::JSContext;
9
10use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{
11 ShadowRootMode, SlotAssignmentMode,
12};
13use crate::dom::bindings::conversions::DerivedFrom;
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::document::Document;
17use crate::dom::element::element::Element;
18use crate::dom::element::{CustomElementCreationMode, ElementCreator};
19use crate::dom::node::{Node, NodeTraits};
20use crate::dom::shadowroot::shadowroot::{IsUserAgentWidget, ShadowRoot};
21
22pub(crate) trait UAShadowRoot<ShadowTree> {
23 fn store_for_shadow_tree(&self, cx: &mut JSContext, shadow_root: DomRoot<ShadowRoot>);
24
25 fn borrow_for_shadow_tree(&self) -> Ref<'_, Option<ShadowTree>>;
26
27 fn ensure_shadow_tree(&self, cx: &mut JSContext, element: &Element) -> Ref<'_, ShadowTree> {
28 if self.borrow_for_shadow_tree().is_none() {
29 self.create_shadow_tree(cx, element);
30 }
31
32 Ref::filter_map(self.borrow_for_shadow_tree(), Option::as_ref)
33 .ok()
34 .expect("UA shadow tree was not created")
35 }
36
37 fn should_mark_as_ua_widget(&self) -> bool {
39 true
40 }
41}
42
43pub(crate) trait CreateUAShadowRootForSelf<ShadowTree>:
44 NodeTraits + DerivedFrom<Node>
45{
46 fn create_element_in_ua_shadowroot(
47 &self,
48 cx: &mut JSContext,
49 local_name: LocalName,
50 ) -> DomRoot<Element> {
51 let document = self.owner_document();
52 Element::create(
53 cx,
54 QualName::new(None, ns!(html), local_name),
55 None,
56 &document,
57 ElementCreator::ScriptCreated,
58 CustomElementCreationMode::Asynchronous,
59 None,
60 )
61 }
62
63 fn shadow_tree(&self, cx: &mut JSContext) -> Ref<'_, ShadowTree>;
64}
65
66impl<ShadowTree, E: UAShadowRoot<ShadowTree> + Castable + DerivedFrom<Element> + DerivedFrom<Node>>
67 CreateUAShadowRootForSelf<ShadowTree> for E
68{
69 fn shadow_tree(&self, cx: &mut JSContext) -> Ref<'_, ShadowTree> {
70 self.ensure_shadow_tree(cx, self.upcast())
71 }
72}
73
74pub(crate) trait SpecificShadowTree<ElementType, ShadowTreeHolder> {
75 fn update(&self, cx: &mut JSContext, holder: &ShadowTreeHolder, element: &ElementType);
76
77 fn create_element_in_ua_shadowroot(
78 cx: &mut JSContext,
79 document: &Document,
80 local_name: LocalName,
81 ) -> DomRoot<Element> {
82 Element::create(
83 cx,
84 QualName::new(None, ns!(html), local_name),
85 None,
86 document,
87 ElementCreator::ScriptCreated,
88 CustomElementCreationMode::Asynchronous,
89 None,
90 )
91 }
92}
93
94trait UAShadowRootHelpers<ShadowTree>: UAShadowRoot<ShadowTree> {
95 fn attach_ua_shadow_root(&self, cx: &mut JSContext, element: &Element) -> DomRoot<ShadowRoot>;
96 fn create_shadow_tree(&self, cx: &mut JSContext, element: &Element);
97}
98
99impl<T: ?Sized + UAShadowRoot<ShadowTree>, ShadowTree> UAShadowRootHelpers<ShadowTree> for T {
100 fn attach_ua_shadow_root(&self, cx: &mut JSContext, element: &Element) -> DomRoot<ShadowRoot> {
116 let root = element
117 .attach_shadow(
118 cx,
119 IsUserAgentWidget::Yes,
120 ShadowRootMode::Closed,
121 false,
122 false,
123 false,
124 SlotAssignmentMode::Manual,
125 )
126 .expect("Attaching UA shadow root failed");
127
128 if self.should_mark_as_ua_widget() {
129 root.upcast::<Node>().mark_in_ua_widget();
130 }
131 root
132 }
133
134 fn create_shadow_tree(&self, cx: &mut JSContext, element: &Element) {
135 let root = element
136 .shadow_root()
137 .unwrap_or_else(|| self.attach_ua_shadow_root(cx, element));
138
139 self.store_for_shadow_tree(cx, root);
140
141 element
142 .upcast::<Node>()
143 .dirty(cx.no_gc(), crate::dom::node::NodeDamage::Other);
144 }
145}