| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |  * Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <LibWeb/CSS/Length.h>
 | 
					
						
							|  |  |  | #include <LibWeb/DOM/Node.h>
 | 
					
						
							|  |  |  | #include <LibWeb/Dump.h>
 | 
					
						
							| 
									
										
										
										
											2021-10-06 20:02:41 +02:00
										 |  |  | #include <LibWeb/Layout/BlockContainer.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-25 20:08:52 +01:00
										 |  |  | #include <LibWeb/Layout/BlockFormattingContext.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  | #include <LibWeb/Layout/Box.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | #include <LibWeb/Layout/InlineFormattingContext.h>
 | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  | #include <LibWeb/Layout/InlineLevelIterator.h>
 | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  | #include <LibWeb/Layout/LineBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  | #include <LibWeb/Layout/ReplacedBox.h>
 | 
					
						
							| 
									
										
										
										
											2022-03-18 22:13:26 +01:00
										 |  |  | #include <LibWeb/Layout/SVGSVGBox.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace Web::Layout { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-24 10:50:57 +02:00
										 |  |  | constexpr double text_justification_threshold = 0.1; | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-16 23:30:32 +02:00
										 |  |  | InlineFormattingContext::InlineFormattingContext(LayoutState& state, BlockContainer const& containing_block, BlockFormattingContext& parent) | 
					
						
							| 
									
										
										
										
											2022-02-19 20:13:47 +01:00
										 |  |  |     : FormattingContext(Type::Inline, state, containing_block, &parent) | 
					
						
							| 
									
										
										
										
											2022-07-09 20:45:55 +02:00
										 |  |  |     , m_containing_block_state(state.get(containing_block)) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 13:21:51 -06:00
										 |  |  | InlineFormattingContext::~InlineFormattingContext() = default; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-23 15:22:18 +01:00
										 |  |  | BlockFormattingContext& InlineFormattingContext::parent() | 
					
						
							| 
									
										
										
										
											2020-12-05 20:10:39 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-01-23 15:22:18 +01:00
										 |  |  |     return static_cast<BlockFormattingContext&>(*FormattingContext::parent()); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-09-23 16:58:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-23 15:22:18 +01:00
										 |  |  | BlockFormattingContext const& InlineFormattingContext::parent() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return static_cast<BlockFormattingContext const&>(*FormattingContext::parent()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  | CSSPixels InlineFormattingContext::leftmost_x_offset_at(CSSPixels y) const | 
					
						
							| 
									
										
										
										
											2022-01-23 15:22:18 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-01-24 02:03:29 +01:00
										 |  |  |     // NOTE: Floats are relative to the BFC root box, not necessarily the containing block of this IFC.
 | 
					
						
							| 
									
										
										
										
											2023-05-31 10:18:34 +02:00
										 |  |  |     auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root()); | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels y_in_root = box_in_root_rect.y() + y; | 
					
						
							| 
									
										
										
										
											2022-03-18 14:44:36 +01:00
										 |  |  |     auto space = parent().space_used_by_floats(y_in_root); | 
					
						
							| 
									
										
										
										
											2023-05-16 09:46:45 +02:00
										 |  |  |     if (box_in_root_rect.x() >= space.left) { | 
					
						
							|  |  |  |         // The left edge of the containing block is to the right of the rightmost left-side float.
 | 
					
						
							|  |  |  |         // We start placing inline content at the left edge of the containing block.
 | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // The left edge of the containing block is to the left of the rightmost left-side float.
 | 
					
						
							|  |  |  |     // We adjust the inline content insertion point by the overlap between the containing block and the float.
 | 
					
						
							| 
									
										
										
										
											2023-06-04 12:55:55 +02:00
										 |  |  |     return space.left - max(CSSPixels(0), box_in_root_rect.x()); | 
					
						
							| 
									
										
										
										
											2022-03-18 14:44:36 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  | CSSPixels InlineFormattingContext::available_space_for_line(CSSPixels y) const | 
					
						
							| 
									
										
										
										
											2022-03-18 14:44:36 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-16 09:46:45 +02:00
										 |  |  |     auto intrusions = parent().intrusion_by_floats_into_box(containing_block(), y); | 
					
						
							|  |  |  |     return m_available_space->width.to_px() - (intrusions.left + intrusions.right); | 
					
						
							| 
									
										
										
										
											2020-12-05 20:10:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  | CSSPixels InlineFormattingContext::automatic_content_width() const | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_automatic_content_width; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  | CSSPixels InlineFormattingContext::automatic_content_height() const | 
					
						
							| 
									
										
										
										
											2022-09-24 13:39:43 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  |     return m_automatic_content_height; | 
					
						
							| 
									
										
										
										
											2022-09-24 13:39:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  | void InlineFormattingContext::run(Box const&, LayoutMode layout_mode, AvailableSpace const& available_space) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |     VERIFY(containing_block().children_are_inline()); | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  |     m_available_space = available_space; | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |     generate_line_boxes(layout_mode); | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels content_height = 0; | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto& line_box : m_containing_block_state.line_boxes) { | 
					
						
							|  |  |  |         content_height += line_box.height(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-03 17:14:15 +02:00
										 |  |  |     // NOTE: We ask the parent BFC to calculate the automatic content width of this IFC.
 | 
					
						
							|  |  |  |     //       This ensures that any floated boxes are taken into account.
 | 
					
						
							|  |  |  |     m_automatic_content_width = parent().greatest_child_width(containing_block()); | 
					
						
							| 
									
										
										
										
											2022-09-27 15:29:17 +02:00
										 |  |  |     m_automatic_content_height = content_height; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  | void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode layout_mode) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     auto width_of_containing_block = m_available_space->width.to_px(); | 
					
						
							| 
									
										
										
										
											2022-02-21 17:42:09 +01:00
										 |  |  |     auto& box_state = m_state.get_mutable(box); | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     auto const& computed_values = box.computed_values(); | 
					
						
							| 
									
										
										
										
											2022-02-14 15:49:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.margin_left = computed_values.margin().left().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     box_state.border_left = computed_values.border_left().width; | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.padding_left = computed_values.padding().left().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.margin_right = computed_values.margin().right().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     box_state.border_right = computed_values.border_right().width; | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.padding_right = computed_values.padding().right().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.margin_top = computed_values.margin().top().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  |     box_state.border_top = computed_values.border_top().width; | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.padding_top = computed_values.padding().top().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.padding_bottom = computed_values.padding().bottom().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  |     box_state.border_bottom = computed_values.border_bottom().width; | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |     box_state.margin_bottom = computed_values.margin().bottom().to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-02-14 15:49:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-08 16:47:50 +01:00
										 |  |  |     if (box_is_sized_as_replaced_element(box)) { | 
					
						
							|  |  |  |         box_state.set_content_width(compute_width_for_replaced_element(box, *m_available_space)); | 
					
						
							|  |  |  |         box_state.set_content_height(compute_height_for_replaced_element(box, *m_available_space)); | 
					
						
							| 
									
										
										
										
											2023-05-19 18:14:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (is<SVGSVGBox>(box)) | 
					
						
							| 
									
										
										
										
											2023-06-08 16:47:50 +01:00
										 |  |  |             (void)layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space)); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  |     // Any box that has simple flow inside should have generated line box fragments already.
 | 
					
						
							| 
									
										
										
										
											2023-04-13 13:37:19 +02:00
										 |  |  |     if (box.display().is_flow_inside()) { | 
					
						
							|  |  |  |         dbgln("FIXME: InlineFormattingContext::dimension_box_on_line got unexpected box in inline context:"); | 
					
						
							|  |  |  |         dump_tree(box); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto const& width_value = box.computed_values().width(); | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels unconstrained_width = 0; | 
					
						
							| 
									
										
										
										
											2022-11-28 16:40:15 +01:00
										 |  |  |     if (should_treat_width_as_auto(box, *m_available_space)) { | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  |         auto result = calculate_shrink_to_fit_widths(box); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto available_width = m_available_space->width.to_px() | 
					
						
							|  |  |  |             - box_state.margin_left | 
					
						
							|  |  |  |             - box_state.border_left | 
					
						
							|  |  |  |             - box_state.padding_left | 
					
						
							|  |  |  |             - box_state.padding_right | 
					
						
							|  |  |  |             - box_state.border_right | 
					
						
							|  |  |  |             - box_state.margin_right; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |         unconstrained_width = min(max(result.preferred_minimum_width, available_width), result.preferred_width); | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         if (width_value.contains_percentage() && !m_available_space->width.is_definite()) { | 
					
						
							|  |  |  |             // NOTE: We can't resolve percentages yet. We'll have to wait until after inner layout.
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2023-01-07 13:38:46 +01:00
										 |  |  |             auto inner_width = calculate_inner_width(box, m_available_space->width, width_value); | 
					
						
							|  |  |  |             unconstrained_width = inner_width.to_px(box); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-15 13:54:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels width = unconstrained_width; | 
					
						
							| 
									
										
										
										
											2022-10-15 13:54:42 +02:00
										 |  |  |     auto computed_max_width = box.computed_values().max_width(); | 
					
						
							|  |  |  |     if (!computed_max_width.is_none()) { | 
					
						
							| 
									
										
										
										
											2023-05-06 16:34:55 +02:00
										 |  |  |         auto max_width = computed_max_width.to_px(box, width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-10-15 13:54:42 +02:00
										 |  |  |         width = min(width, max_width); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto computed_min_width = box.computed_values().min_width(); | 
					
						
							|  |  |  |     if (!computed_min_width.is_auto()) { | 
					
						
							| 
									
										
										
										
											2023-01-07 13:38:46 +01:00
										 |  |  |         auto min_width = calculate_inner_width(box, m_available_space->width, computed_min_width).to_px(box); | 
					
						
							| 
									
										
										
										
											2022-10-15 13:54:42 +02:00
										 |  |  |         width = max(width, min_width); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-04 20:32:50 +00:00
										 |  |  |     box_state.set_content_width(width); | 
					
						
							| 
									
										
										
										
											2022-10-15 13:54:42 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  |     auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto const& height_value = box.computed_values().height(); | 
					
						
							|  |  |  |     if (height_value.is_auto()) { | 
					
						
							|  |  |  |         // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7.
 | 
					
						
							|  |  |  |         parent().compute_height(box, AvailableSpace(AvailableSize::make_indefinite(), AvailableSize::make_indefinite())); | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2023-01-07 13:38:46 +01:00
										 |  |  |         auto inner_height = calculate_inner_height(box, AvailableSize::make_definite(m_containing_block_state.content_height()), height_value); | 
					
						
							|  |  |  |         box_state.set_content_height(inner_height.to_px(box)); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-06 20:29:31 +02:00
										 |  |  |     if (independent_formatting_context) | 
					
						
							|  |  |  |         independent_formatting_context->parent_context_did_dimension_child_root_box(); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  | void InlineFormattingContext::apply_justification_to_fragments(CSS::TextJustify text_justify, LineBox& line_box, bool is_last_line) | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-03-12 19:32:03 +00:00
										 |  |  |     switch (text_justify) { | 
					
						
							|  |  |  |     case CSS::TextJustify::None: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     // FIXME: These two cases currently fall back to auto, handle them as well.
 | 
					
						
							|  |  |  |     case CSS::TextJustify::InterCharacter: | 
					
						
							|  |  |  |     case CSS::TextJustify::InterWord: | 
					
						
							|  |  |  |     case CSS::TextJustify::Auto: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 09:51:33 +02:00
										 |  |  |     CSSPixels excess_horizontal_space = line_box.original_available_width() - line_box.width(); | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Only justify the text if the excess horizontal space is less than or
 | 
					
						
							|  |  |  |     // equal to 10%, or if we are not looking at the last line box.
 | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  |     if (is_last_line && excess_horizontal_space / m_available_space->width.to_px().value() > text_justification_threshold) | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels excess_horizontal_space_including_whitespace = excess_horizontal_space; | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |     size_t whitespace_count = 0; | 
					
						
							|  |  |  |     for (auto& fragment : line_box.fragments()) { | 
					
						
							|  |  |  |         if (fragment.is_justifiable_whitespace()) { | 
					
						
							|  |  |  |             ++whitespace_count; | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |             excess_horizontal_space_including_whitespace += fragment.width(); | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-24 10:50:57 +02:00
										 |  |  |     CSSPixels justified_space_width = whitespace_count > 0 ? (excess_horizontal_space_including_whitespace / static_cast<double>(whitespace_count)) : 0; | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // This is the amount that each fragment will be offset by. If a whitespace
 | 
					
						
							|  |  |  |     // fragment is shorter than the justified space width, it increases to push
 | 
					
						
							|  |  |  |     // subsequent fragments, and decreases to pull them back otherwise.
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels running_diff = 0; | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |     for (size_t i = 0; i < line_box.fragments().size(); ++i) { | 
					
						
							|  |  |  |         auto& fragment = line_box.fragments()[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         auto offset = fragment.offset(); | 
					
						
							|  |  |  |         offset.translate_by(running_diff, 0); | 
					
						
							|  |  |  |         fragment.set_offset(offset); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (fragment.is_justifiable_whitespace() | 
					
						
							|  |  |  |             && fragment.width() != justified_space_width) { | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |             running_diff += justified_space_width - fragment.width(); | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |             fragment.set_width(justified_space_width); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  | void InlineFormattingContext::generate_line_boxes(LayoutMode layout_mode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-02-21 17:42:09 +01:00
										 |  |  |     auto& containing_block_state = m_state.get_mutable(containing_block()); | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     auto& line_boxes = containing_block_state.line_boxes; | 
					
						
							|  |  |  |     line_boxes.clear_with_capacity(); | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     InlineLevelIterator iterator(*this, m_state, containing_block(), layout_mode); | 
					
						
							| 
									
										
										
										
											2022-08-14 16:43:08 +02:00
										 |  |  |     LineBuilder line_builder(*this, m_state); | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  |         auto item_opt = iterator.next(line_builder.available_width_for_current_line()); | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |         if (!item_opt.has_value()) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         auto& item = item_opt.value(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-21 14:15:10 +01:00
										 |  |  |         // Ignore collapsible whitespace chunks at the start of line, and if the last fragment already ends in whitespace.
 | 
					
						
							| 
									
										
										
										
											2022-03-27 21:02:24 +02:00
										 |  |  |         if (item.is_collapsible_whitespace && (line_boxes.is_empty() || line_boxes.last().is_empty_or_ends_in_whitespace())) | 
					
						
							| 
									
										
										
										
											2022-01-21 14:15:10 +01:00
										 |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  |         switch (item.type) { | 
					
						
							|  |  |  |         case InlineLevelIterator::Item::Type::ForcedBreak: | 
					
						
							|  |  |  |             line_builder.break_line(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case InlineLevelIterator::Item::Type::Element: { | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |             auto& box = verify_cast<Layout::Box>(*item.node); | 
					
						
							| 
									
										
										
										
											2023-04-28 11:44:21 +02:00
										 |  |  |             compute_inset(box); | 
					
						
							| 
									
										
										
										
											2022-07-09 15:17:47 +02:00
										 |  |  |             line_builder.break_if_needed(item.border_box_width()); | 
					
						
							| 
									
										
										
										
											2022-03-09 18:46:07 +01:00
										 |  |  |             line_builder.append_box(box, item.border_start + item.padding_start, item.padding_end + item.border_end, item.margin_start, item.margin_end); | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-07 22:27:09 +01:00
										 |  |  |         case InlineLevelIterator::Item::Type::AbsolutelyPositionedElement: | 
					
						
							|  |  |  |             if (is<Box>(*item.node)) | 
					
						
							|  |  |  |                 parent().add_absolutely_positioned_box(static_cast<Layout::Box const&>(*item.node)); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 19:18:05 +01:00
										 |  |  |         case InlineLevelIterator::Item::Type::FloatingElement: | 
					
						
							|  |  |  |             if (is<Box>(*item.node)) | 
					
						
							| 
									
										
										
										
											2022-12-25 17:13:21 +03:00
										 |  |  |                 parent().layout_floating_box(static_cast<Layout::Box const&>(*item.node), containing_block(), layout_mode, *m_available_space, 0, &line_builder); | 
					
						
							| 
									
										
										
										
											2022-03-22 19:18:05 +01:00
										 |  |  |             break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  |         case InlineLevelIterator::Item::Type::Text: { | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |             auto& text_node = verify_cast<Layout::TextNode>(*item.node); | 
					
						
							| 
									
										
										
										
											2022-04-03 21:05:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-09 15:17:47 +02:00
										 |  |  |             if (text_node.computed_values().white_space() != CSS::WhiteSpace::Nowrap && line_builder.break_if_needed(item.border_box_width())) { | 
					
						
							| 
									
										
										
										
											2022-03-29 13:35:21 +02:00
										 |  |  |                 // If whitespace caused us to break, we swallow the whitespace instead of
 | 
					
						
							|  |  |  |                 // putting it on the next line.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // If we're in a whitespace-collapsing context, we can simply check the flag.
 | 
					
						
							| 
									
										
										
										
											2022-03-26 18:50:43 +01:00
										 |  |  |                 if (item.is_collapsible_whitespace) | 
					
						
							|  |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2022-03-29 13:35:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 // In whitespace-preserving contexts (white-space: pre*), we have to check manually.
 | 
					
						
							|  |  |  |                 auto view = text_node.text_for_rendering().substring_view(item.offset_in_node, item.length_in_node); | 
					
						
							|  |  |  |                 if (view.is_whitespace()) | 
					
						
							|  |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2022-03-26 18:50:43 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  |             line_builder.append_text_chunk( | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |                 text_node, | 
					
						
							|  |  |  |                 item.offset_in_node, | 
					
						
							|  |  |  |                 item.length_in_node, | 
					
						
							| 
									
										
										
										
											2022-02-14 15:52:29 +01:00
										 |  |  |                 item.border_start + item.padding_start, | 
					
						
							|  |  |  |                 item.padding_end + item.border_end, | 
					
						
							| 
									
										
										
										
											2022-03-09 18:46:07 +01:00
										 |  |  |                 item.margin_start, | 
					
						
							|  |  |  |                 item.margin_end, | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |                 item.width, | 
					
						
							| 
									
										
										
										
											2022-03-29 22:33:44 +02:00
										 |  |  |                 text_node.line_height()); | 
					
						
							| 
									
										
										
										
											2022-01-19 11:59:44 +01:00
										 |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     for (auto& line_box : line_boxes) { | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |         line_box.trim_trailing_whitespace(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-22 10:32:49 +01:00
										 |  |  |     line_builder.remove_last_line_if_empty(); | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     auto const& containing_block = this->containing_block(); | 
					
						
							|  |  |  |     auto text_align = containing_block.computed_values().text_align(); | 
					
						
							| 
									
										
										
										
											2022-03-12 19:32:03 +00:00
										 |  |  |     auto text_justify = containing_block.computed_values().text_justify(); | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |     if (text_align == CSS::TextAlign::Justify) { | 
					
						
							|  |  |  |         for (size_t i = 0; i < line_boxes.size(); i++) { | 
					
						
							|  |  |  |             auto& line_box = line_boxes[i]; | 
					
						
							|  |  |  |             auto is_last_line = i == line_boxes.size() - 1; | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  |             apply_justification_to_fragments(text_justify, line_box, is_last_line); | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  | bool InlineFormattingContext::any_floats_intrude_at_y(CSSPixels y) const | 
					
						
							| 
									
										
										
										
											2022-09-11 22:39:01 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-31 10:18:34 +02:00
										 |  |  |     auto box_in_root_rect = content_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root()); | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  |     CSSPixels y_in_root = box_in_root_rect.y() + y; | 
					
						
							| 
									
										
										
										
											2022-09-11 22:39:01 +02:00
										 |  |  |     auto space = parent().space_used_by_floats(y_in_root); | 
					
						
							|  |  |  |     return space.left > 0 || space.right > 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-03 17:48:46 +00:00
										 |  |  | bool InlineFormattingContext::can_fit_new_line_at_y(CSSPixels y) const | 
					
						
							| 
									
										
										
										
											2022-09-16 14:21:52 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-05-16 09:46:45 +02:00
										 |  |  |     auto top_intrusions = parent().intrusion_by_floats_into_box(containing_block(), y); | 
					
						
							|  |  |  |     auto bottom_intrusions = parent().intrusion_by_floats_into_box(containing_block(), y + containing_block().line_height() - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto left_edge = [](auto& space) -> CSSPixels { | 
					
						
							|  |  |  |         return space.left; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto right_edge = [this](auto& space) -> CSSPixels { | 
					
						
							|  |  |  |         return m_available_space->width.to_px() - space.right; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto top_left_edge = left_edge(top_intrusions); | 
					
						
							|  |  |  |     auto top_right_edge = right_edge(top_intrusions); | 
					
						
							|  |  |  |     auto bottom_left_edge = left_edge(bottom_intrusions); | 
					
						
							|  |  |  |     auto bottom_right_edge = right_edge(bottom_intrusions); | 
					
						
							| 
									
										
										
										
											2022-09-16 14:21:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (top_left_edge > bottom_right_edge) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (bottom_left_edge > top_right_edge) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | } |