script/dom/range/
abstractrange.rs1use std::cell::Cell;
6use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
7
8use deny_public_fields::DenyPublicFields;
9use dom_struct::dom_struct;
10use script_bindings::reflector::Reflector;
11
12use crate::dom::bindings::codegen::Bindings::AbstractRangeBinding::AbstractRangeMethods;
13use crate::dom::bindings::codegen::Bindings::NodeBinding::{NodeConstants, NodeMethods};
14use crate::dom::bindings::root::{DomRoot, MutDom};
15use crate::dom::iterators::ShadowIncluding;
16use crate::dom::node::Node;
17
18#[dom_struct]
19pub(crate) struct AbstractRange {
20 reflector_: Reflector,
21 start: BoundaryPoint,
22 end: BoundaryPoint,
23}
24
25impl AbstractRange {
26 pub(crate) fn new_inherited(
27 start_container: &Node,
28 start_offset: u32,
29 end_container: &Node,
30 end_offset: u32,
31 ) -> AbstractRange {
32 AbstractRange {
33 reflector_: Reflector::new(),
34 start: BoundaryPoint::new(start_container, start_offset),
35 end: BoundaryPoint::new(end_container, end_offset),
36 }
37 }
38
39 pub(crate) fn start(&self) -> &BoundaryPoint {
40 &self.start
41 }
42
43 pub(crate) fn end(&self) -> &BoundaryPoint {
44 &self.end
45 }
46}
47
48impl AbstractRangeMethods<crate::DomTypeHolder> for AbstractRange {
49 fn StartContainer(&self) -> DomRoot<Node> {
51 self.start.node.get()
52 }
53
54 fn StartOffset(&self) -> u32 {
56 self.start.offset.get()
57 }
58
59 fn EndContainer(&self) -> DomRoot<Node> {
61 self.end.node.get()
62 }
63
64 fn EndOffset(&self) -> u32 {
66 self.end.offset.get()
67 }
68
69 fn Collapsed(&self) -> bool {
71 self.start == self.end
73 }
74}
75
76#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)]
78#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
79pub(crate) struct BoundaryPoint {
80 node: MutDom<Node>,
82 offset: Cell<u32>,
84}
85
86impl BoundaryPoint {
87 fn new(node: &Node, offset: u32) -> BoundaryPoint {
88 debug_assert!(!node.is_doctype());
89 BoundaryPoint {
90 node: MutDom::new(node),
91 offset: Cell::new(offset),
92 }
93 }
94
95 pub(crate) fn set(&self, node: &Node, offset: u32) {
96 self.node.set(node);
97 self.set_offset(offset);
98 }
99
100 pub(crate) fn set_offset(&self, offset: u32) {
101 self.offset.set(offset);
102 }
103
104 pub(crate) fn node(&self) -> &MutDom<Node> {
105 &self.node
106 }
107}
108
109impl PartialOrd for BoundaryPoint {
110 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
111 bp_position(
112 &self.node.get(),
113 self.offset.get(),
114 &other.node.get(),
115 other.offset.get(),
116 )
117 }
118}
119
120impl PartialEq for BoundaryPoint {
122 fn eq(&self, other: &Self) -> bool {
123 self.node.get() == other.node.get() && self.offset.get() == other.offset.get()
125 }
126}
127
128pub(crate) fn bp_position(
130 a_node: &Node,
131 a_offset: u32,
132 b_node: &Node,
133 b_offset: u32,
134) -> Option<Ordering> {
135 if std::ptr::eq(a_node, b_node) {
136 return Some(a_offset.cmp(&b_offset));
138 }
139 let position = b_node.CompareDocumentPosition(a_node);
140 if position & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
141 None
143 } else if position & NodeConstants::DOCUMENT_POSITION_FOLLOWING != 0 {
144 match bp_position(b_node, b_offset, a_node, a_offset).unwrap() {
146 Ordering::Less => Some(Ordering::Greater),
147 Ordering::Greater => Some(Ordering::Less),
148 Ordering::Equal => unreachable!(),
149 }
150 } else if position & NodeConstants::DOCUMENT_POSITION_CONTAINS != 0 {
151 let mut b_ancestors = b_node.inclusive_ancestors(ShadowIncluding::No);
153 let child = b_ancestors
154 .find(|child| &*child.GetParentNode().unwrap() == a_node)
155 .unwrap();
156 if child.index() < a_offset {
158 Some(Ordering::Greater)
159 } else {
160 Some(Ordering::Less)
162 }
163 } else {
164 Some(Ordering::Less)
166 }
167}