1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::context::JSContext;
9use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
10
11use crate::dom::bindings::codegen::Bindings::NodeBinding::{GetRootNodeOptions, NodeMethods};
12use crate::dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
13use crate::dom::bindings::codegen::Bindings::SelectionBinding::SelectionMethods;
14use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
15use crate::dom::bindings::inheritance::Castable;
16use crate::dom::bindings::refcounted::Trusted;
17use crate::dom::bindings::reflector::DomGlobal;
18use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
19use crate::dom::bindings::str::DOMString;
20use crate::dom::document::Document;
21use crate::dom::eventtarget::EventTarget;
22use crate::dom::node::{Node, NodeTraits};
23use crate::dom::range::Range;
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 has_scheduled_selectionchange_event: Cell<bool>,
40}
41
42impl Selection {
43 fn new_inherited(document: &Document) -> Selection {
44 Selection {
45 reflector_: Reflector::new(),
46 document: Dom::from_ref(document),
47 range: MutNullableDom::new(None),
48 direction: Cell::new(Direction::Directionless),
49 has_scheduled_selectionchange_event: Cell::new(false),
50 }
51 }
52
53 pub(crate) fn new(cx: &mut JSContext, document: &Document) -> DomRoot<Selection> {
54 reflect_dom_object_with_cx(
55 Box::new(Selection::new_inherited(document)),
56 &*document.global(),
57 cx,
58 )
59 }
60
61 fn set_range(&self, range: &Range) {
62 if let Some(existing) = self.range.get() &&
66 &*existing == range
67 {
68 return;
69 }
70 self.range.set(Some(range));
71 range.associate_selection(self);
72 self.queue_selectionchange_task();
73 }
74
75 fn clear_range(&self) {
76 if let Some(range) = self.range.get() {
79 range.disassociate_selection(self);
80 self.range.set(None);
81 self.queue_selectionchange_task();
82 }
83 }
84
85 pub(crate) fn queue_selectionchange_task(&self) {
87 self.document.clear_command_overrides();
93
94 if self.has_scheduled_selectionchange_event.get() {
96 return;
97 }
98 self.has_scheduled_selectionchange_event.set(true);
100 let this = Trusted::new(self);
102 self.document
103 .owner_global()
104 .task_manager()
105 .user_interaction_task_source() .queue(
107 task!(selectionchange_task_steps: move |cx| {
109 let this = this.root();
110 this.has_scheduled_selectionchange_event.set(false);
112 this.document.upcast::<EventTarget>().fire_event(cx, atom!("selectionchange"));
119 }),
120 );
121 }
122
123 fn is_same_root(&self, node: &Node) -> bool {
124 &*node.GetRootNode(&GetRootNodeOptions::empty()) == self.document.upcast::<Node>()
125 }
126
127 pub(crate) fn active_range(&self) -> Option<DomRoot<Range>> {
129 self.range.get()
131 }
132
133 pub(crate) fn collapse_current_range(&self, node: &Node, offset: u32) {
134 let range = self.range.get().expect("Must always have a range");
135 range.set_start(node, offset);
136 range.set_end(node, offset);
137 }
138
139 pub(crate) fn extend_current_range(&self, node: &Node, offset: u32) {
140 let range = self.range.get().expect("Must always have a range");
141 assert!(range.collapsed(), "Must only extend after collapsing");
142
143 let anchor_node = range.start_container();
144 if (*anchor_node == *node && range.start_offset() < offset) || anchor_node.is_before(node) {
145 range.set_end(node, offset);
146 self.direction.set(Direction::Forwards);
147 } else {
148 range.set_start(node, offset);
149 self.direction.set(Direction::Backwards);
150 }
151 }
152}
153
154impl SelectionMethods<crate::DomTypeHolder> for Selection {
155 fn GetAnchorNode(&self) -> Option<DomRoot<Node>> {
157 if let Some(range) = self.range.get() {
158 match self.direction.get() {
159 Direction::Forwards => Some(range.start_container()),
160 _ => Some(range.end_container()),
161 }
162 } else {
163 None
164 }
165 }
166
167 fn AnchorOffset(&self) -> u32 {
169 if let Some(range) = self.range.get() {
170 match self.direction.get() {
171 Direction::Forwards => range.start_offset(),
172 _ => range.end_offset(),
173 }
174 } else {
175 0
176 }
177 }
178
179 fn GetFocusNode(&self) -> Option<DomRoot<Node>> {
181 if let Some(range) = self.range.get() {
182 match self.direction.get() {
183 Direction::Forwards => Some(range.end_container()),
184 _ => Some(range.start_container()),
185 }
186 } else {
187 None
188 }
189 }
190
191 fn FocusOffset(&self) -> u32 {
193 if let Some(range) = self.range.get() {
194 match self.direction.get() {
195 Direction::Forwards => range.end_offset(),
196 _ => range.start_offset(),
197 }
198 } else {
199 0
200 }
201 }
202
203 fn IsCollapsed(&self) -> bool {
205 if let Some(range) = self.range.get() {
206 range.collapsed()
207 } else {
208 true
209 }
210 }
211
212 fn RangeCount(&self) -> u32 {
214 if self.range.get().is_some() { 1 } else { 0 }
215 }
216
217 fn Type(&self) -> DOMString {
219 if let Some(range) = self.range.get() {
220 if range.collapsed() {
221 DOMString::from("Caret")
222 } else {
223 DOMString::from("Range")
224 }
225 } else {
226 DOMString::from("None")
227 }
228 }
229
230 fn GetRangeAt(&self, index: u32) -> Fallible<DomRoot<Range>> {
232 if index != 0 {
233 Err(Error::IndexSize(None))
234 } else if let Some(range) = self.range.get() {
235 Ok(DomRoot::from_ref(&range))
236 } else {
237 Err(Error::IndexSize(None))
238 }
239 }
240
241 fn AddRange(&self, range: &Range) {
243 if !self.is_same_root(&range.start_container()) {
245 return;
246 }
247
248 if self.RangeCount() != 0 {
250 return;
251 }
252
253 self.set_range(range);
255 self.direction.set(Direction::Forwards);
257 }
258
259 fn RemoveRange(&self, range: &Range) -> ErrorResult {
261 if let Some(own_range) = self.range.get() &&
262 &*own_range == range
263 {
264 self.clear_range();
265 return Ok(());
266 }
267 Err(Error::NotFound(None))
268 }
269
270 fn RemoveAllRanges(&self) {
272 self.clear_range();
273 }
274
275 fn Empty(&self) {
279 self.clear_range();
280 }
281
282 fn Collapse(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
284 if let Some(node) = node {
285 if node.is_doctype() {
286 return Err(Error::InvalidNodeType(None));
288 }
289 if offset > node.len() {
290 return Err(Error::IndexSize(None));
292 }
293
294 if !self.is_same_root(node) {
295 return Ok(());
297 }
298
299 let range = Range::new(cx, &self.document, node, offset, node, offset);
301
302 self.set_range(&range);
304 self.direction.set(Direction::Forwards);
307 } else {
308 self.clear_range();
310 }
311 Ok(())
312 }
313
314 fn SetPosition(&self, cx: &mut JSContext, node: Option<&Node>, offset: u32) -> ErrorResult {
319 self.Collapse(cx, node, offset)
320 }
321
322 fn CollapseToStart(&self, cx: &mut JSContext) -> ErrorResult {
324 if let Some(range) = self.range.get() {
325 self.Collapse(cx, Some(&*range.start_container()), range.start_offset())
326 } else {
327 Err(Error::InvalidState(None))
328 }
329 }
330
331 fn CollapseToEnd(&self, cx: &mut JSContext) -> ErrorResult {
333 if let Some(range) = self.range.get() {
334 self.Collapse(cx, Some(&*range.end_container()), range.end_offset())
335 } else {
336 Err(Error::InvalidState(None))
337 }
338 }
339
340 fn Extend(&self, cx: &mut JSContext, node: &Node, offset: u32) -> ErrorResult {
344 if !self.is_same_root(node) {
345 return Ok(());
347 }
348 if let Some(range) = self.range.get() {
349 if node.is_doctype() {
350 return Err(Error::InvalidNodeType(None));
352 }
353
354 if offset > node.len() {
355 return Err(Error::IndexSize(None));
358 }
359
360 if !self.is_same_root(&range.start_container()) {
362 self.set_range(&Range::new(cx, &self.document, node, offset, node, offset));
364 self.direction.set(Direction::Forwards);
365 } else {
366 let old_anchor_node = &*self.GetAnchorNode().unwrap(); let old_anchor_offset = self.AnchorOffset();
368 let is_old_anchor_before_or_equal = {
369 if old_anchor_node == node {
370 old_anchor_offset <= offset
371 } else {
372 old_anchor_node.is_before(node)
373 }
374 };
375 if is_old_anchor_before_or_equal {
376 self.set_range(&Range::new(
378 cx,
379 &self.document,
380 old_anchor_node,
381 old_anchor_offset,
382 node,
383 offset,
384 ));
385 self.direction.set(Direction::Forwards);
386 } else {
387 self.set_range(&Range::new(
389 cx,
390 &self.document,
391 node,
392 offset,
393 old_anchor_node,
394 old_anchor_offset,
395 ));
396 self.direction.set(Direction::Backwards);
397 }
398 };
399 } else {
400 return Err(Error::InvalidState(None));
402 }
403 Ok(())
404 }
405
406 fn SetBaseAndExtent(
408 &self,
409 cx: &mut JSContext,
410 anchor_node: &Node,
411 anchor_offset: u32,
412 focus_node: &Node,
413 focus_offset: u32,
414 ) -> ErrorResult {
415 if anchor_node.is_doctype() || focus_node.is_doctype() {
417 return Err(Error::InvalidNodeType(None));
419 }
420
421 if anchor_offset > anchor_node.len() || focus_offset > focus_node.len() {
422 return Err(Error::IndexSize(None));
423 }
424
425 if !self.is_same_root(anchor_node) || !self.is_same_root(focus_node) {
427 return Ok(());
428 }
429
430 let is_focus_before_anchor = {
432 if anchor_node == focus_node {
433 focus_offset < anchor_offset
434 } else {
435 focus_node.is_before(anchor_node)
436 }
437 };
438 if is_focus_before_anchor {
439 self.set_range(&Range::new(
440 cx,
441 &self.document,
442 focus_node,
443 focus_offset,
444 anchor_node,
445 anchor_offset,
446 ));
447 self.direction.set(Direction::Backwards);
448 } else {
449 self.set_range(&Range::new(
450 cx,
451 &self.document,
452 anchor_node,
453 anchor_offset,
454 focus_node,
455 focus_offset,
456 ));
457 self.direction.set(Direction::Forwards);
458 }
459 Ok(())
460 }
461
462 fn SelectAllChildren(&self, cx: &mut JSContext, node: &Node) -> ErrorResult {
464 if node.is_doctype() {
465 return Err(Error::InvalidNodeType(None));
467 }
468 if !self.is_same_root(node) {
469 return Ok(());
470 }
471
472 self.set_range(&Range::new(
476 cx,
477 &self.document,
478 node,
479 0,
480 node,
481 node.children_count(),
482 ));
483
484 self.direction.set(Direction::Forwards);
485 Ok(())
486 }
487
488 fn DeleteFromDocument(&self, cx: &mut JSContext) -> ErrorResult {
490 if let Some(range) = self.range.get() {
491 return range.DeleteContents(cx);
494 }
495 Ok(())
496 }
497
498 fn ContainsNode(&self, node: &Node, allow_partial_containment: bool) -> bool {
500 if !self.is_same_root(node) {
503 return false;
504 }
505 if let Some(range) = self.range.get() {
506 let start_node = &*range.start_container();
507 if !self.is_same_root(start_node) {
508 return false;
510 }
511 if allow_partial_containment {
512 if node.is_before(start_node) {
514 return false;
515 }
516 let end_node = &*range.end_container();
517 if end_node.is_before(node) {
518 return false;
519 }
520 if node == start_node {
521 return range.start_offset() < node.len();
522 }
523 if node == end_node {
524 return range.end_offset() > 0;
525 }
526 true
527 } else {
528 if node.is_before(start_node) {
529 return false;
530 }
531 let end_node = &*range.end_container();
532 if end_node.is_before(node) {
533 return false;
534 }
535 if node == start_node {
536 return range.start_offset() == 0;
537 }
538 if node == end_node {
539 return range.end_offset() == node.len();
540 }
541 true
542 }
543 } else {
544 false
546 }
547 }
548
549 fn Stringifier(&self) -> DOMString {
551 if let Some(range) = self.range.get() {
556 range.Stringifier()
557 } else {
558 DOMString::from("")
559 }
560 }
561}