2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
									
										
										
										
											2024-10-04 13:19:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( c )  2021 - 2022 ,  Andreas  Kling  < andreas @ ladybird . org > 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-22 09:58:40 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( c )  2025 ,  Jelle  Raaijmakers  < jelle @ ladybird . org > 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  SPDX - License - Identifier :  BSD - 2 - Clause 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-01 16:34:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibUnicode/Segmenter.h> 
  
						 
					
						
							
								
									
										
										
											
												LibWeb: Remove unecessary dependence on Window from assorted classes
These classes only needed Window to get at its realm. Pass a realm
directly to construct Crypto, Encoding, HRT, IntersectionObserver,
NavigationTiming, Page, RequestIdleCallback, Selection, Streams, URL,
and XML classes.
											 
										 
										
											2022-09-25 18:11:21 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Bindings/Intrinsics.h> 
  
						 
					
						
							
								
									
										
										
										
											2024-04-27 12:09:58 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Bindings/SelectionPrototype.h> 
  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Document.h> 
  
						 
					
						
							
								
									
										
										
										
											2024-12-16 22:16:33 +04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Node.h> 
  
						 
					
						
							
								
									
										
											 
										
											
												LibWeb: Separate text control input events handling from contenteditable
This input event handling change is intended to address the following
design issues:
- Having `DOM::Position` is unnecessary complexity when `Selection`
  exists because caret position could be described by the selection
  object with a collapsed state. Before this change, we had to
  synchronize those whenever one of them was modified, and there were
  already bugs caused by that, i.e., caret position was not changed when
  selection offset was modified from the JS side.
- Selection API exposes selection offset within `<textarea>` and
  `<input>`, which is not supposed to happen. These objects should
  manage their selection state by themselves and have selection offset
  even when they are not displayed.
- `EventHandler` looks only at `DOM::Text` owned by `DOM::Position`
  while doing text manipulations. It works fine for `<input>` and
  `<textarea>`, but `contenteditable` needs to consider all text
  descendant text nodes; i.e., if the cursor is moved outside of
  `DOM::Text`, we need to look for an adjacent text node to move the
  cursor there.
With this change, `EventHandler` no longer does direct manipulations on
caret position or text content, but instead delegates them to the active
`InputEventsTarget`, which could be either
`FormAssociatedTextControlElement` (for `<input>` and `<textarea>`) or
`EditingHostManager` (for `contenteditable`). The `Selection` object is
used to manage both selection and caret position for `contenteditable`,
and text control elements manage their own selection state that is not
exposed by Selection API.
This change improves text editing on Discord, as now we don't have to
refocus the `contenteditable` element after character input. The problem
was that selection manipulations from the JS side were not propagated
to `DOM::Position`.
I expect this change to make future correctness improvements for
`contenteditable` (and `designMode`) easier, as now it's decoupled from
`<input>` and `<textarea>` and separated from `EventHandler`, which is
quite a busy file.
											 
										 
										
											2024-10-23 21:26:58 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Position.h> 
  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Range.h> 
  
						 
					
						
							
								
									
										
										
										
											2024-11-01 16:34:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Text.h> 
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/Selection/Selection.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								namespace  Web : : Selection  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC_DEFINE_ALLOCATOR ( Selection ) ;  
						 
					
						
							
								
									
										
										
										
											2023-11-19 19:47:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ref < Selection >  Selection : : create ( GC : : Ref < JS : : Realm >  realm ,  GC : : Ref < DOM : : Document >  document )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-11-14 05:50:17 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  realm - > create < Selection > ( realm ,  document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Selection : : Selection ( GC : : Ref < JS : : Realm >  realm ,  GC : : Ref < DOM : : Document >  document )  
						 
					
						
							
								
									
										
										
											
												LibWeb: Remove unecessary dependence on Window from assorted classes
These classes only needed Window to get at its realm. Pass a realm
directly to construct Crypto, Encoding, HRT, IntersectionObserver,
NavigationTiming, Page, RequestIdleCallback, Selection, Streams, URL,
and XML classes.
											 
										 
										
											2022-09-25 18:11:21 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    :  PlatformObject ( realm ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ,  m_document ( document ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-04 13:20:53 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								Selection : : ~ Selection ( )  =  default ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-07 08:41:28 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Selection : : initialize ( JS : : Realm &  realm )  
						 
					
						
							
								
									
										
										
										
											2023-01-10 06:28:20 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-03-16 13:13:08 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    WEB_SET_PROTOTYPE_FOR_INTERFACE ( Selection ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-04-20 16:22:57 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Base : : initialize ( realm ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-10 06:28:20 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dfn-empty
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								bool  Selection : : is_empty ( )  const  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Each selection can be associated with a single range.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // When there is no range associated with the selection, the selection is empty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // The selection must be initially empty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // NOTE: This function should not be confused with Selection.empty() which empties the selection.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  ! m_range ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Selection : : visit_edges ( Cell : : Visitor &  visitor )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    Base : : visit_edges ( visitor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    visitor . visit ( m_range ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    visitor . visit ( m_document ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dfn-anchor
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ptr < DOM : : Node >  Selection : : anchor_node ( )  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  nullptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_direction  = =  Direction : : Forwards ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  m_range - > start_container ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_range - > end_container ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dfn-anchor
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								unsigned  Selection : : anchor_offset ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_direction  = =  Direction : : Forwards ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  m_range - > start_offset ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_range - > end_offset ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dfn-focus
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ptr < DOM : : Node >  Selection : : focus_node ( )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  nullptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_direction  = =  Direction : : Forwards ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  m_range - > end_container ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_range - > start_container ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dfn-focus
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								unsigned  Selection : : focus_offset ( )  const  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_direction  = =  Direction : : Forwards ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  m_range - > end_offset ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_range - > start_offset ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-iscollapsed
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								bool  Selection : : is_collapsed ( )  const  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The attribute must return true if and only if the anchor and focus are the same
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // (including if both are null). Otherwise it must return false.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-12 02:42:55 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  const_cast < Selection * > ( this ) - > anchor_node ( )  = =  const_cast < Selection * > ( this ) - > focus_node ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        & &  m_range - > start_offset ( )  = =  m_range - > end_offset ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-rangecount
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								unsigned  Selection : : range_count ( )  const  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-26 16:39:52 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								String  Selection : : type ( )  const  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-26 16:39:52 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  " None " _string ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( m_range - > collapsed ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-26 16:39:52 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  " Caret " _string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  " Range " _string ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-10-13 14:38:25 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								String  Selection : : direction ( )  const  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range  | |  m_direction  = =  Direction : : Directionless ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  " none " _string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_direction  = =  Direction : : Forwards ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  " forward " _string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  " backward " _string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-getrangeat
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < GC : : Ptr < DOM : : Range > >  Selection : : get_range_at ( unsigned  index )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-12-16 22:16:33 +04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    GC : : Ptr < DOM : : Node >  focus  =  focus_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    GC : : Ptr < DOM : : Node >  anchor  =  anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // The method must throw an IndexSizeError exception if index is not 0, or if this is empty or either focus or anchor is not in the document tree.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  is_focus_in_document_tree  =  focus  & &  & focus - > document ( )  = =  document ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  is_anchor_in_document_tree  =  anchor  & &  & anchor - > document ( )  = =  document ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( index  ! =  0  | |  is_empty ( )  | |  ! is_focus_in_document_tree  | |  ! is_anchor_in_document_tree ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : IndexSizeError : : create ( realm ( ) ,  " Selection.getRangeAt() on empty Selection or with invalid argument " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Otherwise, it must return a reference to (not a copy of) this's range.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_range ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-addrange
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Selection : : add_range ( GC : : Ref < DOM : : Range >  range )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. If the root of the range's boundary points are not the document associated with this, abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( & range - > start_container ( ) - > root ( )  ! =  m_document . ptr ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. If rangeCount is not 0, abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( range_count ( )  ! =  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Set this's range to range by a strong reference (not by making a copy).
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( range ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-13 14:39:02 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // AD-HOC: WPT selection/removeAllRanges.html and selection/addRange.htm expect this
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    m_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-removerange
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : remove_range ( GC : : Ref < DOM : : Range >  range )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The method must make this empty by disassociating its range if this's range is range.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_range  = =  range )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        set_range ( nullptr ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Otherwise, it must throw a NotFoundError.
 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  WebIDL : : NotFoundError : : create ( realm ( ) ,  " Selection.removeRange() with invalid argument " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-removeallranges
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								void  Selection : : remove_all_ranges ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The method must make this empty by disassociating its range if this has an associated range.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( nullptr ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-empty
  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								void  Selection : : empty ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The method must be an alias, and behave identically, to removeAllRanges().
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    remove_all_ranges ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-collapse
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : collapse ( GC : : Ptr < DOM : : Node >  node ,  unsigned  offset )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. If node is null, this method must behave identically as removeAllRanges() and abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! node )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        remove_all_ranges ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 2. If node is a DocumentType, throw an InvalidNodeTypeError exception and abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( node - > is_document_type ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : InvalidNodeTypeError : : create ( realm ( ) ,  " Selection.collapse() with DocumentType node " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-16 10:04:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 3. The method must throw an IndexSizeError exception if offset is longer than node's length and abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( offset  >  node - > length ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : IndexSizeError : : create ( realm ( ) ,  " Selection.collapse() with offset longer than node's length " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 4. If document associated with this is not a shadow-including inclusive ancestor of node, abort these steps.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-09-02 14:03:45 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_document - > is_shadow_including_inclusive_ancestor_of ( * node ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 5. Otherwise, let newRange be a new range.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-13 13:05:26 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  new_range  =  DOM : : Range : : create ( * m_document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 6. Set the start the start and the end of newRange to (node, offset).
 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    TRY ( new_range - > set_start ( * node ,  offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 7. Set this's range to newRange.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( new_range ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-setposition
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : set_position ( GC : : Ptr < DOM : : Node >  node ,  unsigned  offset )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The method must be an alias, and behave identically, to collapse().
 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 21:57:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  collapse ( node ,  offset ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-collapsetostart
  
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:08:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : collapse_to_start ( )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:08:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. The method must throw InvalidStateError exception if the this is empty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : InvalidStateError : : create ( realm ( ) ,  " Selection.collapse_to_start() on empty range " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:08:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. Otherwise, it must create a new range
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-13 13:05:26 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  new_range  =  DOM : : Range : : create ( * m_document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:08:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Set the start both its start and end to the start of this's range
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-20 11:34:49 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    TRY ( new_range - > set_start ( * m_range - > start_container ( ) ,  m_range - > start_offset ( ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    TRY ( new_range - > set_end ( * m_range - > start_container ( ) ,  m_range - > start_offset ( ) ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:08:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 4. Then set this's range to the newly-created range.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( new_range ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:08:16 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-collapsetoend
  
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:09:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : collapse_to_end ( )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:09:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. The method must throw InvalidStateError exception if the this is empty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : InvalidStateError : : create ( realm ( ) ,  " Selection.collapse_to_end() on empty range " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:09:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. Otherwise, it must create a new range
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-13 13:05:26 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  new_range  =  DOM : : Range : : create ( * m_document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:09:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Set the start both its start and end to the start of this's range
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-20 11:34:49 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    TRY ( new_range - > set_start ( * m_range - > end_container ( ) ,  m_range - > end_offset ( ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    TRY ( new_range - > set_end ( * m_range - > end_container ( ) ,  m_range - > end_offset ( ) ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:09:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 4. Then set this's range to the newly-created range.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( new_range ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 22:09:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-extend
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : extend ( GC : : Ref < DOM : : Node >  node ,  unsigned  offset )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-10-13 15:28:25 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. If the document associated with this is not a shadow-including inclusive ancestor of node, abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_document - > is_shadow_including_inclusive_ancestor_of ( node ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. If this is empty, throw an InvalidStateError exception and abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : InvalidStateError : : create ( realm ( ) ,  " Selection.extend() on empty range " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Let oldAnchor and oldFocus be the this's anchor and focus, and let newFocus be the boundary point (node, offset).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  old_anchor_node  =  * anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  old_anchor_offset  =  anchor_offset ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  new_focus_node  =  node ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  new_focus_offset  =  offset ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 4. Let newRange be a new range.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-13 13:05:26 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  new_range  =  DOM : : Range : : create ( * m_document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 5. If node's root is not the same as the this's range's root, set the start newRange's start and end to newFocus.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( & node - > root ( )  ! =  & m_range - > start_container ( ) - > root ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-30 17:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        TRY ( new_range - > set_start ( new_focus_node ,  new_focus_offset ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-13 15:28:25 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        TRY ( new_range - > set_end ( new_focus_node ,  new_focus_offset ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 6. Otherwise, if oldAnchor is before or equal to newFocus, set the start newRange's start to oldAnchor, then set its end to newFocus.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-18 13:30:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    else  if  ( DOM : : position_of_boundary_point_relative_to_other_boundary_point ( {  old_anchor_node ,  old_anchor_offset  } ,  {  new_focus_node ,  new_focus_offset  } )  ! =  DOM : : RelativeBoundaryPointPosition : : After )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-10-13 15:28:25 +11:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        TRY ( new_range - > set_start ( old_anchor_node ,  old_anchor_offset ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-30 17:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        TRY ( new_range - > set_end ( new_focus_node ,  new_focus_offset ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 7. Otherwise, set the start newRange's start to newFocus, then set its end to oldAnchor.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-30 17:50:04 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        TRY ( new_range - > set_start ( new_focus_node ,  new_focus_offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        TRY ( new_range - > set_end ( old_anchor_node ,  old_anchor_offset ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 8. Set this's range to newRange.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( new_range ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 9. If newFocus is before oldAnchor, set this's direction to backwards. Otherwise, set it to forwards.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-18 13:30:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( DOM : : position_of_boundary_point_relative_to_other_boundary_point ( {  new_focus_node ,  new_focus_offset  } ,  {  old_anchor_node ,  old_anchor_offset  } )  = =  DOM : : RelativeBoundaryPointPosition : : Before )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        m_direction  =  Direction : : Backwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-setbaseandextent
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : set_base_and_extent ( GC : : Ref < DOM : : Node >  anchor_node ,  unsigned  anchor_offset ,  GC : : Ref < DOM : : Node >  focus_node ,  unsigned  focus_offset )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. If anchorOffset is longer than anchorNode's length or if focusOffset is longer than focusNode's length, throw an IndexSizeError exception and abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( anchor_offset  >  anchor_node - > length ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : IndexSizeError : : create ( realm ( ) ,  " Anchor offset points outside of the anchor node " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( focus_offset  >  focus_node - > length ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : IndexSizeError : : create ( realm ( ) ,  " Focus offset points outside of the focus node " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-07-02 10:21:06 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 2. If document associated with this is not a shadow-including inclusive ancestor of anchorNode or focusNode, abort these steps.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-07-19 16:39:34 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_document - > is_shadow_including_inclusive_ancestor_of ( anchor_node )  | |  ! m_document - > is_shadow_including_inclusive_ancestor_of ( focus_node ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Let anchor be the boundary point (anchorNode, anchorOffset) and let focus be the boundary point (focusNode, focusOffset).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 4. Let newRange be a new range.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-13 13:05:26 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  new_range  =  DOM : : Range : : create ( * m_document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 5. If anchor is before focus, set the start the newRange's start to anchor and its end to focus. Otherwise, set the start them to focus and anchor respectively.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-18 13:30:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  position_of_anchor_relative_to_focus  =  DOM : : position_of_boundary_point_relative_to_other_boundary_point ( {  anchor_node ,  anchor_offset  } ,  {  focus_node ,  focus_offset  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( position_of_anchor_relative_to_focus  = =  DOM : : RelativeBoundaryPointPosition : : Before )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        TRY ( new_range - > set_start ( anchor_node ,  anchor_offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        TRY ( new_range - > set_end ( focus_node ,  focus_offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        TRY ( new_range - > set_start ( focus_node ,  focus_offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        TRY ( new_range - > set_end ( anchor_node ,  anchor_offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 6. Set this's range to newRange.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( new_range ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 19:00:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 7. If focus is before anchor, set this's direction to backwards. Otherwise, set it to forwards
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // NOTE: "Otherwise" can be seen as "focus is equal to or after anchor".
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( position_of_anchor_relative_to_focus  = =  DOM : : RelativeBoundaryPointPosition : : After ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_direction  =  Direction : : Backwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-selectallchildren
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : select_all_children ( GC : : Ref < DOM : : Node >  node )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 1. If node is a DocumentType, throw an InvalidNodeTypeError exception and abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( node - > is_document_type ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-07 19:31:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  WebIDL : : InvalidNodeTypeError : : create ( realm ( ) ,  " Selection.selectAllChildren() with DocumentType node " _utf16 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-16 10:04:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 2. If node's root is not the document associated with this, abort these steps.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( & node - > root ( )  ! =  m_document . ptr ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 3. Let newRange be a new range and childCount be the number of children of node.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-13 13:05:26 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  new_range  =  DOM : : Range : : create ( * m_document ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  child_count  =  node - > child_count ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 4. Set newRange's start to (node, 0).
 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    TRY ( new_range - > set_start ( node ,  0 ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 5. Set newRange's end to (node, childCount).
 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    TRY ( new_range - > set_end ( node ,  child_count ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 6. Set this's range to newRange.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    set_range ( new_range ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-11 16:43:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // 7. Set this's direction to forwards.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    m_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-05-15 12:31:41 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-modify
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : modify ( Optional < String >  alter ,  Optional < String >  direction ,  Optional < String >  granularity )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  anchor_node  =  this - > anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! anchor_node  | |  ! is < DOM : : Text > ( * anchor_node ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  text_node  =  static_cast < DOM : : Text & > ( * anchor_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 1. If alter is not ASCII case-insensitive match with "extend" or "move", abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! alter . has_value ( )  | |  ! alter . value ( ) . bytes_as_string_view ( ) . is_one_of_ignoring_ascii_case ( " extend " sv ,  " move " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. If direction is not ASCII case-insensitive match with "forward", "backward", "left", or "right", abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! direction . has_value ( )  | |  ! direction . value ( ) . bytes_as_string_view ( ) . is_one_of_ignoring_ascii_case ( " forward " sv ,  " backward " sv ,  " left " sv ,  " right " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. If granularity is not ASCII case-insensitive match with "character", "word", "sentence", "line", "paragraph",
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    //    "lineboundary", "sentenceboundary", "paragraphboundary", "documentboundary", abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! granularity . has_value ( )  | |  ! granularity . value ( ) . bytes_as_string_view ( ) . is_one_of_ignoring_ascii_case ( " character " sv ,  " word " sv ,  " sentence " sv ,  " line " sv ,  " paragraph " sv ,  " lineboundary " sv ,  " sentenceboundary " sv ,  " paragraphboundary " sv ,  " documentboundary " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 4. If this selection is empty, abort these steps.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is_empty ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 5. Let effectiveDirection be backwards.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  effective_direction  =  Direction : : Backwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 6. If direction is ASCII case-insensitive match with "forward", set effectiveDirection to forwards.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( direction . value ( ) . equals_ignoring_ascii_case ( " forward " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        effective_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 7. If direction is ASCII case-insensitive match with "right" and inline base direction of this selection's focus is ltr, set effectiveDirection to forwards.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( direction . value ( ) . equals_ignoring_ascii_case ( " right " sv )  & &  text_node . directionality ( )  = =  DOM : : Element : : Directionality : : Ltr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        effective_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 8. If direction is ASCII case-insensitive match with "left" and inline base direction of this selection's focus is rtl, set effectiveDirection to forwards.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( direction . value ( ) . equals_ignoring_ascii_case ( " left " sv )  & &  text_node . directionality ( )  = =  DOM : : Element : : Directionality : : Rtl ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        effective_direction  =  Direction : : Forwards ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 9. Set this selection's direction to effectiveDirection.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // NOTE: This is handled by calls to move_offset_to_* later on
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 10. If alter is ASCII case-insensitive match with "extend", set this selection's focus to the location as if the user had requested to extend selection by granularity.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 11. Otherwise, set this selection's focus and anchor to the location as if the user had requested to move selection by granularity.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  collapse_selection  =  alter . value ( ) . equals_ignoring_ascii_case ( " move " sv ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // TODO: Implement the other granularity options.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( effective_direction  = =  Direction : : Forwards )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( granularity . value ( ) . equals_ignoring_ascii_case ( " character " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            move_offset_to_next_character ( collapse_selection ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( granularity . value ( ) . equals_ignoring_ascii_case ( " word " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            move_offset_to_next_word ( collapse_selection ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( granularity . value ( ) . equals_ignoring_ascii_case ( " character " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            move_offset_to_previous_character ( collapse_selection ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( granularity . value ( ) . equals_ignoring_ascii_case ( " word " sv ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            move_offset_to_previous_word ( collapse_selection ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-deletefromdocument
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								WebIDL : : ExceptionOr < void >  Selection : : delete_from_document ( )  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The method must invoke deleteContents() on this's range if this is not empty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Otherwise the method must do nothing.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! is_empty ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  m_range - > delete_contents ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// https://w3c.github.io/selection-api/#dom-selection-containsnode
  
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								bool  Selection : : contains_node ( GC : : Ref < DOM : : Node >  node ,  bool  allow_partial_containment )  const  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // The method must return false if this is empty or if node's root is not the document associated with this.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( & node - > root ( )  ! =  m_document . ptr ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Otherwise, if allowPartialContainment is false, the method must return true if and only if
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // start of its range is before or visually equivalent to the first boundary point in the node
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // and end of its range is after or visually equivalent to the last boundary point in the node.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! allow_partial_containment )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-18 13:30:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  start_relative_position  =  DOM : : position_of_boundary_point_relative_to_other_boundary_point ( m_range - > start ( ) ,  {  node ,  0  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  end_relative_position  =  DOM : : position_of_boundary_point_relative_to_other_boundary_point ( m_range - > end ( ) ,  {  node ,  static_cast < WebIDL : : UnsignedLong > ( node - > length ( ) )  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  ( start_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : Before  | |  start_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : Equal ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            & &  ( end_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : Equal  | |  end_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : After ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // If allowPartialContainment is true, the method must return true if and only if
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // start of its range is before or visually equivalent to the last boundary point in the node
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // and end of its range is after or visually equivalent to the first boundary point in the node.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-12-18 13:30:19 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  start_relative_position  =  DOM : : position_of_boundary_point_relative_to_other_boundary_point ( m_range - > start ( ) ,  {  node ,  static_cast < WebIDL : : UnsignedLong > ( node - > length ( ) )  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  end_relative_position  =  DOM : : position_of_boundary_point_relative_to_other_boundary_point ( m_range - > end ( ) ,  {  node ,  0  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  ( start_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : Before  | |  start_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : Equal ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        & &  ( end_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : Equal  | |  end_relative_position  = =  DOM : : RelativeBoundaryPointPosition : : After ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-24 14:39:11 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Utf16String  Selection : : to_string ( )  const  
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-11 16:54:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // FIXME: This needs more work to be compatible with other engines.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    //        See https://www.w3.org/Bugs/Public/show_bug.cgi?id=10583
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_range ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-24 14:39:11 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  { } ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-26 16:46:33 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  m_range - > to_string ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ref < DOM : : Document >  Selection : : document ( )  const  
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_document ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ptr < DOM : : Range >  Selection : : range ( )  const  
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:45:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_range ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Selection : : set_range ( GC : : Ptr < DOM : : Range >  range )  
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:25:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  old_range  =  m_range ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( old_range  = =  range ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:25:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( old_range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        old_range - > set_associated_selection ( { } ,  nullptr ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    m_range  =  range ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:25:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( range ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        range - > set_associated_selection ( { } ,  this ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-22 09:58:40 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // https://w3c.github.io/editing/docs/execCommand/#state-override
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Whenever the number of ranges in the selection changes to something different, and whenever a boundary point of
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // the range at a given index in the selection changes to something different, the state override and value override
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // must be unset for every command.
 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:25:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ( ( old_range  = =  nullptr )  ! =  ( range  = =  nullptr ) )  | |  ( old_range  & &  * old_range  ! =  * range ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-24 10:44:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        m_document - > reset_command_state_overrides ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_document - > reset_command_value_overrides ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-31 14:25:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // https://developer.mozilla.org/en-US/docs/Web/API/Selection#behavior_of_selection_api_in_terms_of_editing_host_focus_changes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // AD-HOC: Focus editing host if the previous selection was outside of it. There seems to be no spec for this.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( range  & &  range - > start_container ( ) - > is_editable_or_editing_host ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        GC : : Ptr  old_editing_host  =  old_range  ?  old_range - > start_container ( ) - > editing_host ( )  :  nullptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        GC : : Ref  new_editing_host  =  * range - > start_container ( ) - > editing_host ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( new_editing_host  ! =  old_editing_host  & &  document ( ) - > focused_element ( )  ! =  new_editing_host )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // FIXME: Determine and propagate the right focus trigger.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            HTML : : run_focusing_steps ( new_editing_host ,  nullptr ,  HTML : : FocusTrigger : : Other ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-11 19:48:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ptr < DOM : : Position >  Selection : : cursor_position ( )  const  
						 
					
						
							
								
									
										
											 
										
											
												LibWeb: Separate text control input events handling from contenteditable
This input event handling change is intended to address the following
design issues:
- Having `DOM::Position` is unnecessary complexity when `Selection`
  exists because caret position could be described by the selection
  object with a collapsed state. Before this change, we had to
  synchronize those whenever one of them was modified, and there were
  already bugs caused by that, i.e., caret position was not changed when
  selection offset was modified from the JS side.
- Selection API exposes selection offset within `<textarea>` and
  `<input>`, which is not supposed to happen. These objects should
  manage their selection state by themselves and have selection offset
  even when they are not displayed.
- `EventHandler` looks only at `DOM::Text` owned by `DOM::Position`
  while doing text manipulations. It works fine for `<input>` and
  `<textarea>`, but `contenteditable` needs to consider all text
  descendant text nodes; i.e., if the cursor is moved outside of
  `DOM::Text`, we need to look for an adjacent text node to move the
  cursor there.
With this change, `EventHandler` no longer does direct manipulations on
caret position or text content, but instead delegates them to the active
`InputEventsTarget`, which could be either
`FormAssociatedTextControlElement` (for `<input>` and `<textarea>`) or
`EditingHostManager` (for `contenteditable`). The `Selection` object is
used to manage both selection and caret position for `contenteditable`,
and text control elements manage their own selection state that is not
exposed by Selection API.
This change improves text editing on Discord, as now we don't have to
refocus the `contenteditable` element after character input. The problem
was that selection manipulations from the JS side were not propagated
to `DOM::Position`.
I expect this change to make future correctness improvements for
`contenteditable` (and `designMode`) easier, as now it's decoupled from
`<input>` and `<textarea>` and separated from `EventHandler`, which is
quite a busy file.
											 
										 
										
											2024-10-23 21:26:58 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2025-06-11 15:32:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! m_range  | |  ! is_collapsed ( ) ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												LibWeb: Separate text control input events handling from contenteditable
This input event handling change is intended to address the following
design issues:
- Having `DOM::Position` is unnecessary complexity when `Selection`
  exists because caret position could be described by the selection
  object with a collapsed state. Before this change, we had to
  synchronize those whenever one of them was modified, and there were
  already bugs caused by that, i.e., caret position was not changed when
  selection offset was modified from the JS side.
- Selection API exposes selection offset within `<textarea>` and
  `<input>`, which is not supposed to happen. These objects should
  manage their selection state by themselves and have selection offset
  even when they are not displayed.
- `EventHandler` looks only at `DOM::Text` owned by `DOM::Position`
  while doing text manipulations. It works fine for `<input>` and
  `<textarea>`, but `contenteditable` needs to consider all text
  descendant text nodes; i.e., if the cursor is moved outside of
  `DOM::Text`, we need to look for an adjacent text node to move the
  cursor there.
With this change, `EventHandler` no longer does direct manipulations on
caret position or text content, but instead delegates them to the active
`InputEventsTarget`, which could be either
`FormAssociatedTextControlElement` (for `<input>` and `<textarea>`) or
`EditingHostManager` (for `contenteditable`). The `Selection` object is
used to manage both selection and caret position for `contenteditable`,
and text control elements manage their own selection state that is not
exposed by Selection API.
This change improves text editing on Discord, as now we don't have to
refocus the `contenteditable` element after character input. The problem
was that selection manipulations from the JS side were not propagated
to `DOM::Position`.
I expect this change to make future correctness improvements for
`contenteditable` (and `designMode`) easier, as now it's decoupled from
`<input>` and `<textarea>` and separated from `EventHandler`, which is
quite a busy file.
											 
										 
										
											2024-10-23 21:26:58 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  nullptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-06-11 15:32:20 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  DOM : : Position : : create ( m_document - > realm ( ) ,  * m_range - > start_container ( ) ,  m_range - > start_offset ( ) ) ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												LibWeb: Separate text control input events handling from contenteditable
This input event handling change is intended to address the following
design issues:
- Having `DOM::Position` is unnecessary complexity when `Selection`
  exists because caret position could be described by the selection
  object with a collapsed state. Before this change, we had to
  synchronize those whenever one of them was modified, and there were
  already bugs caused by that, i.e., caret position was not changed when
  selection offset was modified from the JS side.
- Selection API exposes selection offset within `<textarea>` and
  `<input>`, which is not supposed to happen. These objects should
  manage their selection state by themselves and have selection offset
  even when they are not displayed.
- `EventHandler` looks only at `DOM::Text` owned by `DOM::Position`
  while doing text manipulations. It works fine for `<input>` and
  `<textarea>`, but `contenteditable` needs to consider all text
  descendant text nodes; i.e., if the cursor is moved outside of
  `DOM::Text`, we need to look for an adjacent text node to move the
  cursor there.
With this change, `EventHandler` no longer does direct manipulations on
caret position or text content, but instead delegates them to the active
`InputEventsTarget`, which could be either
`FormAssociatedTextControlElement` (for `<input>` and `<textarea>`) or
`EditingHostManager` (for `contenteditable`). The `Selection` object is
used to manage both selection and caret position for `contenteditable`,
and text control elements manage their own selection state that is not
exposed by Selection API.
This change improves text editing on Discord, as now we don't have to
refocus the `contenteditable` element after character input. The problem
was that selection manipulations from the JS side were not propagated
to `DOM::Position`.
I expect this change to make future correctness improvements for
`contenteditable` (and `designMode`) easier, as now it's decoupled from
`<input>` and `<textarea>` and separated from `EventHandler`, which is
quite a busy file.
											 
										 
										
											2024-10-23 21:26:58 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-01 16:34:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Selection : : move_offset_to_next_character ( bool  collapse_selection )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  anchor_node  =  this - > anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! anchor_node  | |  ! is < DOM : : Text > ( * anchor_node ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  text_node  =  static_cast < DOM : : Text & > ( * anchor_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( auto  offset  =  text_node . grapheme_segmenter ( ) . next_boundary ( focus_offset ( ) ) ;  offset . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( collapse_selection )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            MUST ( collapse ( * anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            m_document - > reset_cursor_blink_cycle ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            MUST ( set_base_and_extent ( * anchor_node ,  anchor_offset ( ) ,  * anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  Selection : : move_offset_to_previous_character ( bool  collapse_selection )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  anchor_node  =  this - > anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! anchor_node  | |  ! is < DOM : : Text > ( * anchor_node ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  text_node  =  static_cast < DOM : : Text & > ( * anchor_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( auto  offset  =  text_node . grapheme_segmenter ( ) . previous_boundary ( focus_offset ( ) ) ;  offset . has_value ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( collapse_selection )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            MUST ( collapse ( * anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            m_document - > reset_cursor_blink_cycle ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            MUST ( set_base_and_extent ( * anchor_node ,  anchor_offset ( ) ,  * anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  Selection : : move_offset_to_next_word ( bool  collapse_selection )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  anchor_node  =  this - > anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! anchor_node  | |  ! is < DOM : : Text > ( * anchor_node ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  text_node  =  static_cast < DOM : : Text & > ( * anchor_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  ( true )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  focus_offset  =  this - > focus_offset ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-24 12:05:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( focus_offset  = =  text_node . data ( ) . length_in_code_units ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-01 16:34:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( auto  offset  =  text_node . word_segmenter ( ) . next_boundary ( focus_offset ) ;  offset . has_value ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-24 12:05:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            auto  word  =  text_node . data ( ) . substring_view ( focus_offset ,  * offset  -  focus_offset ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-01 16:34:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  ( collapse_selection )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                MUST ( collapse ( anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                m_document - > reset_cursor_blink_cycle ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                MUST ( set_base_and_extent ( * anchor_node ,  this - > anchor_offset ( ) ,  * anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( Unicode : : Segmenter : : should_continue_beyond_word ( word ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  Selection : : move_offset_to_previous_word ( bool  collapse_selection )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  anchor_node  =  this - > anchor_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! anchor_node  | |  ! is < DOM : : Text > ( * anchor_node ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  text_node  =  static_cast < DOM : : Text & > ( * anchor_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  ( true )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  focus_offset  =  this - > focus_offset ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( auto  offset  =  text_node . word_segmenter ( ) . previous_boundary ( focus_offset ) ;  offset . has_value ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-07-24 12:05:52 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            auto  word  =  text_node . data ( ) . substring_view ( * offset ,  focus_offset  -  * offset ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-01 16:34:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  ( collapse_selection )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                MUST ( collapse ( anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                m_document - > reset_cursor_blink_cycle ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                MUST ( set_base_and_extent ( * anchor_node ,  anchor_offset ( ) ,  * anchor_node ,  * offset ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( Unicode : : Segmenter : : should_continue_beyond_word ( word ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-10 19:12:32 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}