1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8
9use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
10use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
11use crate::dom::bindings::codegen::Bindings::SelectionBinding::SelectionMethods;
12use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
13use crate::dom::bindings::inheritance::Castable;
14use crate::dom::bindings::refcounted::Trusted;
15use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
16use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
17use crate::dom::bindings::str::DOMString;
18use crate::dom::document::Document;
19use crate::dom::eventtarget::EventTarget;
20use crate::dom::node::{Node, NodeTraits};
21use crate::dom::range::Range;
22use crate::script_runtime::CanGc;
23
24#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
25enum Direction {
26 Forwards,
27 Backwards,
28 Directionless,
29}
30
31#[dom_struct]
32pub(crate) struct Selection {
33 reflector_: Reflector,
34 document: Dom<Document>,
35 range: MutNullableDom<Range>,
36 direction: Cell<Direction>,
37 task_queued: Cell<bool>,
38}
39
40impl Selection {
41 fn new_inherited(document: &Document) -> Selection {
42 Selection {
43 reflector_: Reflector::new(),
44 document: Dom::from_ref(document),
45 range: MutNullableDom::new(None),
46 direction: Cell::new(Direction::Directionless),
47 task_queued: Cell::new(false),
48 }
49 }
50
51 pub(crate) fn new(document: &Document, can_gc: CanGc) -> DomRoot<Selection> {
52 reflect_dom_object(
53 Box::new(Selection::new_inherited(document)),
54 &*document.global(),
55 can_gc,
56 )
57 }
58
59 fn set_range(&self, range: &Range) {
60 if let Some(existing) = self.range.get() {
64 if &*existing == range {
65 return;
66 }
67 }
68 self.range.set(Some(range));
69 range.associate_selection(self);
70 self.queue_selectionchange_task();
71 }
72
73 fn clear_range(&self) {
74 if let Some(range) = self.range.get() {
77 range.disassociate_selection(self);
78 self.range.set(None);
79 self.queue_selectionchange_task();
80 }
81 }
82
83 pub(crate) fn queue_selectionchange_task(&self) {
84 if self.task_queued.get() {
85 return;
89 }
90 let this = Trusted::new(self);
91 self.document
92 .owner_global()
93 .task_manager()
94 .user_interaction_task_source() .queue(
96 task!(selectionchange_task_steps: move || {
97 let this = this.root();
98 this.task_queued.set(false);
99 this.document.upcast::<EventTarget>().fire_event(atom!("selectionchange"), CanGc::note());
100 })
101 );
102 self.task_queued.set(true);
103 }
104
105 fn is_same_root(&self, node: &Node) -> bool {
106 &*node.GetRootNode(&GetRootNodeOptions::empty()) == self.document.upcast::<Node>()
107 }
108}
109
110impl SelectionMethods<crate::DomTypeHolder> for Selection {
111 fn GetAnchorNode(&self) -> Option<DomRoot<Node>> {
113 if let Some(range) = self.range.get() {
114 match self.direction.get() {
115 Direction::Forwards => Some(range.start_container()),
116 _ => Some(range.end_container()),
117 }
118 } else {
119 None
120 }
121 }
122
123 fn AnchorOffset(&self) -> u32 {
125 if let Some(range) = self.range.get() {
126 match self.direction.get() {
127 Direction::Forwards => range.start_offset(),
128 _ => range.end_offset(),
129 }
130 } else {
131 0
132 }
133 }
134
135 fn GetFocusNode(&self) -> Option<DomRoot<Node>> {
137 if let Some(range) = self.range.get() {
138 match self.direction.get() {
139 Direction::Forwards => Some(range.end_container()),
140 _ => Some(range.start_container()),
141 }
142 } else {
143 None
144 }
145 }
146
147 fn FocusOffset(&self) -> u32 {
149 if let Some(range) = self.range.get() {
150 match self.direction.get() {
151 Direction::Forwards => range.end_offset(),
152 _ => range.start_offset(),
153 }
154 } else {
155 0
156 }
157 }
158
159 fn IsCollapsed(&self) -> bool {
161 if let Some(range) = self.range.get() {
162 range.collapsed()
163 } else {
164 true
165 }
166 }
167
168 fn RangeCount(&self) -> u32 {
170 if self.range.get().is_some() { 1 } else { 0 }
171 }
172
173 fn Type(&self) -> DOMString {
175 if let Some(range) = self.range.get() {
176 if range.collapsed() {
177 DOMString::from("Caret")
178 } else {
179 DOMString::from("Range")
180 }
181 } else {
182 DOMString::from("None")
183 }
184 }
185
186 fn GetRangeAt(&self, index: u32) -> Fallible<DomRoot<Range>> {
188 if index != 0 {
189 Err(Error::IndexSize)
190 } else if let Some(range) = self.range.get() {
191 Ok(DomRoot::from_ref(&range))
192 } else {
193 Err(Error::IndexSize)
194 }
195 }
196
197 fn AddRange(&self, range: &Range) {
199 if !self.is_same_root(&range.start_container()) {
201 return;
202 }
203
204 if self.RangeCount() != 0 {
206 return;
207 }
208
209 self.set_range(range);
211 self.direction.set(Direction::Forwards);
213 }
214
215 fn RemoveRange(&self, range: &Range) -> ErrorResult {
217 if let Some(own_range) = self.range.get() {
218 if &*own_range == range {
219 self.clear_range();
220 return Ok(());
221 }
222 }
223 Err(Error::NotFound)
224 }
225
226 fn RemoveAllRanges(&self) {
228 self.clear_range();
229 }
230
231 fn Empty(&self) {
235 self.clear_range();
236 }
237
238 fn Collapse(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult {
240 if let Some(node) = node {
241 if node.is_doctype() {
242 return Err(Error::InvalidNodeType);
244 }
245 if offset > node.len() {
246 return Err(Error::IndexSize);
248 }
249
250 if !self.is_same_root(node) {
251 return Ok(());
253 }
254
255 let range = Range::new(&self.document, node, offset, node, offset, can_gc);
257
258 self.set_range(&range);
260 self.direction.set(Direction::Forwards);
263 } else {
264 self.clear_range();
266 }
267 Ok(())
268 }
269
270 fn SetPosition(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult {
275 self.Collapse(node, offset, can_gc)
276 }
277
278 fn CollapseToStart(&self, can_gc: CanGc) -> ErrorResult {
280 if let Some(range) = self.range.get() {
281 self.Collapse(
282 Some(&*range.start_container()),
283 range.start_offset(),
284 can_gc,
285 )
286 } else {
287 Err(Error::InvalidState)
288 }
289 }
290
291 fn CollapseToEnd(&self, can_gc: CanGc) -> ErrorResult {
293 if let Some(range) = self.range.get() {
294 self.Collapse(Some(&*range.end_container()), range.end_offset(), can_gc)
295 } else {
296 Err(Error::InvalidState)
297 }
298 }
299
300 fn Extend(&self, node: &Node, offset: u32, can_gc: CanGc) -> ErrorResult {
304 if !self.is_same_root(node) {
305 return Ok(());
307 }
308 if let Some(range) = self.range.get() {
309 if node.is_doctype() {
310 return Err(Error::InvalidNodeType);
312 }
313
314 if offset > node.len() {
315 return Err(Error::IndexSize);
318 }
319
320 if !self.is_same_root(&range.start_container()) {
322 self.set_range(&Range::new(
324 &self.document,
325 node,
326 offset,
327 node,
328 offset,
329 can_gc,
330 ));
331 self.direction.set(Direction::Forwards);
332 } else {
333 let old_anchor_node = &*self.GetAnchorNode().unwrap(); let old_anchor_offset = self.AnchorOffset();
335 let is_old_anchor_before_or_equal = {
336 if old_anchor_node == node {
337 old_anchor_offset <= offset
338 } else {
339 old_anchor_node.is_before(node)
340 }
341 };
342 if is_old_anchor_before_or_equal {
343 self.set_range(&Range::new(
345 &self.document,
346 old_anchor_node,
347 old_anchor_offset,
348 node,
349 offset,
350 can_gc,
351 ));
352 self.direction.set(Direction::Forwards);
353 } else {
354 self.set_range(&Range::new(
356 &self.document,
357 node,
358 offset,
359 old_anchor_node,
360 old_anchor_offset,
361 can_gc,
362 ));
363 self.direction.set(Direction::Backwards);
364 }
365 };
366 } else {
367 return Err(Error::InvalidState);
369 }
370 Ok(())
371 }
372
373 fn SetBaseAndExtent(
375 &self,
376 anchor_node: &Node,
377 anchor_offset: u32,
378 focus_node: &Node,
379 focus_offset: u32,
380 can_gc: CanGc,
381 ) -> ErrorResult {
382 if anchor_node.is_doctype() || focus_node.is_doctype() {
384 return Err(Error::InvalidNodeType);
386 }
387
388 if anchor_offset > anchor_node.len() || focus_offset > focus_node.len() {
389 return Err(Error::IndexSize);
390 }
391
392 if !self.is_same_root(anchor_node) || !self.is_same_root(focus_node) {
394 return Ok(());
395 }
396
397 let is_focus_before_anchor = {
399 if anchor_node == focus_node {
400 focus_offset < anchor_offset
401 } else {
402 focus_node.is_before(anchor_node)
403 }
404 };
405 if is_focus_before_anchor {
406 self.set_range(&Range::new(
407 &self.document,
408 focus_node,
409 focus_offset,
410 anchor_node,
411 anchor_offset,
412 can_gc,
413 ));
414 self.direction.set(Direction::Backwards);
415 } else {
416 self.set_range(&Range::new(
417 &self.document,
418 anchor_node,
419 anchor_offset,
420 focus_node,
421 focus_offset,
422 can_gc,
423 ));
424 self.direction.set(Direction::Forwards);
425 }
426 Ok(())
427 }
428
429 fn SelectAllChildren(&self, node: &Node, can_gc: CanGc) -> ErrorResult {
431 if node.is_doctype() {
432 return Err(Error::InvalidNodeType);
434 }
435 if !self.is_same_root(node) {
436 return Ok(());
437 }
438
439 self.set_range(&Range::new(
443 &self.document,
444 node,
445 0,
446 node,
447 node.children_count(),
448 can_gc,
449 ));
450
451 self.direction.set(Direction::Forwards);
452 Ok(())
453 }
454
455 fn DeleteFromDocument(&self) -> ErrorResult {
457 if let Some(range) = self.range.get() {
458 return range.DeleteContents();
461 }
462 Ok(())
463 }
464
465 fn ContainsNode(&self, node: &Node, allow_partial_containment: bool) -> bool {
467 if !self.is_same_root(node) {
470 return false;
471 }
472 if let Some(range) = self.range.get() {
473 let start_node = &*range.start_container();
474 if !self.is_same_root(start_node) {
475 return false;
477 }
478 if allow_partial_containment {
479 if node.is_before(start_node) {
481 return false;
482 }
483 let end_node = &*range.end_container();
484 if end_node.is_before(node) {
485 return false;
486 }
487 if node == start_node {
488 return range.start_offset() < node.len();
489 }
490 if node == end_node {
491 return range.end_offset() > 0;
492 }
493 true
494 } else {
495 if node.is_before(start_node) {
496 return false;
497 }
498 let end_node = &*range.end_container();
499 if end_node.is_before(node) {
500 return false;
501 }
502 if node == start_node {
503 return range.start_offset() == 0;
504 }
505 if node == end_node {
506 return range.end_offset() == node.len();
507 }
508 true
509 }
510 } else {
511 false
513 }
514 }
515
516 fn Stringifier(&self) -> DOMString {
518 if let Some(range) = self.range.get() {
523 range.Stringifier()
524 } else {
525 DOMString::from("")
526 }
527 }
528}