From 4814253589e87e23de4d4472bd09d8f32d7fb459 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 15 Oct 2019 16:48:38 +0200 Subject: [PATCH] LibHTML: Introduce LayoutBox and LayoutNodeWithStyleAndBoxModelMetrics To streamline the layout tree and remove irrelevant data from classes that don't need it, this patch adds two new LayoutNode subclasses. LayoutNodeWithStyleAndBoxModelMetrics should be inherited by any layout node that cares about box model metrics (margin, border, and padding.) LayoutBox should be inherited by any layout node that can have a rect. This makes LayoutText significantly smaller (from 140 to 40 bytes) and clarifies a lot of things about the layout tree. I'm also adding next_sibling() and previous_sibling() overloads to LayoutBlock that return a LayoutBlock*. This is okay since blocks only ever have block siblings. Do also note that the semantics of is slightly change in this patch: is(nullptr) now returns true, to facilitate allowing to(nullptr). --- Libraries/LibHTML/DOM/Node.h | 2 +- Libraries/LibHTML/Dump.cpp | 57 ++++++----- Libraries/LibHTML/Layout/LayoutBlock.cpp | 13 ++- Libraries/LibHTML/Layout/LayoutBlock.h | 9 +- Libraries/LibHTML/Layout/LayoutBox.cpp | 95 +++++++++++++++++++ Libraries/LibHTML/Layout/LayoutBox.h | 39 ++++++++ Libraries/LibHTML/Layout/LayoutBreak.cpp | 2 +- Libraries/LibHTML/Layout/LayoutBreak.h | 2 +- Libraries/LibHTML/Layout/LayoutDocument.cpp | 9 +- Libraries/LibHTML/Layout/LayoutInline.cpp | 2 +- Libraries/LibHTML/Layout/LayoutInline.h | 7 +- .../LibHTML/Layout/LayoutListItemMarker.cpp | 2 +- .../LibHTML/Layout/LayoutListItemMarker.h | 4 +- Libraries/LibHTML/Layout/LayoutNode.cpp | 74 +-------------- Libraries/LibHTML/Layout/LayoutNode.h | 36 +++---- Libraries/LibHTML/Layout/LayoutReplaced.cpp | 2 +- Libraries/LibHTML/Layout/LayoutReplaced.h | 4 +- Libraries/LibHTML/Makefile.shared | 1 + 18 files changed, 219 insertions(+), 141 deletions(-) create mode 100644 Libraries/LibHTML/Layout/LayoutBox.cpp create mode 100644 Libraries/LibHTML/Layout/LayoutBox.h diff --git a/Libraries/LibHTML/DOM/Node.h b/Libraries/LibHTML/DOM/Node.h index 66ff78f4f7..a32f631092 100644 --- a/Libraries/LibHTML/DOM/Node.h +++ b/Libraries/LibHTML/DOM/Node.h @@ -89,7 +89,7 @@ inline bool is(const Node&) template inline bool is(const Node* node) { - return node && is(*node); + return !node || is(*node); } template<> diff --git a/Libraries/LibHTML/Dump.cpp b/Libraries/LibHTML/Dump.cpp index c16d78f5cd..7d3cd81769 100644 --- a/Libraries/LibHTML/Dump.cpp +++ b/Libraries/LibHTML/Dump.cpp @@ -58,35 +58,40 @@ void dump_tree(const LayoutNode& layout_node) else tag_name = "???"; - dbgprintf("%s {%s} at (%d,%d) size %dx%d", - layout_node.class_name(), - tag_name.characters(), - layout_node.x(), - layout_node.y(), - layout_node.width(), - layout_node.height()); + if (!layout_node.is_box()) { + dbgprintf("%s {%s}\n", layout_node.class_name(), tag_name.characters()); + } else { + auto& layout_box = to(layout_node); + dbgprintf("%s {%s} at (%d,%d) size %dx%d", + layout_box.class_name(), + tag_name.characters(), + layout_box.x(), + layout_box.y(), + layout_box.width(), + layout_box.height()); - // Dump the horizontal box properties - dbgprintf(" [%d+%d+%d %d %d+%d+%d]", - layout_node.box_model().margin().left.to_px(), - layout_node.box_model().border().left.to_px(), - layout_node.box_model().padding().left.to_px(), - layout_node.width(), - layout_node.box_model().padding().right.to_px(), - layout_node.box_model().border().right.to_px(), - layout_node.box_model().margin().right.to_px()); + // Dump the horizontal box properties + dbgprintf(" [%d+%d+%d %d %d+%d+%d]", + layout_box.box_model().margin().left.to_px(), + layout_box.box_model().border().left.to_px(), + layout_box.box_model().padding().left.to_px(), + layout_box.width(), + layout_box.box_model().padding().right.to_px(), + layout_box.box_model().border().right.to_px(), + layout_box.box_model().margin().right.to_px()); - // And the vertical box properties - dbgprintf(" [%d+%d+%d %d %d+%d+%d]", - layout_node.box_model().margin().top.to_px(), - layout_node.box_model().border().top.to_px(), - layout_node.box_model().padding().top.to_px(), - layout_node.height(), - layout_node.box_model().padding().bottom.to_px(), - layout_node.box_model().border().bottom.to_px(), - layout_node.box_model().margin().bottom.to_px()); + // And the vertical box properties + dbgprintf(" [%d+%d+%d %d %d+%d+%d]", + layout_box.box_model().margin().top.to_px(), + layout_box.box_model().border().top.to_px(), + layout_box.box_model().padding().top.to_px(), + layout_box.height(), + layout_box.box_model().padding().bottom.to_px(), + layout_box.box_model().border().bottom.to_px(), + layout_box.box_model().margin().bottom.to_px()); - dbgprintf("\n"); + dbgprintf("\n"); + } if (layout_node.is_block() && static_cast(layout_node).children_are_inline()) { auto& block = static_cast(layout_node); diff --git a/Libraries/LibHTML/Layout/LayoutBlock.cpp b/Libraries/LibHTML/Layout/LayoutBlock.cpp index 8cce2f9431..734ada9f00 100644 --- a/Libraries/LibHTML/Layout/LayoutBlock.cpp +++ b/Libraries/LibHTML/Layout/LayoutBlock.cpp @@ -3,9 +3,10 @@ #include #include #include +#include LayoutBlock::LayoutBlock(const Node* node, NonnullRefPtr style) - : LayoutNodeWithStyle(node, move(style)) + : LayoutBox(node, move(style)) { } @@ -39,8 +40,10 @@ void LayoutBlock::layout_block_children() ASSERT(!children_are_inline()); int content_height = 0; for_each_child([&](auto& child) { - child.layout(); - content_height = child.rect().bottom() + child.box_model().full_margin().bottom - rect().top(); + ASSERT(is(child)); + auto& child_block = static_cast(child); + child_block.layout(); + content_height = child_block.rect().bottom() + child_block.box_model().full_margin().bottom - rect().top(); }); rect().set_height(content_height); } @@ -69,8 +72,8 @@ void LayoutBlock::layout_inline_children() fragment.rect().set_x(x() + fragment.rect().x()); fragment.rect().set_y(y() + content_height + (max_height - fragment.rect().height())); - if (fragment.layout_node().is_replaced()) - const_cast(fragment.layout_node()).set_rect(fragment.rect()); + if (is(fragment.layout_node())) + const_cast(to(fragment.layout_node())).set_rect(fragment.rect()); } content_height += max_height; diff --git a/Libraries/LibHTML/Layout/LayoutBlock.h b/Libraries/LibHTML/Layout/LayoutBlock.h index 91b21c8e60..39178be809 100644 --- a/Libraries/LibHTML/Layout/LayoutBlock.h +++ b/Libraries/LibHTML/Layout/LayoutBlock.h @@ -1,11 +1,11 @@ #pragma once -#include +#include #include class Element; -class LayoutBlock : public LayoutNodeWithStyle { +class LayoutBlock : public LayoutBox { public: LayoutBlock(const Node*, NonnullRefPtr); virtual ~LayoutBlock() override; @@ -27,6 +27,11 @@ public: virtual HitTestResult hit_test(const Point&) const override; + LayoutBlock* previous_sibling() { return to(LayoutNode::previous_sibling()); } + const LayoutBlock* previous_sibling() const { return to(LayoutNode::previous_sibling()); } + LayoutBlock* next_sibling() { return to(LayoutNode::next_sibling()); } + const LayoutBlock* next_sibling() const { return to(LayoutNode::next_sibling()); } + private: virtual bool is_block() const override { return true; } diff --git a/Libraries/LibHTML/Layout/LayoutBox.cpp b/Libraries/LibHTML/Layout/LayoutBox.cpp new file mode 100644 index 0000000000..0e7d69afc9 --- /dev/null +++ b/Libraries/LibHTML/Layout/LayoutBox.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +//#define DRAW_BOXES_AROUND_LAYOUT_NODES +//#define DRAW_BOXES_AROUND_HOVERED_NODES + +void LayoutBox::render(RenderingContext& context) +{ +#ifdef DRAW_BOXES_AROUND_LAYOUT_NODES + context.painter().draw_rect(m_rect, Color::Blue); +#endif +#ifdef DRAW_BOXES_AROUND_HOVERED_NODES + if (!is_anonymous() && node() == document().hovered_node()) + context.painter().draw_rect(m_rect, Color::Red); +#endif + + Rect padded_rect; + padded_rect.set_x(x() - box_model().padding().left.to_px()); + padded_rect.set_width(width() + box_model().padding().left.to_px() + box_model().padding().right.to_px()); + padded_rect.set_y(y() - box_model().padding().top.to_px()); + padded_rect.set_height(height() + box_model().padding().top.to_px() + box_model().padding().bottom.to_px()); + + auto bgcolor = style().property(CSS::PropertyID::BackgroundColor); + if (bgcolor.has_value() && bgcolor.value()->is_color()) { + context.painter().fill_rect(padded_rect, bgcolor.value()->to_color(document())); + } + + // FIXME: Respect all individual border sides + auto border_width_value = style().property(CSS::PropertyID::BorderTopWidth); + auto border_color_value = style().property(CSS::PropertyID::BorderTopColor); + auto border_style_value = style().property(CSS::PropertyID::BorderTopStyle); + if (border_width_value.has_value() && border_color_value.has_value()) { + int border_width = border_width_value.value()->to_length().to_px(); + Color border_color = border_color_value.value()->to_color(document()); + + if (border_style_value.has_value() && border_style_value.value()->to_string() == "inset") { + // border-style: inset + auto shadow_color = Color::from_rgb(0x888888); + auto highlight_color = Color::from_rgb(0x5a5a5a); + context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), highlight_color, border_width); + context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), shadow_color, border_width); + context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), shadow_color, border_width); + context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), highlight_color, border_width); + } else if (border_style_value.has_value() && border_style_value.value()->to_string() == "outset") { + // border-style: outset + auto highlight_color = Color::from_rgb(0x888888); + auto shadow_color = Color::from_rgb(0x5a5a5a); + context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), highlight_color, border_width); + context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), shadow_color, border_width); + context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), shadow_color, border_width); + context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), highlight_color, border_width); + } else { + // border-style: solid + context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), border_color, border_width); + context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), border_color, border_width); + context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), border_color, border_width); + context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), border_color, border_width); + } + } +} + +HitTestResult LayoutBox::hit_test(const Point& position) const +{ + // FIXME: It would be nice if we could confidently skip over hit testing + // parts of the layout tree, but currently we can't just check + // m_rect.contains() since inline text rects can't be trusted.. + HitTestResult result { m_rect.contains(position) ? this : nullptr }; + for_each_child([&](auto& child) { + auto child_result = child.hit_test(position); + if (child_result.layout_node) + result = child_result; + }); + return result; +} + +void LayoutBox::set_needs_display() +{ + auto* frame = document().frame(); + ASSERT(frame); + + if (!is_inline()) { + const_cast(frame)->set_needs_display(rect()); + return; + } + + for_each_fragment_of_this([&](auto& fragment) { + if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) { + const_cast(frame)->set_needs_display(fragment.rect()); + } + return IterationDecision::Continue; + }); +} diff --git a/Libraries/LibHTML/Layout/LayoutBox.h b/Libraries/LibHTML/Layout/LayoutBox.h new file mode 100644 index 0000000000..f66be67571 --- /dev/null +++ b/Libraries/LibHTML/Layout/LayoutBox.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +class LayoutBox : public LayoutNodeWithStyleAndBoxModelMetrics { +public: + const Rect& rect() const { return m_rect; } + Rect& rect() { return m_rect; } + void set_rect(const Rect& rect) { m_rect = rect; } + + int x() const { return rect().x(); } + int y() const { return rect().y(); } + int width() const { return rect().width(); } + int height() const { return rect().height(); } + Size size() const { return rect().size(); } + Point position() const { return rect().location(); } + + virtual HitTestResult hit_test(const Point& position) const override; + virtual void set_needs_display() override; + +protected: + LayoutBox(const Node* node, NonnullRefPtr style) + : LayoutNodeWithStyleAndBoxModelMetrics(node, move(style)) + { + } + + virtual void render(RenderingContext&) override; + +private: + virtual bool is_box() const override { return true; } + + Rect m_rect; +}; + +template<> +inline bool is(const LayoutNode& node) +{ + return node.is_box(); +} diff --git a/Libraries/LibHTML/Layout/LayoutBreak.cpp b/Libraries/LibHTML/Layout/LayoutBreak.cpp index c971d96a75..6332f3476b 100644 --- a/Libraries/LibHTML/Layout/LayoutBreak.cpp +++ b/Libraries/LibHTML/Layout/LayoutBreak.cpp @@ -2,7 +2,7 @@ #include LayoutBreak::LayoutBreak(const HTMLBRElement& element) - : LayoutNode(&element) + : LayoutNodeWithStyleAndBoxModelMetrics(&element, StyleProperties::create()) { set_inline(true); } diff --git a/Libraries/LibHTML/Layout/LayoutBreak.h b/Libraries/LibHTML/Layout/LayoutBreak.h index af803e7ae3..24b87436c2 100644 --- a/Libraries/LibHTML/Layout/LayoutBreak.h +++ b/Libraries/LibHTML/Layout/LayoutBreak.h @@ -3,7 +3,7 @@ #include #include -class LayoutBreak final : public LayoutNode { +class LayoutBreak final : public LayoutNodeWithStyleAndBoxModelMetrics { public: explicit LayoutBreak(const HTMLBRElement&); virtual ~LayoutBreak() override; diff --git a/Libraries/LibHTML/Layout/LayoutDocument.cpp b/Libraries/LibHTML/Layout/LayoutDocument.cpp index afd39456dd..9776803902 100644 --- a/Libraries/LibHTML/Layout/LayoutDocument.cpp +++ b/Libraries/LibHTML/Layout/LayoutDocument.cpp @@ -1,4 +1,5 @@ #include +#include #include LayoutDocument::LayoutDocument(const Document& document, NonnullRefPtr style) @@ -17,10 +18,14 @@ void LayoutDocument::layout() LayoutNode::layout(); + ASSERT(!children_are_inline()); + int lowest_bottom = 0; for_each_child([&](auto& child) { - if (child.rect().bottom() > lowest_bottom) - lowest_bottom = child.rect().bottom(); + ASSERT(is(child)); + auto& child_block = to(child); + if (child_block.rect().bottom() > lowest_bottom) + lowest_bottom = child_block.rect().bottom(); }); rect().set_bottom(lowest_bottom); } diff --git a/Libraries/LibHTML/Layout/LayoutInline.cpp b/Libraries/LibHTML/Layout/LayoutInline.cpp index 5265d9a357..6e4d526461 100644 --- a/Libraries/LibHTML/Layout/LayoutInline.cpp +++ b/Libraries/LibHTML/Layout/LayoutInline.cpp @@ -3,7 +3,7 @@ #include LayoutInline::LayoutInline(const Element& element, NonnullRefPtr style) - : LayoutNodeWithStyle(&element, move(style)) + : LayoutNodeWithStyleAndBoxModelMetrics(&element, move(style)) { set_inline(true); } diff --git a/Libraries/LibHTML/Layout/LayoutInline.h b/Libraries/LibHTML/Layout/LayoutInline.h index 8a12d5e3fa..3fb133d947 100644 --- a/Libraries/LibHTML/Layout/LayoutInline.h +++ b/Libraries/LibHTML/Layout/LayoutInline.h @@ -1,15 +1,12 @@ #pragma once -#include +#include class LayoutBlock; -class LayoutInline : public LayoutNodeWithStyle { +class LayoutInline : public LayoutNodeWithStyleAndBoxModelMetrics { public: LayoutInline(const Element&, NonnullRefPtr); virtual ~LayoutInline() override; - virtual const char* class_name() const override { return "LayoutInline"; } - -private: }; diff --git a/Libraries/LibHTML/Layout/LayoutListItemMarker.cpp b/Libraries/LibHTML/Layout/LayoutListItemMarker.cpp index de2698049b..c82d79a1a1 100644 --- a/Libraries/LibHTML/Layout/LayoutListItemMarker.cpp +++ b/Libraries/LibHTML/Layout/LayoutListItemMarker.cpp @@ -2,7 +2,7 @@ #include LayoutListItemMarker::LayoutListItemMarker() - : LayoutNode(nullptr) + : LayoutBox(nullptr, StyleProperties::create()) { } diff --git a/Libraries/LibHTML/Layout/LayoutListItemMarker.h b/Libraries/LibHTML/Layout/LayoutListItemMarker.h index 245c182c6f..63bf75b90b 100644 --- a/Libraries/LibHTML/Layout/LayoutListItemMarker.h +++ b/Libraries/LibHTML/Layout/LayoutListItemMarker.h @@ -1,8 +1,8 @@ #pragma once -#include +#include -class LayoutListItemMarker final : public LayoutNode { +class LayoutListItemMarker final : public LayoutBox { public: LayoutListItemMarker(); virtual ~LayoutListItemMarker() override; diff --git a/Libraries/LibHTML/Layout/LayoutNode.cpp b/Libraries/LibHTML/Layout/LayoutNode.cpp index 22efbde750..dbd79398af 100644 --- a/Libraries/LibHTML/Layout/LayoutNode.cpp +++ b/Libraries/LibHTML/Layout/LayoutNode.cpp @@ -5,9 +5,6 @@ #include #include -//#define DRAW_BOXES_AROUND_LAYOUT_NODES -//#define DRAW_BOXES_AROUND_HOVERED_NODES - LayoutNode::LayoutNode(const Node* node) : m_node(node) { @@ -42,58 +39,6 @@ void LayoutNode::render(RenderingContext& context) if (!is_visible()) return; -#ifdef DRAW_BOXES_AROUND_LAYOUT_NODES - context.painter().draw_rect(m_rect, Color::Blue); -#endif -#ifdef DRAW_BOXES_AROUND_HOVERED_NODES - if (!is_anonymous() && node() == document().hovered_node()) - context.painter().draw_rect(m_rect, Color::Red); -#endif - - Rect padded_rect; - padded_rect.set_x(x() - box_model().padding().left.to_px()); - padded_rect.set_width(width() + box_model().padding().left.to_px() + box_model().padding().right.to_px()); - padded_rect.set_y(y() - box_model().padding().top.to_px()); - padded_rect.set_height(height() + box_model().padding().top.to_px() + box_model().padding().bottom.to_px()); - - auto bgcolor = style().property(CSS::PropertyID::BackgroundColor); - if (bgcolor.has_value() && bgcolor.value()->is_color()) { - context.painter().fill_rect(padded_rect, bgcolor.value()->to_color(document())); - } - - // FIXME: Respect all individual border sides - auto border_width_value = style().property(CSS::PropertyID::BorderTopWidth); - auto border_color_value = style().property(CSS::PropertyID::BorderTopColor); - auto border_style_value = style().property(CSS::PropertyID::BorderTopStyle); - if (border_width_value.has_value() && border_color_value.has_value()) { - int border_width = border_width_value.value()->to_length().to_px(); - Color border_color = border_color_value.value()->to_color(document()); - - if (border_style_value.has_value() && border_style_value.value()->to_string() == "inset") { - // border-style: inset - auto shadow_color = Color::from_rgb(0x888888); - auto highlight_color = Color::from_rgb(0x5a5a5a); - context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), highlight_color, border_width); - context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), shadow_color, border_width); - context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), shadow_color, border_width); - context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), highlight_color, border_width); - } else if (border_style_value.has_value() && border_style_value.value()->to_string() == "outset") { - // border-style: outset - auto highlight_color = Color::from_rgb(0x888888); - auto shadow_color = Color::from_rgb(0x5a5a5a); - context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), highlight_color, border_width); - context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), shadow_color, border_width); - context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), shadow_color, border_width); - context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), highlight_color, border_width); - } else { - // border-style: solid - context.painter().draw_line(padded_rect.top_left(), padded_rect.top_right(), border_color, border_width); - context.painter().draw_line(padded_rect.top_right(), padded_rect.bottom_right(), border_color, border_width); - context.painter().draw_line(padded_rect.bottom_right(), padded_rect.bottom_left(), border_color, border_width); - context.painter().draw_line(padded_rect.bottom_left(), padded_rect.top_left(), border_color, border_width); - } - } - // TODO: render our border for_each_child([&](auto& child) { child.render(context); @@ -102,10 +47,7 @@ void LayoutNode::render(RenderingContext& context) HitTestResult LayoutNode::hit_test(const Point& position) const { - // FIXME: It would be nice if we could confidently skip over hit testing - // parts of the layout tree, but currently we can't just check - // m_rect.contains() since inline text rects can't be trusted.. - HitTestResult result { m_rect.contains(position) ? this : nullptr }; + HitTestResult result; for_each_child([&](auto& child) { auto child_result = child.hit_test(position); if (child_result.layout_node) @@ -134,18 +76,4 @@ void LayoutNode::split_into_lines(LayoutBlock& container) void LayoutNode::set_needs_display() { - auto* frame = document().frame(); - ASSERT(frame); - - if (!is_inline()) { - const_cast(frame)->set_needs_display(rect()); - return; - } - - for_each_fragment_of_this([&](auto& fragment) { - if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) { - const_cast(frame)->set_needs_display(fragment.rect()); - } - return IterationDecision::Continue; - }); } diff --git a/Libraries/LibHTML/Layout/LayoutNode.h b/Libraries/LibHTML/Layout/LayoutNode.h index 1318f634c6..bc26c2e811 100644 --- a/Libraries/LibHTML/Layout/LayoutNode.h +++ b/Libraries/LibHTML/Layout/LayoutNode.h @@ -24,20 +24,6 @@ class LayoutNode : public TreeNode { public: virtual ~LayoutNode(); - const Rect& rect() const { return m_rect; } - Rect& rect() { return m_rect; } - void set_rect(const Rect& rect) { m_rect = rect; } - - int x() const { return rect().x(); } - int y() const { return rect().y(); } - int width() const { return rect().width(); } - int height() const { return rect().height(); } - Size size() const { return rect().size(); } - Point position() const { return rect().location(); } - - BoxModelMetrics& box_model() { return m_box_metrics; } - const BoxModelMetrics& box_model() const { return m_box_metrics; } - virtual HitTestResult hit_test(const Point&) const; bool is_anonymous() const { return !m_node; } @@ -63,6 +49,7 @@ public: virtual bool is_text() const { return false; } virtual bool is_block() const { return false; } virtual bool is_replaced() const { return false; } + virtual bool is_box() const { return false; } bool has_style() const { return m_has_style; } bool is_inline() const { return m_inline; } @@ -87,7 +74,7 @@ public: bool is_visible() const { return m_visible; } void set_visible(bool visible) { m_visible = visible; } - void set_needs_display(); + virtual void set_needs_display(); template void for_each_fragment_of_this(Callback); @@ -100,8 +87,6 @@ private: const Node* m_node { nullptr }; - BoxModelMetrics m_box_metrics; - Rect m_rect; bool m_inline { false }; bool m_has_style { false }; bool m_visible { true }; @@ -126,6 +111,21 @@ private: NonnullRefPtr m_style; }; +class LayoutNodeWithStyleAndBoxModelMetrics : public LayoutNodeWithStyle { +public: + BoxModelMetrics& box_model() { return m_box_model; } + const BoxModelMetrics& box_model() const { return m_box_model; } + +protected: + LayoutNodeWithStyleAndBoxModelMetrics(const Node* node, NonnullRefPtr style) + : LayoutNodeWithStyle(node, move(style)) + { + } + +private: + BoxModelMetrics m_box_model; +}; + inline const StyleProperties& LayoutNode::style() const { if (m_has_style) @@ -147,7 +147,7 @@ inline bool is(const LayoutNode&) template inline bool is(const LayoutNode* node) { - return node && is(*node); + return !node || is(*node); } template<> diff --git a/Libraries/LibHTML/Layout/LayoutReplaced.cpp b/Libraries/LibHTML/Layout/LayoutReplaced.cpp index 46acbcefee..2551ecd4c8 100644 --- a/Libraries/LibHTML/Layout/LayoutReplaced.cpp +++ b/Libraries/LibHTML/Layout/LayoutReplaced.cpp @@ -3,7 +3,7 @@ #include LayoutReplaced::LayoutReplaced(const Element& element, NonnullRefPtr style) - : LayoutNodeWithStyle(&element, move(style)) + : LayoutBox(&element, move(style)) { // FIXME: Allow non-inline replaced elements. set_inline(true); diff --git a/Libraries/LibHTML/Layout/LayoutReplaced.h b/Libraries/LibHTML/Layout/LayoutReplaced.h index a3392997ec..de80a9294a 100644 --- a/Libraries/LibHTML/Layout/LayoutReplaced.h +++ b/Libraries/LibHTML/Layout/LayoutReplaced.h @@ -1,7 +1,7 @@ #include -#include +#include -class LayoutReplaced : public LayoutNodeWithStyle { +class LayoutReplaced : public LayoutBox { public: LayoutReplaced(const Element&, NonnullRefPtr); virtual ~LayoutReplaced() override; diff --git a/Libraries/LibHTML/Makefile.shared b/Libraries/LibHTML/Makefile.shared index feac259fb3..bbacce889e 100644 --- a/Libraries/LibHTML/Makefile.shared +++ b/Libraries/LibHTML/Makefile.shared @@ -34,6 +34,7 @@ LIBHTML_OBJS = \ Parser/HTMLParser.o \ Parser/CSSParser.o \ Layout/LayoutNode.o \ + Layout/LayoutBox.o \ Layout/LayoutText.o \ Layout/LayoutBlock.o \ Layout/LayoutInline.o \