ladybird/Libraries/LibHTML/DOM/Document.cpp
Conrad Pankoff ef8b754a46 LibHTML: Add function for invalidating the document layout
This allows any external actor to signal that the document layout may be
stale. This can be used when loading resources, changing the size or
placement of an element, adding/removing nodes, or really any time.
2019-10-06 14:33:00 +02:00

153 lines
3.7 KiB
C++

#include <AK/FileSystemPath.h>
#include <AK/StringBuilder.h>
#include <LibHTML/CSS/StyleResolver.h>
#include <LibHTML/DOM/Document.h>
#include <LibHTML/DOM/Element.h>
#include <LibHTML/DOM/HTMLBodyElement.h>
#include <LibHTML/DOM/HTMLHeadElement.h>
#include <LibHTML/DOM/HTMLHtmlElement.h>
#include <LibHTML/DOM/HTMLTitleElement.h>
#include <LibHTML/Frame.h>
#include <LibHTML/Layout/LayoutDocument.h>
#include <stdio.h>
Document::Document()
: ParentNode(*this, NodeType::DOCUMENT_NODE)
{
}
Document::~Document()
{
}
StyleResolver& Document::style_resolver()
{
if (!m_style_resolver)
m_style_resolver = make<StyleResolver>(*this);
return *m_style_resolver;
}
void Document::normalize()
{
if (first_child() != nullptr && first_child()->is_element()) {
const Element& el = static_cast<const Element&>(*first_child());
if (el.tag_name() == "html")
return;
}
NonnullRefPtr<Element> body = adopt(*new Element(*this, "body"));
NonnullRefPtr<Element> html = adopt(*new Element(*this, "html"));
html->append_child(body);
this->donate_all_children_to(body);
this->append_child(html);
}
const HTMLHtmlElement* Document::document_element() const
{
return static_cast<const HTMLHtmlElement*>(first_child_with_tag_name("html"));
}
const HTMLHeadElement* Document::head() const
{
auto* html = document_element();
if (!html)
return nullptr;
return static_cast<const HTMLHeadElement*>(html->first_child_with_tag_name("head"));
}
const HTMLBodyElement* Document::body() const
{
auto* html = document_element();
if (!html)
return nullptr;
return static_cast<const HTMLBodyElement*>(html->first_child_with_tag_name("body"));
}
String Document::title() const
{
auto* head_element = head();
if (!head_element)
return {};
auto* title_element = static_cast<const HTMLTitleElement*>(head_element->first_child_with_tag_name("title"));
if (!title_element)
return {};
return title_element->text_content();
}
void Document::attach_to_frame(Badge<Frame>, Frame& frame)
{
m_frame = frame.make_weak_ptr();
}
void Document::detach_from_frame(Badge<Frame>, Frame&)
{
}
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;
auto background_color = body_layout_node->style().property("background-color");
if (!background_color.has_value() || !background_color.value()->is_color())
return Color::White;
return background_color.value()->to_color(*this);
}
URL Document::complete_url(const String& string) const
{
URL url(string);
if (url.is_valid())
return url;
FileSystemPath fspath(m_url.path());
StringBuilder builder;
builder.append('/');
for (int i = 0; i < fspath.parts().size(); ++i) {
if (i == fspath.parts().size() - 1)
break;
builder.append(fspath.parts()[i]);
builder.append('/');
}
builder.append(string);
auto built = builder.to_string();
fspath = FileSystemPath(built);
url = m_url;
url.set_path(fspath.string());
return url;
}
void Document::invalidate_layout()
{
if (on_invalidate_layout)
on_invalidate_layout();
}
RefPtr<LayoutNode> Document::create_layout_node(const StyleResolver&, const StyleProperties*) const
{
return adopt(*new LayoutDocument(*this, StyleProperties::create()));
}
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;
}