#pragma once #include #include #include #include #include #include #include #include #include class Document; class Element; class LayoutBlock; class LayoutDocument; class LayoutNode; class LayoutNodeWithStyle; class LineBoxFragment; class Node; struct HitTestResult { RefPtr layout_node; int index_in_node { 0 }; }; class LayoutNode : public TreeNode { public: virtual ~LayoutNode(); virtual HitTestResult hit_test(const Point&) const; bool is_anonymous() const { return !m_node; } const Node* node() const { return m_node; } Document& document(); const Document& document() const; const LayoutDocument& root() const; LayoutDocument& root(); template inline void for_each_child(Callback callback) const { for (auto* node = first_child(); node; node = node->next_sibling()) callback(*node); } template inline void for_each_child(Callback callback) { for (auto* node = first_child(); node; node = node->next_sibling()) callback(*node); } virtual const char* class_name() const { return "LayoutNode"; } virtual bool is_text() const { return false; } virtual bool is_block() const { return false; } virtual bool is_replaced() const { return false; } virtual bool is_widget() const { return false; } virtual bool is_image() const { return false; } virtual bool is_box() const { return false; } virtual bool is_table() const { return false; } virtual bool is_table_row() const { return false; } virtual bool is_table_cell() const { return false; } bool has_style() const { return m_has_style; } bool is_inline() const { return m_inline; } void set_inline(bool b) { m_inline = b; } virtual void layout(); virtual void render(RenderingContext&); const LayoutBlock* containing_block() const; virtual LayoutNode& inline_wrapper() { return *this; } const StyleProperties& style() const; LayoutNodeWithStyle* parent(); const LayoutNodeWithStyle* parent() const; void inserted_into(LayoutNode&) {} void removed_from(LayoutNode&) {} virtual void split_into_lines(LayoutBlock& container); bool is_visible() const { return m_visible; } void set_visible(bool visible) { m_visible = visible; } virtual void set_needs_display(); bool children_are_inline() const { return m_children_are_inline; } void set_children_are_inline(bool value) { m_children_are_inline = value; } template const U* next_sibling_of_type() const; template U* next_sibling_of_type(); template const T* first_child_of_type() const; template T* first_child_of_type(); template const T* first_ancestor_of_type() const; template T* first_ancestor_of_type(); FloatPoint box_type_agnostic_position() const; protected: explicit LayoutNode(const Node*); private: friend class LayoutNodeWithStyle; const Node* m_node { nullptr }; bool m_inline { false }; bool m_has_style { false }; bool m_visible { true }; bool m_children_are_inline { false }; }; class LayoutNodeWithStyle : public LayoutNode { public: virtual ~LayoutNodeWithStyle() override {} const StyleProperties& style() const { return m_style; } void set_style(const StyleProperties& style) { m_style = style; } protected: explicit LayoutNodeWithStyle(const Node* node, NonnullRefPtr style) : LayoutNode(node) , m_style(move(style)) { m_has_style = true; } 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) return static_cast(this)->style(); return parent()->style(); } inline const LayoutNodeWithStyle* LayoutNode::parent() const { return static_cast(TreeNode::parent()); } inline LayoutNodeWithStyle* LayoutNode::parent() { return static_cast(TreeNode::parent()); } template inline bool is(const LayoutNode&) { return false; } template inline bool is(const LayoutNode* node) { return !node || is(*node); } template<> inline bool is(const LayoutNode&) { return true; } template<> inline bool is(const LayoutNode& node) { return node.has_style(); } template inline const T& to(const LayoutNode& node) { ASSERT(is(node)); return static_cast(node); } template inline T* to(LayoutNode* node) { ASSERT(is(node)); return static_cast(node); } template inline const T* to(const LayoutNode* node) { ASSERT(is(node)); return static_cast(node); } template inline T& to(LayoutNode& node) { ASSERT(is(node)); return static_cast(node); } template inline const T* LayoutNode::next_sibling_of_type() const { for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) { if (is(*sibling)) return &to(*sibling); } return nullptr; } template inline T* LayoutNode::next_sibling_of_type() { for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) { if (is(*sibling)) return &to(*sibling); } return nullptr; } template inline const T* LayoutNode::first_child_of_type() const { for (auto* child = first_child(); child; child = child->next_sibling()) { if (is(*child)) return &to(*child); } return nullptr; } template inline T* LayoutNode::first_child_of_type() { for (auto* child = first_child(); child; child = child->next_sibling()) { if (is(*child)) return &to(*child); } return nullptr; } template inline const T* LayoutNode::first_ancestor_of_type() const { for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { if (is(*ancestor)) return &to(*ancestor); } return nullptr; } template inline T* LayoutNode::first_ancestor_of_type() { for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { if (is(*ancestor)) return &to(*ancestor); } return nullptr; }