Kaynağa Gözat

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.
Andreas Kling 3 yıl önce
ebeveyn
işleme
7af03df4c3

+ 2 - 2
Userland/Libraries/LibWeb/Dump.cpp

@@ -226,8 +226,8 @@ void dump_tree(StringBuilder& builder, Layout::Node const& layout_node, bool sho
 
 
     if (is<Layout::BlockContainer>(layout_node) && static_cast<Layout::BlockContainer const&>(layout_node).children_are_inline()) {
     if (is<Layout::BlockContainer>(layout_node) && static_cast<Layout::BlockContainer const&>(layout_node).children_are_inline()) {
         auto& block = static_cast<Layout::BlockContainer const&>(layout_node);
         auto& block = static_cast<Layout::BlockContainer const&>(layout_node);
-        for (size_t line_box_index = 0; line_box_index < block.m_paint_box->line_boxes().size(); ++line_box_index) {
-            auto& line_box = block.m_paint_box->line_boxes()[line_box_index];
+        for (size_t line_box_index = 0; line_box_index < block.paint_box()->line_boxes().size(); ++line_box_index) {
+            auto& line_box = block.paint_box()->line_boxes()[line_box_index];
             for (size_t i = 0; i < indent; ++i)
             for (size_t i = 0; i < indent; ++i)
                 builder.append("  ");
                 builder.append("  ");
             builder.appendff("  {}line {}{} width: {}, bottom: {}, baseline: {}\n",
             builder.appendff("  {}line {}{} width: {}, bottom: {}, baseline: {}\n",

+ 1 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -266,6 +266,7 @@ class PerformanceTiming;
 namespace Web::Painting {
 namespace Web::Painting {
 enum class PaintPhase;
 enum class PaintPhase;
 class Box;
 class Box;
+class BoxWithLines;
 }
 }
 
 
 namespace Web::RequestIdleCallback {
 namespace Web::RequestIdleCallback {

+ 9 - 4
Userland/Libraries/LibWeb/Layout/BlockContainer.cpp

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

+ 2 - 0
Userland/Libraries/LibWeb/Layout/BlockContainer.h

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

+ 5 - 0
Userland/Libraries/LibWeb/Layout/Box.cpp

@@ -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)
 void Box::paint(PaintContext& context, Painting::PaintPhase phase)
 {
 {
     if (!is_visible())
     if (!is_visible())

+ 3 - 0
Userland/Libraries/LibWeb/Layout/Box.h

@@ -20,6 +20,9 @@ struct LineBoxFragmentCoordinate {
 
 
 class Box : public NodeWithStyleAndBoxModelMetrics {
 class Box : public NodeWithStyleAndBoxModelMetrics {
 public:
 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;
     OwnPtr<Painting::Box> m_paint_box;
 
 
     bool is_out_of_flow(FormattingContext const&) const;
     bool is_out_of_flow(FormattingContext const&) const;

+ 8 - 2
Userland/Libraries/LibWeb/Layout/FormattingState.cpp

@@ -41,12 +41,18 @@ void FormattingState::commit()
         // For boxes, transfer all the state needed for painting.
         // For boxes, transfer all the state needed for painting.
         if (is<Layout::Box>(node)) {
         if (is<Layout::Box>(node)) {
             auto& box = static_cast<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_offset(node_state.offset);
             box.m_paint_box->set_content_size(node_state.content_width, node_state.content_height);
             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_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_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));
         }
         }
     }
     }
 }
 }

+ 1 - 1
Userland/Libraries/LibWeb/Layout/InlineNode.cpp

@@ -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!
     // FIXME: This will be slow if the containing block has a lot of fragments!
     Vector<LineBoxFragment const&> 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()))
         if (is_inclusive_ancestor_of(fragment.layout_node()))
             fragments.append(fragment);
             fragments.append(fragment);
         return IterationDecision::Continue;
         return IterationDecision::Continue;

+ 2 - 2
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -112,7 +112,7 @@ InitialContainingBlock& Node::root()
 void Node::set_needs_display()
 void Node::set_needs_display()
 {
 {
     if (auto* block = containing_block()) {
     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())) {
             if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
                 browsing_context().set_needs_display(enclosing_int_rect(fragment.absolute_rect()));
                 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());
     VERIFY(is_inline());
     Gfx::FloatPoint position;
     Gfx::FloatPoint position;
     if (auto* block = containing_block()) {
     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())) {
             if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
                 position = fragment.absolute_rect().location();
                 position = fragment.absolute_rect().location();
                 return IterationDecision::Break;
                 return IterationDecision::Break;

+ 19 - 1
Userland/Libraries/LibWeb/Painting/Box.cpp

@@ -9,6 +9,24 @@
 
 
 namespace Web::Painting {
 namespace Web::Painting {
 
 
+Box::Box(Layout::Box const& layout_box)
+    : m_layout_box(layout_box)
+{
+}
+
+Box::~Box()
+{
+}
+
+BoxWithLines::BoxWithLines(Layout::BlockContainer const& layout_box)
+    : Box(layout_box)
+{
+}
+
+BoxWithLines::~BoxWithLines()
+{
+}
+
 void Box::set_offset(const Gfx::FloatPoint& offset)
 void Box::set_offset(const Gfx::FloatPoint& offset)
 {
 {
     if (m_offset == offset)
     if (m_offset == offset)
@@ -30,7 +48,7 @@ void Box::set_content_size(Gfx::FloatSize const& size)
 Gfx::FloatPoint Box::effective_offset() const
 Gfx::FloatPoint Box::effective_offset() const
 {
 {
     if (m_containing_line_box_fragment.has_value()) {
     if (m_containing_line_box_fragment.has_value()) {
-        auto const& fragment = m_layout_box.containing_block()->m_paint_box->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index];
+        auto const& fragment = m_layout_box.containing_block()->paint_box()->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index];
         return fragment.offset();
         return fragment.offset();
     }
     }
     return m_offset;
     return m_offset;

+ 27 - 14
Userland/Libraries/LibWeb/Painting/Box.h

@@ -20,10 +20,7 @@ public:
         return adopt_own(*new Box(layout_box));
         return adopt_own(*new Box(layout_box));
     }
     }
 
 
-    explicit Box(Layout::Box const& layout_box)
-        : m_layout_box(layout_box)
-    {
-    }
+    virtual ~Box();
 
 
     Layout::Box const& m_layout_box;
     Layout::Box const& m_layout_box;
 
 
@@ -39,11 +36,6 @@ public:
     Gfx::FloatPoint m_offset;
     Gfx::FloatPoint m_offset;
     Gfx::FloatSize m_content_size;
     Gfx::FloatSize m_content_size;
 
 
-    Vector<Layout::LineBox> const& line_boxes() const { return m_line_boxes; }
-    void set_line_boxes(Vector<Layout::LineBox>&& line_boxes) { m_line_boxes = move(line_boxes); }
-
-    Vector<Layout::LineBox> m_line_boxes;
-
     // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc)
     // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc)
     Optional<Layout::LineBoxFragmentCoordinate> m_containing_line_box_fragment;
     Optional<Layout::LineBoxFragmentCoordinate> m_containing_line_box_fragment;
 
 
@@ -112,6 +104,29 @@ public:
     void set_overflow_data(Optional<OverflowData> data) { m_overflow_data = move(data); }
     void set_overflow_data(Optional<OverflowData> data) { m_overflow_data = move(data); }
     void set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate>);
     void set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate>);
 
 
+    StackingContext* stacking_context() { return m_stacking_context; }
+    StackingContext const* stacking_context() const { return m_stacking_context; }
+    void set_stacking_context(NonnullOwnPtr<Painting::StackingContext> context) { m_stacking_context = move(context); }
+    StackingContext* enclosing_stacking_context();
+
+protected:
+    explicit Box(Layout::Box const&);
+
+private:
+    OwnPtr<Painting::StackingContext> m_stacking_context;
+};
+
+class BoxWithLines : public Box {
+public:
+    static NonnullOwnPtr<BoxWithLines> create(Layout::BlockContainer const& block_container)
+    {
+        return adopt_own(*new BoxWithLines(block_container));
+    }
+    virtual ~BoxWithLines() override;
+
+    Vector<Layout::LineBox> const& line_boxes() const { return m_line_boxes; }
+    void set_line_boxes(Vector<Layout::LineBox>&& line_boxes) { m_line_boxes = move(line_boxes); }
+
     template<typename Callback>
     template<typename Callback>
     void for_each_fragment(Callback callback) const
     void for_each_fragment(Callback callback) const
     {
     {
@@ -123,12 +138,10 @@ public:
         }
         }
     }
     }
 
 
-    StackingContext* stacking_context() { return m_stacking_context; }
-    StackingContext const* stacking_context() const { return m_stacking_context; }
-    void set_stacking_context(NonnullOwnPtr<Painting::StackingContext> context) { m_stacking_context = move(context); }
-    StackingContext* enclosing_stacking_context();
+private:
+    BoxWithLines(Layout::BlockContainer const&);
 
 
-    OwnPtr<Painting::StackingContext> m_stacking_context;
+    Vector<Layout::LineBox> m_line_boxes;
 };
 };
 
 
 }
 }