diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 81838b4502..27541f15d4 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -284,8 +284,20 @@ set(SOURCES Page/Page.cpp Painting/BackgroundPainting.cpp Painting/BorderPainting.cpp - Painting/Paintable.cpp + Painting/ButtonPaintable.cpp + Painting/CanvasPaintable.cpp + Painting/CheckBoxPaintable.cpp + Painting/ImagePaintable.cpp + Painting/MarkerPaintable.cpp + Painting/NestedBrowsingContextPaintable.cpp Painting/PaintContext.cpp + Painting/Paintable.cpp + Painting/ProgressPaintable.cpp + Painting/RadioButtonPaintable.cpp + Painting/SVGGeometryPaintable.cpp + Painting/SVGGraphicsPaintable.cpp + Painting/SVGPaintable.cpp + Painting/SVGSVGPaintable.cpp Painting/ShadowPainting.cpp Painting/StackingContext.cpp RequestIdleCallback/IdleDeadline.cpp diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp index d3ce8d6d16..f0340e72d4 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.cpp @@ -29,57 +29,6 @@ BlockContainer::~BlockContainer() { } -bool BlockContainer::should_clip_overflow() const -{ - return computed_values().overflow_x() != CSS::Overflow::Visible && computed_values().overflow_y() != CSS::Overflow::Visible; -} - -void BlockContainer::paint(PaintContext& context, Painting::PaintPhase phase) -{ - if (!is_visible()) - return; - - Box::paint(context, phase); - - if (!children_are_inline()) - return; - - 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(m_paint_box->absolute_padding_box_rect())); - context.painter().translate(-m_scroll_offset.to_type()); - } - - for (auto& line_box : paint_box()->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(fragment).paint(context, phase); - } - } - - if (should_clip_overflow()) { - context.painter().restore(); - } - - // FIXME: Merge this loop with the above somehow.. - if (phase == Painting::PaintPhase::FocusOutline) { - for (auto& line_box : paint_box()->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()); - } - } - } -} - HitTestResult BlockContainer::hit_test(const Gfx::IntPoint& position, HitTestType type) const { if (!children_are_inline()) @@ -136,4 +85,9 @@ Painting::PaintableWithLines const* BlockContainer::paint_box() const return static_cast(Box::paint_box()); } +OwnPtr BlockContainer::create_paintable() const +{ + return Painting::PaintableWithLines::create(*this); +} + } diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.h b/Userland/Libraries/LibWeb/Layout/BlockContainer.h index 6b5b547a19..737fca4fb5 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockContainer.h +++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.h @@ -18,8 +18,6 @@ public: BlockContainer(DOM::Document&, DOM::Node*, CSS::ComputedValues); virtual ~BlockContainer() override; - virtual void paint(PaintContext&, Painting::PaintPhase) override; - virtual HitTestResult hit_test(const Gfx::IntPoint&, HitTestType) const override; BlockContainer* previous_sibling() { return verify_cast(Node::previous_sibling()); } @@ -33,13 +31,13 @@ public: Painting::PaintableWithLines const* paint_box() const; + virtual OwnPtr create_paintable() const override; + private: virtual bool is_block_container() const final { return true; } virtual bool wants_mouse_events() const override { return false; } virtual bool handle_mousewheel(Badge, const Gfx::IntPoint&, unsigned buttons, unsigned modifiers, int wheel_delta_x, int wheel_delta_y) override; - bool should_clip_overflow() const; - Gfx::FloatPoint m_scroll_offset; }; diff --git a/Userland/Libraries/LibWeb/Layout/Box.cpp b/Userland/Libraries/LibWeb/Layout/Box.cpp index 2f7bff7904..ea8382921f 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.cpp +++ b/Userland/Libraries/LibWeb/Layout/Box.cpp @@ -39,137 +39,6 @@ void Box::set_paint_box(OwnPtr paint_box) m_paint_box = move(paint_box); } -void Box::paint(PaintContext& context, Painting::PaintPhase phase) -{ - if (!is_visible()) - return; - - if (phase == Painting::PaintPhase::Background) { - paint_background(context); - paint_box_shadow(context); - } - - if (phase == Painting::PaintPhase::Border) { - paint_border(context); - } - - if (phase == Painting::PaintPhase::Overlay && dom_node() && document().inspected_node() == dom_node()) { - auto content_rect = m_paint_box->absolute_rect(); - - auto margin_box = box_model().margin_box(); - Gfx::FloatRect margin_rect; - margin_rect.set_x(m_paint_box->absolute_x() - margin_box.left); - margin_rect.set_width(m_paint_box->content_width() + margin_box.left + margin_box.right); - margin_rect.set_y(m_paint_box->absolute_y() - margin_box.top); - margin_rect.set_height(m_paint_box->content_height() + margin_box.top + margin_box.bottom); - - auto border_rect = m_paint_box->absolute_border_box_rect(); - auto padding_rect = m_paint_box->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 (dom_node()) - builder.append(dom_node()->debug_description()); - else - builder.append(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 == Painting::PaintPhase::FocusOutline && dom_node() && dom_node()->is_element() && verify_cast(*dom_node()).is_focused()) { - context.painter().draw_rect(enclosing_int_rect(m_paint_box->absolute_rect()), context.palette().focus_outline()); - } -} - -void Box::paint_border(PaintContext& context) -{ - auto borders_data = Painting::BordersData { - .top = computed_values().border_top(), - .right = computed_values().border_right(), - .bottom = computed_values().border_bottom(), - .left = computed_values().border_left(), - }; - Painting::paint_all_borders(context, m_paint_box->absolute_border_box_rect(), normalized_border_radius_data(), borders_data); -} - -void Box::paint_background(PaintContext& context) -{ - // 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; - - Gfx::IntRect background_rect; - Color background_color = computed_values().background_color(); - auto* background_layers = &computed_values().background_layers(); - - 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_layers = document().background_layers(); - background_color = document().background_color(context.palette()); - } - } else { - background_rect = enclosing_int_rect(m_paint_box->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(m_paint_box->absolute_border_box_rect()); - - Painting::paint_background(context, *this, background_rect, background_color, background_layers, normalized_border_radius_data()); -} - -void Box::paint_box_shadow(PaintContext& context) -{ - auto box_shadow_data = computed_values().box_shadow(); - if (box_shadow_data.is_empty()) - return; - - Vector 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(layer.offset_x.to_px(*this)), - static_cast(layer.offset_y.to_px(*this)), - static_cast(layer.blur_radius.to_px(*this)), - static_cast(layer.spread_distance.to_px(*this)), - layer.placement == CSS::BoxShadowPlacement::Outer ? Painting::BoxShadowPlacement::Outer : Painting::BoxShadowPlacement::Inner); - } - Painting::paint_box_shadow(context, enclosing_int_rect(m_paint_box->absolute_border_box_rect()), resolved_box_shadow_data); -} - -Painting::BorderRadiusData Box::normalized_border_radius_data() -{ - return Painting::normalized_border_radius_data(*this, m_paint_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()); -} - // https://www.w3.org/TR/css-display-3/#out-of-flow bool Box::is_out_of_flow(FormattingContext const& formatting_context) const { @@ -222,22 +91,9 @@ bool Box::is_body() const return dom_node() && dom_node() == document().body(); } -void Box::before_children_paint(PaintContext& context, Painting::PaintPhase phase) +OwnPtr Box::create_paintable() const { - NodeWithStyleAndBoxModelMetrics::before_children_paint(context, phase); - // 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(m_paint_box->absolute_border_box_rect())); - } -} - -void Box::after_children_paint(PaintContext& context, Painting::PaintPhase phase) -{ - NodeWithStyleAndBoxModelMetrics::after_children_paint(context, phase); - // FIXME: Support more overflow variations. - if (computed_values().overflow_x() == CSS::Overflow::Hidden && computed_values().overflow_y() == CSS::Overflow::Hidden) - context.painter().restore(); + return Painting::Paintable::create(*this); } } diff --git a/Userland/Libraries/LibWeb/Layout/Box.h b/Userland/Libraries/LibWeb/Layout/Box.h index 03c4f13565..730bebcbf4 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.h +++ b/Userland/Libraries/LibWeb/Layout/Box.h @@ -32,13 +32,6 @@ public: bool is_body() const; - virtual void paint(PaintContext&, Painting::PaintPhase) override; - virtual void paint_border(PaintContext& context); - virtual void paint_box_shadow(PaintContext& context); - virtual void paint_background(PaintContext& context); - - Painting::BorderRadiusData normalized_border_radius_data(); - virtual Optional intrinsic_width() const { return {}; } virtual Optional intrinsic_height() const { return {}; } virtual Optional intrinsic_aspect_ratio() const { return {}; } @@ -47,13 +40,12 @@ public: bool has_intrinsic_height() const { return intrinsic_height().has_value(); } bool has_intrinsic_aspect_ratio() const { return intrinsic_aspect_ratio().has_value(); } - virtual void before_children_paint(PaintContext&, Painting::PaintPhase) override; - virtual void after_children_paint(PaintContext&, Painting::PaintPhase) override; - virtual ~Box() override; virtual void did_set_rect() { } + virtual OwnPtr create_paintable() const; + protected: Box(DOM::Document&, DOM::Node*, NonnullRefPtr); Box(DOM::Document&, DOM::Node*, CSS::ComputedValues); diff --git a/Userland/Libraries/LibWeb/Layout/BreakNode.cpp b/Userland/Libraries/LibWeb/Layout/BreakNode.cpp index 3097e2df80..4fa194bf2a 100644 --- a/Userland/Libraries/LibWeb/Layout/BreakNode.cpp +++ b/Userland/Libraries/LibWeb/Layout/BreakNode.cpp @@ -20,8 +20,4 @@ BreakNode::~BreakNode() { } -void BreakNode::paint(PaintContext&, Painting::PaintPhase) -{ -} - } diff --git a/Userland/Libraries/LibWeb/Layout/BreakNode.h b/Userland/Libraries/LibWeb/Layout/BreakNode.h index 31672f3041..320f442722 100644 --- a/Userland/Libraries/LibWeb/Layout/BreakNode.h +++ b/Userland/Libraries/LibWeb/Layout/BreakNode.h @@ -20,7 +20,6 @@ public: private: virtual bool is_break_node() const final { return true; } - virtual void paint(PaintContext&, Painting::PaintPhase) override; }; template<> diff --git a/Userland/Libraries/LibWeb/Layout/ButtonBox.cpp b/Userland/Libraries/LibWeb/Layout/ButtonBox.cpp index 11b64eec2b..a69fbc9c84 100644 --- a/Userland/Libraries/LibWeb/Layout/ButtonBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/ButtonBox.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include namespace Web::Layout { @@ -31,21 +31,6 @@ void ButtonBox::prepare_for_replaced_layout() set_intrinsic_height(font().glyph_height()); } -void ButtonBox::paint(PaintContext& context, Painting::PaintPhase phase) -{ - if (!is_visible()) - return; - - LabelableNode::paint(context, phase); - - if (phase == Painting::PaintPhase::Foreground) { - auto text_rect = enclosing_int_rect(m_paint_box->absolute_rect()); - if (m_being_pressed) - text_rect.translate_by(1, 1); - context.painter().draw_text(text_rect, dom_node().value(), font(), Gfx::TextAlignment::Center, computed_values().color()); - } -} - void ButtonBox::handle_mousedown(Badge, const Gfx::IntPoint&, unsigned button, unsigned) { if (button != GUI::MouseButton::Primary || !dom_node().enabled()) @@ -121,4 +106,9 @@ void ButtonBox::handle_associated_label_mousemove(Badge