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
38pub(crate) trait CreateUAShadowRootForSelf<ShadowTree>:
39 NodeTraits + DerivedFrom<Node>
40{
41 fn create_element_in_ua_shadowroot(
42 &self,
43 cx: &mut JSContext,
44 local_name: LocalName,
45 ) -> DomRoot<Element> {
46 let document = self.owner_document();
47 Element::create(
48 cx,
49 QualName::new(None, ns!(html), local_name),
50 None,
51 &document,
52 ElementCreator::ScriptCreated,
53 CustomElementCreationMode::Asynchronous,
54 None,
55 )
56 }
57
58 fn shadow_tree(&self, cx: &mut JSContext) -> Ref<'_, ShadowTree>;
59}
60
61impl<ShadowTree, E: UAShadowRoot<ShadowTree> + Castable + DerivedFrom<Element> + DerivedFrom<Node>>
62 CreateUAShadowRootForSelf<ShadowTree> for E
63{
64 fn shadow_tree(&self, cx: &mut JSContext) -> Ref<'_, ShadowTree> {
65 self.ensure_shadow_tree(cx, self.upcast())
66 }
67}
68
69pub(crate) trait SpecificShadowTree<ElementType, ShadowTreeHolder> {
70 fn update(&self, cx: &mut JSContext, holder: &ShadowTreeHolder, element: &ElementType);
71
72 fn create_element_in_ua_shadowroot(
73 cx: &mut JSContext,
74 document: &Document,
75 local_name: LocalName,
76 ) -> DomRoot<Element> {
77 Element::create(
78 cx,
79 QualName::new(None, ns!(html), local_name),
80 None,
81 document,
82 ElementCreator::ScriptCreated,
83 CustomElementCreationMode::Asynchronous,
84 None,
85 )
86 }
87}
88
89pub(crate) trait UpdateUAShadowRootForOther<ElementType, ShadowTree>:
90 UAShadowRoot<ShadowTree>
91{
92 fn update_shadow_tree(&self, cx: &mut JSContext, element: &ElementType);
93}
94
95impl<
96 T: UAShadowRoot<ShadowTree>,
97 ShadowTree: SpecificShadowTree<ElementType, T>,
98 ElementType: Castable + DerivedFrom<Element>,
99> UpdateUAShadowRootForOther<ElementType, ShadowTree> for T
100{
101 fn update_shadow_tree(&self, cx: &mut JSContext, element: &ElementType) {
102 self.ensure_shadow_tree(cx, element.upcast())
103 .update(cx, self, element)
104 }
105}
106
107trait UAShadowRootHelpers<ShadowTree>: UAShadowRoot<ShadowTree> {
108 fn attach_ua_shadow_root(cx: &mut JSContext, element: &Element) -> DomRoot<ShadowRoot>;
109 fn create_shadow_tree(&self, cx: &mut JSContext, element: &Element);
110}
111
112impl<T: ?Sized + UAShadowRoot<ShadowTree>, ShadowTree> UAShadowRootHelpers<ShadowTree> for T {
113 fn attach_ua_shadow_root(cx: &mut JSContext, element: &Element) -> DomRoot<ShadowRoot> {
129 let root = element
130 .attach_shadow(
131 cx,
132 IsUserAgentWidget::Yes,
133 ShadowRootMode::Closed,
134 false,
135 false,
136 false,
137 SlotAssignmentMode::Manual,
138 )
139 .expect("Attaching UA shadow root failed");
140
141 root.upcast::<Node>().set_in_ua_widget(true);
142 root
143 }
144
145 fn create_shadow_tree(&self, cx: &mut JSContext, element: &Element) {
146 let root = element
147 .shadow_root()
148 .unwrap_or_else(|| Self::attach_ua_shadow_root(cx, element));
149
150 self.store_for_shadow_tree(cx, root);
151
152 element
153 .upcast::<Node>()
154 .dirty(cx.no_gc(), crate::dom::node::NodeDamage::Other);
155 }
156}