2020-01-18 09:38:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
									
										
										
										
											2022-02-21 01:43:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( c )  2018 - 2022 ,  Andreas  Kling  < kling @ serenityos . org > 
							 
						 
					
						
							
								
									
										
										
										
											2023-03-24 15:04:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( c )  2022 - 2023 ,  Sam  Atkins  < atkinssj @ serenityos . org > 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-22 16:08:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( c )  2022 ,  MacDue  < macdue @ dueutil . tech > 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-18 09:38:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-22 01:24:48 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  SPDX - License - Identifier :  BSD - 2 - Clause 
							 
						 
					
						
							
								
									
										
										
										
											2020-01-18 09:38:21 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-06 03:08:20 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <AK/Error.h> 
  
						 
					
						
							
								
									
										
										
										
											2021-08-05 10:26:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <AK/Optional.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <AK/TemporaryChange.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-05-08 06:37:18 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/CSS/StyleComputer.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-04-26 21:05:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/CSS/StyleValues/DisplayStyleValue.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-03-24 15:04:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/CSS/StyleValues/IdentifierStyleValue.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-03-24 17:28:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/CSS/StyleValues/PercentageStyleValue.h> 
  
						 
					
						
							
								
									
										
										
										
											2020-03-07 10:32:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Document.h> 
  
						 
					
						
							
								
									
										
										
										
											2021-01-06 14:10:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/Element.h> 
  
						 
					
						
							
								
									
										
										
										
											2020-03-07 10:32:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/ParentNode.h> 
  
						 
					
						
							
								
									
										
										
										
											2021-02-10 18:23:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/DOM/ShadowRoot.h> 
  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Dump.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/HTMLButtonElement.h> 
  
						 
					
						
							
								
									
										
										
										
											2022-11-30 22:15:12 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/HTMLInputElement.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-10-11 18:42:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/HTMLLIElement.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/HTMLOListElement.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-09-05 15:17:10 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/HTML/HTMLSlotElement.h> 
  
						 
					
						
							
								
									
										
										
										
											2022-02-21 01:43:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/ListItemBox.h> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/ListItemMarkerBox.h> 
  
						 
					
						
							
								
									
										
										
										
											2020-11-22 15:53:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/Node.h> 
  
						 
					
						
							
								
									
										
										
										
											2024-03-27 00:13:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/SVGClipBox.h> 
  
						 
					
						
							
								
									
										
										
										
											2024-03-11 18:26:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/SVGMaskBox.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/TableGrid.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-01-14 14:48:20 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/TableWrapper.h> 
  
						 
					
						
							
								
									
										
										
										
											2020-11-22 15:53:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/TextNode.h> 
  
						 
					
						
							
								
									
										
										
										
											2020-11-25 20:29:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/TreeBuilder.h> 
  
						 
					
						
							
								
									
										
										
										
											2023-02-25 11:04:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/Layout/Viewport.h> 
  
						 
					
						
							
								
									
										
										
										
											2022-11-10 13:54:57 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <LibWeb/SVG/SVGForeignObjectElement.h> 
  
						 
					
						
							
								
									
										
										
										
											2019-10-15 12:22:41 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-11-22 15:53:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								namespace  Web : : Layout  {  
						 
					
						
							
								
									
										
										
										
											2020-03-07 10:27:02 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-14 13:21:51 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								TreeBuilder : : TreeBuilder ( )  =  default ;  
						 
					
						
							
								
									
										
										
										
											2019-10-15 12:22:41 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-22 19:13:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  has_inline_or_in_flow_block_children ( Layout : : Node  const &  layout_node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( auto  child  =  layout_node . first_child ( ) ;  child ;  child  =  child - > next_sibling ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-22 19:13:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( child - > is_inline ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! child - > is_floating ( )  & &  ! child - > is_absolutely_positioned ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  bool  has_in_flow_block_children ( Layout : : Node  const &  layout_node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( layout_node . children_are_inline ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( auto  child  =  layout_node . first_child ( ) ;  child ;  child  =  child - > next_sibling ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-22 19:13:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( child - > is_inline ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! child - > is_floating ( )  & &  ! child - > is_absolutely_positioned ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The insertion_parent_for_*() functions maintain the invariant that the in-flow children of
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// block-level boxes must be either all block-level or all inline-level.
  
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-06 14:10:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  Layout : : Node &  insertion_parent_for_inline_node ( Layout : : NodeWithStyle &  layout_parent )  
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2023-10-10 19:27:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  last_child_creating_anonymous_wrapper_if_needed  =  [ ] ( auto &  layout_parent )  - >  Layout : : Node &  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! layout_parent . last_child ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            | |  ! layout_parent . last_child ( ) - > is_anonymous ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            | |  ! layout_parent . last_child ( ) - > children_are_inline ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            | |  layout_parent . last_child ( ) - > is_generated ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            layout_parent . append_child ( layout_parent . create_anonymous_wrapper ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  * layout_parent . last_child ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-07 12:47:46 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( layout_parent . display ( ) . is_inline_outside ( )  & &  layout_parent . display ( ) . is_flow_inside ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  layout_parent ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-10-10 19:27:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( layout_parent . display ( ) . is_flex_inside ( )  | |  layout_parent . display ( ) . is_grid_inside ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  last_child_creating_anonymous_wrapper_if_needed ( layout_parent ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-29 17:18:49 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-22 19:13:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! has_in_flow_block_children ( layout_parent )  | |  layout_parent . children_are_inline ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  layout_parent ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Parent has block-level children, insert into an anonymous wrapper block (and create it first if needed)
 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-10 19:27:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  last_child_creating_anonymous_wrapper_if_needed ( layout_parent ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-24 18:03:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  Layout : : Node &  insertion_parent_for_block_node ( Layout : : NodeWithStyle &  layout_parent ,  Layout : : Node &  layout_node )  
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-03-22 19:13:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! has_inline_or_in_flow_block_children ( layout_parent ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // Parent block has no children, insert this block into parent.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  layout_parent ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-03-25 15:33:22 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    bool  is_out_of_flow  =  layout_node . is_absolutely_positioned ( )  | |  layout_node . is_floating ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is_out_of_flow 
							 
						 
					
						
							
								
									
										
										
										
											2023-04-06 18:01:01 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        & &  ! layout_parent . display ( ) . is_flex_inside ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        & &  ! layout_parent . display ( ) . is_grid_inside ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-03-25 15:33:22 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        & &  layout_parent . last_child ( ) - > is_anonymous ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        & &  layout_parent . last_child ( ) - > children_are_inline ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Block is out-of-flow & previous sibling was wrapped in an anonymous block.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Join the previous sibling inside the anonymous block.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  * layout_parent . last_child ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-15 22:17:27 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! layout_parent . children_are_inline ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Parent block has block-level children, insert this block into parent.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-22 19:13:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  layout_parent ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-03-25 15:33:22 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( is_out_of_flow )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-23 00:55:12 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // Block is out-of-flow, it can have inline siblings if necessary.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  layout_parent ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Parent block has inline-level children (our siblings).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // First move these siblings into an anonymous wrapper block.
 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Vector < JS : : Handle < Layout : : Node > >  children ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 21:33:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        JS : : GCPtr < Layout : : Node >  next ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( JS : : GCPtr < Layout : : Node >  child  =  layout_parent . first_child ( ) ;  child ;  child  =  next )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            next  =  child - > next_sibling ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // NOTE: We let out-of-flow children stay in the parent, to preserve tree structure.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( child - > is_floating ( )  | |  child - > is_absolutely_positioned ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            layout_parent . remove_child ( * child ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            children . append ( * child ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-24 18:03:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    layout_parent . append_child ( layout_parent . create_anonymous_wrapper ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    layout_parent . set_children_are_inline ( false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( auto &  child  :  children )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        layout_parent . last_child ( ) - > append_child ( * child ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-02 03:30:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    layout_parent . last_child ( ) - > set_children_are_inline ( true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Then it's safe to insert this block into parent.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  layout_parent ; 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 14:14:16 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  TreeBuilder : : insert_node_into_inline_or_block_ancestor ( Layout : : Node &  node ,  CSS : : Display  display ,  AppendOrPrepend  mode )  
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2023-07-27 23:31:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( node . display ( ) . is_contents ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 20:57:29 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( display . is_inline_outside ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-23 20:10:42 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // Inlines can be inserted into the nearest ancestor without "display: contents".
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  nearest_ancestor_without_display_contents  =  [ & ] ( )  - >  Layout : : NodeWithStyle &  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  ( auto &  ancestor  :  m_ancestor_stack . in_reverse ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                if  ( ! ancestor - > display ( ) . is_contents ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    return  ancestor ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            VERIFY_NOT_REACHED ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  insertion_point  =  insertion_parent_for_inline_node ( nearest_ancestor_without_display_contents ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( mode  = =  AppendOrPrepend : : Prepend ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            insertion_point . prepend_child ( node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            insertion_point . append_child ( node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        insertion_point . set_children_are_inline ( true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Non-inlines can't be inserted into an inline parent, so find the nearest non-inline ancestor.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  nearest_non_inline_ancestor  =  [ & ] ( )  - >  Layout : : NodeWithStyle &  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  ( auto &  ancestor  :  m_ancestor_stack . in_reverse ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-07-27 23:31:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( ancestor - > display ( ) . is_contents ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-26 16:09:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( ! ancestor - > display ( ) . is_inline_outside ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 21:03:30 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    return  ancestor ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-26 16:09:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( ! ancestor - > display ( ) . is_flow_inside ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    return  ancestor ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-26 16:09:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( ancestor - > dom_node ( )  & &  is < SVG : : SVGForeignObjectElement > ( * ancestor - > dom_node ( ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-10 13:54:57 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    return  ancestor ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            VERIFY_NOT_REACHED ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  insertion_point  =  insertion_parent_for_block_node ( nearest_non_inline_ancestor ,  node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( mode  = =  AppendOrPrepend : : Prepend ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            insertion_point . prepend_child ( node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            insertion_point . append_child ( node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // After inserting an in-flow block-level box into a parent, mark the parent as having non-inline children.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! node . is_floating ( )  & &  ! node . is_absolutely_positioned ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            insertion_point . set_children_are_inline ( false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  TreeBuilder : : create_pseudo_element_if_needed ( DOM : : Element &  element ,  CSS : : Selector : : PseudoElement : : Type  pseudo_element ,  AppendOrPrepend  mode )  
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  document  =  element . document ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  style_computer  =  document . style_computer ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  pseudo_element_style  =  style_computer . compute_pseudo_element_style_if_needed ( element ,  pseudo_element ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-03-14 16:36:20 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! pseudo_element_style ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-03-14 16:36:20 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 15:41:17 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  initial_quote_nesting_level  =  m_quote_nesting_level ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  [ pseudo_element_content ,  final_quote_nesting_level ]  =  pseudo_element_style - > content ( initial_quote_nesting_level ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    m_quote_nesting_level  =  final_quote_nesting_level ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  pseudo_element_display  =  pseudo_element_style - > display ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // ::before and ::after only exist if they have content. `content: normal` computes to `none` for them.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // We also don't create them if they are `display: none`.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( pseudo_element_display . is_none ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        | |  pseudo_element_content . type  = =  CSS : : ContentData : : Type : : Normal 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        | |  pseudo_element_content . type  = =  CSS : : ContentData : : Type : : None ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-03-14 16:36:20 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  pseudo_element_node  =  DOM : : Element : : create_layout_node_for_display_type ( document ,  pseudo_element_display ,  * pseudo_element_style ,  nullptr ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! pseudo_element_node ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 01:29:55 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  generated_for  =  Node : : GeneratedFor : : NotGenerated ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 21:00:03 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( pseudo_element  = =  CSS : : Selector : : PseudoElement : : Type : : Before )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 01:29:55 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        generated_for  =  Node : : GeneratedFor : : PseudoBefore ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 21:00:03 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  if  ( pseudo_element  = =  CSS : : Selector : : PseudoElement : : Type : : After )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 01:29:55 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        generated_for  =  Node : : GeneratedFor : : PseudoAfter ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        VERIFY_NOT_REACHED ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pseudo_element_node - > set_generated_for ( generated_for ,  element ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 15:41:17 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    pseudo_element_node - > set_initial_quote_nesting_level ( initial_quote_nesting_level ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 01:29:55 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // FIXME: Handle images, and multiple values
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( pseudo_element_content . type  = =  CSS : : ContentData : : Type : : String )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-06 15:17:20 +12:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  text  =  document . heap ( ) . allocate < DOM : : Text > ( document . realm ( ) ,  document ,  pseudo_element_content . data ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  text_node  =  document . heap ( ) . allocate_without_realm < Layout : : TextNode > ( document ,  * text ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 01:29:55 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        text_node - > set_generated_for ( generated_for ,  element ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        push_parent ( verify_cast < NodeWithStyle > ( * pseudo_element_node ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        insert_node_into_inline_or_block_ancestor ( * text_node ,  text_node - > display ( ) ,  AppendOrPrepend : : Append ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        pop_parent ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        TODO ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 20:42:22 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    element . set_pseudo_element_node ( { } ,  pseudo_element ,  pseudo_element_node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 14:14:16 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    insert_node_into_inline_or_block_ancestor ( * pseudo_element_node ,  pseudo_element_display ,  mode ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:56:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2022-10-06 13:10:03 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  is_ignorable_whitespace ( Layout : : Node  const &  node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2023-11-21 10:56:29 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( node . is_text_node ( )  & &  static_cast < TextNode  const & > ( node ) . text_for_rendering ( ) . bytes_as_string_view ( ) . is_whitespace ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( node . is_anonymous ( )  & &  node . is_block_container ( )  & &  static_cast < BlockContainer  const & > ( node ) . children_are_inline ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        bool  contains_only_white_space  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        node . for_each_in_inclusive_subtree_of_type < TextNode > ( [ & contains_only_white_space ] ( auto &  text_node )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-21 10:56:29 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  ( ! text_node . text_for_rendering ( ) . bytes_as_string_view ( ) . is_whitespace ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                contains_only_white_space  =  false ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:47:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                return  TraversalDecision : : Break ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:47:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            return  TraversalDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( contains_only_white_space ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-10-11 18:42:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								i32  TreeBuilder : : calculate_list_item_index ( DOM : : Node &  dom_node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is < HTML : : HTMLLIElement > ( dom_node ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  li  =  static_cast < HTML : : HTMLLIElement & > ( dom_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( li . value ( )  ! =  0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  li . value ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( dom_node . previous_sibling ( )  ! =  nullptr )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        DOM : : Node *  current  =  dom_node . previous_sibling ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        while  ( current  ! =  nullptr )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( is < HTML : : HTMLLIElement > ( * current ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                return  calculate_list_item_index ( * current )  +  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            current  =  current - > previous_sibling ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is < HTML : : HTMLOListElement > ( * dom_node . parent ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  ol  =  static_cast < HTML : : HTMLOListElement & > ( * dom_node . parent ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  ol . start ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  TreeBuilder : : create_layout_tree ( DOM : : Node &  dom_node ,  TreeBuilder : : Context &  context )  
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2024-03-28 16:53:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( dom_node . is_element ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  element  =  static_cast < DOM : : Element & > ( dom_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( element . in_top_layer ( )  & &  ! context . layout_top_layer ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
											 
										
											
												LibWeb: Use an ancestor filter to quickly reject many CSS selectors
Given a selector like `.foo .bar #baz`, we know that elements with
the class names `foo` and `bar` must be present in the ancestor chain of
the candidate element, or the selector cannot match.
By keeping track of the current ancestor chain during style computation,
and which strings are used in tag names and attribute names, we can do
a quick check before evaluating the selector itself, to see if all the
required ancestors are present.
The way this works:
1. CSS::Selector now has a cache of up to 8 strings that must be present
   in the ancestor chain of a matching element. Note that we actually
   store string *hashes*, not the strings themselves.
2. When Document performs a recursive style update, we now push and pop
   elements to the ancestor chain stack as they are entered and exited.
3. When entering/exiting an ancestor, StyleComputer collects all the
   relevant string hashes from that ancestor element and updates a
   counting bloom filter.
4. Before evaluating a selector, we first check if any of the hashes
   required by the selector are definitely missing from the ancestor
   filter. If so, it cannot be a match, and we reject it immediately.
5. Otherwise, we carry on and evaluate the selector as usual.
I originally tried doing this with a HashMap, but we ended up losing
a huge chunk of the time saved to HashMap instead. As it turns out,
a simple counting bloom filter is way better at handling this.
The cost is a flat 8KB per StyleComputer, and since it's a bloom filter,
false positives are a thing.
This is extremely efficient, and allows us to quickly reject the
majority of selectors on many huge websites.
Some example rejection rates:
- https://amazon.com: 77%
- https://github.com/SerenityOS/serenity: 61%
- https://nytimes.com: 57%
- https://store.steampowered.com: 55%
- https://en.wikipedia.org: 45%
- https://youtube.com: 32%
- https://shopify.com: 25%
This also yields a chunky 37% speedup on StyleBench. :^)
											 
										 
										
											2024-03-22 13:50:33 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( dom_node . is_element ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dom_node . document ( ) . style_computer ( ) . push_ancestor ( static_cast < DOM : : Element  const & > ( dom_node ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ScopeGuard  pop_ancestor_guard  =  [ & ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( dom_node . is_element ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dom_node . document ( ) . style_computer ( ) . pop_ancestor ( static_cast < DOM : : Element  const & > ( dom_node ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-01 08:23:13 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    JS : : GCPtr < Layout : : Node >  layout_node ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-05 10:26:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Optional < TemporaryChange < bool > >  has_svg_root_change ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-01 08:23:13 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    ScopeGuard  remove_stale_layout_node_guard  =  [ & ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // If we didn't create a layout node for this DOM node,
 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-13 12:34:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // go through the DOM tree and remove any old layout & paint nodes since they are now all stale.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-01 08:23:13 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( ! layout_node )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dom_node . for_each_in_inclusive_subtree ( [ & ] ( auto &  node )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                node . detach_layout_node ( { } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-13 12:34:53 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                node . set_paintable ( nullptr ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-01 08:23:13 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( is < DOM : : Element > ( node ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    static_cast < DOM : : Element & > ( node ) . clear_pseudo_element_nodes ( { } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:47:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                return  TraversalDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-01 08:23:13 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-05 10:26:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( dom_node . is_svg_container ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        has_svg_root_change . emplace ( context . has_svg_root ,  true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    }  else  if  ( dom_node . requires_svg_container ( )  & &  ! context . has_svg_root )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-05 10:26:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-02-05 13:17:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto &  document  =  dom_node . document ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto &  style_computer  =  document . style_computer ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-12 13:24:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    RefPtr < CSS : : StyleProperties >  style ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 14:14:16 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    CSS : : Display  display ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-05 13:17:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is < DOM : : Element > ( dom_node ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  element  =  static_cast < DOM : : Element & > ( dom_node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-17 21:03:28 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        element . clear_pseudo_element_nodes ( { } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        VERIFY ( ! element . needs_style_update ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        style  =  element . computed_css_values ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        display  =  style - > display ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 14:14:16 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( display . is_none ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            return ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 17:02:18 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( context . layout_svg_mask_or_clip_path )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( is < SVG : : SVGMaskElement > ( dom_node ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                layout_node  =  document . heap ( ) . allocate_without_realm < Layout : : SVGMaskBox > ( document ,  static_cast < SVG : : SVGMaskElement & > ( dom_node ) ,  * style ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else  if  ( is < SVG : : SVGClipPathElement > ( dom_node ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                layout_node  =  document . heap ( ) . allocate_without_realm < Layout : : SVGClipBox > ( document ,  static_cast < SVG : : SVGClipPathElement & > ( dom_node ) ,  * style ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                VERIFY_NOT_REACHED ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Only layout direct uses of SVG masks/clipPaths.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            context . layout_svg_mask_or_clip_path  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            layout_node  =  element . create_layout_node ( * style ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-05 13:17:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  if  ( is < DOM : : Document > ( dom_node ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-12 13:24:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        style  =  style_computer . create_document_style ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 14:14:16 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        display  =  style - > display ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-25 11:04:29 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        layout_node  =  document . heap ( ) . allocate_without_realm < Layout : : Viewport > ( static_cast < DOM : : Document & > ( dom_node ) ,  * style ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-05 13:17:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  if  ( is < DOM : : Text > ( dom_node ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        layout_node  =  document . heap ( ) . allocate_without_realm < Layout : : TextNode > ( document ,  static_cast < DOM : : Text & > ( dom_node ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        display  =  CSS : : Display ( CSS : : DisplayOutside : : Inline ,  CSS : : DisplayInside : : Flow ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-05 13:17:01 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! layout_node ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-17 23:32:08 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-02-25 11:59:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! dom_node . parent_or_shadow_host ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        m_layout_root  =  layout_node ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-18 22:13:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  if  ( layout_node - > is_svg_box ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-26 16:09:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        m_ancestor_stack . last ( ) - > append_child ( * layout_node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-25 11:59:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    }  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 14:14:16 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        insert_node_into_inline_or_block_ancestor ( * layout_node ,  display ,  AppendOrPrepend : : Append ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-28 20:22:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto *  shadow_root  =  is < DOM : : Element > ( dom_node )  ?  verify_cast < DOM : : Element > ( dom_node ) . shadow_root_internal ( )  :  nullptr ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-02-10 18:23:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 17:47:42 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Add node for the ::before pseudo-element.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is < DOM : : Element > ( dom_node )  & &  layout_node - > can_have_children ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  element  =  static_cast < DOM : : Element & > ( dom_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        push_parent ( verify_cast < NodeWithStyle > ( * layout_node ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        create_pseudo_element_if_needed ( element ,  CSS : : Selector : : PseudoElement : : Type : : Before ,  AppendOrPrepend : : Prepend ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 17:47:42 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        pop_parent ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-02-10 18:23:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ( dom_node . has_children ( )  | |  shadow_root )  & &  layout_node - > can_have_children ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-06-24 19:53:42 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        push_parent ( verify_cast < NodeWithStyle > ( * layout_node ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 12:34:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( shadow_root )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  ( auto *  node  =  shadow_root - > first_child ( ) ;  node ;  node  =  node - > next_sibling ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                create_layout_tree ( * node ,  context ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 12:34:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-01 22:34:49 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // This is the same as verify_cast<DOM::ParentNode>(dom_node).for_each_child
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  ( auto *  node  =  verify_cast < DOM : : ParentNode > ( dom_node ) . first_child ( ) ;  node ;  node  =  node - > next_sibling ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                create_layout_tree ( * node ,  context ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-25 12:34:54 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-28 16:53:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( dom_node . is_document ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Elements in the top layer do not lay out normally based on their position in the document; instead they
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // generate boxes as if they were siblings of the root element.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            TemporaryChange < bool >  layout_mask ( context . layout_top_layer ,  true ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for  ( auto  const &  top_layer_element  :  document . top_layer_elements ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                create_layout_tree ( top_layer_element ,  context ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        pop_parent ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-21 01:43:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( is < ListItemBox > ( * layout_node ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-03-03 17:50:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto &  element  =  static_cast < DOM : : Element & > ( dom_node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  marker_style  =  style_computer . compute_style ( element ,  CSS : : Selector : : PseudoElement : : Type : : Marker ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-10-11 18:42:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  list_item_marker  =  document . heap ( ) . allocate_without_realm < ListItemMarkerBox > ( document ,  layout_node - > computed_values ( ) . list_style_type ( ) ,  layout_node - > computed_values ( ) . list_style_position ( ) ,  calculate_list_item_index ( dom_node ) ,  * marker_style ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-21 01:43:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        static_cast < ListItemBox & > ( * layout_node ) . set_marker ( list_item_marker ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-12-10 21:00:03 +13:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        element . set_pseudo_element_node ( { } ,  CSS : : Selector : : PseudoElement : : Type : : Marker ,  list_item_marker ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        layout_node - > append_child ( * list_item_marker ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-21 01:43:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2022-07-22 16:08:03 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-05 15:17:10 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( is < HTML : : HTMLSlotElement > ( dom_node ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  slottables  =  static_cast < HTML : : HTMLSlotElement & > ( dom_node ) . assigned_nodes_internal ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        push_parent ( verify_cast < NodeWithStyle > ( * layout_node ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for  ( auto  const &  slottable  :  slottables ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            slottable . visit ( [ & ] ( auto &  node )  {  create_layout_tree ( node ,  context ) ;  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-05 15:17:10 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        pop_parent ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-03-11 18:26:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( is < SVG : : SVGGraphicsElement > ( dom_node ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  graphics_element  =  static_cast < SVG : : SVGGraphicsElement & > ( dom_node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-27 00:13:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // Create the layout tree for the SVG mask/clip paths as a child of the masked element.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Note: This will create a new subtree for each use of the mask (so there's  not a 1-to-1 mapping
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // from DOM node to mask layout node). Each use of a mask may be laid out differently so this
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // duplication is necessary.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  layout_mask_or_clip_path  =  [ & ] ( JS : : GCPtr < SVG : : SVGElement  const >  mask_or_clip_path )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            TemporaryChange < bool >  layout_mask ( context . layout_svg_mask_or_clip_path ,  true ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-11 18:26:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            push_parent ( verify_cast < NodeWithStyle > ( * layout_node ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-27 00:13:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            create_layout_tree ( const_cast < SVG : : SVGElement & > ( * mask_or_clip_path ) ,  context ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-11 18:26:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            pop_parent ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-27 00:13:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( auto  mask  =  graphics_element . mask ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            layout_mask_or_clip_path ( mask ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( auto  clip_path  =  graphics_element . clip_path ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            layout_mask_or_clip_path ( clip_path ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-11 18:26:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-09 17:13:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // https://html.spec.whatwg.org/multipage/rendering.html#button-layout
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( dom_node . is_html_button_element ( )  & &  dom_node . layout_node ( ) - > computed_values ( ) . width ( ) . is_auto ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  computed_values  =  verify_cast < NodeWithStyle > ( * dom_node . layout_node ( ) ) . mutable_computed_values ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        computed_values . set_width ( CSS : : Size : : make_fit_content ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // https://html.spec.whatwg.org/multipage/rendering.html#button-layout
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // If the element is an input element, or if it is a button element and its computed value for
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // 'display' is not 'inline-grid', 'grid', 'inline-flex', or 'flex', then the element's box has
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // a child anonymous button content box with the following behaviors:
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-09 17:13:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( dom_node . is_html_button_element ( )  & &  ! display . is_grid_inside ( )  & &  ! display . is_flex_inside ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto &  parent  =  * dom_node . layout_node ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // If the box does not overflow in the vertical axis, then it is centered vertically.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-03 11:07:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // FIXME: Only apply alignment when box overflows
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  flex_computed_values  =  parent . computed_values ( ) . clone_inherited_values ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-27 08:38:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto &  mutable_flex_computed_values  =  static_cast < CSS : : MutableComputedValues & > ( * flex_computed_values ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        mutable_flex_computed_values . set_display ( CSS : : Display  {  CSS : : DisplayOutside : : Block ,  CSS : : DisplayInside : : Flex  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-03 11:07:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        mutable_flex_computed_values . set_justify_content ( CSS : : JustifyContent : : Center ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        mutable_flex_computed_values . set_flex_direction ( CSS : : FlexDirection : : Column ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        mutable_flex_computed_values . set_height ( CSS : : Size : : make_percentage ( CSS : : Percentage ( 100 ) ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-28 11:39:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        mutable_flex_computed_values . set_min_height ( parent . computed_values ( ) . min_height ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-03 11:07:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  flex_wrapper  =  parent . heap ( ) . template  allocate_without_realm < BlockContainer > ( parent . document ( ) ,  nullptr ,  move ( flex_computed_values ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  content_box_computed_values  =  parent . computed_values ( ) . clone_inherited_values ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  content_box_wrapper  =  parent . heap ( ) . template  allocate_without_realm < BlockContainer > ( parent . document ( ) ,  nullptr ,  move ( content_box_computed_values ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        content_box_wrapper - > set_children_are_inline ( parent . children_are_inline ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        Vector < JS : : Handle < Node > >  sequence ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( auto  child  =  parent . first_child ( ) ;  child ;  child  =  child - > next_sibling ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 17:47:42 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  ( child - > is_generated_for_before_pseudo_element ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-11 03:19:31 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            sequence . append ( * child ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( auto &  node  :  sequence )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            parent . remove_child ( * node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-03 11:07:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            content_box_wrapper - > append_child ( * node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-03 11:07:38 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        flex_wrapper - > append_child ( * content_box_wrapper ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        parent . append_child ( * flex_wrapper ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-10 22:14:25 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        parent . set_children_are_inline ( false ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-06 15:59:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 17:47:42 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Add nodes for the ::after pseudo-element.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-14 14:30:39 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( is < DOM : : Element > ( dom_node )  & &  layout_node - > can_have_children ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-10 22:34:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto &  element  =  static_cast < DOM : : Element & > ( dom_node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        push_parent ( verify_cast < NodeWithStyle > ( * layout_node ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        create_pseudo_element_if_needed ( element ,  CSS : : Selector : : PseudoElement : : Type : : After ,  AppendOrPrepend : : Append ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-10 22:34:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        pop_parent ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-15 12:22:41 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								JS : : GCPtr < Layout : : Node >  TreeBuilder : : build ( DOM : : Node &  dom_node )  
						 
					
						
							
								
									
										
										
										
											2019-10-15 12:22:41 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-03-14 20:25:58 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    VERIFY ( dom_node . is_document ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												LibWeb: Use an ancestor filter to quickly reject many CSS selectors
Given a selector like `.foo .bar #baz`, we know that elements with
the class names `foo` and `bar` must be present in the ancestor chain of
the candidate element, or the selector cannot match.
By keeping track of the current ancestor chain during style computation,
and which strings are used in tag names and attribute names, we can do
a quick check before evaluating the selector itself, to see if all the
required ancestors are present.
The way this works:
1. CSS::Selector now has a cache of up to 8 strings that must be present
   in the ancestor chain of a matching element. Note that we actually
   store string *hashes*, not the strings themselves.
2. When Document performs a recursive style update, we now push and pop
   elements to the ancestor chain stack as they are entered and exited.
3. When entering/exiting an ancestor, StyleComputer collects all the
   relevant string hashes from that ancestor element and updates a
   counting bloom filter.
4. Before evaluating a selector, we first check if any of the hashes
   required by the selector are definitely missing from the ancestor
   filter. If so, it cannot be a match, and we reject it immediately.
5. Otherwise, we carry on and evaluate the selector as usual.
I originally tried doing this with a HashMap, but we ended up losing
a huge chunk of the time saved to HashMap instead. As it turns out,
a simple counting bloom filter is way better at handling this.
The cost is a flat 8KB per StyleComputer, and since it's a bloom filter,
false positives are a thing.
This is extremely efficient, and allows us to quickly reject the
majority of selectors on many huge websites.
Some example rejection rates:
- https://amazon.com: 77%
- https://github.com/SerenityOS/serenity: 61%
- https://nytimes.com: 57%
- https://store.steampowered.com: 55%
- https://en.wikipedia.org: 45%
- https://youtube.com: 32%
- https://shopify.com: 25%
This also yields a chunky 37% speedup on StyleBench. :^)
											 
										 
										
											2024-03-22 13:50:33 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    dom_node . document ( ) . style_computer ( ) . reset_ancestor_filter ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-05 10:26:09 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Context  context ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-18 15:41:17 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    m_quote_nesting_level  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-03-05 18:10:02 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    create_layout_tree ( dom_node ,  context ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( auto *  root  =  dom_node . document ( ) . layout_node ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        fixup_tables ( * root ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-11-26 21:18:34 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  move ( m_layout_root ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-15 12:22:41 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2020-03-07 10:27:02 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								template < CSS : : DisplayInternal  internal ,  typename  Callback >  
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:57:44 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  TreeBuilder : : for_each_in_tree_with_internal_display ( NodeWithStyle &  root ,  Callback  callback )  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2021-04-06 18:38:10 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    root . for_each_in_inclusive_subtree_of_type < Box > ( [ & ] ( auto &  box )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 16:02:53 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  const  display  =  box . display ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:57:44 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( display . is_internal ( )  & &  display . internal ( )  = =  internal ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            callback ( box ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:47:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  TraversalDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:57:44 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								template < CSS : : DisplayInside  inside ,  typename  Callback >  
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:57:44 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  TreeBuilder : : for_each_in_tree_with_inside_display ( NodeWithStyle &  root ,  Callback  callback )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    root . for_each_in_inclusive_subtree_of_type < Box > ( [ & ] ( auto &  box )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-06 16:02:53 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  const  display  =  box . display ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-04-13 01:03:40 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( display . is_outside_and_inside ( )  & &  display . inside ( )  = =  inside ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            callback ( box ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:47:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  TraversalDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  TreeBuilder : : fixup_tables ( NodeWithStyle &  root )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    remove_irrelevant_boxes ( root ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    generate_missing_child_wrappers ( root ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  table_root_boxes  =  generate_missing_parents ( root ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    missing_cells_fixup ( table_root_boxes ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  TreeBuilder : : remove_irrelevant_boxes ( NodeWithStyle &  root )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // The following boxes are discarded as if they were display:none:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Vector < JS : : Handle < Node > >  to_remove ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Children of a table-column.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_internal_display < CSS : : DisplayInternal : : TableColumn > ( root ,  [ & ] ( Box &  table_column )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        table_column . for_each_child ( [ & ] ( auto &  child )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            to_remove . append ( child ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:59:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            return  IterationDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Children of a table-column-group which are not a table-column.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_internal_display < CSS : : DisplayInternal : : TableColumnGroup > ( root ,  [ & ] ( Box &  table_column_group )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        table_column_group . for_each_child ( [ & ] ( auto &  child )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-06-04 14:18:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  ( ! child . display ( ) . is_table_column ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                to_remove . append ( child ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:59:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            return  IterationDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // FIXME:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Anonymous inline boxes which contain only white space and are between two immediate siblings each of which is a table-non-root box.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Anonymous inline boxes which meet all of the following criteria:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // - they contain only white space
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // - they are the first and/or last child of a tabular container
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // - whose immediate sibling, if any, is a table-non-root box
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( auto &  box  :  to_remove ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        box - > parent ( ) - > remove_child ( * box ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  bool  is_table_track ( CSS : : Display  display )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:57:44 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  display . is_table_row ( )  | |  display . is_table_column ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  bool  is_table_track_group ( CSS : : Display  display )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2021-04-18 18:21:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Unless explicitly mentioned otherwise, mentions of table-row-groups in this spec also encompass the specialized
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // table-header-groups and table-footer-groups.
 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-06 17:57:44 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  display . is_table_row_group ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        | |  display . is_table_header_group ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        | |  display . is_table_footer_group ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        | |  display . is_table_column_group ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  is_proper_table_child ( Node  const &  node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  const  display  =  node . display ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  is_table_track_group ( display )  | |  is_table_track ( display )  | |  display . is_table_caption ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-04-01 20:58:27 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  is_not_proper_table_child ( Node  const &  node )  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! node . has_style ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  ! is_proper_table_child ( node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  bool  is_table_row ( Node  const &  node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  node . display ( ) . is_table_row ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-04-01 20:58:27 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  is_not_table_row ( Node  const &  node )  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! node . has_style ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  ! is_table_row ( node ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  bool  is_table_cell ( Node  const &  node )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  node . display ( ) . is_table_cell ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-04-01 20:58:27 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  bool  is_not_table_cell ( Node  const &  node )  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! node . has_style ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return  ! is_table_cell ( node ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								template < typename  Matcher ,  typename  Callback >  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  for_each_sequence_of_consecutive_children_matching ( NodeWithStyle &  parent ,  Matcher  matcher ,  Callback  callback )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Vector < JS : : Handle < Node > >  sequence ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-27 18:20:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    auto  sequence_is_all_ignorable_whitespace  =  [ & ] ( )  - >  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for  ( auto &  node  :  sequence )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            if  ( ! is_ignorable_whitespace ( * node ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-27 18:20:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 13:53:51 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( auto  child  =  parent . first_child ( ) ;  child ;  child  =  child - > next_sibling ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( matcher ( * child )  | |  ( ! sequence . is_empty ( )  & &  is_ignorable_whitespace ( * child ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            sequence . append ( * child ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( ! sequence . is_empty ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-27 18:20:41 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( ! sequence_is_all_ignorable_whitespace ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 13:53:51 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    callback ( sequence ,  child ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                sequence . clear ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-09 13:53:51 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( ! sequence . is_empty ( )  & &  ! sequence_is_all_ignorable_whitespace ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        callback ( sequence ,  nullptr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								template < typename  WrapperBoxType >  
						 
					
						
							
								
									
										
										
										
											2023-05-29 14:11:19 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  wrap_in_anonymous ( Vector < JS : : Handle < Node > > &  sequence ,  Node *  nearest_sibling ,  CSS : : Display  display )  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2021-02-23 20:42:32 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    VERIFY ( ! sequence . is_empty ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto &  parent  =  * sequence . first ( ) - > parent ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  computed_values  =  parent . computed_values ( ) . clone_inherited_values ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-27 08:38:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    static_cast < CSS : : MutableComputedValues & > ( * computed_values ) . set_display ( display ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    auto  wrapper  =  parent . heap ( ) . template  allocate_without_realm < WrapperBoxType > ( parent . document ( ) ,  nullptr ,  move ( computed_values ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for  ( auto &  child  :  sequence )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        parent . remove_child ( * child ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        wrapper - > append_child ( * child ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-22 02:59:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    wrapper - > set_children_are_inline ( parent . children_are_inline ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( nearest_sibling ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        parent . insert_before ( * wrapper ,  * nearest_sibling ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    else 
							 
						 
					
						
							
								
									
										
										
										
											2022-10-17 14:41:50 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        parent . append_child ( * wrapper ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  TreeBuilder : : generate_missing_child_wrappers ( NodeWithStyle &  root )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // An anonymous table-row box must be generated around each sequence of consecutive children of a table-root box which are not proper table child boxes.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_inside_display < CSS : : DisplayInside : : Table > ( root ,  [ & ] ( auto &  parent )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for_each_sequence_of_consecutive_children_matching ( parent ,  is_not_proper_table_child ,  [ & ] ( auto  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display  {  CSS : : DisplayInternal : : TableRow  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // An anonymous table-row box must be generated around each sequence of consecutive children of a table-row-group box which are not table-row boxes.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_internal_display < CSS : : DisplayInternal : : TableRowGroup > ( root ,  [ & ] ( auto &  parent )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for_each_sequence_of_consecutive_children_matching ( parent ,  is_not_table_row ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display  {  CSS : : DisplayInternal : : TableRow  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-18 18:21:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    // Unless explicitly mentioned otherwise, mentions of table-row-groups in this spec also encompass the specialized
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // table-header-groups and table-footer-groups.
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_internal_display < CSS : : DisplayInternal : : TableHeaderGroup > ( root ,  [ & ] ( auto &  parent )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-18 18:21:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for_each_sequence_of_consecutive_children_matching ( parent ,  is_not_table_row ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display  {  CSS : : DisplayInternal : : TableRow  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-18 18:21:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_internal_display < CSS : : DisplayInternal : : TableFooterGroup > ( root ,  [ & ] ( auto &  parent )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-18 18:21:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for_each_sequence_of_consecutive_children_matching ( parent ,  is_not_table_row ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display  {  CSS : : DisplayInternal : : TableRow  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-04-18 18:21:26 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // An anonymous table-cell box must be generated around each sequence of consecutive children of a table-row box which are not table-cell boxes. !Testcase
 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    for_each_in_tree_with_internal_display < CSS : : DisplayInternal : : TableRow > ( root ,  [ & ] ( auto &  parent )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        for_each_sequence_of_consecutive_children_matching ( parent ,  is_not_table_cell ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            wrap_in_anonymous < BlockContainer > ( sequence ,  nearest_sibling ,  CSS : : Display  {  CSS : : DisplayInternal : : TableCell  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								Vector < JS : : Handle < Box > >  TreeBuilder : : generate_missing_parents ( NodeWithStyle &  root )  
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2023-05-29 14:11:19 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    Vector < JS : : Handle < Box > >  table_roots_to_wrap ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    root . for_each_in_inclusive_subtree_of_type < Box > ( [ & ] ( auto &  parent )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // An anonymous table-row box must be generated around each sequence of consecutive table-cell boxes whose parent is not a table-row.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( is_not_table_row ( parent ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for_each_sequence_of_consecutive_children_matching ( parent ,  is_table_cell ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-09-04 17:39:15 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display  {  CSS : : DisplayInternal : : TableRow  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // A table-row is misparented if its parent is neither a table-row-group nor a table-root box.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! parent . display ( ) . is_table_inside ( )  & &  ! is_proper_table_child ( parent ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for_each_sequence_of_consecutive_children_matching ( parent ,  is_table_row ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-29 14:11:19 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display : : from_short ( parent . display ( ) . is_inline_outside ( )  ?  CSS : : Display : : Short : : InlineTable  :  CSS : : Display : : Short : : Table ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // A table-row-group, table-column-group, or table-caption box is misparented if its parent is not a table-root box.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( ! parent . display ( ) . is_table_inside ( )  & &  ! is_proper_table_child ( parent ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for_each_sequence_of_consecutive_children_matching ( parent ,  is_proper_table_child ,  [ & ] ( auto &  sequence ,  auto  nearest_sibling )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-29 14:11:19 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                wrap_in_anonymous < Box > ( sequence ,  nearest_sibling ,  CSS : : Display : : from_short ( parent . display ( ) . is_inline_outside ( )  ?  CSS : : Display : : Short : : InlineTable  :  CSS : : Display : : Short : : Table ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-09 08:27:39 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // An anonymous table-wrapper box must be generated around each table-root.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( parent . display ( ) . is_table_inside ( ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-29 14:11:19 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            table_roots_to_wrap . append ( parent ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-09 08:27:39 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:47:04 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  TraversalDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-04 16:38:42 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-09 08:27:39 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( auto &  table_box  :  table_roots_to_wrap )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto *  nearest_sibling  =  table_box - > next_sibling ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  parent  =  * table_box - > parent ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-27 08:38:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  wrapper_computed_values  =  table_box - > computed_values ( ) . clone_inherited_values ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        table_box - > transfer_table_box_computed_values_to_wrapper_computed_values ( * wrapper_computed_values ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-09 08:27:39 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-01-14 14:48:20 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  wrapper  =  parent . heap ( ) . allocate_without_realm < TableWrapper > ( parent . document ( ) ,  nullptr ,  move ( wrapper_computed_values ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-09 08:27:39 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        parent . remove_child ( * table_box ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        wrapper - > append_child ( * table_box ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-02-07 01:33:10 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( nearest_sibling ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            parent . insert_before ( * wrapper ,  * nearest_sibling ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            parent . append_child ( * wrapper ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-01-09 08:27:39 +03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return  table_roots_to_wrap ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								template < typename  Matcher ,  typename  Callback >  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  for_each_child_box_matching ( Box &  parent ,  Matcher  matcher ,  Callback  callback )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    parent . for_each_child_of_type < Box > ( [ & ] ( Box &  child_box )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( matcher ( child_box ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            callback ( child_box ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-05-04 14:59:52 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return  IterationDecision : : Continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-07 18:00:51 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  fixup_row ( Box &  row_box ,  TableGrid  const &  table_grid ,  size_t  row_index )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( size_t  column_index  =  0 ;  column_index  <  table_grid . column_count ( ) ;  + + column_index )  { 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-22 21:11:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( table_grid . occupancy_grid ( ) . contains ( {  column_index ,  row_index  } ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            continue ; 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-22 21:11:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2024-01-27 08:38:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        auto  computed_values  =  row_box . computed_values ( ) . clone_inherited_values ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto &  mutable_computed_values  =  static_cast < CSS : : MutableComputedValues & > ( * computed_values ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        mutable_computed_values . set_display ( Web : : CSS : : Display  {  CSS : : DisplayInternal : : TableCell  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        // Ensure that the cell (with zero content height) will have the same height as the row by setting vertical-align to middle.
 
							 
						 
					
						
							
								
									
										
										
										
											2024-01-27 08:38:27 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        mutable_computed_values . set_vertical_align ( CSS : : VerticalAlign : : Middle ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  cell_box  =  row_box . heap ( ) . template  allocate_without_realm < BlockContainer > ( row_box . document ( ) ,  nullptr ,  move ( computed_values ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-08-05 05:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        row_box . append_child ( cell_box ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								void  TreeBuilder : : missing_cells_fixup ( Vector < JS : : Handle < Box > >  const &  table_root_boxes )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    // Implements https://www.w3.org/TR/css-tables-3/#missing-cells-fixup.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( auto &  table_box  :  table_root_boxes )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        auto  table_grid  =  TableGrid : : calculate_row_column_grid ( * table_box ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        size_t  row_index  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for_each_child_box_matching ( * table_box ,  TableGrid : : is_table_row_group ,  [ & ] ( auto &  row_group_box )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            for_each_child_box_matching ( row_group_box ,  is_table_row ,  [ & ] ( auto &  row_box )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                fixup_row ( row_box ,  table_grid ,  row_index ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                + + row_index ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                return  IterationDecision : : Continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        for_each_child_box_matching ( * table_box ,  is_table_row ,  [ & ] ( auto &  row_box )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            fixup_row ( row_box ,  table_grid ,  row_index ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            + + row_index ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            return  IterationDecision : : Continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2020-03-07 10:27:02 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}