2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Copyright  ( c )  2024 ,  the  Ladybird  developers . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  SPDX - License - Identifier :  BSD - 2 - Clause 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <AK/TypeCasts.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Document.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/EventDispatcher.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/IDLEventListener.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/CloseWatcher.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/CloseWatcherManager.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/Window.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								namespace  Web : : HTML  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC_DEFINE_ALLOCATOR ( CloseWatcherManager ) ;  
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								GC : : Ref < CloseWatcherManager >  CloseWatcherManager : : create ( JS : : Realm &  realm )  
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-11-14 05:50:17 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  realm . create < CloseWatcherManager > ( realm ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								CloseWatcherManager : : CloseWatcherManager ( JS : : Realm &  realm )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    :  PlatformObject ( realm ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  CloseWatcherManager : : add ( GC : : Ref < CloseWatcher >  close_watcher )  
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // If manager's groups's size is less than manager's allowed number of groups
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_groups . size ( )  <  m_allowed_number_of_groups )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // then append « closeWatcher » to manager's groups.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-26 14:32:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        GC : : RootVector < GC : : Ref < CloseWatcher > >  new_group ( realm ( ) . heap ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        new_group . append ( close_watcher ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_groups . append ( move ( new_group ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Assert: manager's groups's size is at least 1 in this branch, since manager's allowed number of groups is always at least 1.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        VERIFY ( ! m_groups . is_empty ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Append closeWatcher to manager's groups's last item.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_groups . last ( ) . append ( close_watcher ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Set manager's next user interaction allows a new group to true.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    m_next_user_interaction_allows_a_new_group  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  CloseWatcherManager : : remove ( CloseWatcher  const &  close_watcher )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. For each group of manager's groups: remove closeWatcher from group
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( auto &  group  :  m_groups )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-11-15 04:01:23 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        group . remove_first_matching ( [ & close_watcher ] ( GC : : Ref < CloseWatcher > &  entry )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            return  entry . ptr ( )  = =  & close_watcher ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Remove any item from manager's group that is empty
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    m_groups . remove_all_matching ( [ ] ( auto &  group )  {  return  group . is_empty ( ) ;  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// https://html.spec.whatwg.org/multipage/interaction.html#process-close-watchers
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								bool  CloseWatcherManager : : process_close_watchers ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 1. Let processedACloseWatcher be false.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    bool  processed_a_close_watcher  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. If window's close watcher manager's groups is not empty:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! m_groups . is_empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // 2.1 Let group be the last item in window's close watcher manager's groups.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  group  =  m_groups . last ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Ambiguous spec wording. We copy the groups to avoid modifying the original while iterating.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // See https://github.com/whatwg/html/issues/10240
 
							 
						 
					
						
							
								
									
										
										
										
											2024-12-26 14:32:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        GC : : RootVector < GC : : Ref < CloseWatcher > >  group_copy ( realm ( ) . heap ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        group_copy . ensure_capacity ( group . size ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( auto &  close_watcher  :  group )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            group_copy . append ( close_watcher ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // 2.2 For each closeWatcher of group, in reverse order:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( auto  it  =  group_copy . rbegin ( ) ;  it  ! =  group_copy . rend ( ) ;  + + it )  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-16 20:37:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // 2.2.1 If the result of running closeWatcher's get enabled state is true, set processedACloseWatcher to true.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( ( * it ) - > get_enabled_state ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                processed_a_close_watcher  =  true ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-24 12:44:17 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // 2.2.2 Let shouldProceed be the result of requesting to close closeWatcher with true.
 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-16 20:37:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            bool  should_proceed  =  ( * it ) - > request_close ( true ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-01-24 12:44:17 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // 2.2.3 If shouldProceed is false, then break;
 
							 
						 
					
						
							
								
									
										
										
										
											2024-06-21 22:53:05 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								            if  ( ! should_proceed ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. If window's close watcher manager's allowed number of groups is greater than 1, decrement it by 1.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_allowed_number_of_groups  >  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_allowed_number_of_groups - - ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 4. Return processedACloseWatcher.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  processed_a_close_watcher ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// https://html.spec.whatwg.org/multipage/interaction.html#notify-the-close-watcher-manager-about-user-activation
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  CloseWatcherManager : : notify_about_user_activation ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 1. Let manager be window's close watcher manager.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 2. If manager's next user interaction allows a new group is true, then increment manager's allowed number of groups.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( m_next_user_interaction_allows_a_new_group ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_allowed_number_of_groups + + ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 3. Set manager's next user interaction allows a new group to false.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    m_next_user_interaction_allows_a_new_group  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// https://html.spec.whatwg.org/multipage/interaction.html#close-watcher-request-close
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								bool  CloseWatcherManager : : can_prevent_close ( )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 5. Let canPreventClose be true if window's close watcher manager's groups's size is less than window's close watcher manager's allowed number of groups...
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  m_groups . size ( )  <  m_allowed_number_of_groups ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  CloseWatcherManager : : visit_edges ( JS : : Cell : : Visitor &  visitor )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    Base : : visit_edges ( visitor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    visitor . visit ( m_groups ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}