Skip to content

Commit

Permalink
LibWeb: Create list-item markers during layout tree construction
Browse files Browse the repository at this point in the history
Previously, these were added during layout. This didn't fit into the new
world where layout doesn't mutate the tree incrementally, so this patch
adds logic to Layout::TreeBuilder for adding a marker to each list-item
box after its children have been constructed.
  • Loading branch information
awesomekling committed Feb 21, 2022
1 parent c9700e1 commit 92266d2
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 54 deletions.
2 changes: 2 additions & 0 deletions Userland/Libraries/LibWeb/Forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ class Label;
class LabelableNode;
class LineBox;
class LineBoxFragment;
class ListItemBox;
class ListItemMarkerBox;
class Node;
class NodeWithStyle;
class NodeWithStyleAndBoxModelMetrics;
Expand Down
39 changes: 35 additions & 4 deletions Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,10 +405,9 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer const& b
if (is<ReplacedBox>(child_box) || is<BlockContainer>(child_box))
place_block_level_element_in_normal_flow_horizontally(child_box, block_container);

// FIXME: This should be factored differently. It's uncool that we mutate the tree *during* layout!
// Instead, we should generate the marker box during the tree build.
if (is<ListItemBox>(child_box))
verify_cast<ListItemBox>(child_box).layout_marker();
if (is<ListItemBox>(child_box)) {
layout_list_item_marker(static_cast<ListItemBox const&>(child_box));
}

content_height = max(content_height, box_state.offset.y() + box_state.content_height + box_state.margin_box_bottom());
content_width = max(content_width, box_state.content_width);
Expand Down Expand Up @@ -663,4 +662,36 @@ void BlockFormattingContext::layout_floating_child(Box const& box, BlockContaine
float_box(FloatSide::Right, m_right_floats);
}
}

void BlockFormattingContext::layout_list_item_marker(ListItemBox const& list_item_box)
{
if (!list_item_box.marker())
return;

auto& marker = *list_item_box.marker();
auto& marker_state = m_state.ensure(marker);
auto& list_item_state = m_state.ensure(list_item_box);

int image_width = 0;
int image_height = 0;
if (auto const* list_style_image = marker.list_style_image_bitmap()) {
image_width = list_style_image->rect().width();
image_height = list_style_image->rect().height();
}

if (marker.text().is_empty()) {
marker_state.content_width = image_width + 4;
} else {
auto text_width = marker.font().width(marker.text());
marker_state.content_width = image_width + text_width;
}

marker_state.content_height = max(image_height, marker.line_height());

marker_state.offset = { -(marker_state.content_width + 4), 0 };

if (marker_state.content_height > list_item_state.content_height)
list_item_state.content_height = marker_state.content_height;
}

}
4 changes: 3 additions & 1 deletion Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Andreas Kling <[email protected]>
* Copyright (c) 2020-2022, Andreas Kling <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
Expand Down Expand Up @@ -58,6 +58,8 @@ class BlockFormattingContext : public FormattingContext {

void apply_transformations_to_children(Box const&);

void layout_list_item_marker(ListItemBox const&);

enum class FloatSide {
Left,
Right,
Expand Down
27 changes: 3 additions & 24 deletions Userland/Libraries/LibWeb/Layout/ListItemBox.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <[email protected]>
* Copyright (c) 2018-2022, Andreas Kling <[email protected]>
* Copyright (c) 2021, Tobias Christiansen <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
Expand All @@ -19,30 +19,9 @@ ListItemBox::~ListItemBox()
{
}

void ListItemBox::layout_marker()
void ListItemBox::set_marker(RefPtr<ListItemMarkerBox> marker)
{
if (m_marker) {
remove_child(*m_marker);
m_marker = nullptr;
}

if (computed_values().list_style_type() == CSS::ListStyleType::None)
return;

if (!m_marker) {
auto* marker_style = dom_node().specified_css_values();
VERIFY(marker_style);
int child_index = parent()->index_of_child<ListItemBox>(*this).value();
m_marker = adopt_ref(*new ListItemMarkerBox(document(), computed_values().list_style_type(), child_index + 1, *marker_style));
if (first_child())
m_marker->set_inline(first_child()->is_inline());
append_child(*m_marker);
}

m_marker->set_offset(-(m_marker->content_width() + 4), 0);

if (m_marker->content_height() > content_height())
set_content_height(m_marker->content_height());
m_marker = move(marker);
}

}
9 changes: 4 additions & 5 deletions Userland/Libraries/LibWeb/Layout/ListItemBox.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <[email protected]>
* Copyright (c) 2018-2022, Andreas Kling <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
Expand All @@ -11,18 +11,17 @@

namespace Web::Layout {

class ListItemMarkerBox;

class ListItemBox final : public BlockContainer {
public:
ListItemBox(DOM::Document&, DOM::Element&, NonnullRefPtr<CSS::StyleProperties>);
virtual ~ListItemBox() override;

void layout_marker();

DOM::Element& dom_node() { return static_cast<DOM::Element&>(*BlockContainer::dom_node()); }
DOM::Element const& dom_node() const { return static_cast<DOM::Element const&>(*BlockContainer::dom_node()); }

ListItemMarkerBox const* marker() const { return m_marker; }
void set_marker(RefPtr<ListItemMarkerBox>);

private:
RefPtr<ListItemMarkerBox> m_marker;
};
Expand Down
18 changes: 1 addition & 17 deletions Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <[email protected]>
* Copyright (c) 2018-2022, Andreas Kling <[email protected]>
* Copyright (c) 2021, Tobias Christiansen <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
Expand Down Expand Up @@ -48,22 +48,6 @@ ListItemMarkerBox::ListItemMarkerBox(DOM::Document& document, CSS::ListStyleType
default:
VERIFY_NOT_REACHED();
}

int image_width = 0;
int image_height = 0;
if (auto const* list_style_image = list_style_image_bitmap()) {
image_width = list_style_image->rect().width();
image_height = list_style_image->rect().height();
}

if (m_text.is_null()) {
set_content_width(image_width + 4);
} else {
auto text_width = font().width(m_text);
set_content_width(image_width + text_width);
}

set_content_height(max(image_height, line_height()));
}

ListItemMarkerBox::~ListItemMarkerBox()
Expand Down
6 changes: 4 additions & 2 deletions Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <[email protected]>
* Copyright (c) 2018-2022, Andreas Kling <[email protected]>
* Copyright (c) 2021, Tobias Christiansen <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
Expand All @@ -18,9 +18,11 @@ class ListItemMarkerBox final : public Box {

virtual void paint(PaintContext&, PaintPhase) override;

Gfx::Bitmap const* list_style_image_bitmap() const;
String const& text() const { return m_text; }

private:
virtual bool can_have_children() const override { return false; }
Gfx::Bitmap const* list_style_image_bitmap() const;

CSS::ListStyleType m_list_style_type { CSS::ListStyleType::None };
size_t m_index;
Expand Down
14 changes: 13 additions & 1 deletion Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2021, Andreas Kling <[email protected]>
* Copyright (c) 2018-2022, Andreas Kling <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
Expand All @@ -12,6 +12,8 @@
#include <LibWeb/DOM/ShadowRoot.h>
#include <LibWeb/Dump.h>
#include <LibWeb/Layout/InitialContainingBlock.h>
#include <LibWeb/Layout/ListItemBox.h>
#include <LibWeb/Layout/ListItemMarkerBox.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Layout/TableBox.h>
#include <LibWeb/Layout/TableCellBox.h>
Expand Down Expand Up @@ -147,6 +149,16 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
});
pop_parent();
}

if (is<ListItemBox>(*layout_node)) {
int child_index = layout_node->parent()->index_of_child<ListItemBox>(*layout_node).value();
auto marker_style = static_cast<DOM::Element const&>(dom_node).specified_css_values();
auto list_item_marker = adopt_ref(*new ListItemMarkerBox(document, layout_node->computed_values().list_style_type(), child_index + 1, *marker_style));
if (layout_node->first_child())
list_item_marker->set_inline(layout_node->first_child()->is_inline());
static_cast<ListItemBox&>(*layout_node).set_marker(list_item_marker);
layout_node->append_child(move(list_item_marker));
}
}

RefPtr<Node> TreeBuilder::build(DOM::Node& dom_node)
Expand Down

0 comments on commit 92266d2

Please sign in to comment.