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