Document.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include <AK/FileSystemPath.h>
  2. #include <AK/StringBuilder.h>
  3. #include <LibHTML/CSS/StyleResolver.h>
  4. #include <LibHTML/DOM/Document.h>
  5. #include <LibHTML/DOM/DocumentType.h>
  6. #include <LibHTML/DOM/Element.h>
  7. #include <LibHTML/DOM/ElementFactory.h>
  8. #include <LibHTML/DOM/HTMLBodyElement.h>
  9. #include <LibHTML/DOM/HTMLHeadElement.h>
  10. #include <LibHTML/DOM/HTMLHtmlElement.h>
  11. #include <LibHTML/DOM/HTMLTitleElement.h>
  12. #include <LibHTML/Frame.h>
  13. #include <LibHTML/Layout/LayoutDocument.h>
  14. #include <stdio.h>
  15. Document::Document()
  16. : ParentNode(*this, NodeType::DOCUMENT_NODE)
  17. {
  18. }
  19. Document::~Document()
  20. {
  21. }
  22. StyleResolver& Document::style_resolver()
  23. {
  24. if (!m_style_resolver)
  25. m_style_resolver = make<StyleResolver>(*this);
  26. return *m_style_resolver;
  27. }
  28. bool Document::is_child_allowed(const Node& node) const
  29. {
  30. switch (node.type()) {
  31. case NodeType::DOCUMENT_NODE:
  32. case NodeType::TEXT_NODE:
  33. return false;
  34. case NodeType::COMMENT_NODE:
  35. return true;
  36. case NodeType::DOCUMENT_TYPE_NODE:
  37. return !first_child_of_type<DocumentType>();
  38. case NodeType::ELEMENT_NODE:
  39. return !first_child_of_type<Element>();
  40. default:
  41. return false;
  42. }
  43. }
  44. void Document::fixup()
  45. {
  46. if (!is<DocumentType>(first_child()))
  47. prepend_child(adopt(*new DocumentType(*this)));
  48. if (is<HTMLHtmlElement>(first_child()->next_sibling()))
  49. return;
  50. auto body = create_element(*this, "body");
  51. auto html = create_element(*this, "html");
  52. html->append_child(body);
  53. this->donate_all_children_to(body);
  54. this->append_child(html);
  55. }
  56. const HTMLHtmlElement* Document::document_element() const
  57. {
  58. return first_child_of_type<HTMLHtmlElement>();
  59. }
  60. const HTMLHeadElement* Document::head() const
  61. {
  62. auto* html = document_element();
  63. if (!html)
  64. return nullptr;
  65. return html->first_child_of_type<HTMLHeadElement>();
  66. }
  67. const HTMLBodyElement* Document::body() const
  68. {
  69. auto* html = document_element();
  70. if (!html)
  71. return nullptr;
  72. return html->first_child_of_type<HTMLBodyElement>();
  73. }
  74. String Document::title() const
  75. {
  76. auto* head_element = head();
  77. if (!head_element)
  78. return {};
  79. auto* title_element = head_element->first_child_of_type<HTMLTitleElement>();
  80. if (!title_element)
  81. return {};
  82. return title_element->text_content();
  83. }
  84. void Document::attach_to_frame(Badge<Frame>, Frame& frame)
  85. {
  86. m_frame = frame.make_weak_ptr();
  87. layout();
  88. }
  89. void Document::detach_from_frame(Badge<Frame>, Frame&)
  90. {
  91. m_layout_root = nullptr;
  92. m_frame = nullptr;
  93. }
  94. Color Document::background_color() const
  95. {
  96. auto* body_element = body();
  97. if (!body_element)
  98. return Color::White;
  99. auto* body_layout_node = body_element->layout_node();
  100. if (!body_layout_node)
  101. return Color::White;
  102. auto background_color = body_layout_node->style().property(CSS::PropertyID::BackgroundColor);
  103. if (!background_color.has_value() || !background_color.value()->is_color())
  104. return Color::White;
  105. return background_color.value()->to_color(*this);
  106. }
  107. URL Document::complete_url(const String& string) const
  108. {
  109. URL url(string);
  110. if (url.is_valid())
  111. return url;
  112. FileSystemPath fspath(m_url.path());
  113. StringBuilder builder;
  114. builder.append('/');
  115. bool document_url_ends_in_slash = m_url.path()[m_url.path().length() - 1] == '/';
  116. for (int i = 0; i < fspath.parts().size(); ++i) {
  117. if (i == fspath.parts().size() - 1 && !document_url_ends_in_slash)
  118. break;
  119. builder.append(fspath.parts()[i]);
  120. builder.append('/');
  121. }
  122. builder.append(string);
  123. auto built = builder.to_string();
  124. fspath = FileSystemPath(built);
  125. url = m_url;
  126. url.set_path(fspath.string());
  127. return url;
  128. }
  129. void Document::layout()
  130. {
  131. m_layout_root = create_layout_tree(style_resolver(), nullptr);
  132. m_layout_root->layout();
  133. }
  134. void Document::invalidate_layout()
  135. {
  136. layout();
  137. if (on_invalidate_layout)
  138. on_invalidate_layout();
  139. }
  140. RefPtr<LayoutNode> Document::create_layout_node(const StyleResolver&, const StyleProperties*) const
  141. {
  142. return adopt(*new LayoutDocument(*this, StyleProperties::create()));
  143. }
  144. void Document::set_link_color(Color color)
  145. {
  146. m_link_color = color;
  147. }
  148. void Document::set_active_link_color(Color color)
  149. {
  150. m_active_link_color = color;
  151. }
  152. void Document::set_visited_link_color(Color color)
  153. {
  154. m_visited_link_color = color;
  155. }
  156. const LayoutDocument* Document::layout_node() const
  157. {
  158. return static_cast<const LayoutDocument*>(Node::layout_node());
  159. }