script/dom/
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, reflect_dom_object};
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::document::Document;
16use crate::dom::iterators::ShadowIncluding;
17use crate::dom::node::Node;
18use crate::script_runtime::CanGc;
19
20#[dom_struct]
21pub(crate) struct AbstractRange {
22 reflector_: Reflector,
23 start: BoundaryPoint,
24 end: BoundaryPoint,
25}
26
27impl AbstractRange {
28 pub(crate) fn new_inherited(
29 start_container: &Node,
30 start_offset: u32,
31 end_container: &Node,
32 end_offset: u32,
33 ) -> AbstractRange {
34 AbstractRange {
35 reflector_: Reflector::new(),
36 start: BoundaryPoint::new(start_container, start_offset),
37 end: BoundaryPoint::new(end_container, end_offset),
38 }
39 }
40
41 pub(crate) fn new(
42 document: &Document,
43 start_container: &Node,
44 start_offset: u32,
45 end_container: &Node,
46 end_offset: u32,
47 can_gc: CanGc,
48 ) -> DomRoot<AbstractRange> {
49 reflect_dom_object(
50 Box::new(AbstractRange::new_inherited(
51 start_container,
52 start_offset,
53 end_container,
54 end_offset,
55 )),
56 document.window(),
57 can_gc,
58 )
59 }
60
61 pub(crate) fn start(&self) -> &BoundaryPoint {
62 &self.start
63 }
64
65 pub(crate) fn end(&self) -> &BoundaryPoint {
66 &self.end
67 }
68}
69
70impl AbstractRangeMethods<crate::DomTypeHolder> for AbstractRange {
71 fn StartContainer(&self) -> DomRoot<Node> {
73 self.start.node.get()
74 }
75
76 fn StartOffset(&self) -> u32 {
78 self.start.offset.get()
79 }
80
81 fn EndContainer(&self) -> DomRoot<Node> {
83 self.end.node.get()
84 }
85
86 fn EndOffset(&self) -> u32 {
88 self.end.offset.get()
89 }
90
91 fn Collapsed(&self) -> bool {
93 self.start == self.end
95 }
96}
97
98#[derive(DenyPublicFields, JSTraceable, MallocSizeOf)]
100#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
101pub(crate) struct BoundaryPoint {
102 node: MutDom<Node>,
104 offset: Cell<u32>,
106}
107
108impl BoundaryPoint {
109 fn new(node: &Node, offset: u32) -> BoundaryPoint {
110 debug_assert!(!node.is_doctype());
111 BoundaryPoint {
112 node: MutDom::new(node),
113 offset: Cell::new(offset),
114 }
115 }
116
117 pub(crate) fn set(&self, node: &Node, offset: u32) {
118 self.node.set(node);
119 self.set_offset(offset);
120 }
121
122 pub(crate) fn set_offset(&self, offset: u32) {
123 self.offset.set(offset);
124 }
125
126 pub(crate) fn node(&self) -> &MutDom<Node> {
127 &self.node
128 }
129}
130
131impl PartialOrd for BoundaryPoint {
132 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
133 bp_position(
134 &self.node.get(),
135 self.offset.get(),
136 &other.node.get(),
137 other.offset.get(),
138 )
139 }
140}
141
142impl PartialEq for BoundaryPoint {
144 fn eq(&self, other: &Self) -> bool {
145 self.node.get() == other.node.get() && self.offset.get() == other.offset.get()
147 }
148}
149
150pub(crate) fn bp_position(
152 a_node: &Node,
153 a_offset: u32,
154 b_node: &Node,
155 b_offset: u32,
156) -> Option<Ordering> {
157 if std::ptr::eq(a_node, b_node) {
158 return Some(a_offset.cmp(&b_offset));
160 }
161 let position = b_node.CompareDocumentPosition(a_node);
162 if position & NodeConstants::DOCUMENT_POSITION_DISCONNECTED != 0 {
163 None
165 } else if position & NodeConstants::DOCUMENT_POSITION_FOLLOWING != 0 {
166 match bp_position(b_node, b_offset, a_node, a_offset).unwrap() {
168 Ordering::Less => Some(Ordering::Greater),
169 Ordering::Greater => Some(Ordering::Less),
170 Ordering::Equal => unreachable!(),
171 }
172 } else if position & NodeConstants::DOCUMENT_POSITION_CONTAINS != 0 {
173 let mut b_ancestors = b_node.inclusive_ancestors(ShadowIncluding::No);
175 let child = b_ancestors
176 .find(|child| &*child.GetParentNode().unwrap() == a_node)
177 .unwrap();
178 if child.index() < a_offset {
180 Some(Ordering::Greater)
181 } else {
182 Some(Ordering::Less)
184 }
185 } else {
186 Some(Ordering::Less)
188 }
189}