Serenity Operating System
at hosted 323 lines 8.7 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/NonnullRefPtr.h> 30#include <AK/Vector.h> 31#include <LibGfx/FloatRect.h> 32#include <LibGfx/Rect.h> 33#include <LibWeb/CSS/StyleProperties.h> 34#include <LibWeb/Layout/BoxModelMetrics.h> 35#include <LibWeb/Layout/LayoutPosition.h> 36#include <LibWeb/RenderingContext.h> 37#include <LibWeb/TreeNode.h> 38 39namespace Web { 40 41class Document; 42class Element; 43class LayoutBlock; 44class LayoutDocument; 45class LayoutNode; 46class LayoutNodeWithStyle; 47class LineBoxFragment; 48class Node; 49 50struct HitTestResult { 51 RefPtr<LayoutNode> layout_node; 52 int index_in_node { 0 }; 53}; 54 55class LayoutNode : public TreeNode<LayoutNode> { 56public: 57 virtual ~LayoutNode(); 58 59 virtual HitTestResult hit_test(const Gfx::Point&) const; 60 61 bool is_anonymous() const { return !m_node; } 62 const Node* node() const { return m_node; } 63 64 Document& document(); 65 const Document& document() const; 66 67 const LayoutDocument& root() const; 68 LayoutDocument& root(); 69 70 template<typename Callback> 71 inline void for_each_child(Callback callback) const 72 { 73 for (auto* node = first_child(); node; node = node->next_sibling()) 74 callback(*node); 75 } 76 77 template<typename Callback> 78 inline void for_each_child(Callback callback) 79 { 80 for (auto* node = first_child(); node; node = node->next_sibling()) 81 callback(*node); 82 } 83 84 virtual const char* class_name() const { return "LayoutNode"; } 85 virtual bool is_text() const { return false; } 86 virtual bool is_block() const { return false; } 87 virtual bool is_replaced() const { return false; } 88 virtual bool is_widget() const { return false; } 89 virtual bool is_image() const { return false; } 90 virtual bool is_canvas() const { return false; } 91 virtual bool is_box() const { return false; } 92 virtual bool is_table() const { return false; } 93 virtual bool is_table_row() const { return false; } 94 virtual bool is_table_cell() const { return false; } 95 bool has_style() const { return m_has_style; } 96 97 bool is_inline() const { return m_inline; } 98 void set_inline(bool b) { m_inline = b; } 99 100 virtual void layout(); 101 virtual void render(RenderingContext&); 102 103 const LayoutBlock* containing_block() const; 104 105 virtual LayoutNode& inline_wrapper() { return *this; } 106 107 const StyleProperties& style() const; 108 109 LayoutNodeWithStyle* parent(); 110 const LayoutNodeWithStyle* parent() const; 111 112 void inserted_into(LayoutNode&) {} 113 void removed_from(LayoutNode&) {} 114 void children_changed() {} 115 116 virtual void split_into_lines(LayoutBlock& container); 117 118 bool is_visible() const { return m_visible; } 119 void set_visible(bool visible) { m_visible = visible; } 120 121 virtual void set_needs_display(); 122 123 bool children_are_inline() const { return m_children_are_inline; } 124 void set_children_are_inline(bool value) { m_children_are_inline = value; } 125 126 template<typename U> 127 const U* next_sibling_of_type() const; 128 129 template<typename U> 130 U* next_sibling_of_type(); 131 132 template<typename T> 133 const T* first_child_of_type() const; 134 135 template<typename T> 136 T* first_child_of_type(); 137 138 template<typename T> 139 const T* first_ancestor_of_type() const; 140 141 template<typename T> 142 T* first_ancestor_of_type(); 143 144 Gfx::FloatPoint box_type_agnostic_position() const; 145 146protected: 147 explicit LayoutNode(const Node*); 148 149private: 150 friend class LayoutNodeWithStyle; 151 152 const Node* m_node { nullptr }; 153 154 bool m_inline { false }; 155 bool m_has_style { false }; 156 bool m_visible { true }; 157 bool m_children_are_inline { false }; 158}; 159 160class LayoutNodeWithStyle : public LayoutNode { 161public: 162 virtual ~LayoutNodeWithStyle() override {} 163 164 const StyleProperties& style() const { return m_style; } 165 void set_style(const StyleProperties& style) { m_style = style; } 166 167protected: 168 explicit LayoutNodeWithStyle(const Node* node, NonnullRefPtr<StyleProperties> style) 169 : LayoutNode(node) 170 , m_style(move(style)) 171 { 172 m_has_style = true; 173 } 174 175private: 176 NonnullRefPtr<StyleProperties> m_style; 177}; 178 179class LayoutNodeWithStyleAndBoxModelMetrics : public LayoutNodeWithStyle { 180public: 181 BoxModelMetrics& box_model() { return m_box_model; } 182 const BoxModelMetrics& box_model() const { return m_box_model; } 183 184protected: 185 LayoutNodeWithStyleAndBoxModelMetrics(const Node* node, NonnullRefPtr<StyleProperties> style) 186 : LayoutNodeWithStyle(node, move(style)) 187 { 188 } 189 190private: 191 BoxModelMetrics m_box_model; 192}; 193 194inline const StyleProperties& LayoutNode::style() const 195{ 196 if (m_has_style) 197 return static_cast<const LayoutNodeWithStyle*>(this)->style(); 198 return parent()->style(); 199} 200 201inline const LayoutNodeWithStyle* LayoutNode::parent() const 202{ 203 return static_cast<const LayoutNodeWithStyle*>(TreeNode<LayoutNode>::parent()); 204} 205 206inline LayoutNodeWithStyle* LayoutNode::parent() 207{ 208 return static_cast<LayoutNodeWithStyle*>(TreeNode<LayoutNode>::parent()); 209} 210 211template<typename T> 212inline bool is(const LayoutNode&) 213{ 214 return false; 215} 216 217template<typename T> 218inline bool is(const LayoutNode* node) 219{ 220 return !node || is<T>(*node); 221} 222 223template<> 224inline bool is<LayoutNode>(const LayoutNode&) 225{ 226 return true; 227} 228 229template<> 230inline bool is<LayoutNodeWithStyle>(const LayoutNode& node) 231{ 232 return node.has_style(); 233} 234 235template<typename T> 236inline const T& to(const LayoutNode& node) 237{ 238 ASSERT(is<T>(node)); 239 return static_cast<const T&>(node); 240} 241 242template<typename T> 243inline T* to(LayoutNode* node) 244{ 245 ASSERT(is<T>(node)); 246 return static_cast<T*>(node); 247} 248 249template<typename T> 250inline const T* to(const LayoutNode* node) 251{ 252 ASSERT(is<T>(node)); 253 return static_cast<const T*>(node); 254} 255 256template<typename T> 257inline T& to(LayoutNode& node) 258{ 259 ASSERT(is<T>(node)); 260 return static_cast<T&>(node); 261} 262 263template<typename T> 264inline const T* LayoutNode::next_sibling_of_type() const 265{ 266 for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) { 267 if (is<T>(*sibling)) 268 return &to<T>(*sibling); 269 } 270 return nullptr; 271} 272 273template<typename T> 274inline T* LayoutNode::next_sibling_of_type() 275{ 276 for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) { 277 if (is<T>(*sibling)) 278 return &to<T>(*sibling); 279 } 280 return nullptr; 281} 282 283template<typename T> 284inline const T* LayoutNode::first_child_of_type() const 285{ 286 for (auto* child = first_child(); child; child = child->next_sibling()) { 287 if (is<T>(*child)) 288 return &to<T>(*child); 289 } 290 return nullptr; 291} 292 293template<typename T> 294inline T* LayoutNode::first_child_of_type() 295{ 296 for (auto* child = first_child(); child; child = child->next_sibling()) { 297 if (is<T>(*child)) 298 return &to<T>(*child); 299 } 300 return nullptr; 301} 302 303template<typename T> 304inline const T* LayoutNode::first_ancestor_of_type() const 305{ 306 for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { 307 if (is<T>(*ancestor)) 308 return &to<T>(*ancestor); 309 } 310 return nullptr; 311} 312 313template<typename T> 314inline T* LayoutNode::first_ancestor_of_type() 315{ 316 for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { 317 if (is<T>(*ancestor)) 318 return &to<T>(*ancestor); 319 } 320 return nullptr; 321} 322 323}