From 5a3422599976f20801828f79d8bad7dcc8d84272 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 19 Oct 2019 11:49:46 +0200 Subject: [PATCH] LibHTML: Implement basic tiled background image support It's now possible to set a page background image via . 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. :^) --- Base/home/anon/www/90s-bg.png | Bin 0 -> 13139 bytes Base/home/anon/www/welcome.html | 8 ++++---- Libraries/LibHTML/CSS/PropertyID.h | 1 + Libraries/LibHTML/CSS/StyleValue.cpp | 21 +++++++++++++++++++++ Libraries/LibHTML/CSS/StyleValue.h | 22 ++++++++++++++++++++++ Libraries/LibHTML/DOM/Document.cpp | 21 +++++++++++++++++++++ Libraries/LibHTML/DOM/Document.h | 1 + Libraries/LibHTML/DOM/HTMLBodyElement.cpp | 2 ++ Libraries/LibHTML/HtmlView.cpp | 8 ++++++++ Libraries/LibHTML/Layout/LayoutBox.cpp | 22 +++++++++++++++++++--- Libraries/LibHTML/Layout/LayoutBox.h | 2 ++ 11 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 Base/home/anon/www/90s-bg.png diff --git a/Base/home/anon/www/90s-bg.png b/Base/home/anon/www/90s-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b7a0b97cd07934a2b576550fcd83f740b30b68c0 GIT binary patch literal 13139 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 /* css comment */ body { - background-color: #fff; - color: #000; /* another css comment */ + background-color: #000; + color: #fff; /* another css comment */ } /* lol a css comment */ h1 { - color: #800; + color: #a00; } - +

Welcome to the Serenity Browser!

This is a very simple browser built on the LibHTML engine.

Some small test pages:

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 +#include #include #include +#include +#include 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 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 #include #include +#include +#include #include +#include #include #include @@ -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 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 m_document; + RefPtr 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 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(*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 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()))); } }); } 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 #include +#include #include #include #include @@ -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(*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 style) : LayoutNodeWithStyleAndBoxModelMetrics(node, move(style))