1use std::cell::Ref;
8use std::cmp::Ordering;
9use std::fmt::Debug;
10use std::rc::Rc;
11
12use html5ever::{LocalName, Namespace, Prefix};
13use script_bindings::callback::ExceptionHandling;
14use script_bindings::codegen::GenericBindings::AttrBinding::AttrMethods;
15use script_bindings::codegen::GenericBindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
16use script_bindings::root::Dom;
17use script_bindings::script_runtime::CanGc;
18use script_bindings::str::DOMString;
19use style::Atom;
20use style::dom::OpaqueNode;
21
22use crate::dom::attr::Attr;
23use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
24use crate::dom::bindings::error::{Error, Fallible};
25use crate::dom::bindings::inheritance::Castable;
26use crate::dom::bindings::root::DomRoot;
27use crate::dom::comment::Comment;
28use crate::dom::document::Document;
29use crate::dom::element::Element;
30use crate::dom::node::{Node, NodeTraits, PrecedingNodeIterator, ShadowIncluding};
31use crate::dom::processinginstruction::ProcessingInstruction;
32use crate::dom::text::Text;
33
34pub(crate) type Value = xpath::Value<XPathWrapper<DomRoot<Node>>>;
35
36#[derive(Clone, Debug, Eq, PartialEq)]
39pub(crate) struct XPathWrapper<T>(pub T);
40
41pub(crate) struct XPathImplementation;
42
43impl xpath::Dom for XPathImplementation {
44 type Node = XPathWrapper<DomRoot<Node>>;
45 type NamespaceResolver = XPathWrapper<Rc<XPathNSResolver>>;
46}
47
48impl xpath::Node for XPathWrapper<DomRoot<Node>> {
49 type ProcessingInstruction = XPathWrapper<DomRoot<ProcessingInstruction>>;
50 type Document = XPathWrapper<DomRoot<Document>>;
51 type Attribute = XPathWrapper<DomRoot<Attr>>;
52 type Element = XPathWrapper<DomRoot<Element>>;
53 type Opaque = OpaqueNode;
55
56 fn is_comment(&self) -> bool {
57 self.0.is::<Comment>()
58 }
59
60 fn is_text(&self) -> bool {
61 self.0.is::<Text>()
62 }
63
64 fn text_content(&self) -> String {
65 self.0.GetTextContent().unwrap_or_default().into()
66 }
67
68 fn language(&self) -> Option<String> {
69 self.0.get_lang()
70 }
71
72 fn parent(&self) -> Option<Self> {
73 if let Some(attribute) = self.0.downcast::<Attr>() {
76 return attribute
77 .GetOwnerElement()
78 .map(DomRoot::upcast)
79 .map(XPathWrapper);
80 }
81
82 self.0.GetParentNode().map(XPathWrapper)
83 }
84
85 fn children(&self) -> impl Iterator<Item = Self> {
86 self.0.children().map(XPathWrapper)
87 }
88
89 fn compare_tree_order(&self, other: &Self) -> Ordering {
90 if self == other {
91 Ordering::Equal
92 } else if self.0.is_before(&other.0) {
93 Ordering::Less
94 } else {
95 Ordering::Greater
96 }
97 }
98
99 fn traverse_preorder(&self) -> impl Iterator<Item = Self> {
100 self.0
101 .traverse_preorder(ShadowIncluding::No)
102 .map(XPathWrapper)
103 }
104
105 fn inclusive_ancestors(&self) -> impl Iterator<Item = Self> {
106 self.0
107 .inclusive_ancestors(ShadowIncluding::No)
108 .map(XPathWrapper)
109 }
110
111 fn preceding_nodes(&self) -> impl Iterator<Item = Self> {
112 PrecedingNodeIteratorWithoutAncestors::new(&self.0).map(XPathWrapper)
113 }
114
115 fn following_nodes(&self) -> impl Iterator<Item = Self> {
116 let owner_document = self.0.owner_document();
117 let next_non_descendant_node = self
118 .0
119 .following_nodes(owner_document.upcast())
120 .next_skipping_children();
121 let following_nodes = next_non_descendant_node
122 .clone()
123 .map(|node| node.following_nodes(owner_document.upcast()))
124 .into_iter()
125 .flatten();
126 next_non_descendant_node
127 .into_iter()
128 .chain(following_nodes)
129 .map(XPathWrapper)
130 }
131
132 fn preceding_siblings(&self) -> impl Iterator<Item = Self> {
133 self.0.preceding_siblings().map(XPathWrapper)
134 }
135
136 fn following_siblings(&self) -> impl Iterator<Item = Self> {
137 self.0.following_siblings().map(XPathWrapper)
138 }
139
140 fn owner_document(&self) -> Self::Document {
141 XPathWrapper(self.0.owner_document())
142 }
143
144 fn to_opaque(&self) -> Self::Opaque {
145 self.0.to_opaque()
146 }
147
148 fn as_processing_instruction(&self) -> Option<Self::ProcessingInstruction> {
149 self.0
150 .downcast::<ProcessingInstruction>()
151 .map(DomRoot::from_ref)
152 .map(XPathWrapper)
153 }
154
155 fn as_attribute(&self) -> Option<Self::Attribute> {
156 self.0
157 .downcast::<Attr>()
158 .map(DomRoot::from_ref)
159 .map(XPathWrapper)
160 }
161
162 fn as_element(&self) -> Option<Self::Element> {
163 self.0
164 .downcast::<Element>()
165 .map(DomRoot::from_ref)
166 .map(XPathWrapper)
167 }
168
169 fn get_root_node(&self) -> Self {
170 XPathWrapper(self.0.GetRootNode(&GetRootNodeOptions::empty()))
171 }
172}
173
174impl xpath::Document for XPathWrapper<DomRoot<Document>> {
175 type Node = XPathWrapper<DomRoot<Node>>;
176
177 fn get_elements_with_id(
178 &self,
179 id: &str,
180 ) -> impl Iterator<Item = XPathWrapper<DomRoot<Element>>> {
181 struct ElementIterator<'a> {
182 elements: Ref<'a, [Dom<Element>]>,
183 position: usize,
184 }
185
186 impl<'a> Iterator for ElementIterator<'a> {
187 type Item = XPathWrapper<DomRoot<Element>>;
188
189 fn next(&mut self) -> Option<Self::Item> {
190 let element = self.elements.get(self.position)?;
191 self.position += 1;
192 Some(element.as_rooted().into())
193 }
194 }
195
196 ElementIterator {
197 elements: self.0.get_elements_with_id(&Atom::from(id)),
198 position: 0,
199 }
200 }
201}
202
203impl xpath::Element for XPathWrapper<DomRoot<Element>> {
204 type Node = XPathWrapper<DomRoot<Node>>;
205 type Attribute = XPathWrapper<DomRoot<Attr>>;
206
207 fn as_node(&self) -> Self::Node {
208 DomRoot::from_ref(self.0.upcast::<Node>()).into()
209 }
210
211 fn attributes(&self) -> impl Iterator<Item = Self::Attribute> {
212 struct AttributeIterator<'a> {
213 attributes: Ref<'a, [Dom<Attr>]>,
214 position: usize,
215 }
216
217 impl<'a> Iterator for AttributeIterator<'a> {
218 type Item = XPathWrapper<DomRoot<Attr>>;
219
220 fn next(&mut self) -> Option<Self::Item> {
221 let attribute = self.attributes.get(self.position)?;
222 self.position += 1;
223 Some(attribute.as_rooted().into())
224 }
225
226 fn size_hint(&self) -> (usize, Option<usize>) {
227 let exact_length = self.attributes.len() - self.position;
228 (exact_length, Some(exact_length))
229 }
230 }
231
232 AttributeIterator {
233 attributes: self.0.attrs(),
234 position: 0,
235 }
236 }
237
238 fn prefix(&self) -> Option<Prefix> {
239 self.0.prefix().clone()
240 }
241
242 fn namespace(&self) -> Namespace {
243 self.0.namespace().clone()
244 }
245
246 fn local_name(&self) -> LocalName {
247 self.0.local_name().clone()
248 }
249
250 fn is_html_element_in_html_document(&self) -> bool {
251 self.0.is_html_element() && self.0.owner_document().is_html_document()
252 }
253}
254
255impl xpath::Attribute for XPathWrapper<DomRoot<Attr>> {
256 type Node = XPathWrapper<DomRoot<Node>>;
257
258 fn as_node(&self) -> Self::Node {
259 XPathWrapper(DomRoot::from_ref(self.0.upcast::<Node>()))
260 }
261
262 fn prefix(&self) -> Option<Prefix> {
263 self.0.prefix().cloned()
264 }
265
266 fn namespace(&self) -> Namespace {
267 self.0.namespace().clone()
268 }
269
270 fn local_name(&self) -> LocalName {
271 self.0.local_name().clone()
272 }
273}
274
275impl xpath::NamespaceResolver for XPathWrapper<Rc<XPathNSResolver>> {
276 fn resolve_namespace_prefix(&self, prefix: &str) -> Option<String> {
277 self.0
278 .LookupNamespaceURI__(
279 Some(DOMString::from(prefix)),
280 ExceptionHandling::Report,
281 CanGc::note(),
282 )
283 .ok()
284 .flatten()
285 .map(String::from)
286 }
287}
288
289impl xpath::ProcessingInstruction for XPathWrapper<DomRoot<ProcessingInstruction>> {
290 fn target(&self) -> String {
291 self.0.target().to_owned().into()
292 }
293}
294
295impl<T> From<T> for XPathWrapper<T> {
296 fn from(value: T) -> Self {
297 Self(value)
298 }
299}
300
301impl<T> XPathWrapper<T> {
302 pub(crate) fn into_inner(self) -> T {
303 self.0
304 }
305}
306
307pub(crate) fn parse_expression(
308 expression: &str,
309 resolver: Option<Rc<XPathNSResolver>>,
310 is_in_html_document: bool,
311) -> Fallible<xpath::Expression> {
312 xpath::parse(expression, resolver.map(XPathWrapper), is_in_html_document).map_err(|error| {
313 match error {
314 xpath::ParserError::FailedToResolveNamespacePrefix => Error::Namespace,
315 _ => Error::Syntax(Some(format!("Failed to parse XPath expression: {error:?}"))),
316 }
317 })
318}
319
320enum PrecedingNodeIteratorWithoutAncestors {
321 Done,
322 NotDone {
323 current: DomRoot<Node>,
324 subtree_iterator: Option<PrecedingNodeIterator>,
327 },
328}
329
330fn previous_non_ancestor_node(node: &Node) -> Option<DomRoot<Node>> {
332 let mut current = DomRoot::from_ref(node);
333 loop {
334 if let Some(previous_sibling) = current.GetPreviousSibling() {
335 return Some(previous_sibling);
336 }
337
338 current = current.GetParentNode()?;
339 }
340}
341
342impl PrecedingNodeIteratorWithoutAncestors {
343 fn new(node: &Node) -> Self {
344 let Some(current) = previous_non_ancestor_node(node) else {
345 return Self::Done;
346 };
347
348 Self::NotDone {
349 subtree_iterator: current
350 .descending_last_children()
351 .last()
352 .map(|node| node.preceding_nodes(¤t)),
353 current,
354 }
355 }
356}
357
358impl Iterator for PrecedingNodeIteratorWithoutAncestors {
359 type Item = DomRoot<Node>;
360
361 fn next(&mut self) -> Option<Self::Item> {
362 let Self::NotDone {
363 current,
364 subtree_iterator,
365 } = self
366 else {
367 return None;
368 };
369
370 if let Some(next_node) = subtree_iterator
371 .as_mut()
372 .and_then(|iterator| iterator.next())
373 {
374 return Some(next_node);
375 }
376
377 let Some(next_subtree) = previous_non_ancestor_node(current) else {
380 *self = Self::Done;
381 return None;
382 };
383
384 *current = next_subtree;
385 *subtree_iterator = current
386 .descending_last_children()
387 .last()
388 .map(|node| node.preceding_nodes(current));
389
390 self.next()
391 }
392}