summaryrefslogtreecommitdiff
path: root/Libraries/LibHTML
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-10-19 11:49:46 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-10-19 11:49:46 +0200
commit5a3422599976f20801828f79d8bad7dcc8d84272 (patch)
tree84bbf5aaaf87fe187e64ffa900b2c11bf19a76a2 /Libraries/LibHTML
parent96f10c8de2a519db92e087fd660f27c1aaa5563f (diff)
downloadserenity-5a3422599976f20801828f79d8bad7dcc8d84272.zip
LibHTML: Implement basic tiled background image support
It's now possible to set a page background image via <body background>. Also, HtmlView now officially handles rendering the body element's background (color, image or both.) LayoutBox is responsible for all other background rendering. Note that it's not yet possible to use CSS background-image properties directly, since we can't parse them yet. :^)
Diffstat (limited to 'Libraries/LibHTML')
-rw-r--r--Libraries/LibHTML/CSS/PropertyID.h1
-rw-r--r--Libraries/LibHTML/CSS/StyleValue.cpp21
-rw-r--r--Libraries/LibHTML/CSS/StyleValue.h22
-rw-r--r--Libraries/LibHTML/DOM/Document.cpp21
-rw-r--r--Libraries/LibHTML/DOM/Document.h1
-rw-r--r--Libraries/LibHTML/DOM/HTMLBodyElement.cpp2
-rw-r--r--Libraries/LibHTML/HtmlView.cpp8
-rw-r--r--Libraries/LibHTML/Layout/LayoutBox.cpp22
-rw-r--r--Libraries/LibHTML/Layout/LayoutBox.h2
9 files changed, 97 insertions, 3 deletions
diff --git a/Libraries/LibHTML/CSS/PropertyID.h b/Libraries/LibHTML/CSS/PropertyID.h
index 6e2be9e091..3702da99b6 100644
--- a/Libraries/LibHTML/CSS/PropertyID.h
+++ b/Libraries/LibHTML/CSS/PropertyID.h
@@ -7,6 +7,7 @@ enum class PropertyID {
Invalid,
BackgroundColor,
+ BackgroundImage,
BorderBottomColor,
BorderBottomStyle,
BorderBottomWidth,
diff --git a/Libraries/LibHTML/CSS/StyleValue.cpp b/Libraries/LibHTML/CSS/StyleValue.cpp
index 77ee2f9c58..6fa6d17fa4 100644
--- a/Libraries/LibHTML/CSS/StyleValue.cpp
+++ b/Libraries/LibHTML/CSS/StyleValue.cpp
@@ -1,5 +1,9 @@
+#include <LibDraw/GraphicsBitmap.h>
+#include <LibDraw/PNGLoader.h>
#include <LibHTML/CSS/StyleValue.h>
#include <LibHTML/DOM/Document.h>
+#include <LibHTML/Frame.h>
+#include <LibHTML/ResourceLoader.h>
StyleValue::StyleValue(Type type)
: m_type(type)
@@ -28,3 +32,20 @@ Color IdentifierStyleValue::to_color(const Document& document) const
return document.link_color();
return {};
}
+
+ImageStyleValue::ImageStyleValue(const URL& url, Document& document)
+ : StyleValue(Type::Image)
+ , m_url(url)
+ , m_document(document.make_weak_ptr())
+{
+ NonnullRefPtr<ImageStyleValue> protector(*this);
+ ResourceLoader::the().load(url, [this, protector](auto& data) {
+ if (!m_document)
+ return;
+ m_bitmap = load_png_from_memory(data.data(), data.size());
+ if (!m_bitmap)
+ return;
+ // FIXME: Do less than a full repaint if possible?
+ m_document->frame()->set_needs_display({});
+ });
+}
diff --git a/Libraries/LibHTML/CSS/StyleValue.h b/Libraries/LibHTML/CSS/StyleValue.h
index bd4e9b4000..53420123a3 100644
--- a/Libraries/LibHTML/CSS/StyleValue.h
+++ b/Libraries/LibHTML/CSS/StyleValue.h
@@ -4,7 +4,10 @@
#include <AK/RefPtr.h>
#include <AK/String.h>
#include <AK/StringView.h>
+#include <AK/URL.h>
+#include <AK/WeakPtr.h>
#include <LibDraw/Color.h>
+#include <LibDraw/GraphicsBitmap.h>
#include <LibHTML/CSS/Length.h>
#include <LibHTML/CSS/PropertyID.h>
@@ -32,6 +35,7 @@ public:
Length,
Color,
Identifier,
+ Image,
};
Type type() const { return m_type; }
@@ -40,6 +44,7 @@ public:
bool is_initial() const { return type() == Type::Initial; }
bool is_color() const { return type() == Type::Color; }
bool is_identifier() const { return type() == Type::Identifier; }
+ bool is_image() const { return type() == Type::Image; }
virtual String to_string() const = 0;
virtual Length to_length() const { return {}; }
@@ -171,3 +176,20 @@ private:
CSS::ValueID m_id { CSS::ValueID::Invalid };
};
+
+class ImageStyleValue final : public StyleValue {
+public:
+ static NonnullRefPtr<ImageStyleValue> create(const URL& url, Document& document) { return adopt(*new ImageStyleValue(url, document)); }
+ virtual ~ImageStyleValue() override {}
+
+ String to_string() const override { return String::format("Image{%s}", m_url.to_string().characters()); }
+
+ const GraphicsBitmap* bitmap() const { return m_bitmap; }
+
+private:
+ ImageStyleValue(const URL&, Document&);
+
+ URL m_url;
+ WeakPtr<Document> m_document;
+ RefPtr<GraphicsBitmap> m_bitmap;
+};
diff --git a/Libraries/LibHTML/DOM/Document.cpp b/Libraries/LibHTML/DOM/Document.cpp
index 9be8bc28a8..9a6c991160 100644
--- a/Libraries/LibHTML/DOM/Document.cpp
+++ b/Libraries/LibHTML/DOM/Document.cpp
@@ -119,6 +119,27 @@ Color Document::background_color() const
return background_color.value()->to_color(*this);
}
+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();
+}
+
URL Document::complete_url(const String& string) const
{
URL url(string);
diff --git a/Libraries/LibHTML/DOM/Document.h b/Libraries/LibHTML/DOM/Document.h
index 032522b694..94fb6ff49d 100644
--- a/Libraries/LibHTML/DOM/Document.h
+++ b/Libraries/LibHTML/DOM/Document.h
@@ -56,6 +56,7 @@ public:
const Frame* frame() const { return m_frame.ptr(); }
Color background_color() const;
+ RefPtr<GraphicsBitmap> background_image() const;
Color link_color() const { return m_link_color; }
void set_link_color(Color);
diff --git a/Libraries/LibHTML/DOM/HTMLBodyElement.cpp b/Libraries/LibHTML/DOM/HTMLBodyElement.cpp
index 724bf31459..03c25c7757 100644
--- a/Libraries/LibHTML/DOM/HTMLBodyElement.cpp
+++ b/Libraries/LibHTML/DOM/HTMLBodyElement.cpp
@@ -23,6 +23,8 @@ void HTMLBodyElement::apply_presentational_hints(StyleProperties& style) const
auto color = Color::from_string(value);
if (color.has_value())
style.set_property(CSS::PropertyID::Color, ColorStyleValue::create(color.value()));
+ } else if (name == "background") {
+ style.set_property(CSS::PropertyID::BackgroundImage, ImageStyleValue::create(document().complete_url(value), const_cast<Document&>(document())));
}
});
}
diff --git a/Libraries/LibHTML/HtmlView.cpp b/Libraries/LibHTML/HtmlView.cpp
index ef99039562..311223dc6b 100644
--- a/Libraries/LibHTML/HtmlView.cpp
+++ b/Libraries/LibHTML/HtmlView.cpp
@@ -25,6 +25,10 @@ HtmlView::HtmlView(GWidget* parent)
, m_main_frame(Frame::create())
{
main_frame().on_set_needs_display = [this](auto& content_rect) {
+ if (content_rect.is_empty()) {
+ update();
+ return;
+ }
Rect adjusted_rect = content_rect;
adjusted_rect.set_location(to_widget_position(content_rect.location()));
update(adjusted_rect);
@@ -118,6 +122,10 @@ void HtmlView::paint_event(GPaintEvent& event)
painter.fill_rect(event.rect(), m_document->background_color());
+ if (auto background_bitmap = m_document->background_image()) {
+ painter.draw_tiled_bitmap(event.rect(), *background_bitmap);
+ }
+
painter.translate(frame_thickness(), frame_thickness());
painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
diff --git a/Libraries/LibHTML/Layout/LayoutBox.cpp b/Libraries/LibHTML/Layout/LayoutBox.cpp
index 39d7c494e8..44ab81fe03 100644
--- a/Libraries/LibHTML/Layout/LayoutBox.cpp
+++ b/Libraries/LibHTML/Layout/LayoutBox.cpp
@@ -1,5 +1,6 @@
#include <LibGUI/GPainter.h>
#include <LibHTML/DOM/Document.h>
+#include <LibHTML/DOM/HTMLBodyElement.h>
#include <LibHTML/Frame.h>
#include <LibHTML/Layout/LayoutBlock.h>
#include <LibHTML/Layout/LayoutBox.h>
@@ -26,9 +27,19 @@ void LayoutBox::render(RenderingContext& context)
padded_rect.set_y(y() - box_model().padding().top.to_px());
padded_rect.set_height(height() + box_model().padding().top.to_px() + box_model().padding().bottom.to_px());
- auto bgcolor = style().property(CSS::PropertyID::BackgroundColor);
- if (bgcolor.has_value() && bgcolor.value()->is_color()) {
- context.painter().fill_rect(padded_rect, bgcolor.value()->to_color(document()));
+ if (!is_body()) {
+ auto bgcolor = style().property(CSS::PropertyID::BackgroundColor);
+ if (bgcolor.has_value() && bgcolor.value()->is_color()) {
+ context.painter().fill_rect(padded_rect, bgcolor.value()->to_color(document()));
+ }
+
+ auto bgimage = style().property(CSS::PropertyID::BackgroundImage);
+ if (bgimage.has_value() && bgimage.value()->is_image()) {
+ auto& image_value = static_cast<const ImageStyleValue&>(*bgimage.value());
+ if (image_value.bitmap()) {
+ context.painter().draw_tiled_bitmap(padded_rect, *image_value.bitmap());
+ }
+ }
}
// FIXME: Respect all individual border sides
@@ -93,3 +104,8 @@ void LayoutBox::set_needs_display()
LayoutNode::set_needs_display();
}
+
+bool LayoutBox::is_body() const
+{
+ return node() && node() == document().body();
+}
diff --git a/Libraries/LibHTML/Layout/LayoutBox.h b/Libraries/LibHTML/Layout/LayoutBox.h
index f66be67571..3fa0c294bf 100644
--- a/Libraries/LibHTML/Layout/LayoutBox.h
+++ b/Libraries/LibHTML/Layout/LayoutBox.h
@@ -18,6 +18,8 @@ public:
virtual HitTestResult hit_test(const Point& position) const override;
virtual void set_needs_display() override;
+ bool is_body() const;
+
protected:
LayoutBox(const Node* node, NonnullRefPtr<StyleProperties> style)
: LayoutNodeWithStyleAndBoxModelMetrics(node, move(style))