| 
									
										
										
										
											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 { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  | constexpr float text_justification_threshold = 0.1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  | InlineFormattingContext::InlineFormattingContext(FormattingState& 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-07-09 20:56:59 +02:00
										 |  |  |     switch (m_containing_block_state.width_constraint) { | 
					
						
							|  |  |  |     case SizeConstraint::MinContent: | 
					
						
							|  |  |  |         m_effective_containing_block_width = 0; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case SizeConstraint::MaxContent: | 
					
						
							|  |  |  |         m_effective_containing_block_width = INFINITY; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         m_effective_containing_block_width = m_containing_block_state.content_width; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											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-03-18 14:44:36 +01:00
										 |  |  | float InlineFormattingContext::leftmost_x_offset_at(float 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.
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     auto box_in_root_rect = margin_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root(), m_state); | 
					
						
							| 
									
										
										
										
											2022-01-24 02:03:29 +01:00
										 |  |  |     float 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); | 
					
						
							| 
									
										
										
										
											2022-07-09 20:45:55 +02:00
										 |  |  |     float containing_block_x = m_containing_block_state.offset.x(); | 
					
						
							| 
									
										
										
										
											2022-03-18 14:44:36 +01:00
										 |  |  |     return max(space.left, containing_block_x) - containing_block_x; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float InlineFormattingContext::available_space_for_line(float y) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  |     if (m_effective_containing_block_width == 0) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!isfinite(m_effective_containing_block_width)) | 
					
						
							|  |  |  |         return INFINITY; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-18 14:44:36 +01:00
										 |  |  |     // NOTE: Floats are relative to the BFC root box, not necessarily the containing block of this IFC.
 | 
					
						
							|  |  |  |     auto box_in_root_rect = margin_box_rect_in_ancestor_coordinate_space(containing_block(), parent().root(), m_state); | 
					
						
							|  |  |  |     float y_in_root = box_in_root_rect.y() + y; | 
					
						
							|  |  |  |     auto space = parent().space_used_by_floats(y_in_root); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto const& root_block_state = m_state.get(parent().root()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-09 20:45:55 +02:00
										 |  |  |     space.left = max(space.left, m_containing_block_state.offset.x()) - m_containing_block_state.offset.x(); | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  |     space.right = min(root_block_state.content_width - space.right, m_containing_block_state.offset.x() + m_effective_containing_block_width); | 
					
						
							| 
									
										
										
										
											2022-03-18 14:44:36 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return space.right - space.left; | 
					
						
							| 
									
										
										
										
											2020-12-05 20:10:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  | void InlineFormattingContext::run(Box const&, LayoutMode layout_mode) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |     VERIFY(containing_block().children_are_inline()); | 
					
						
							| 
									
										
										
										
											2022-01-17 15:07:19 +01:00
										 |  |  |     generate_line_boxes(layout_mode); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  |     auto width_of_containing_block = CSS::Length::make_px(m_effective_containing_block_width); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     box_state.margin_left = computed_values.margin().left.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							|  |  |  |     box_state.border_left = computed_values.border_left().width; | 
					
						
							|  |  |  |     box_state.padding_left = computed_values.padding().left.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |     box_state.margin_right = computed_values.margin().right.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							|  |  |  |     box_state.border_right = computed_values.border_right().width; | 
					
						
							|  |  |  |     box_state.padding_right = computed_values.padding().right.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     box_state.margin_top = computed_values.margin().top.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							|  |  |  |     box_state.border_top = computed_values.border_top().width; | 
					
						
							| 
									
										
										
										
											2022-02-21 02:16:21 +01:00
										 |  |  |     box_state.padding_top = computed_values.padding().top.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 02:16:21 +01:00
										 |  |  |     box_state.padding_bottom = computed_values.padding().bottom.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							| 
									
										
										
										
											2022-03-20 13:27:47 +01:00
										 |  |  |     box_state.border_bottom = computed_values.border_bottom().width; | 
					
						
							| 
									
										
										
										
											2022-02-21 02:16:21 +01:00
										 |  |  |     box_state.margin_bottom = computed_values.margin().bottom.resolved(box, width_of_containing_block).to_px(box); | 
					
						
							| 
									
										
										
										
											2022-02-14 15:49:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-01 18:55:47 +01:00
										 |  |  |     if (is<ReplacedBox>(box)) { | 
					
						
							| 
									
										
										
										
											2021-06-24 19:53:42 +02:00
										 |  |  |         auto& replaced = verify_cast<ReplacedBox>(box); | 
					
						
							| 
									
										
										
										
											2022-03-18 22:13:26 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (is<SVGSVGBox>(box)) | 
					
						
							|  |  |  |             (void)layout_inside(replaced, layout_mode); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |         box_state.content_width = compute_width_for_replaced_element(m_state, replaced); | 
					
						
							|  |  |  |         box_state.content_height = compute_height_for_replaced_element(m_state, replaced); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (box.is_inline_block()) { | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |         auto const& inline_block = verify_cast<BlockContainer>(box); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-18 15:10:11 +00:00
										 |  |  |         auto& width_value = inline_block.computed_values().width(); | 
					
						
							| 
									
										
										
										
											2022-07-07 12:36:02 +02:00
										 |  |  |         if (width_value.is_auto()) { | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |             auto result = calculate_shrink_to_fit_widths(inline_block); | 
					
						
							| 
									
										
										
										
											2020-11-29 22:00:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-09 20:45:55 +02:00
										 |  |  |             auto available_width = m_containing_block_state.content_width | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |                 - box_state.margin_left | 
					
						
							|  |  |  |                 - box_state.border_left | 
					
						
							|  |  |  |                 - box_state.padding_left | 
					
						
							|  |  |  |                 - box_state.padding_right | 
					
						
							|  |  |  |                 - box_state.border_right | 
					
						
							|  |  |  |                 - box_state.margin_right; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             auto width = min(max(result.preferred_minimum_width, available_width), result.preferred_width); | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |             box_state.content_width = width; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  |             auto container_width = CSS::Length::make_px(m_effective_containing_block_width); | 
					
						
							| 
									
										
										
										
											2022-07-07 12:36:02 +02:00
										 |  |  |             box_state.content_width = width_value.resolved(box, container_width).to_px(inline_block); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-12 19:54:09 +01:00
										 |  |  |         auto independent_formatting_context = layout_inside(inline_block, layout_mode); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-18 15:10:11 +00:00
										 |  |  |         auto& height_value = inline_block.computed_values().height(); | 
					
						
							| 
									
										
										
										
											2022-07-07 12:36:02 +02:00
										 |  |  |         if (height_value.is_auto()) { | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |             // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7.
 | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |             BlockFormattingContext::compute_height(inline_block, m_state); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2022-07-09 20:45:55 +02:00
										 |  |  |             auto container_height = CSS::Length::make_px(m_containing_block_state.content_height); | 
					
						
							| 
									
										
										
										
											2022-07-07 12:36:02 +02:00
										 |  |  |             box_state.content_height = height_value.resolved(box, container_height).to_px(inline_block); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-12 19:54:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         independent_formatting_context->parent_context_did_dimension_child_root_box(); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Non-replaced, non-inline-block, box on a line!?
 | 
					
						
							|  |  |  |     // I don't think we should be here. Dump the box tree so we can take a look at it.
 | 
					
						
							|  |  |  |     dbgln("FIXME: I've been asked to dimension a non-replaced, non-inline-block box on a line:"); | 
					
						
							|  |  |  |     dump_tree(box); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-09 20:56:59 +02:00
										 |  |  |     float excess_horizontal_space = m_effective_containing_block_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-07-09 20:56:59 +02:00
										 |  |  |     if (is_last_line && excess_horizontal_space / m_effective_containing_block_width > text_justification_threshold) | 
					
						
							| 
									
										
										
										
											2022-03-12 17:01:06 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float excess_horizontal_space_including_whitespace = excess_horizontal_space; | 
					
						
							|  |  |  |     size_t whitespace_count = 0; | 
					
						
							|  |  |  |     for (auto& fragment : line_box.fragments()) { | 
					
						
							|  |  |  |         if (fragment.is_justifiable_whitespace()) { | 
					
						
							|  |  |  |             ++whitespace_count; | 
					
						
							|  |  |  |             excess_horizontal_space_including_whitespace += fragment.width(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float justified_space_width = whitespace_count > 0 ? (excess_horizontal_space_including_whitespace / static_cast<float>(whitespace_count)) : 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // 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.
 | 
					
						
							|  |  |  |     float running_diff = 0; | 
					
						
							|  |  |  |     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) { | 
					
						
							|  |  |  |             running_diff += justified_space_width - fragment.width(); | 
					
						
							|  |  |  |             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-03-18 14:39:07 +01:00
										 |  |  |     LineBuilder line_builder(*this, m_state, layout_mode); | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							| 
									
										
										
										
											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)) | 
					
						
							|  |  |  |                 parent().layout_floating_box(static_cast<Layout::Box const&>(*item.node), containing_block(), layout_mode, &line_builder); | 
					
						
							|  |  |  |             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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  | } |