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