| 
									
										
										
										
											2019-10-05 10:16:27 +02:00
										 |  |  | #include <AK/FileSystemPath.h>
 | 
					
						
							|  |  |  | #include <AK/StringBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-19 18:57:02 +02:00
										 |  |  | #include <LibCore/CTimer.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-29 21:42:07 +02:00
										 |  |  | #include <LibHTML/CSS/StyleResolver.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-15 23:41:15 +02:00
										 |  |  | #include <LibHTML/DOM/Document.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-09 20:17:01 +02:00
										 |  |  | #include <LibHTML/DOM/DocumentType.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-15 23:41:15 +02:00
										 |  |  | #include <LibHTML/DOM/Element.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-12 13:02:38 +02:00
										 |  |  | #include <LibHTML/DOM/ElementFactory.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  | #include <LibHTML/DOM/HTMLBodyElement.h>
 | 
					
						
							| 
									
										
										
										
											2019-09-29 16:24:57 +02:00
										 |  |  | #include <LibHTML/DOM/HTMLHeadElement.h>
 | 
					
						
							|  |  |  | #include <LibHTML/DOM/HTMLHtmlElement.h>
 | 
					
						
							|  |  |  | #include <LibHTML/DOM/HTMLTitleElement.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-04 15:50:04 +02:00
										 |  |  | #include <LibHTML/Frame.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-15 23:41:15 +02:00
										 |  |  | #include <LibHTML/Layout/LayoutDocument.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-15 12:22:41 +02:00
										 |  |  | #include <LibHTML/Layout/LayoutTreeBuilder.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-15 22:49:44 +02:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2019-06-15 18:55:47 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Document::Document() | 
					
						
							| 
									
										
										
										
											2019-09-29 11:43:07 +02:00
										 |  |  |     : ParentNode(*this, NodeType::DOCUMENT_NODE) | 
					
						
							| 
									
										
										
										
											2019-10-15 15:06:16 +02:00
										 |  |  |     , m_style_resolver(make<StyleResolver>(*this)) | 
					
						
							| 
									
										
										
										
											2019-06-15 18:55:47 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-19 18:57:02 +02:00
										 |  |  |     m_style_update_timer = CTimer::construct(); | 
					
						
							|  |  |  |     m_style_update_timer->set_single_shot(true); | 
					
						
							|  |  |  |     m_style_update_timer->set_interval(0); | 
					
						
							|  |  |  |     m_style_update_timer->on_timeout = [this] { | 
					
						
							|  |  |  |         update_style(); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2019-06-15 18:55:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Document::~Document() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-19 18:57:02 +02:00
										 |  |  | void Document::schedule_style_update() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_style_update_timer->is_active()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     m_style_update_timer->start(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-12 23:26:47 +02:00
										 |  |  | bool Document::is_child_allowed(const Node& node) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (node.type()) { | 
					
						
							|  |  |  |     case NodeType::DOCUMENT_NODE: | 
					
						
							|  |  |  |     case NodeType::TEXT_NODE: | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     case NodeType::COMMENT_NODE: | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     case NodeType::DOCUMENT_TYPE_NODE: | 
					
						
							|  |  |  |         return !first_child_of_type<DocumentType>(); | 
					
						
							|  |  |  |     case NodeType::ELEMENT_NODE: | 
					
						
							|  |  |  |         return !first_child_of_type<Element>(); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-09 18:54:34 +02:00
										 |  |  | void Document::fixup() | 
					
						
							| 
									
										
										
										
											2019-09-25 12:26:26 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-19 21:20:42 +02:00
										 |  |  |     if (!first_child() || !is<DocumentType>(*first_child())) | 
					
						
							| 
									
										
										
										
											2019-10-09 20:17:01 +02:00
										 |  |  |         prepend_child(adopt(*new DocumentType(*this))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is<HTMLHtmlElement>(first_child()->next_sibling())) | 
					
						
							| 
									
										
										
										
											2019-10-06 20:37:39 +02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2019-09-25 12:26:26 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-12 13:02:38 +02:00
										 |  |  |     auto body = create_element(*this, "body"); | 
					
						
							|  |  |  |     auto html = create_element(*this, "html"); | 
					
						
							| 
									
										
										
										
											2019-09-25 12:26:26 +03:00
										 |  |  |     html->append_child(body); | 
					
						
							|  |  |  |     this->donate_all_children_to(body); | 
					
						
							|  |  |  |     this->append_child(html); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-29 16:24:57 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const HTMLHtmlElement* Document::document_element() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-06 20:47:57 +02:00
										 |  |  |     return first_child_of_type<HTMLHtmlElement>(); | 
					
						
							| 
									
										
										
										
											2019-09-29 16:24:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const HTMLHeadElement* Document::head() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto* html = document_element(); | 
					
						
							|  |  |  |     if (!html) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2019-10-06 20:47:57 +02:00
										 |  |  |     return html->first_child_of_type<HTMLHeadElement>(); | 
					
						
							| 
									
										
										
										
											2019-09-29 16:24:57 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  | const HTMLBodyElement* Document::body() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto* html = document_element(); | 
					
						
							|  |  |  |     if (!html) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							| 
									
										
										
										
											2019-10-06 20:47:57 +02:00
										 |  |  |     return html->first_child_of_type<HTMLBodyElement>(); | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-29 16:24:57 +02:00
										 |  |  | String Document::title() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto* head_element = head(); | 
					
						
							|  |  |  |     if (!head_element) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 20:47:57 +02:00
										 |  |  |     auto* title_element = head_element->first_child_of_type<HTMLTitleElement>(); | 
					
						
							| 
									
										
										
										
											2019-09-29 16:24:57 +02:00
										 |  |  |     if (!title_element) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return title_element->text_content(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-04 15:50:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void Document::attach_to_frame(Badge<Frame>, Frame& frame) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_frame = frame.make_weak_ptr(); | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  |     layout(); | 
					
						
							| 
									
										
										
										
											2019-10-04 15:50:04 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Document::detach_from_frame(Badge<Frame>, Frame&) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  |     m_layout_root = nullptr; | 
					
						
							| 
									
										
										
										
											2019-10-09 21:52:38 +02:00
										 |  |  |     m_frame = nullptr; | 
					
						
							| 
									
										
										
										
											2019-10-04 15:50:04 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | Color Document::background_color() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto* body_element = body(); | 
					
						
							|  |  |  |     if (!body_element) | 
					
						
							|  |  |  |         return Color::White; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto* body_layout_node = body_element->layout_node(); | 
					
						
							|  |  |  |     if (!body_layout_node) | 
					
						
							|  |  |  |         return Color::White; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-08 15:34:19 +02:00
										 |  |  |     auto background_color = body_layout_node->style().property(CSS::PropertyID::BackgroundColor); | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  |     if (!background_color.has_value() || !background_color.value()->is_color()) | 
					
						
							|  |  |  |         return Color::White; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 10:11:54 +02:00
										 |  |  |     return background_color.value()->to_color(*this); | 
					
						
							| 
									
										
										
										
											2019-10-04 21:05:52 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-05 10:16:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-19 11:49:46 +02:00
										 |  |  | RefPtr<GraphicsBitmap> Document::background_image() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     auto* body_element = body(); | 
					
						
							|  |  |  |     if (!body_element) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto* body_layout_node = body_element->layout_node(); | 
					
						
							|  |  |  |     if (!body_layout_node) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto background_image = body_layout_node->style().property(CSS::PropertyID::BackgroundImage); | 
					
						
							|  |  |  |     if (!background_image.has_value() || !background_image.value()->is_image()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& image_value = static_cast<const ImageStyleValue&>(*background_image.value()); | 
					
						
							|  |  |  |     if (!image_value.bitmap()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return *image_value.bitmap(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 10:16:27 +02:00
										 |  |  | URL Document::complete_url(const String& string) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-11-18 22:04:39 +01:00
										 |  |  |     return m_url.complete_url(string); | 
					
						
							| 
									
										
										
										
											2019-10-05 10:16:27 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-05 22:27:52 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 20:51:45 +01:00
										 |  |  | void Document::force_layout() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_layout_root = nullptr; | 
					
						
							|  |  |  |     layout(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  | void Document::layout() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-15 12:22:41 +02:00
										 |  |  |     if (!m_layout_root) { | 
					
						
							|  |  |  |         LayoutTreeBuilder tree_builder; | 
					
						
							|  |  |  |         m_layout_root = tree_builder.build(*this); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  |     m_layout_root->layout(); | 
					
						
							| 
									
										
										
										
											2019-10-28 20:51:45 +01:00
										 |  |  |     m_layout_root->set_needs_display(); | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 17:56:19 +02:00
										 |  |  | void Document::update_style() | 
					
						
							| 
									
										
										
										
											2019-10-13 12:49:43 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-19 18:57:02 +02:00
										 |  |  |     for_each_in_subtree([&](Node& node) { | 
					
						
							| 
									
										
										
										
											2019-10-21 12:01:30 +02:00
										 |  |  |         if (node.needs_style_update()) | 
					
						
							|  |  |  |             to<Element>(node).recompute_style(); | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							| 
									
										
										
										
											2019-10-19 18:57:02 +02:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-10-14 17:56:19 +02:00
										 |  |  |     update_layout(); | 
					
						
							| 
									
										
										
										
											2019-10-13 12:49:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 17:56:19 +02:00
										 |  |  | void Document::update_layout() | 
					
						
							| 
									
										
										
										
											2019-10-06 22:58:18 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  |     layout(); | 
					
						
							| 
									
										
										
										
											2019-10-14 17:56:19 +02:00
										 |  |  |     if (on_layout_updated) | 
					
						
							|  |  |  |         on_layout_updated(); | 
					
						
							| 
									
										
										
										
											2019-10-06 22:58:18 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-15 15:06:16 +02:00
										 |  |  | RefPtr<LayoutNode> Document::create_layout_node(const StyleProperties*) const | 
					
						
							| 
									
										
										
										
											2019-10-05 22:27:52 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return adopt(*new LayoutDocument(*this, StyleProperties::create())); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-06 10:11:54 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void Document::set_link_color(Color color) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_link_color = color; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Document::set_active_link_color(Color color) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_active_link_color = color; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Document::set_visited_link_color(Color color) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_visited_link_color = color; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-13 12:34:25 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const LayoutDocument* Document::layout_node() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return static_cast<const LayoutDocument*>(Node::layout_node()); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-14 17:54:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-04 19:37:52 +01:00
										 |  |  | LayoutDocument* Document::layout_node() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return static_cast<LayoutDocument*>(Node::layout_node()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-09 11:58:50 +01:00
										 |  |  | void Document::set_inspected_node(Node* node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_inspected_node == node) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_inspected_node && m_inspected_node->layout_node()) | 
					
						
							|  |  |  |         m_inspected_node->layout_node()->set_needs_display(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_inspected_node = node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_inspected_node && m_inspected_node->layout_node()) | 
					
						
							|  |  |  |         m_inspected_node->layout_node()->set_needs_display(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 17:54:17 +02:00
										 |  |  | void Document::set_hovered_node(Node* node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_hovered_node == node) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-14 18:32:02 +02:00
										 |  |  |     RefPtr<Node> old_hovered_node = move(m_hovered_node); | 
					
						
							| 
									
										
										
										
											2019-10-14 17:54:17 +02:00
										 |  |  |     m_hovered_node = node; | 
					
						
							| 
									
										
										
										
											2019-10-14 18:32:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-19 18:57:02 +02:00
										 |  |  |     invalidate_style(); | 
					
						
							| 
									
										
										
										
											2019-10-14 17:54:17 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-10-21 12:01:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const Element* Document::get_element_by_id(const String& id) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const Element* element = nullptr; | 
					
						
							|  |  |  |     for_each_in_subtree([&](auto& node) { | 
					
						
							|  |  |  |         if (is<Element>(node) && to<Element>(node).attribute("id") == id) { | 
					
						
							|  |  |  |             element = &to<Element>(node); | 
					
						
							|  |  |  |             return IterationDecision::Break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return element; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Vector<const Element*> Document::get_elements_by_name(const String& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Vector<const Element*> elements; | 
					
						
							|  |  |  |     for_each_in_subtree([&](auto& node) { | 
					
						
							|  |  |  |         if (is<Element>(node) && to<Element>(node).attribute("name") == name) | 
					
						
							|  |  |  |             elements.append(&to<Element>(node)); | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return elements; | 
					
						
							|  |  |  | } |