summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/Layout/InlineNode.cpp
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-02-14 15:52:29 +0100
committerAndreas Kling <kling@serenityos.org>2022-02-14 18:00:21 +0100
commitf2a917229ad1c30b50c26afa383933c941b8a472 (patch)
treed7d4ffffc929f8a47cee969a62f9bcd76e4fdf36 /Userland/Libraries/LibWeb/Layout/InlineNode.cpp
parent7d2a49eeb80d010e035307d9eb255d2b670835e7 (diff)
downloadserenity-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.cpp41
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);
+ }
}
}