summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-03-10 23:13:37 +0100
committerAndreas Kling <kling@serenityos.org>2022-03-11 00:21:49 +0100
commitba606d90570f2a57cc094c19cf4fd35a43e22102 (patch)
treee8f657406e15c0ca46f956309ad1e6a75fcc2019 /Userland/Libraries/LibWeb
parentf017c1c064e30399a569dde21051b377ab91528d (diff)
downloadserenity-ba606d90570f2a57cc094c19cf4fd35a43e22102.zip
LibWeb: Move PaintingBox to its own .cpp and .h files
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibWeb/DOM/Element.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Dump.cpp2
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLElement.cpp2
-rw-r--r--Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp2
-rw-r--r--Userland/Libraries/LibWeb/InProcessWebView.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Layout/BlockContainer.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Layout/Box.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Layout/FormattingState.h2
-rw-r--r--Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Page/EventHandler.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Painting/CanvasPaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/ImagePaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/InlinePaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/LabelablePaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/MarkerPaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/Paintable.cpp297
-rw-r--r--Userland/Libraries/LibWeb/Painting/Paintable.h153
-rw-r--r--Userland/Libraries/LibWeb/Painting/PaintableBox.cpp310
-rw-r--r--Userland/Libraries/LibWeb/Painting/PaintableBox.h166
-rw-r--r--Userland/Libraries/LibWeb/Painting/ProgressPaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/SVGPaintable.h2
-rw-r--r--Userland/Libraries/LibWeb/Painting/StackingContext.cpp2
-rw-r--r--Userland/Libraries/LibWeb/Painting/TextPaintable.h2
25 files changed, 497 insertions, 470 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt
index 1635d1e59b..3b31f94a9e 100644
--- a/Userland/Libraries/LibWeb/CMakeLists.txt
+++ b/Userland/Libraries/LibWeb/CMakeLists.txt
@@ -295,6 +295,7 @@ set(SOURCES
Painting/NestedBrowsingContextPaintable.cpp
Painting/PaintContext.cpp
Painting/Paintable.cpp
+ Painting/PaintableBox.cpp
Painting/ProgressPaintable.cpp
Painting/RadioButtonPaintable.cpp
Painting/SVGGeometryPaintable.cpp
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index 1aa7495ade..cd8e49d433 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -35,7 +35,7 @@
#include <LibWeb/Layout/TableRowGroupBox.h>
#include <LibWeb/Layout/TreeBuilder.h>
#include <LibWeb/Namespace.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::DOM {
diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp
index 467df34caf..7d83a52691 100644
--- a/Userland/Libraries/LibWeb/Dump.cpp
+++ b/Userland/Libraries/LibWeb/Dump.cpp
@@ -26,7 +26,7 @@
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Layout/SVGBox.h>
#include <LibWeb/Layout/TextNode.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <stdio.h>
namespace Web {
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
index cc88e2d38d..23c3f7fe9a 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
@@ -22,7 +22,7 @@
#include <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/BreakNode.h>
#include <LibWeb/Layout/TextNode.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/UIEvents/EventNames.h>
#include <LibWeb/UIEvents/FocusEvent.h>
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
index bc45f8a9fc..79de7a9e13 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
@@ -13,7 +13,7 @@
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/Layout/ImageBox.h>
#include <LibWeb/Loader/ResourceLoader.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::HTML {
diff --git a/Userland/Libraries/LibWeb/InProcessWebView.cpp b/Userland/Libraries/LibWeb/InProcessWebView.cpp
index 8d33870f8a..2ab239bdea 100644
--- a/Userland/Libraries/LibWeb/InProcessWebView.cpp
+++ b/Userland/Libraries/LibWeb/InProcessWebView.cpp
@@ -22,7 +22,7 @@
#include <LibWeb/Loader/ResourceLoader.h>
#include <LibWeb/Page/EventHandler.h>
#include <LibWeb/Painting/PaintContext.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/UIEvents/MouseEvent.h>
REGISTER_WIDGET(Web, InProcessWebView)
diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp
index bdb925185a..4871d6e477 100644
--- a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp
+++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp
@@ -11,7 +11,7 @@
#include <LibWeb/Layout/InlineFormattingContext.h>
#include <LibWeb/Layout/ReplacedBox.h>
#include <LibWeb/Layout/TextNode.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Layout {
diff --git a/Userland/Libraries/LibWeb/Layout/Box.cpp b/Userland/Libraries/LibWeb/Layout/Box.cpp
index a5ab762a43..5ee1e745e0 100644
--- a/Userland/Libraries/LibWeb/Layout/Box.cpp
+++ b/Userland/Libraries/LibWeb/Layout/Box.cpp
@@ -15,7 +15,7 @@
#include <LibWeb/Layout/FormattingContext.h>
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/BorderPainting.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Painting/ShadowPainting.h>
namespace Web::Layout {
diff --git a/Userland/Libraries/LibWeb/Layout/FormattingState.h b/Userland/Libraries/LibWeb/Layout/FormattingState.h
index 9779c90215..5e55509b71 100644
--- a/Userland/Libraries/LibWeb/Layout/FormattingState.h
+++ b/Userland/Libraries/LibWeb/Layout/FormattingState.h
@@ -10,7 +10,7 @@
#include <LibGfx/Point.h>
#include <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/LineBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Layout {
diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp b/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp
index 9e905a8d63..5a4adb37a4 100644
--- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp
+++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.cpp
@@ -8,7 +8,7 @@
#include <LibWeb/Dump.h>
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/Layout/InitialContainingBlock.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Painting/StackingContext.h>
namespace Web::Layout {
diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp
index b6ab1dba89..e14a1c30f0 100644
--- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp
+++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp
@@ -16,7 +16,7 @@
#include <LibWeb/Layout/InitialContainingBlock.h>
#include <LibWeb/Page/EventHandler.h>
#include <LibWeb/Page/Page.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/UIEvents/EventNames.h>
#include <LibWeb/UIEvents/KeyboardEvent.h>
#include <LibWeb/UIEvents/MouseEvent.h>
diff --git a/Userland/Libraries/LibWeb/Painting/CanvasPaintable.h b/Userland/Libraries/LibWeb/Painting/CanvasPaintable.h
index 67df38c5de..8b369b16f5 100644
--- a/Userland/Libraries/LibWeb/Painting/CanvasPaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/CanvasPaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/CanvasBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/ImagePaintable.h b/Userland/Libraries/LibWeb/Painting/ImagePaintable.h
index 693d5f8bff..377a4e377c 100644
--- a/Userland/Libraries/LibWeb/Painting/ImagePaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/ImagePaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/ImageBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h
index f4ea54c30e..5d5750fa5a 100644
--- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/InlineNode.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/LabelablePaintable.h b/Userland/Libraries/LibWeb/Painting/LabelablePaintable.h
index 33538cad54..8047e36da6 100644
--- a/Userland/Libraries/LibWeb/Painting/LabelablePaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/LabelablePaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/LabelableNode.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/MarkerPaintable.h b/Userland/Libraries/LibWeb/Painting/MarkerPaintable.h
index 011366d0ec..77e8edee1d 100644
--- a/Userland/Libraries/LibWeb/Painting/MarkerPaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/MarkerPaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/ListItemMarkerBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.h b/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.h
index 32fd33525d..559f0ff15c 100644
--- a/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/NestedBrowsingContextPaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/FrameBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/Paintable.cpp b/Userland/Libraries/LibWeb/Painting/Paintable.cpp
index 8747e80a16..88b384dcdc 100644
--- a/Userland/Libraries/LibWeb/Painting/Paintable.cpp
+++ b/Userland/Libraries/LibWeb/Painting/Paintable.cpp
@@ -5,288 +5,11 @@
*/
#include <LibWeb/DOM/Document.h>
-#include <LibWeb/HTML/HTMLHtmlElement.h>
#include <LibWeb/Layout/BlockContainer.h>
-#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/Paintable.h>
-#include <LibWeb/Painting/ShadowPainting.h>
namespace Web::Painting {
-NonnullRefPtr<PaintableBox> PaintableBox::create(Layout::Box const& layout_box)
-{
- return adopt_ref(*new PaintableBox(layout_box));
-}
-
-PaintableBox::PaintableBox(Layout::Box const& layout_box)
- : Paintable(layout_box)
-{
-}
-
-PaintableBox::~PaintableBox()
-{
-}
-
-PaintableWithLines::PaintableWithLines(Layout::BlockContainer const& layout_box)
- : PaintableBox(layout_box)
-{
-}
-
-PaintableWithLines::~PaintableWithLines()
-{
-}
-
-void PaintableBox::set_offset(const Gfx::FloatPoint& offset)
-{
- if (m_offset == offset)
- return;
- m_offset = offset;
- // FIXME: This const_cast is gross.
- const_cast<Layout::Box&>(layout_box()).did_set_rect();
-}
-
-void PaintableBox::set_content_size(Gfx::FloatSize const& size)
-{
- if (m_content_size == size)
- return;
- m_content_size = size;
- // FIXME: This const_cast is gross.
- const_cast<Layout::Box&>(layout_box()).did_set_rect();
-}
-
-Gfx::FloatPoint PaintableBox::effective_offset() const
-{
- if (m_containing_line_box_fragment.has_value()) {
- auto const& fragment = layout_box().containing_block()->paint_box()->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index];
- return fragment.offset();
- }
- return m_offset;
-}
-
-Gfx::FloatRect PaintableBox::absolute_rect() const
-{
- Gfx::FloatRect rect { effective_offset(), content_size() };
- for (auto* block = layout_box().containing_block(); block; block = block->containing_block())
- rect.translate_by(block->paint_box()->effective_offset());
- return rect;
-}
-
-void PaintableBox::set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate> fragment_coordinate)
-{
- m_containing_line_box_fragment = fragment_coordinate;
-}
-
-Painting::StackingContext* PaintableBox::enclosing_stacking_context()
-{
- for (auto* ancestor = layout_box().parent(); ancestor; ancestor = ancestor->parent()) {
- if (!is<Layout::Box>(ancestor))
- continue;
- auto& ancestor_box = static_cast<Layout::Box&>(const_cast<Layout::NodeWithStyle&>(*ancestor));
- if (!ancestor_box.establishes_stacking_context())
- continue;
- VERIFY(ancestor_box.paint_box()->stacking_context());
- return const_cast<StackingContext*>(ancestor_box.paint_box()->stacking_context());
- }
- // We should always reach the Layout::InitialContainingBlock stacking context.
- VERIFY_NOT_REACHED();
-}
-
-void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
-{
- if (!is_visible())
- return;
-
- if (phase == PaintPhase::Background) {
- paint_background(context);
- paint_box_shadow(context);
- }
-
- if (phase == PaintPhase::Border) {
- paint_border(context);
- }
-
- if (phase == PaintPhase::Overlay && layout_box().dom_node() && layout_box().document().inspected_node() == layout_box().dom_node()) {
- auto content_rect = absolute_rect();
-
- auto margin_box = box_model().margin_box();
- Gfx::FloatRect margin_rect;
- margin_rect.set_x(absolute_x() - margin_box.left);
- margin_rect.set_width(content_width() + margin_box.left + margin_box.right);
- margin_rect.set_y(absolute_y() - margin_box.top);
- margin_rect.set_height(content_height() + margin_box.top + margin_box.bottom);
-
- auto border_rect = absolute_border_box_rect();
- auto padding_rect = absolute_padding_box_rect();
-
- auto paint_inspector_rect = [&](Gfx::FloatRect const& rect, Color color) {
- context.painter().fill_rect(enclosing_int_rect(rect), Color(color).with_alpha(100));
- context.painter().draw_rect(enclosing_int_rect(rect), Color(color));
- };
-
- paint_inspector_rect(margin_rect, Color::Yellow);
- paint_inspector_rect(padding_rect, Color::Cyan);
- paint_inspector_rect(border_rect, Color::Green);
- paint_inspector_rect(content_rect, Color::Magenta);
-
- StringBuilder builder;
- if (layout_box().dom_node())
- builder.append(layout_box().dom_node()->debug_description());
- else
- builder.append(layout_box().debug_description());
- builder.appendff(" {}x{} @ {},{}", border_rect.width(), border_rect.height(), border_rect.x(), border_rect.y());
- auto size_text = builder.to_string();
- auto size_text_rect = border_rect;
- size_text_rect.set_y(border_rect.y() + border_rect.height());
- size_text_rect.set_top(size_text_rect.top());
- size_text_rect.set_width((float)context.painter().font().width(size_text) + 4);
- size_text_rect.set_height(context.painter().font().glyph_height() + 4);
- context.painter().fill_rect(enclosing_int_rect(size_text_rect), context.palette().color(Gfx::ColorRole::Tooltip));
- context.painter().draw_rect(enclosing_int_rect(size_text_rect), context.palette().threed_shadow1());
- context.painter().draw_text(enclosing_int_rect(size_text_rect), size_text, Gfx::TextAlignment::Center, context.palette().color(Gfx::ColorRole::TooltipText));
- }
-
- if (phase == PaintPhase::FocusOutline && layout_box().dom_node() && layout_box().dom_node()->is_element() && verify_cast<DOM::Element>(*layout_box().dom_node()).is_focused()) {
- context.painter().draw_rect(enclosing_int_rect(absolute_rect()), context.palette().focus_outline());
- }
-}
-
-void PaintableBox::paint_border(PaintContext& context) const
-{
- auto borders_data = BordersData {
- .top = computed_values().border_top(),
- .right = computed_values().border_right(),
- .bottom = computed_values().border_bottom(),
- .left = computed_values().border_left(),
- };
- paint_all_borders(context, absolute_border_box_rect(), normalized_border_radius_data(), borders_data);
-}
-
-void PaintableBox::paint_background(PaintContext& context) const
-{
- // If the body's background properties were propagated to the root element, do no re-paint the body's background.
- if (layout_box().is_body() && document().html_element()->should_use_body_background_properties())
- return;
-
- Gfx::IntRect background_rect;
- Color background_color = computed_values().background_color();
- auto* background_layers = &computed_values().background_layers();
-
- if (layout_box().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_layers = document().background_layers();
- background_color = document().background_color(context.palette());
- }
- } else {
- background_rect = enclosing_int_rect(absolute_padding_box_rect());
- }
-
- // HACK: If the Box has a border, use the bordered_rect to paint the background.
- // This way if we have a border-radius there will be no gap between the filling and actual border.
- if (computed_values().border_top().width || computed_values().border_right().width || computed_values().border_bottom().width || computed_values().border_left().width)
- background_rect = enclosing_int_rect(absolute_border_box_rect());
-
- Painting::paint_background(context, layout_box(), background_rect, background_color, background_layers, normalized_border_radius_data());
-}
-
-void PaintableBox::paint_box_shadow(PaintContext& context) const
-{
- auto box_shadow_data = computed_values().box_shadow();
- if (box_shadow_data.is_empty())
- return;
-
- Vector<BoxShadowData> resolved_box_shadow_data;
- resolved_box_shadow_data.ensure_capacity(box_shadow_data.size());
- for (auto const& layer : box_shadow_data) {
- resolved_box_shadow_data.empend(
- layer.color,
- static_cast<int>(layer.offset_x.to_px(layout_box())),
- static_cast<int>(layer.offset_y.to_px(layout_box())),
- static_cast<int>(layer.blur_radius.to_px(layout_box())),
- static_cast<int>(layer.spread_distance.to_px(layout_box())),
- layer.placement == CSS::BoxShadowPlacement::Outer ? BoxShadowPlacement::Outer : BoxShadowPlacement::Inner);
- }
- Painting::paint_box_shadow(context, enclosing_int_rect(absolute_border_box_rect()), resolved_box_shadow_data);
-}
-
-BorderRadiusData PaintableBox::normalized_border_radius_data() const
-{
- return Painting::normalized_border_radius_data(layout_box(), absolute_border_box_rect(),
- computed_values().border_top_left_radius(),
- computed_values().border_top_right_radius(),
- computed_values().border_bottom_right_radius(),
- computed_values().border_bottom_left_radius());
-}
-
-void PaintableBox::before_children_paint(PaintContext& context, PaintPhase) const
-{
- // FIXME: Support more overflow variations.
- if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden) {
- context.painter().save();
- context.painter().add_clip_rect(enclosing_int_rect(absolute_border_box_rect()));
- }
-}
-
-void PaintableBox::after_children_paint(PaintContext& context, PaintPhase) const
-{
- // FIXME: Support more overflow variations.
- if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden)
- context.painter().restore();
-}
-
-void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
-{
- if (!is_visible())
- return;
-
- PaintableBox::paint(context, phase);
-
- if (m_line_boxes.is_empty())
- return;
-
- bool should_clip_overflow = computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible;
-
- if (should_clip_overflow) {
- context.painter().save();
- // FIXME: Handle overflow-x and overflow-y being different values.
- context.painter().add_clip_rect(enclosing_int_rect(absolute_padding_box_rect()));
- auto scroll_offset = static_cast<Layout::BlockContainer const&>(layout_box()).scroll_offset();
- context.painter().translate(-scroll_offset.to_type<int>());
- }
-
- for (auto& line_box : m_line_boxes) {
- for (auto& fragment : line_box.fragments()) {
- if (context.should_show_line_box_borders())
- context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Green);
- const_cast<Layout::LineBoxFragment&>(fragment).paint(context, phase);
- }
- }
-
- if (should_clip_overflow) {
- context.painter().restore();
- }
-
- // FIXME: Merge this loop with the above somehow..
- if (phase == PaintPhase::FocusOutline) {
- for (auto& line_box : m_line_boxes) {
- for (auto& fragment : line_box.fragments()) {
- auto* node = fragment.layout_node().dom_node();
- if (!node)
- continue;
- auto* parent = node->parent_element();
- if (!parent)
- continue;
- if (parent->is_focused())
- context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), context.palette().focus_outline());
- }
- }
- }
-}
-
void Paintable::handle_mousedown(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned)
{
}
@@ -315,24 +38,4 @@ bool Paintable::handle_mousewheel(Badge<EventHandler>, Gfx::IntPoint const&, uns
return false;
}
-bool PaintableWithLines::handle_mousewheel(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y)
-{
- if (!layout_box().is_scrollable())
- return false;
- auto new_offset = layout_box().scroll_offset();
- new_offset.translate_by(wheel_delta_x, wheel_delta_y);
- const_cast<Layout::BlockContainer&>(layout_box()).set_scroll_offset(new_offset);
- return true;
-}
-
-Layout::BlockContainer const& PaintableWithLines::layout_box() const
-{
- return static_cast<Layout::BlockContainer const&>(PaintableBox::layout_box());
-}
-
-Layout::BlockContainer& PaintableWithLines::layout_box()
-{
- return static_cast<Layout::BlockContainer&>(PaintableBox::layout_box());
-}
-
}
diff --git a/Userland/Libraries/LibWeb/Painting/Paintable.h b/Userland/Libraries/LibWeb/Painting/Paintable.h
index 364dd9fc7f..ecb9a66759 100644
--- a/Userland/Libraries/LibWeb/Painting/Paintable.h
+++ b/Userland/Libraries/LibWeb/Painting/Paintable.h
@@ -51,157 +51,4 @@ private:
Layout::Node const& m_layout_node;
};
-class PaintableBox : public Paintable {
-public:
- static NonnullRefPtr<PaintableBox> create(Layout::Box const&);
- virtual ~PaintableBox();
-
- virtual void paint(PaintContext&, PaintPhase) const override;
-
- bool is_visible() const { return layout_box().is_visible(); }
-
- Layout::Box& layout_box() { return static_cast<Layout::Box&>(Paintable::layout_node()); }
- Layout::Box const& layout_box() const { return static_cast<Layout::Box const&>(Paintable::layout_node()); }
-
- auto const& box_model() const { return layout_box().box_model(); }
-
- struct OverflowData {
- Gfx::FloatRect scrollable_overflow_rect;
- Gfx::FloatPoint scroll_offset;
- };
- Optional<OverflowData> m_overflow_data;
-
- Gfx::FloatPoint m_offset;
- Gfx::FloatSize m_content_size;
-
- // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc)
- Optional<Layout::LineBoxFragmentCoordinate> m_containing_line_box_fragment;
-
- Gfx::FloatRect absolute_rect() const;
- Gfx::FloatPoint effective_offset() const;
-
- void set_offset(Gfx::FloatPoint const&);
- void set_offset(float x, float y) { set_offset({ x, y }); }
-
- Gfx::FloatSize const& content_size() const { return m_content_size; }
- void set_content_size(Gfx::FloatSize const&);
- void set_content_size(float width, float height) { set_content_size({ width, height }); }
-
- void set_content_width(float width) { set_content_size(width, content_height()); }
- void set_content_height(float height) { set_content_size(content_width(), height); }
- float content_width() const { return m_content_size.width(); }
- float content_height() const { return m_content_size.height(); }
-
- Gfx::FloatRect absolute_padding_box_rect() const
- {
- auto absolute_rect = this->absolute_rect();
- Gfx::FloatRect rect;
- rect.set_x(absolute_rect.x() - box_model().padding.left);
- rect.set_width(content_width() + box_model().padding.left + box_model().padding.right);
- rect.set_y(absolute_rect.y() - box_model().padding.top);
- rect.set_height(content_height() + box_model().padding.top + box_model().padding.bottom);
- return rect;
- }
-
- Gfx::FloatRect absolute_border_box_rect() const
- {
- auto padded_rect = this->absolute_padding_box_rect();
- Gfx::FloatRect rect;
- rect.set_x(padded_rect.x() - box_model().border.left);
- rect.set_width(padded_rect.width() + box_model().border.left + box_model().border.right);
- rect.set_y(padded_rect.y() - box_model().border.top);
- rect.set_height(padded_rect.height() + box_model().border.top + box_model().border.bottom);
- return rect;
- }
-
- float border_box_width() const
- {
- auto border_box = box_model().border_box();
- return content_width() + border_box.left + border_box.right;
- }
-
- float border_box_height() const
- {
- auto border_box = box_model().border_box();
- return content_height() + border_box.top + border_box.bottom;
- }
-
- float absolute_x() const { return absolute_rect().x(); }
- float absolute_y() const { return absolute_rect().y(); }
- Gfx::FloatPoint absolute_position() const { return absolute_rect().location(); }
-
- bool has_overflow() const { return m_overflow_data.has_value(); }
-
- Optional<Gfx::FloatRect> scrollable_overflow_rect() const
- {
- if (!m_overflow_data.has_value())
- return {};
- return m_overflow_data->scrollable_overflow_rect;
- }
-
- void set_overflow_data(Optional<OverflowData> data) { m_overflow_data = move(data); }
- void set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate>);
-
- StackingContext* stacking_context() { return m_stacking_context; }
- StackingContext const* stacking_context() const { return m_stacking_context; }
- void set_stacking_context(NonnullOwnPtr<Painting::StackingContext> context) { m_stacking_context = move(context); }
- StackingContext* enclosing_stacking_context();
-
- DOM::Node const* dom_node() const { return layout_box().dom_node(); }
- DOM::Node* dom_node() { return layout_box().dom_node(); }
-
- DOM::Document const& document() const { return layout_box().document(); }
- DOM::Document& document() { return layout_box().document(); }
-
- virtual void before_children_paint(PaintContext&, PaintPhase) const override;
- virtual void after_children_paint(PaintContext&, PaintPhase) const override;
-
-protected:
- explicit PaintableBox(Layout::Box const&);
-
- virtual void paint_border(PaintContext&) const;
- virtual void paint_background(PaintContext&) const;
- virtual void paint_box_shadow(PaintContext&) const;
-
-private:
- Painting::BorderRadiusData normalized_border_radius_data() const;
-
- OwnPtr<Painting::StackingContext> m_stacking_context;
-};
-
-class PaintableWithLines : public PaintableBox {
-public:
- static NonnullRefPtr<PaintableWithLines> create(Layout::BlockContainer const& block_container)
- {
- return adopt_ref(*new PaintableWithLines(block_container));
- }
- virtual ~PaintableWithLines() override;
-
- Layout::BlockContainer const& layout_box() const;
- Layout::BlockContainer& layout_box();
-
- Vector<Layout::LineBox> const& line_boxes() const { return m_line_boxes; }
- void set_line_boxes(Vector<Layout::LineBox>&& line_boxes) { m_line_boxes = move(line_boxes); }
-
- template<typename Callback>
- void for_each_fragment(Callback callback) const
- {
- for (auto& line_box : line_boxes()) {
- for (auto& fragment : line_box.fragments()) {
- if (callback(fragment) == IterationDecision::Break)
- return;
- }
- }
- }
-
- virtual void paint(PaintContext&, PaintPhase) const override;
- virtual bool wants_mouse_events() const override { return false; }
- virtual bool handle_mousewheel(Badge<EventHandler>, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y) override;
-
-private:
- PaintableWithLines(Layout::BlockContainer const&);
-
- Vector<Layout::LineBox> m_line_boxes;
-};
-
}
diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
new file mode 100644
index 0000000000..3315a654cd
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/DOM/Document.h>
+#include <LibWeb/HTML/HTMLHtmlElement.h>
+#include <LibWeb/Layout/BlockContainer.h>
+#include <LibWeb/Painting/BackgroundPainting.h>
+#include <LibWeb/Painting/PaintableBox.h>
+#include <LibWeb/Painting/ShadowPainting.h>
+
+namespace Web::Painting {
+
+NonnullRefPtr<PaintableBox> PaintableBox::create(Layout::Box const& layout_box)
+{
+ return adopt_ref(*new PaintableBox(layout_box));
+}
+
+PaintableBox::PaintableBox(Layout::Box const& layout_box)
+ : Paintable(layout_box)
+{
+}
+
+PaintableBox::~PaintableBox()
+{
+}
+
+PaintableWithLines::PaintableWithLines(Layout::BlockContainer const& layout_box)
+ : PaintableBox(layout_box)
+{
+}
+
+PaintableWithLines::~PaintableWithLines()
+{
+}
+
+void PaintableBox::set_offset(const Gfx::FloatPoint& offset)
+{
+ if (m_offset == offset)
+ return;
+ m_offset = offset;
+ // FIXME: This const_cast is gross.
+ const_cast<Layout::Box&>(layout_box()).did_set_rect();
+}
+
+void PaintableBox::set_content_size(Gfx::FloatSize const& size)
+{
+ if (m_content_size == size)
+ return;
+ m_content_size = size;
+ // FIXME: This const_cast is gross.
+ const_cast<Layout::Box&>(layout_box()).did_set_rect();
+}
+
+Gfx::FloatPoint PaintableBox::effective_offset() const
+{
+ if (m_containing_line_box_fragment.has_value()) {
+ auto const& fragment = layout_box().containing_block()->paint_box()->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index];
+ return fragment.offset();
+ }
+ return m_offset;
+}
+
+Gfx::FloatRect PaintableBox::absolute_rect() const
+{
+ Gfx::FloatRect rect { effective_offset(), content_size() };
+ for (auto* block = layout_box().containing_block(); block; block = block->containing_block())
+ rect.translate_by(block->paint_box()->effective_offset());
+ return rect;
+}
+
+void PaintableBox::set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate> fragment_coordinate)
+{
+ m_containing_line_box_fragment = fragment_coordinate;
+}
+
+Painting::StackingContext* PaintableBox::enclosing_stacking_context()
+{
+ for (auto* ancestor = layout_box().parent(); ancestor; ancestor = ancestor->parent()) {
+ if (!is<Layout::Box>(ancestor))
+ continue;
+ auto& ancestor_box = static_cast<Layout::Box&>(const_cast<Layout::NodeWithStyle&>(*ancestor));
+ if (!ancestor_box.establishes_stacking_context())
+ continue;
+ VERIFY(ancestor_box.paint_box()->stacking_context());
+ return const_cast<StackingContext*>(ancestor_box.paint_box()->stacking_context());
+ }
+ // We should always reach the Layout::InitialContainingBlock stacking context.
+ VERIFY_NOT_REACHED();
+}
+
+void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
+{
+ if (!is_visible())
+ return;
+
+ if (phase == PaintPhase::Background) {
+ paint_background(context);
+ paint_box_shadow(context);
+ }
+
+ if (phase == PaintPhase::Border) {
+ paint_border(context);
+ }
+
+ if (phase == PaintPhase::Overlay && layout_box().dom_node() && layout_box().document().inspected_node() == layout_box().dom_node()) {
+ auto content_rect = absolute_rect();
+
+ auto margin_box = box_model().margin_box();
+ Gfx::FloatRect margin_rect;
+ margin_rect.set_x(absolute_x() - margin_box.left);
+ margin_rect.set_width(content_width() + margin_box.left + margin_box.right);
+ margin_rect.set_y(absolute_y() - margin_box.top);
+ margin_rect.set_height(content_height() + margin_box.top + margin_box.bottom);
+
+ auto border_rect = absolute_border_box_rect();
+ auto padding_rect = absolute_padding_box_rect();
+
+ auto paint_inspector_rect = [&](Gfx::FloatRect const& rect, Color color) {
+ context.painter().fill_rect(enclosing_int_rect(rect), Color(color).with_alpha(100));
+ context.painter().draw_rect(enclosing_int_rect(rect), Color(color));
+ };
+
+ paint_inspector_rect(margin_rect, Color::Yellow);
+ paint_inspector_rect(padding_rect, Color::Cyan);
+ paint_inspector_rect(border_rect, Color::Green);
+ paint_inspector_rect(content_rect, Color::Magenta);
+
+ StringBuilder builder;
+ if (layout_box().dom_node())
+ builder.append(layout_box().dom_node()->debug_description());
+ else
+ builder.append(layout_box().debug_description());
+ builder.appendff(" {}x{} @ {},{}", border_rect.width(), border_rect.height(), border_rect.x(), border_rect.y());
+ auto size_text = builder.to_string();
+ auto size_text_rect = border_rect;
+ size_text_rect.set_y(border_rect.y() + border_rect.height());
+ size_text_rect.set_top(size_text_rect.top());
+ size_text_rect.set_width((float)context.painter().font().width(size_text) + 4);
+ size_text_rect.set_height(context.painter().font().glyph_height() + 4);
+ context.painter().fill_rect(enclosing_int_rect(size_text_rect), context.palette().color(Gfx::ColorRole::Tooltip));
+ context.painter().draw_rect(enclosing_int_rect(size_text_rect), context.palette().threed_shadow1());
+ context.painter().draw_text(enclosing_int_rect(size_text_rect), size_text, Gfx::TextAlignment::Center, context.palette().color(Gfx::ColorRole::TooltipText));
+ }
+
+ if (phase == PaintPhase::FocusOutline && layout_box().dom_node() && layout_box().dom_node()->is_element() && verify_cast<DOM::Element>(*layout_box().dom_node()).is_focused()) {
+ context.painter().draw_rect(enclosing_int_rect(absolute_rect()), context.palette().focus_outline());
+ }
+}
+
+void PaintableBox::paint_border(PaintContext& context) const
+{
+ auto borders_data = BordersData {
+ .top = computed_values().border_top(),
+ .right = computed_values().border_right(),
+ .bottom = computed_values().border_bottom(),
+ .left = computed_values().border_left(),
+ };
+ paint_all_borders(context, absolute_border_box_rect(), normalized_border_radius_data(), borders_data);
+}
+
+void PaintableBox::paint_background(PaintContext& context) const
+{
+ // If the body's background properties were propagated to the root element, do no re-paint the body's background.
+ if (layout_box().is_body() && document().html_element()->should_use_body_background_properties())
+ return;
+
+ Gfx::IntRect background_rect;
+ Color background_color = computed_values().background_color();
+ auto* background_layers = &computed_values().background_layers();
+
+ if (layout_box().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_layers = document().background_layers();
+ background_color = document().background_color(context.palette());
+ }
+ } else {
+ background_rect = enclosing_int_rect(absolute_padding_box_rect());
+ }
+
+ // HACK: If the Box has a border, use the bordered_rect to paint the background.
+ // This way if we have a border-radius there will be no gap between the filling and actual border.
+ if (computed_values().border_top().width || computed_values().border_right().width || computed_values().border_bottom().width || computed_values().border_left().width)
+ background_rect = enclosing_int_rect(absolute_border_box_rect());
+
+ Painting::paint_background(context, layout_box(), background_rect, background_color, background_layers, normalized_border_radius_data());
+}
+
+void PaintableBox::paint_box_shadow(PaintContext& context) const
+{
+ auto box_shadow_data = computed_values().box_shadow();
+ if (box_shadow_data.is_empty())
+ return;
+
+ Vector<BoxShadowData> resolved_box_shadow_data;
+ resolved_box_shadow_data.ensure_capacity(box_shadow_data.size());
+ for (auto const& layer : box_shadow_data) {
+ resolved_box_shadow_data.empend(
+ layer.color,
+ static_cast<int>(layer.offset_x.to_px(layout_box())),
+ static_cast<int>(layer.offset_y.to_px(layout_box())),
+ static_cast<int>(layer.blur_radius.to_px(layout_box())),
+ static_cast<int>(layer.spread_distance.to_px(layout_box())),
+ layer.placement == CSS::BoxShadowPlacement::Outer ? BoxShadowPlacement::Outer : BoxShadowPlacement::Inner);
+ }
+ Painting::paint_box_shadow(context, enclosing_int_rect(absolute_border_box_rect()), resolved_box_shadow_data);
+}
+
+BorderRadiusData PaintableBox::normalized_border_radius_data() const
+{
+ return Painting::normalized_border_radius_data(layout_box(), absolute_border_box_rect(),
+ computed_values().border_top_left_radius(),
+ computed_values().border_top_right_radius(),
+ computed_values().border_bottom_right_radius(),
+ computed_values().border_bottom_left_radius());
+}
+
+void PaintableBox::before_children_paint(PaintContext& context, PaintPhase) const
+{
+ // FIXME: Support more overflow variations.
+ if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden) {
+ context.painter().save();
+ context.painter().add_clip_rect(enclosing_int_rect(absolute_border_box_rect()));
+ }
+}
+
+void PaintableBox::after_children_paint(PaintContext& context, PaintPhase) const
+{
+ // FIXME: Support more overflow variations.
+ if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden)
+ context.painter().restore();
+}
+
+void PaintableWithLines::paint(PaintContext& context, PaintPhase phase) const
+{
+ if (!is_visible())
+ return;
+
+ PaintableBox::paint(context, phase);
+
+ if (m_line_boxes.is_empty())
+ return;
+
+ bool should_clip_overflow = computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible;
+
+ if (should_clip_overflow) {
+ context.painter().save();
+ // FIXME: Handle overflow-x and overflow-y being different values.
+ context.painter().add_clip_rect(enclosing_int_rect(absolute_padding_box_rect()));
+ auto scroll_offset = static_cast<Layout::BlockContainer const&>(layout_box()).scroll_offset();
+ context.painter().translate(-scroll_offset.to_type<int>());
+ }
+
+ for (auto& line_box : m_line_boxes) {
+ for (auto& fragment : line_box.fragments()) {
+ if (context.should_show_line_box_borders())
+ context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), Color::Green);
+ const_cast<Layout::LineBoxFragment&>(fragment).paint(context, phase);
+ }
+ }
+
+ if (should_clip_overflow) {
+ context.painter().restore();
+ }
+
+ // FIXME: Merge this loop with the above somehow..
+ if (phase == PaintPhase::FocusOutline) {
+ for (auto& line_box : m_line_boxes) {
+ for (auto& fragment : line_box.fragments()) {
+ auto* node = fragment.layout_node().dom_node();
+ if (!node)
+ continue;
+ auto* parent = node->parent_element();
+ if (!parent)
+ continue;
+ if (parent->is_focused())
+ context.painter().draw_rect(enclosing_int_rect(fragment.absolute_rect()), context.palette().focus_outline());
+ }
+ }
+ }
+}
+
+bool PaintableWithLines::handle_mousewheel(Badge<EventHandler>, Gfx::IntPoint const&, unsigned, unsigned, int wheel_delta_x, int wheel_delta_y)
+{
+ if (!layout_box().is_scrollable())
+ return false;
+ auto new_offset = layout_box().scroll_offset();
+ new_offset.translate_by(wheel_delta_x, wheel_delta_y);
+ const_cast<Layout::BlockContainer&>(layout_box()).set_scroll_offset(new_offset);
+ return true;
+}
+
+Layout::BlockContainer const& PaintableWithLines::layout_box() const
+{
+ return static_cast<Layout::BlockContainer const&>(PaintableBox::layout_box());
+}
+
+Layout::BlockContainer& PaintableWithLines::layout_box()
+{
+ return static_cast<Layout::BlockContainer&>(PaintableBox::layout_box());
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h
new file mode 100644
index 0000000000..43dc3ef0b8
--- /dev/null
+++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/Painting/Paintable.h>
+
+namespace Web::Painting {
+
+class PaintableBox : public Paintable {
+public:
+ static NonnullRefPtr<PaintableBox> create(Layout::Box const&);
+ virtual ~PaintableBox();
+
+ virtual void paint(PaintContext&, PaintPhase) const override;
+
+ bool is_visible() const { return layout_box().is_visible(); }
+
+ Layout::Box& layout_box() { return static_cast<Layout::Box&>(Paintable::layout_node()); }
+ Layout::Box const& layout_box() const { return static_cast<Layout::Box const&>(Paintable::layout_node()); }
+
+ auto const& box_model() const { return layout_box().box_model(); }
+
+ struct OverflowData {
+ Gfx::FloatRect scrollable_overflow_rect;
+ Gfx::FloatPoint scroll_offset;
+ };
+ Optional<OverflowData> m_overflow_data;
+
+ Gfx::FloatPoint m_offset;
+ Gfx::FloatSize m_content_size;
+
+ // Some boxes hang off of line box fragments. (inline-block, inline-table, replaced, etc)
+ Optional<Layout::LineBoxFragmentCoordinate> m_containing_line_box_fragment;
+
+ Gfx::FloatRect absolute_rect() const;
+ Gfx::FloatPoint effective_offset() const;
+
+ void set_offset(Gfx::FloatPoint const&);
+ void set_offset(float x, float y) { set_offset({ x, y }); }
+
+ Gfx::FloatSize const& content_size() const { return m_content_size; }
+ void set_content_size(Gfx::FloatSize const&);
+ void set_content_size(float width, float height) { set_content_size({ width, height }); }
+
+ void set_content_width(float width) { set_content_size(width, content_height()); }
+ void set_content_height(float height) { set_content_size(content_width(), height); }
+ float content_width() const { return m_content_size.width(); }
+ float content_height() const { return m_content_size.height(); }
+
+ Gfx::FloatRect absolute_padding_box_rect() const
+ {
+ auto absolute_rect = this->absolute_rect();
+ Gfx::FloatRect rect;
+ rect.set_x(absolute_rect.x() - box_model().padding.left);
+ rect.set_width(content_width() + box_model().padding.left + box_model().padding.right);
+ rect.set_y(absolute_rect.y() - box_model().padding.top);
+ rect.set_height(content_height() + box_model().padding.top + box_model().padding.bottom);
+ return rect;
+ }
+
+ Gfx::FloatRect absolute_border_box_rect() const
+ {
+ auto padded_rect = this->absolute_padding_box_rect();
+ Gfx::FloatRect rect;
+ rect.set_x(padded_rect.x() - box_model().border.left);
+ rect.set_width(padded_rect.width() + box_model().border.left + box_model().border.right);
+ rect.set_y(padded_rect.y() - box_model().border.top);
+ rect.set_height(padded_rect.height() + box_model().border.top + box_model().border.bottom);
+ return rect;
+ }
+
+ float border_box_width() const
+ {
+ auto border_box = box_model().border_box();
+ return content_width() + border_box.left + border_box.right;
+ }
+
+ float border_box_height() const
+ {
+ auto border_box = box_model().border_box();
+ return content_height() + border_box.top + border_box.bottom;
+ }
+
+ float absolute_x() const { return absolute_rect().x(); }
+ float absolute_y() const { return absolute_rect().y(); }
+ Gfx::FloatPoint absolute_position() const { return absolute_rect().location(); }
+
+ bool has_overflow() const { return m_overflow_data.has_value(); }
+
+ Optional<Gfx::FloatRect> scrollable_overflow_rect() const
+ {
+ if (!m_overflow_data.has_value())
+ return {};
+ return m_overflow_data->scrollable_overflow_rect;
+ }
+
+ void set_overflow_data(Optional<OverflowData> data) { m_overflow_data = move(data); }
+ void set_containing_line_box_fragment(Optional<Layout::LineBoxFragmentCoordinate>);
+
+ StackingContext* stacking_context() { return m_stacking_context; }
+ StackingContext const* stacking_context() const { return m_stacking_context; }
+ void set_stacking_context(NonnullOwnPtr<Painting::StackingContext> context) { m_stacking_context = move(context); }
+ StackingContext* enclosing_stacking_context();
+
+ DOM::Node const* dom_node() const { return layout_box().dom_node(); }
+ DOM::Node* dom_node() { return layout_box().dom_node(); }
+
+ DOM::Document const& document() const { return layout_box().document(); }
+ DOM::Document& document() { return layout_box().document(); }
+
+ virtual void before_children_paint(PaintContext&, PaintPhase) const override;
+ virtual void after_children_paint(PaintContext&, PaintPhase) const override;
+
+protected:
+ explicit PaintableBox(Layout::Box const&);
+
+ virtual void paint_border(PaintContext&) const;
+ virtual void paint_background(PaintContext&) const;
+ virtual void paint_box_shadow(PaintContext&) const;
+
+private:
+ Painting::BorderRadiusData normalized_border_radius_data() const;
+
+ OwnPtr<Painting::StackingContext> m_stacking_context;
+};
+
+class PaintableWithLines : public PaintableBox {
+public:
+ static NonnullRefPtr<PaintableWithLines> create(Layout::BlockContainer const& block_container)
+ {
+ return adopt_ref(*new PaintableWithLines(block_container));
+ }
+ virtual ~PaintableWithLines() override;
+
+ Layout::BlockContainer const& layout_box() const;
+ Layout::BlockContainer& layout_box();
+
+ Vector<Layout::LineBox> const& line_boxes() const { return m_line_boxes; }
+ void set_line_boxes(Vector<Layout::LineBox>&& line_boxes) { m_line_boxes = move(line_boxes); }
+
+ template<typename Callback>
+ void for_each_fragment(Callback callback) const
+ {
+ for (auto& line_box : line_boxes()) {
+ for (auto& fragment : line_box.fragments()) {
+ if (callback(fragment) == IterationDecision::Break)
+ return;
+ }
+ }
+ }
+
+ virtual void paint(PaintContext&, PaintPhase) const override;
+ virtual bool wants_mouse_events() const override { return false; }
+ virtual bool handle_mousewheel(Badge<EventHandler>, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y) override;
+
+private:
+ PaintableWithLines(Layout::BlockContainer const&);
+
+ Vector<Layout::LineBox> m_line_boxes;
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/Painting/ProgressPaintable.h b/Userland/Libraries/LibWeb/Painting/ProgressPaintable.h
index 7e488a19cc..e8f3d57e47 100644
--- a/Userland/Libraries/LibWeb/Painting/ProgressPaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/ProgressPaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/Progress.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/SVGPaintable.h b/Userland/Libraries/LibWeb/Painting/SVGPaintable.h
index d1a2250bd8..59eb8f008e 100644
--- a/Userland/Libraries/LibWeb/Painting/SVGPaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/SVGPaintable.h
@@ -7,7 +7,7 @@
#pragma once
#include <LibWeb/Layout/SVGBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp
index 1204310ed9..ae2f106aa6 100644
--- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp
+++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp
@@ -10,7 +10,7 @@
#include <LibWeb/Layout/Box.h>
#include <LibWeb/Layout/InitialContainingBlock.h>
#include <LibWeb/Layout/ReplacedBox.h>
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
#include <LibWeb/Painting/StackingContext.h>
namespace Web::Painting {
diff --git a/Userland/Libraries/LibWeb/Painting/TextPaintable.h b/Userland/Libraries/LibWeb/Painting/TextPaintable.h
index 172bdf4754..b2030b3221 100644
--- a/Userland/Libraries/LibWeb/Painting/TextPaintable.h
+++ b/Userland/Libraries/LibWeb/Painting/TextPaintable.h
@@ -6,7 +6,7 @@
#pragma once
-#include <LibWeb/Painting/Paintable.h>
+#include <LibWeb/Painting/PaintableBox.h>
namespace Web::Painting {