Ver código fonte

LibWeb: Resolve outline CSS property before paint commands recording

Refactor to resolve paint-only properties before painting, aiming to
stop using layout nodes during recording of painting commands.

Also adds a test, as we have not had any for outlines yet.
Aliaksandr Kalenik 1 ano atrás
pai
commit
95d91a37d2

+ 11 - 0
Tests/LibWeb/Ref/outlines.html

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<link rel="match" href="reference/outlines-ref.html" />
+<style>
+    .outline {
+        width: 100px;
+        height: 100px;
+        outline: 5px solid black;
+    }
+</style>
+<div class="outline">hello from paintable box</div>
+<p><span class="outline">hello from inline paintable</span></p>

+ 12 - 0
Tests/LibWeb/Ref/reference/outlines-ref.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="match" href="reference/outlines-ref.html" />
+<style>
+    .border {
+        width: 100px;
+        height: 100px;
+        border: 5px solid black;
+        margin: -5px;
+    }
+</style>
+<div class="border">hello from paintable box</div>
+<p><span class="border">hello from inline paintable</span></p>

+ 2 - 4
Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp

@@ -167,11 +167,9 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
     }
 
     if (phase == PaintPhase::Outline) {
-        auto outline_width = computed_values().outline_width().to_px(layout_node());
-        auto maybe_outline_data = borders_data_for_outline(layout_node(), computed_values().outline_color(), computed_values().outline_style(), outline_width);
-        if (maybe_outline_data.has_value()) {
+        auto maybe_outline_data = this->outline_data();
+        if (maybe_outline_data.has_value())
             paint_border_or_outline(maybe_outline_data.value(), computed_values().outline_offset().to_px(layout_node()));
-        }
     }
 
     if (phase == PaintPhase::Foreground) {

+ 8 - 0
Userland/Libraries/LibWeb/Painting/InlinePaintable.h

@@ -37,6 +37,12 @@ public:
     void set_box_shadow_data(Vector<ShadowData>&& box_shadow_data) { m_box_shadow_data = move(box_shadow_data); }
     Vector<ShadowData> const& box_shadow_data() const { return m_box_shadow_data; }
 
+    void set_outline_data(Optional<BordersData> outline_data) { m_outline_data = outline_data; }
+    Optional<BordersData> const& outline_data() const { return m_outline_data; }
+
+    void set_outline_offset(CSSPixels outline_offset) { m_outline_offset = outline_offset; }
+    CSSPixels outline_offset() const { return m_outline_offset; }
+
     void set_enclosing_scroll_frame(RefPtr<ScrollFrame> scroll_frame) { m_enclosing_scroll_frame = scroll_frame; }
     void set_enclosing_clip_frame(RefPtr<ClipFrame> clip_frame) { m_enclosing_clip_frame = clip_frame; }
 
@@ -55,6 +61,8 @@ private:
     RefPtr<ClipFrame const> m_enclosing_clip_frame;
 
     Vector<ShadowData> m_box_shadow_data;
+    Optional<BordersData> m_outline_data;
+    CSSPixels m_outline_offset { 0 };
     Vector<PaintableFragment> m_fragments;
 };
 

+ 6 - 7
Userland/Libraries/LibWeb/Painting/PaintableBox.cpp

@@ -259,10 +259,9 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
     }
 
     if (phase == PaintPhase::Outline) {
-        auto outline_width = computed_values().outline_width().to_px(layout_node());
-        auto borders_data = borders_data_for_outline(layout_node(), computed_values().outline_color(), computed_values().outline_style(), outline_width);
-        if (borders_data.has_value()) {
-            auto outline_offset = computed_values().outline_offset().to_px(layout_node());
+        auto const& outline_data = this->outline_data();
+        if (outline_data.has_value()) {
+            auto outline_offset = this->outline_offset();
             auto border_radius_data = normalized_border_radii_data(ShrinkRadiiForBorders::No);
             auto borders_rect = absolute_border_box_rect();
 
@@ -279,10 +278,10 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
             if ((borders_rect.height() / 2) + outline_offset_y < 0)
                 outline_offset_y = -borders_rect.height() / 2;
 
-            border_radius_data.inflate(outline_width + outline_offset_y, outline_width + outline_offset_x, outline_width + outline_offset_y, outline_width + outline_offset_x);
-            borders_rect.inflate(outline_width + outline_offset_y, outline_width + outline_offset_x, outline_width + outline_offset_y, outline_width + outline_offset_x);
+            border_radius_data.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
+            borders_rect.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
 
-            context.recording_painter().paint_borders(context.rounded_device_rect(borders_rect), border_radius_data.as_corners(context), borders_data->to_device_pixels(context));
+            context.recording_painter().paint_borders(context.rounded_device_rect(borders_rect), border_radius_data.as_corners(context), outline_data->to_device_pixels(context));
         }
     }
 

+ 9 - 0
Userland/Libraries/LibWeb/Painting/PaintableBox.h

@@ -195,6 +195,12 @@ public:
     void set_transform_origin(CSSPixelPoint transform_origin) { m_transform_origin = transform_origin; }
     CSSPixelPoint const& transform_origin() const { return m_transform_origin; }
 
+    void set_outline_data(Optional<BordersData> outline_data) { m_outline_data = outline_data; }
+    Optional<BordersData> const& outline_data() const { return m_outline_data; }
+
+    void set_outline_offset(CSSPixels outline_offset) { m_outline_offset = outline_offset; }
+    CSSPixels outline_offset() const { return m_outline_offset; }
+
     CSSPixelRect compute_absolute_padding_rect_with_css_transform_applied() const;
     Gfx::AffineTransform compute_combined_css_transform() const;
 
@@ -243,6 +249,9 @@ private:
     Vector<ShadowData> m_box_shadow_data;
     Gfx::FloatMatrix4x4 m_transform { Gfx::FloatMatrix4x4::identity() };
     CSSPixelPoint m_transform_origin;
+
+    Optional<BordersData> m_outline_data;
+    CSSPixels m_outline_offset { 0 };
 };
 
 class PaintableWithLines : public PaintableBox {

+ 16 - 0
Userland/Libraries/LibWeb/Painting/ViewportPaintable.cpp

@@ -227,6 +227,7 @@ void ViewportPaintable::resolve_paint_only_properties()
     // - Text shadows
     // - Transforms
     // - Transform origins
+    // - Outlines
     for_each_in_inclusive_subtree([&](Paintable& paintable) {
         auto& node = paintable.layout_node();
 
@@ -416,6 +417,21 @@ void ViewportPaintable::resolve_paint_only_properties()
             paintable_box.set_transform_origin({ x, y });
         }
 
+        // Outlines
+        auto const& computed_values = node.computed_values();
+        auto outline_width = computed_values.outline_width().to_px(node);
+        auto outline_data = borders_data_for_outline(node, computed_values.outline_color(), computed_values.outline_style(), outline_width);
+        auto outline_offset = computed_values.outline_offset().to_px(node);
+        if (is_paintable_box) {
+            auto& paintable_box = static_cast<Painting::PaintableBox&>(paintable);
+            paintable_box.set_outline_data(outline_data);
+            paintable_box.set_outline_offset(outline_offset);
+        } else if (is_inline_paintable) {
+            auto& inline_paintable = static_cast<Painting::InlinePaintable&>(paintable);
+            inline_paintable.set_outline_data(outline_data);
+            inline_paintable.set_outline_offset(outline_offset);
+        }
+
         return TraversalDecision::Continue;
     });
 }