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 pub(crate) fn active_range(&self) -> Option<DomRoot<Range>> {
111 self.range.get()
113 }
114}
115
116impl SelectionMethods<crate::DomTypeHolder> for Selection {
117 fn GetAnchorNode(&self) -> Option<DomRoot<Node>> {
119 if let Some(range) = self.range.get() {
120 match self.direction.get() {
121 Direction::Forwards => Some(range.start_container()),
122 _ => Some(range.end_container()),
123 }
124 } else {
125 None
126 }
127 }
128
129 fn AnchorOffset(&self) -> u32 {
131 if let Some(range) = self.range.get() {
132 match self.direction.get() {
133 Direction::Forwards => range.start_offset(),
134 _ => range.end_offset(),
135 }
136 } else {
137 0
138 }
139 }
140
141 fn GetFocusNode(&self) -> Option<DomRoot<Node>> {
143 if let Some(range) = self.range.get() {
144 match self.direction.get() {
145 Direction::Forwards => Some(range.end_container()),
146 _ => Some(range.start_container()),
147 }
148 } else {
149 None
150 }
151 }
152
153 fn FocusOffset(&self) -> u32 {
155 if let Some(range) = self.range.get() {
156 match self.direction.get() {
157 Direction::Forwards => range.end_offset(),
158 _ => range.start_offset(),
159 }
160 } else {
161 0
162 }
163 }
164
165 fn IsCollapsed(&self) -> bool {
167 if let Some(range) = self.range.get() {
168 range.collapsed()
169 } else {
170 true
171 }
172 }
173
174 fn RangeCount(&self) -> u32 {
176 if self.range.get().is_some() { 1 } else { 0 }
177 }
178
179 fn Type(&self) -> DOMString {
181 if let Some(range) = self.range.get() {
182 if range.collapsed() {
183 DOMString::from("Caret")
184 } else {
185 DOMString::from("Range")
186 }
187 } else {
188 DOMString::from("None")
189 }
190 }
191
192 fn GetRangeAt(&self, index: u32) -> Fallible<DomRoot<Range>> {
194 if index != 0 {
195 Err(Error::IndexSize(None))
196 } else if let Some(range) = self.range.get() {
197 Ok(DomRoot::from_ref(&range))
198 } else {
199 Err(Error::IndexSize(None))
200 }
201 }
202
203 fn AddRange(&self, range: &Range) {
205 if !self.is_same_root(&range.start_container()) {
207 return;
208 }
209
210 if self.RangeCount() != 0 {
212 return;
213 }
214
215 self.set_range(range);
217 self.direction.set(Direction::Forwards);
219 }
220
221 fn RemoveRange(&self, range: &Range) -> ErrorResult {
223 if let Some(own_range) = self.range.get() {
224 if &*own_range == range {
225 self.clear_range();
226 return Ok(());
227 }
228 }
229 Err(Error::NotFound(None))
230 }
231
232 fn RemoveAllRanges(&self) {
234 self.clear_range();
235 }
236
237 fn Empty(&self) {
241 self.clear_range();
242 }
243
244 fn Collapse(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult {
246 if let Some(node) = node {
247 if node.is_doctype() {
248 return Err(Error::InvalidNodeType(None));
250 }
251 if offset > node.len() {
252 return Err(Error::IndexSize(None));
254 }
255
256 if !self.is_same_root(node) {
257 return Ok(());
259 }
260
261 let range = Range::new(&self.document, node, offset, node, offset, can_gc);
263
264 self.set_range(&range);
266 self.direction.set(Direction::Forwards);
269 } else {
270 self.clear_range();
272 }
273 Ok(())
274 }
275
276 fn SetPosition(&self, node: Option<&Node>, offset: u32, can_gc: CanGc) -> ErrorResult {
281 self.Collapse(node, offset, can_gc)
282 }
283
284 fn CollapseToStart(&self, can_gc: CanGc) -> ErrorResult {
286 if let Some(range) = self.range.get() {
287 self.Collapse(
288 Some(&*range.start_container()),
289 range.start_offset(),
290 can_gc,
291 )
292 } else {
293 Err(Error::InvalidState(None))
294 }
295 }
296
297 fn CollapseToEnd(&self, can_gc: CanGc) -> ErrorResult {
299 if let Some(range) = self.range.get() {
300 self.Collapse(Some(&*range.end_container()), range.end_offset(), can_gc)
301 } else {
302 Err(Error::InvalidState(None))
303 }
304 }
305
306 fn Extend(&self, node: &Node, offset: u32, can_gc: CanGc) -> ErrorResult {
310 if !self.is_same_root(node) {
311 return Ok(());
313 }
314 if let Some(range) = self.range.get() {
315 if node.is_doctype() {
316 return Err(Error::InvalidNodeType(None));
318 }
319
320 if offset > node.len() {
321 return Err(Error::IndexSize(None));
324 }
325
326 if !self.is_same_root(&range.start_container()) {
328 self.set_range(&Range::new(
330 &self.document,
331 node,
332 offset,
333 node,
334 offset,
335 can_gc,
336 ));
337 self.direction.set(Direction::Forwards);
338 } else {
339 let old_anchor_node = &*self.GetAnchorNode().unwrap(); let old_anchor_offset = self.AnchorOffset();
341 let is_old_anchor_before_or_equal = {
342 if old_anchor_node == node {
343 old_anchor_offset <= offset
344 } else {
345 old_anchor_node.is_before(node)
346 }
347 };
348 if is_old_anchor_before_or_equal {
349 self.set_range(&Range::new(
351 &self.document,
352 old_anchor_node,
353 old_anchor_offset,
354 node,
355 offset,
356 can_gc,
357 ));
358 self.direction.set(Direction::Forwards);
359 } else {
360 self.set_range(&Range::new(
362 &self.document,
363 node,
364 offset,
365 old_anchor_node,
366 old_anchor_offset,
367 can_gc,
368 ));
369 self.direction.set(Direction::Backwards);
370 }
371 };
372 } else {
373 return Err(Error::InvalidState(None));
375 }
376 Ok(())
377 }
378
379 fn SetBaseAndExtent(
381 &self,
382 anchor_node: &Node,
383 anchor_offset: u32,
384 focus_node: &Node,
385 focus_offset: u32,
386 can_gc: CanGc,
387 ) -> ErrorResult {
388 if anchor_node.is_doctype() || focus_node.is_doctype() {
390 return Err(Error::InvalidNodeType(None));
392 }
393
394 if anchor_offset > anchor_node.len() || focus_offset > focus_node.len() {
395 return Err(Error::IndexSize(None));
396 }
397
398 if !self.is_same_root(anchor_node) || !self.is_same_root(focus_node) {
400 return Ok(());
401 }
402
403 let is_focus_before_anchor = {
405 if anchor_node == focus_node {
406 focus_offset < anchor_offset
407 } else {
408 focus_node.is_before(anchor_node)
409 }
410 };
411 if is_focus_before_anchor {
412 self.set_range(&Range::new(
413 &self.document,
414 focus_node,
415 focus_offset,
416 anchor_node,
417 anchor_offset,
418 can_gc,
419 ));
420 self.direction.set(Direction::Backwards);
421 } else {
422 self.set_range(&Range::new(
423 &self.document,
424 anchor_node,
425 anchor_offset,
426 focus_node,
427 focus_offset,
428 can_gc,
429 ));
430 self.direction.set(Direction::Forwards);
431 }
432 Ok(())
433 }
434
435 fn SelectAllChildren(&self, node: &Node, can_gc: CanGc) -> ErrorResult {
437 if node.is_doctype() {
438 return Err(Error::InvalidNodeType(None));
440 }
441 if !self.is_same_root(node) {
442 return Ok(());
443 }
444
445 self.set_range(&Range::new(
449 &self.document,
450 node,
451 0,
452 node,
453 node.children_count(),
454 can_gc,
455 ));
456
457 self.direction.set(Direction::Forwards);
458 Ok(())
459 }
460
461 fn DeleteFromDocument(&self) -> ErrorResult {
463 if let Some(range) = self.range.get() {
464 return range.DeleteContents();
467 }
468 Ok(())
469 }
470
471 fn ContainsNode(&self, node: &Node, allow_partial_containment: bool) -> bool {
473 if !self.is_same_root(node) {
476 return false;
477 }
478 if let Some(range) = self.range.get() {
479 let start_node = &*range.start_container();
480 if !self.is_same_root(start_node) {
481 return false;
483 }
484 if allow_partial_containment {
485 if node.is_before(start_node) {
487 return false;
488 }
489 let end_node = &*range.end_container();
490 if end_node.is_before(node) {
491 return false;
492 }
493 if node == start_node {
494 return range.start_offset() < node.len();
495 }
496 if node == end_node {
497 return range.end_offset() > 0;
498 }
499 true
500 } else {
501 if node.is_before(start_node) {
502 return false;
503 }
504 let end_node = &*range.end_container();
505 if end_node.is_before(node) {
506 return false;
507 }
508 if node == start_node {
509 return range.start_offset() == 0;
510 }
511 if node == end_node {
512 return range.end_offset() == node.len();
513 }
514 true
515 }
516 } else {
517 false
519 }
520 }
521
522 fn Stringifier(&self) -> DOMString {
524 if let Some(range) = self.range.get() {
529 range.Stringifier()
530 } else {
531 DOMString::from("")
532 }
533 }
534}