diff --git a/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.cpp
index 8932aeb93c5..675e068df71 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.cpp
@@ -17,4 +17,12 @@ HTMLHtmlElement::~HTMLHtmlElement()
{
}
+bool HTMLHtmlElement::should_use_body_background_properties() const
+{
+ auto background_color = layout_node()->computed_values().background_color();
+ const auto* background_image = layout_node()->background_image();
+
+ return (background_color == Color::Transparent) && !background_image;
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.h b/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.h
index 2f97417a042..3e689b5a5b3 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLHtmlElement.h
@@ -16,6 +16,8 @@ public:
HTMLHtmlElement(DOM::Document&, QualifiedName);
virtual ~HTMLHtmlElement() override;
+
+ bool should_use_body_background_properties() const;
};
}
diff --git a/Userland/Libraries/LibWeb/Layout/Box.cpp b/Userland/Libraries/LibWeb/Layout/Box.cpp
index d3cd09e1fc7..23b98e36046 100644
--- a/Userland/Libraries/LibWeb/Layout/Box.cpp
+++ b/Userland/Libraries/LibWeb/Layout/Box.cpp
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -25,13 +26,37 @@ void Box::paint(PaintContext& context, PaintPhase phase)
auto padded_rect = this->padded_rect();
- if (phase == PaintPhase::Background && !is_body()) {
- auto background_rect = enclosing_int_rect(padded_rect);
- context.painter().fill_rect(background_rect, computed_values().background_color());
+ if (phase == PaintPhase::Background) {
+ // If the body's background properties were propagated to the root element, do no re-paint the body's background.
+ if (is_body() && document().html_element()->should_use_body_background_properties())
+ return;
- if (background_image() && background_image()->bitmap()) {
- paint_background_image(context, *background_image()->bitmap(), computed_values().background_repeat_x(), computed_values().background_repeat_y(), move(background_rect));
+ Gfx::IntRect background_rect;
+
+ Color background_color = computed_values().background_color();
+ const Gfx::Bitmap* background_image = this->background_image() ? this->background_image()->bitmap() : nullptr;
+ CSS::Repeat background_repeat_x = computed_values().background_repeat_x();
+ CSS::Repeat background_repeat_y = computed_values().background_repeat_y();
+
+ if (is_root_element()) {
+ // CSS 2.1 Appendix E.2: If the element is a root element, paint the background over the entire canvas.
+ background_rect = context.viewport_rect();
+
+ // Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent,
+ // user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element.
+ if (document().html_element()->should_use_body_background_properties()) {
+ background_color = document().background_color(context.palette());
+ background_image = document().background_image();
+ background_repeat_x = document().background_repeat_x();
+ background_repeat_y = document().background_repeat_y();
+ }
+ } else {
+ background_rect = enclosing_int_rect(padded_rect);
}
+
+ context.painter().fill_rect(background_rect, move(background_color));
+ if (background_image)
+ paint_background_image(context, *background_image, background_repeat_x, background_repeat_y, move(background_rect));
}
if (phase == PaintPhase::Border) {
diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp
index 0b71a20cfa9..3cd7f29a33e 100644
--- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp
+++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.cpp
@@ -42,20 +42,9 @@ void InitialContainingBlockBox::build_stacking_context_tree()
});
}
-void InitialContainingBlockBox::paint_document_background(PaintContext& context)
-{
- context.painter().fill_rect(Gfx::IntRect { {}, context.viewport_rect().size() }, document().background_color(context.palette()));
- context.painter().translate(-context.viewport_rect().location());
-
- if (auto background_bitmap = document().background_image()) {
- Gfx::IntRect background_rect = { 0, 0, context.viewport_rect().x() + context.viewport_rect().width(), context.viewport_rect().y() + context.viewport_rect().height() };
- paint_background_image(context, *background_bitmap, document().background_repeat_x(), document().background_repeat_y(), move(background_rect));
- }
-}
-
void InitialContainingBlockBox::paint_all_phases(PaintContext& context)
{
- paint_document_background(context);
+ context.painter().translate(-context.viewport_rect().location());
stacking_context()->paint(context);
}
diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h
index 1466b4bbc0c..e32d283da4a 100644
--- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h
+++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlockBox.h
@@ -20,8 +20,6 @@ public:
void paint_all_phases(PaintContext&);
- void paint_document_background(PaintContext&);
-
virtual HitTestResult hit_test(const Gfx::IntPoint&, HitTestType) const override;
const LayoutRange& selection() const { return m_selection; }