1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 14:27:35 +00:00

LibWeb: Make Painting::Box virtual and add Painting::BoxWithLines

BlockContainer paint boxes are the only ones that have line boxes
associated, so let's not waste memory on line boxes in all the other
types of boxes.

This also adds Layout::Box::paint_box() and the more tightly typed
Layout::BlockContainer::paint_box() to get at the paint box from the
corresponding layout box.
This commit is contained in:
Andreas Kling 2022-03-10 11:12:06 +01:00
parent 9f5cbcaad3
commit 7af03df4c3
11 changed files with 79 additions and 26 deletions

View file

@ -51,11 +51,11 @@ void BlockContainer::paint(PaintContext& context, Painting::PaintPhase phase)
context.painter().translate(-m_scroll_offset.to_type<int>());
}
for (auto& line_box : m_paint_box->m_line_boxes) {
for (auto& line_box : paint_box()->line_boxes()) {
for (auto& fragment : line_box.fragments()) {
if (context.should_show_line_box_borders())
context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Green);
fragment.paint(context, phase);
const_cast<LineBoxFragment&>(fragment).paint(context, phase);
}
}
@ -65,7 +65,7 @@ void BlockContainer::paint(PaintContext& context, Painting::PaintPhase phase)
// FIXME: Merge this loop with the above somehow..
if (phase == Painting::PaintPhase::FocusOutline) {
for (auto& line_box : m_paint_box->m_line_boxes) {
for (auto& line_box : paint_box()->line_boxes()) {
for (auto& fragment : line_box.fragments()) {
auto* node = fragment.layout_node().dom_node();
if (!node)
@ -86,7 +86,7 @@ HitTestResult BlockContainer::hit_test(const Gfx::IntPoint& position, HitTestTyp
return Box::hit_test(position, type);
HitTestResult last_good_candidate;
for (auto& line_box : m_paint_box->m_line_boxes) {
for (auto& line_box : paint_box()->line_boxes()) {
for (auto& fragment : line_box.fragments()) {
if (is<Box>(fragment.layout_node()) && verify_cast<Box>(fragment.layout_node()).m_paint_box->stacking_context())
continue;
@ -131,4 +131,9 @@ bool BlockContainer::handle_mousewheel(Badge<EventHandler>, const Gfx::IntPoint&
return true;
}
Painting::BoxWithLines const* BlockContainer::paint_box() const
{
return static_cast<Painting::BoxWithLines const*>(Box::paint_box());
}
}

View file

@ -31,6 +31,8 @@ public:
const Gfx::FloatPoint& scroll_offset() const { return m_scroll_offset; }
void set_scroll_offset(const Gfx::FloatPoint&);
Painting::BoxWithLines const* paint_box() const;
private:
virtual bool is_block_container() const final { return true; }
virtual bool wants_mouse_events() const override { return false; }

View file

@ -34,6 +34,11 @@ Box::~Box()
{
}
void Box::set_paint_box(OwnPtr<Painting::Box> paint_box)
{
m_paint_box = move(paint_box);
}
void Box::paint(PaintContext& context, Painting::PaintPhase phase)
{
if (!is_visible())

View file

@ -20,6 +20,9 @@ struct LineBoxFragmentCoordinate {
class Box : public NodeWithStyleAndBoxModelMetrics {
public:
Painting::Box const* paint_box() const { return m_paint_box.ptr(); }
void set_paint_box(OwnPtr<Painting::Box>);
OwnPtr<Painting::Box> m_paint_box;
bool is_out_of_flow(FormattingContext const&) const;

View file

@ -41,12 +41,18 @@ void FormattingState::commit()
// For boxes, transfer all the state needed for painting.
if (is<Layout::Box>(node)) {
auto& box = static_cast<Layout::Box&>(node);
box.m_paint_box = Painting::Box::create(box);
box.set_paint_box([](Layout::Box const& layout_box) -> OwnPtr<Painting::Box> {
if (is<Layout::BlockContainer>(layout_box))
return Painting::BoxWithLines::create(static_cast<Layout::BlockContainer const&>(layout_box));
return Painting::Box::create(static_cast<Layout::Box const&>(layout_box));
}(box));
box.m_paint_box->set_offset(node_state.offset);
box.m_paint_box->set_content_size(node_state.content_width, node_state.content_height);
box.m_paint_box->set_overflow_data(move(node_state.overflow_data));
box.m_paint_box->set_containing_line_box_fragment(node_state.containing_line_box_fragment);
box.m_paint_box->set_line_boxes(move(node_state.line_boxes));
if (is<Layout::BlockContainer>(box))
static_cast<Painting::BoxWithLines&>(*box.m_paint_box).set_line_boxes(move(node_state.line_boxes));
}
}
}

View file

@ -130,7 +130,7 @@ 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()->m_paint_box->for_each_fragment([&](auto& fragment) {
containing_block()->paint_box()->for_each_fragment([&](auto& fragment) {
if (is_inclusive_ancestor_of(fragment.layout_node()))
fragments.append(fragment);
return IterationDecision::Continue;

View file

@ -112,7 +112,7 @@ InitialContainingBlock& Node::root()
void Node::set_needs_display()
{
if (auto* block = containing_block()) {
block->m_paint_box->for_each_fragment([&](auto& fragment) {
block->paint_box()->for_each_fragment([&](auto& fragment) {
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
browsing_context().set_needs_display(enclosing_int_rect(fragment.absolute_rect()));
}
@ -128,7 +128,7 @@ Gfx::FloatPoint Node::box_type_agnostic_position() const
VERIFY(is_inline());
Gfx::FloatPoint position;
if (auto* block = containing_block()) {
block->m_paint_box->for_each_fragment([&](auto& fragment) {
block->paint_box()->for_each_fragment([&](auto& fragment) {
if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
position = fragment.absolute_rect().location();
return IterationDecision::Break;