mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 14:32:46 +00:00 
			
		
		
		
	LibWeb: Start making our layout system "transactional"
This patch adds a map of Layout::Node to FormattingState::NodeState. Instead of updating layout nodes incrementally as layout progresses through the formatting contexts, all updates are now written to the corresponding NodeState instead. At the end of layout, FormattingState::commit() is called, which transfers all the values from the NodeState objects to the Node. This will soon allow us to perform completely non-destructive layouts which don't affect the tree. Note that there are many imperfections here, and still many places where we assign to the NodeState, but later read directly from the Node instead. I'm just committing at this stage to make subsequent diffs easier to understand.
This commit is contained in:
		
							parent
							
								
									561612f219
								
							
						
					
					
						commit
						c9700e100e
					
				
					 27 changed files with 754 additions and 571 deletions
				
			
		
							
								
								
									
										73
									
								
								Userland/Libraries/LibWeb/Layout/FormattingState.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								Userland/Libraries/LibWeb/Layout/FormattingState.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #include <LibWeb/Layout/BlockContainer.h> | ||||
| #include <LibWeb/Layout/FormattingState.h> | ||||
| 
 | ||||
| namespace Web::Layout { | ||||
| 
 | ||||
| void FormattingState::commit() | ||||
| { | ||||
|     for (auto& it : nodes) { | ||||
|         auto& node = const_cast<Layout::NodeWithStyleAndBoxModelMetrics&>(*it.key); | ||||
|         auto& node_state = *it.value; | ||||
| 
 | ||||
|         // Transfer box model metrics.
 | ||||
|         node.box_model().offset = { node_state.offset_top, node_state.offset_right, node_state.offset_bottom, node_state.offset_left }; | ||||
|         node.box_model().padding = { node_state.padding_top, node_state.padding_right, node_state.padding_bottom, node_state.padding_left }; | ||||
|         node.box_model().border = { node_state.border_top, node_state.border_right, node_state.border_bottom, node_state.border_left }; | ||||
|         node.box_model().margin = { node_state.margin_top, node_state.margin_right, node_state.margin_bottom, node_state.margin_left }; | ||||
| 
 | ||||
|         // For boxes, transfer relative offset and size.
 | ||||
|         if (is<Layout::Box>(node)) { | ||||
|             auto& box = static_cast<Layout::Box&>(node); | ||||
|             box.set_offset(node_state.offset); | ||||
|             box.set_content_size(node_state.content_width, node_state.content_height); | ||||
|         } | ||||
| 
 | ||||
|         // For block containers, transfer line boxes.
 | ||||
|         if (is<Layout::BlockContainer>(node)) { | ||||
|             auto& block_container = static_cast<Layout::BlockContainer&>(node); | ||||
|             block_container.set_line_boxes(move(node_state.line_boxes)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Gfx::FloatRect margin_box_rect(Box const& box, FormattingState const& state) | ||||
| { | ||||
|     auto const& box_state = state.get(box); | ||||
|     auto rect = Gfx::FloatRect { box_state.offset, { box_state.content_width, 0 } }; | ||||
|     rect.set_x(rect.x() - box_state.margin_box_left()); | ||||
|     rect.set_width(rect.width() + box_state.margin_box_left() + box_state.margin_box_right()); | ||||
|     rect.set_y(rect.y() - box_state.margin_box_top()); | ||||
|     rect.set_height(rect.height() + box_state.margin_box_top() + box_state.margin_box_bottom()); | ||||
|     return rect; | ||||
| } | ||||
| 
 | ||||
| Gfx::FloatRect margin_box_rect_in_ancestor_coordinate_space(Box const& box, Box const& ancestor_box, FormattingState const& state) | ||||
| { | ||||
|     auto rect = margin_box_rect(box, state); | ||||
|     for (auto const* current = box.parent(); current; current = current->parent()) { | ||||
|         if (current == &ancestor_box) | ||||
|             break; | ||||
|         if (is<Box>(*current)) { | ||||
|             auto const& current_state = state.get(static_cast<Box const&>(*current)); | ||||
|             rect.translate_by(current_state.offset); | ||||
|         } | ||||
|     } | ||||
|     return rect; | ||||
| } | ||||
| 
 | ||||
| Gfx::FloatRect absolute_content_rect(Box const& box, FormattingState const& state) | ||||
| { | ||||
|     auto const& box_state = state.get(box); | ||||
|     Gfx::FloatRect rect { box_state.offset, { box_state.content_width, box_state.content_height } }; | ||||
|     for (auto* block = box.containing_block(); block; block = block->containing_block()) | ||||
|         rect.translate_by(state.get(*block).offset); | ||||
|     return rect; | ||||
| } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling