diff options
author | Andreas Kling <kling@serenityos.org> | 2022-02-14 15:52:29 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-14 18:00:21 +0100 |
commit | f2a917229ad1c30b50c26afa383933c941b8a472 (patch) | |
tree | d7d4ffffc929f8a47cee969a62f9bcd76e4fdf36 /Userland/Libraries/LibWeb/Layout/InlineNode.cpp | |
parent | 7d2a49eeb80d010e035307d9eb255d2b670835e7 (diff) | |
download | serenity-f2a917229ad1c30b50c26afa383933c941b8a472.zip |
LibWeb: Support inline-level padding and border properly
Here's roughly how this works:
- InlineLevelIterator keeps a nesting stack of inline-level nodes with
box model metrics.
- When entering a node with box model metrics, we add them to the
current "leading metrics".
- When exiting a node with box model metrics, we add them to the
current "trailing metrics".
- Pending leading metrics are consumed by the first fragment added
to the line.
- Pending trailing metrics are consumed by the last fragment added
to the line.
Like before, the position of a line box fragment is the top left of its
content box. However, fragments are placed horizontally along the line
with space inserted for padding and border.
InlineNode::paint() now expands the content rect as appropriate when
painting background and borders.
Note that margins and margin collapsing is not yet implemented.
This makes the eyes on ACID2 horizontally centered. :^)
Diffstat (limited to 'Userland/Libraries/LibWeb/Layout/InlineNode.cpp')
-rw-r--r-- | Userland/Libraries/LibWeb/Layout/InlineNode.cpp | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/InlineNode.cpp b/Userland/Libraries/LibWeb/Layout/InlineNode.cpp index 1ac4fd6b98..3f4300f830 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineNode.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineNode.cpp @@ -38,8 +38,20 @@ void InlineNode::paint(PaintContext& context, PaintPhase phase) auto bottom_left_border_radius = computed_values().border_bottom_left_radius(); auto containing_block_position_in_absolute_coordinates = containing_block()->absolute_position(); - for_each_fragment([&](auto const& fragment) { + for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) { Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() }; + + if (is_first_fragment) { + float extra_start_width = box_model().padding.left; + absolute_fragment_rect.translate_by(-extra_start_width, 0); + absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_start_width); + } + + if (is_last_fragment) { + float extra_end_width = box_model().padding.right; + absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width); + } + auto border_radius_data = Painting::normalized_border_radius_data(*this, absolute_fragment_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius); Painting::paint_background(context, *this, enclosing_int_rect(absolute_fragment_rect), computed_values().background_color(), &computed_values().background_layers(), border_radius_data); @@ -77,8 +89,20 @@ void InlineNode::paint(PaintContext& context, PaintPhase phase) auto containing_block_position_in_absolute_coordinates = containing_block()->absolute_position(); - for_each_fragment([&](auto& fragment) { + for_each_fragment([&](auto const& fragment, bool is_first_fragment, bool is_last_fragment) { Gfx::FloatRect absolute_fragment_rect { containing_block_position_in_absolute_coordinates.translated(fragment.offset()), fragment.size() }; + + if (is_first_fragment) { + float extra_start_width = box_model().padding.left; + absolute_fragment_rect.translate_by(-extra_start_width, 0); + absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_start_width); + } + + if (is_last_fragment) { + float extra_end_width = box_model().padding.right; + absolute_fragment_rect.set_width(absolute_fragment_rect.width() + extra_end_width); + } + auto bordered_rect = absolute_fragment_rect.inflated(borders_data.top.width, borders_data.right.width, borders_data.bottom.width, borders_data.left.width); auto border_radius_data = Painting::normalized_border_radius_data(*this, bordered_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius); @@ -92,7 +116,7 @@ void InlineNode::paint(PaintContext& context, PaintPhase phase) // FIXME: This paints a double-thick border between adjacent fragments, where ideally there // would be none. Once we implement non-rectangular outlines for the `outline` CSS // property, we can use that here instead. - for_each_fragment([&](auto& fragment) { + for_each_fragment([&](auto& fragment, bool, bool) { painter.draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Magenta); return IterationDecision::Continue; }); @@ -103,11 +127,16 @@ template<typename Callback> void InlineNode::for_each_fragment(Callback callback) { // FIXME: This will be slow if the containing block has a lot of fragments! + Vector<LineBoxFragment const&> fragments; containing_block()->for_each_fragment([&](auto& fragment) { - if (!is_inclusive_ancestor_of(fragment.layout_node())) - return IterationDecision::Continue; - return callback(fragment); + if (is_inclusive_ancestor_of(fragment.layout_node())) + fragments.append(fragment); + return IterationDecision::Continue; }); + for (size_t i = 0; i < fragments.size(); ++i) { + auto const& fragment = fragments[i]; + callback(fragment, i == 0, i == fragments.size() - 1); + } } } |