mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 17:02:45 +00:00 
			
		
		
		
	LibHTML: Move layout root from HtmlView to Document
The layout root is now kept alive via Document::m_layout_root. This will allow us to do more layout-related things inside the inner layer of LibHTML without reaching out to the HtmlView. I'd like to keep HtmlView at a slightly higher level, to prevent it from getting too complex. This patch also fixes accidental disconnection of the layout tree from the DOM after doing a layout tree rebuild. ~LayoutNode() now only unsets the DOM node's layout_node() if it's itself.
This commit is contained in:
		
							parent
							
								
									48ef1d1bd1
								
							
						
					
					
						commit
						49ac0c2e24
					
				
					 6 changed files with 51 additions and 20 deletions
				
			
		|  | @ -14,6 +14,7 @@ | ||||||
| #include <LibHTML/Dump.h> | #include <LibHTML/Dump.h> | ||||||
| #include <LibHTML/HtmlView.h> | #include <LibHTML/HtmlView.h> | ||||||
| #include <LibHTML/Layout/LayoutBlock.h> | #include <LibHTML/Layout/LayoutBlock.h> | ||||||
|  | #include <LibHTML/Layout/LayoutDocument.h> | ||||||
| #include <LibHTML/Layout/LayoutInline.h> | #include <LibHTML/Layout/LayoutInline.h> | ||||||
| #include <LibHTML/Layout/LayoutNode.h> | #include <LibHTML/Layout/LayoutNode.h> | ||||||
| #include <LibHTML/Parser/CSSParser.h> | #include <LibHTML/Parser/CSSParser.h> | ||||||
|  |  | ||||||
|  | @ -98,10 +98,12 @@ String Document::title() const | ||||||
| void Document::attach_to_frame(Badge<Frame>, Frame& frame) | void Document::attach_to_frame(Badge<Frame>, Frame& frame) | ||||||
| { | { | ||||||
|     m_frame = frame.make_weak_ptr(); |     m_frame = frame.make_weak_ptr(); | ||||||
|  |     layout(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Document::detach_from_frame(Badge<Frame>, Frame&) | void Document::detach_from_frame(Badge<Frame>, Frame&) | ||||||
| { | { | ||||||
|  |     m_layout_root = nullptr; | ||||||
|     m_frame = nullptr; |     m_frame = nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -149,8 +151,15 @@ URL Document::complete_url(const String& string) const | ||||||
|     return url; |     return url; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Document::layout() | ||||||
|  | { | ||||||
|  |     m_layout_root = create_layout_tree(style_resolver(), nullptr); | ||||||
|  |     m_layout_root->layout(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void Document::invalidate_layout() | void Document::invalidate_layout() | ||||||
| { | { | ||||||
|  |     layout(); | ||||||
|     if (on_invalidate_layout) |     if (on_invalidate_layout) | ||||||
|         on_invalidate_layout(); |         on_invalidate_layout(); | ||||||
| } | } | ||||||
|  | @ -174,3 +183,8 @@ void Document::set_visited_link_color(Color color) | ||||||
| { | { | ||||||
|     m_visited_link_color = color; |     m_visited_link_color = color; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | const LayoutDocument* Document::layout_node() const | ||||||
|  | { | ||||||
|  |     return static_cast<const LayoutDocument*>(Node::layout_node()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ class Frame; | ||||||
| class HTMLBodyElement; | class HTMLBodyElement; | ||||||
| class HTMLHtmlElement; | class HTMLHtmlElement; | ||||||
| class HTMLHeadElement; | class HTMLHeadElement; | ||||||
|  | class LayoutDocument; | ||||||
| class LayoutNode; | class LayoutNode; | ||||||
| class StyleResolver; | class StyleResolver; | ||||||
| class StyleSheet; | class StyleSheet; | ||||||
|  | @ -64,11 +65,15 @@ public: | ||||||
|     Color visited_link_color() const { return m_visited_link_color; } |     Color visited_link_color() const { return m_visited_link_color; } | ||||||
|     void set_visited_link_color(Color); |     void set_visited_link_color(Color); | ||||||
| 
 | 
 | ||||||
|  |     void layout(); | ||||||
|  | 
 | ||||||
|     void invalidate_layout(); |     void invalidate_layout(); | ||||||
|     Function<void()> on_invalidate_layout; |     Function<void()> on_invalidate_layout; | ||||||
| 
 | 
 | ||||||
|     virtual bool is_child_allowed(const Node&) const override; |     virtual bool is_child_allowed(const Node&) const override; | ||||||
| 
 | 
 | ||||||
|  |     const LayoutDocument* layout_node() const; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     virtual RefPtr<LayoutNode> create_layout_node(const StyleResolver&, const StyleProperties* parent_style) const override; |     virtual RefPtr<LayoutNode> create_layout_node(const StyleResolver&, const StyleProperties* parent_style) const override; | ||||||
| 
 | 
 | ||||||
|  | @ -78,6 +83,8 @@ private: | ||||||
|     WeakPtr<Frame> m_frame; |     WeakPtr<Frame> m_frame; | ||||||
|     URL m_url; |     URL m_url; | ||||||
| 
 | 
 | ||||||
|  |     RefPtr<LayoutDocument> m_layout_root; | ||||||
|  | 
 | ||||||
|     Color m_link_color { Color::Blue }; |     Color m_link_color { Color::Blue }; | ||||||
|     Color m_active_link_color { Color::Red }; |     Color m_active_link_color { Color::Red }; | ||||||
|     Color m_visited_link_color { Color::Magenta }; |     Color m_visited_link_color { Color::Magenta }; | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| #include <LibHTML/Dump.h> | #include <LibHTML/Dump.h> | ||||||
| #include <LibHTML/Frame.h> | #include <LibHTML/Frame.h> | ||||||
| #include <LibHTML/HtmlView.h> | #include <LibHTML/HtmlView.h> | ||||||
|  | #include <LibHTML/Layout/LayoutDocument.h> | ||||||
| #include <LibHTML/Layout/LayoutNode.h> | #include <LibHTML/Layout/LayoutNode.h> | ||||||
| #include <LibHTML/Parser/HTMLParser.h> | #include <LibHTML/Parser/HTMLParser.h> | ||||||
| #include <LibHTML/RenderingContext.h> | #include <LibHTML/RenderingContext.h> | ||||||
|  | @ -46,24 +47,18 @@ void HtmlView::set_document(Document* document) | ||||||
|     m_document = document; |     m_document = document; | ||||||
| 
 | 
 | ||||||
|     if (m_document) { |     if (m_document) { | ||||||
|         m_document->on_invalidate_layout = [this]() { |         m_document->on_invalidate_layout = [this] { | ||||||
|             m_layout_root = m_document->create_layout_tree(m_document->style_resolver(), nullptr); |  | ||||||
|             layout_and_sync_size(); |             layout_and_sync_size(); | ||||||
|             update(); |             update(); | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     m_layout_root = nullptr; |  | ||||||
| 
 |  | ||||||
|     main_frame().set_document(document); |     main_frame().set_document(document); | ||||||
| 
 | 
 | ||||||
|     if (document) |  | ||||||
|         m_layout_root = document->create_layout_tree(document->style_resolver(), nullptr); |  | ||||||
| 
 |  | ||||||
| #ifdef HTML_DEBUG | #ifdef HTML_DEBUG | ||||||
|     if (document != nullptr) { |     if (document != nullptr) { | ||||||
|         dbgprintf("\033[33;1mLayout tree before layout:\033[0m\n"); |         dbgprintf("\033[33;1mLayout tree before layout:\033[0m\n"); | ||||||
|         ::dump_tree(*m_layout_root); |         ::dump_tree(*layout_root()); | ||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | @ -73,16 +68,16 @@ void HtmlView::set_document(Document* document) | ||||||
| 
 | 
 | ||||||
| void HtmlView::layout_and_sync_size() | void HtmlView::layout_and_sync_size() | ||||||
| { | { | ||||||
|     if (!m_layout_root) |     if (!document()) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     main_frame().set_size(available_size()); |     main_frame().set_size(available_size()); | ||||||
|     m_layout_root->layout(); |     document()->layout(); | ||||||
|     set_content_size(m_layout_root->rect().size()); |     set_content_size(layout_root()->rect().size()); | ||||||
| 
 | 
 | ||||||
| #ifdef HTML_DEBUG | #ifdef HTML_DEBUG | ||||||
|     dbgprintf("\033[33;1mLayout tree after layout:\033[0m\n"); |     dbgprintf("\033[33;1mLayout tree after layout:\033[0m\n"); | ||||||
|     ::dump_tree(*m_layout_root); |     ::dump_tree(*layout_root()); | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -100,7 +95,7 @@ void HtmlView::paint_event(GPaintEvent& event) | ||||||
|     painter.add_clip_rect(widget_inner_rect()); |     painter.add_clip_rect(widget_inner_rect()); | ||||||
|     painter.add_clip_rect(event.rect()); |     painter.add_clip_rect(event.rect()); | ||||||
| 
 | 
 | ||||||
|     if (!m_layout_root) { |     if (!layout_root()) { | ||||||
|         painter.fill_rect(event.rect(), background_color()); |         painter.fill_rect(event.rect(), background_color()); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | @ -112,17 +107,17 @@ void HtmlView::paint_event(GPaintEvent& event) | ||||||
| 
 | 
 | ||||||
|     RenderingContext context { painter }; |     RenderingContext context { painter }; | ||||||
|     context.set_should_show_line_box_borders(m_should_show_line_box_borders); |     context.set_should_show_line_box_borders(m_should_show_line_box_borders); | ||||||
|     m_layout_root->render(context); |     layout_root()->render(context); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HtmlView::mousemove_event(GMouseEvent& event) | void HtmlView::mousemove_event(GMouseEvent& event) | ||||||
| { | { | ||||||
|     if (!m_layout_root) |     if (!layout_root()) | ||||||
|         return GScrollableWidget::mousemove_event(event); |         return GScrollableWidget::mousemove_event(event); | ||||||
| 
 | 
 | ||||||
|     bool hovered_node_changed = false; |     bool hovered_node_changed = false; | ||||||
|     bool is_hovering_link = false; |     bool is_hovering_link = false; | ||||||
|     auto result = m_layout_root->hit_test(to_content_position(event.position())); |     auto result = layout_root()->hit_test(to_content_position(event.position())); | ||||||
|     if (result.layout_node) { |     if (result.layout_node) { | ||||||
|         auto* node = result.layout_node->node(); |         auto* node = result.layout_node->node(); | ||||||
|         hovered_node_changed = node != m_document->hovered_node(); |         hovered_node_changed = node != m_document->hovered_node(); | ||||||
|  | @ -154,11 +149,11 @@ void HtmlView::mousemove_event(GMouseEvent& event) | ||||||
| 
 | 
 | ||||||
| void HtmlView::mousedown_event(GMouseEvent& event) | void HtmlView::mousedown_event(GMouseEvent& event) | ||||||
| { | { | ||||||
|     if (!m_layout_root) |     if (!layout_root()) | ||||||
|         return GScrollableWidget::mousemove_event(event); |         return GScrollableWidget::mousemove_event(event); | ||||||
| 
 | 
 | ||||||
|     bool hovered_node_changed = false; |     bool hovered_node_changed = false; | ||||||
|     auto result = m_layout_root->hit_test(to_content_position(event.position())); |     auto result = layout_root()->hit_test(to_content_position(event.position())); | ||||||
|     if (result.layout_node) { |     if (result.layout_node) { | ||||||
|         auto* node = result.layout_node->node(); |         auto* node = result.layout_node->node(); | ||||||
|         hovered_node_changed = node != m_document->hovered_node(); |         hovered_node_changed = node != m_document->hovered_node(); | ||||||
|  | @ -205,3 +200,15 @@ void HtmlView::load(const URL& url) | ||||||
|             on_title_change(document->title()); |             on_title_change(document->title()); | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | const LayoutDocument* HtmlView::layout_root() const | ||||||
|  | { | ||||||
|  |     return document() ? document()->layout_node() : nullptr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | LayoutDocument* HtmlView::layout_root() | ||||||
|  | { | ||||||
|  |     if (!document()) | ||||||
|  |         return nullptr; | ||||||
|  |     return const_cast<LayoutDocument*>(document()->layout_node()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -15,6 +15,9 @@ public: | ||||||
|     const Document* document() const { return m_document; } |     const Document* document() const { return m_document; } | ||||||
|     void set_document(Document*); |     void set_document(Document*); | ||||||
| 
 | 
 | ||||||
|  |     const LayoutDocument* layout_root() const; | ||||||
|  |     LayoutDocument* layout_root(); | ||||||
|  | 
 | ||||||
|     Frame& main_frame() { return *m_main_frame; } |     Frame& main_frame() { return *m_main_frame; } | ||||||
|     const Frame& main_frame() const { return *m_main_frame; } |     const Frame& main_frame() const { return *m_main_frame; } | ||||||
| 
 | 
 | ||||||
|  | @ -42,7 +45,6 @@ private: | ||||||
| 
 | 
 | ||||||
|     RefPtr<Frame> m_main_frame; |     RefPtr<Frame> m_main_frame; | ||||||
|     RefPtr<Document> m_document; |     RefPtr<Document> m_document; | ||||||
|     RefPtr<LayoutNode> m_layout_root; |  | ||||||
| 
 | 
 | ||||||
|     bool m_should_show_line_box_borders { false }; |     bool m_should_show_line_box_borders { false }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ LayoutNode::LayoutNode(const Node* node) | ||||||
| 
 | 
 | ||||||
| LayoutNode::~LayoutNode() | LayoutNode::~LayoutNode() | ||||||
| { | { | ||||||
|     if (m_node) |     if (m_node && m_node->layout_node() == this) | ||||||
|         m_node->set_layout_node({}, nullptr); |         m_node->set_layout_node({}, nullptr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling