فهرست منبع

LibWeb: Compute the final border-style property before painting

Instead of doing a CSS property lookup for the line style of each
border edge during paint, we now cache the final CSS::LineStyle to use
in the Layout::BorderData.
Andreas Kling 4 سال پیش
والد
کامیت
2cbbab8f73

+ 29 - 0
Libraries/LibWeb/CSS/StyleProperties.cpp

@@ -259,6 +259,35 @@ Optional<CSS::WhiteSpace> StyleProperties::white_space() const
     return {};
 }
 
+Optional<CSS::LineStyle> StyleProperties::line_style(CSS::PropertyID property_id) const
+{
+    auto value = property(property_id);
+    if (!value.has_value() || !value.value()->is_string())
+        return {};
+    auto string = value.value()->to_string();
+    if (string == "none")
+        return CSS::LineStyle::None;
+    if (string == "hidden")
+        return CSS::LineStyle::Hidden;
+    if (string == "dotted")
+        return CSS::LineStyle::Dotted;
+    if (string == "dashed")
+        return CSS::LineStyle::Dashed;
+    if (string == "solid")
+        return CSS::LineStyle::Solid;
+    if (string == "double")
+        return CSS::LineStyle::Double;
+    if (string == "groove")
+        return CSS::LineStyle::Groove;
+    if (string == "ridge")
+        return CSS::LineStyle::Ridge;
+    if (string == "inset")
+        return CSS::LineStyle::Inset;
+    if (string == "outset")
+        return CSS::LineStyle::Outset;
+    return {};
+}
+
 Optional<CSS::Float> StyleProperties::float_() const
 {
     auto value = property(CSS::PropertyID::Float);

+ 1 - 0
Libraries/LibWeb/CSS/StyleProperties.h

@@ -64,6 +64,7 @@ public:
     CSS::Display display() const;
     Optional<CSS::Float> float_() const;
     Optional<CSS::WhiteSpace> white_space() const;
+    Optional<CSS::LineStyle> line_style(CSS::PropertyID) const;
 
     const Gfx::Font& font() const
     {

+ 13 - 0
Libraries/LibWeb/CSS/StyleValue.h

@@ -149,6 +149,19 @@ enum class Float {
     Right,
 };
 
+enum class LineStyle {
+    None,
+    Hidden,
+    Dotted,
+    Dashed,
+    Solid,
+    Double,
+    Groove,
+    Ridge,
+    Inset,
+    Outset,
+};
+
 class StyleValue : public RefCounted<StyleValue> {
 public:
     virtual ~StyleValue();

+ 26 - 39
Libraries/LibWeb/Layout/Box.cpp

@@ -33,66 +33,53 @@
 
 namespace Web::Layout {
 
-void Box::paint_border(PaintContext& context, Edge edge, const Gfx::FloatRect& rect, CSS::PropertyID style_property_id, const BorderData& border_data)
+void Box::paint_border(PaintContext& context, Edge edge, const Gfx::FloatRect& rect, const BorderData& border_data)
 {
     float width = border_data.width;
     if (width <= 0)
         return;
 
     auto color = border_data.color;
-    auto border_style = specified_style().property(style_property_id);
+    auto border_style = border_data.line_style;
     int int_width = max((int)width, 1);
 
-    auto first_point_for_edge = [](Edge edge, const Gfx::FloatRect& rect) {
-        switch (edge) {
-        case Edge::Top:
-            return rect.top_left();
-        case Edge::Right:
-            return rect.top_right();
-        case Edge::Bottom:
-            return rect.bottom_left();
-        case Edge::Left:
-        default:
-            return rect.top_left();
-        }
+    struct Points {
+        Gfx::FloatPoint p1;
+        Gfx::FloatPoint p2;
     };
 
-    auto second_point_for_edge = [](Edge edge, const Gfx::FloatRect& rect) {
+    auto points_for_edge = [](Edge edge, const Gfx::FloatRect& rect) -> Points {
         switch (edge) {
         case Edge::Top:
-            return rect.top_right();
+            return { rect.top_left(), rect.top_right() };
         case Edge::Right:
-            return rect.bottom_right();
+            return { rect.top_right(), rect.bottom_right() };
         case Edge::Bottom:
-            return rect.bottom_right();
-        case Edge::Left:
-        default:
-            return rect.bottom_left();
+            return { rect.bottom_left(), rect.bottom_right() };
+        default: // Edge::Left
+            return { rect.top_left(), rect.bottom_left() };
         }
     };
 
-    auto p1 = first_point_for_edge(edge, rect);
-    auto p2 = second_point_for_edge(edge, rect);
+    auto [p1, p2] = points_for_edge(edge, rect);
 
-    if (border_style.has_value() && border_style.value()->to_string() == "inset") {
+    if (border_style == CSS::LineStyle::Inset) {
         auto top_left_color = Color::from_rgb(0x5a5a5a);
         auto bottom_right_color = Color::from_rgb(0x888888);
         color = (edge == Edge::Left || edge == Edge::Top) ? top_left_color : bottom_right_color;
-    } else if (border_style.has_value() && border_style.value()->to_string() == "outset") {
+    } else if (border_style == CSS::LineStyle::Outset) {
         auto top_left_color = Color::from_rgb(0x888888);
         auto bottom_right_color = Color::from_rgb(0x5a5a5a);
         color = (edge == Edge::Left || edge == Edge::Top) ? top_left_color : bottom_right_color;
     }
 
-    auto line_style = Gfx::Painter::LineStyle::Solid;
-    if (border_style.has_value()) {
-        if (border_style.value()->to_string() == "dotted")
-            line_style = Gfx::Painter::LineStyle::Dotted;
-        if (border_style.value()->to_string() == "dashed")
-            line_style = Gfx::Painter::LineStyle::Dashed;
-    }
+    auto gfx_line_style = Gfx::Painter::LineStyle::Solid;
+    if (border_style == CSS::LineStyle::Dotted)
+        gfx_line_style = Gfx::Painter::LineStyle::Dotted;
+    if (border_style == CSS::LineStyle::Dashed)
+        gfx_line_style = Gfx::Painter::LineStyle::Dashed;
 
-    if (line_style != Gfx::Painter::LineStyle::Solid) {
+    if (gfx_line_style != Gfx::Painter::LineStyle::Solid) {
         switch (edge) {
         case Edge::Top:
             p1.move_by(int_width / 2, int_width / 2);
@@ -111,12 +98,12 @@ void Box::paint_border(PaintContext& context, Edge edge, const Gfx::FloatRect& r
             p2.move_by(int_width / 2, -int_width / 2);
             break;
         }
-        context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, int_width, line_style);
+        context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, int_width, gfx_line_style);
         return;
     }
 
     auto draw_line = [&](auto& p1, auto& p2) {
-        context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, 1, line_style);
+        context.painter().draw_line({ (int)p1.x(), (int)p1.y() }, { (int)p2.x(), (int)p2.y() }, color, 1, gfx_line_style);
     };
 
     float p1_step = 0;
@@ -200,10 +187,10 @@ void Box::paint(PaintContext& context, PaintPhase phase)
         bordered_rect.set_y(padded_rect.y() - box_model().border.top.to_px(*this));
         bordered_rect.set_height(padded_rect.height() + box_model().border.top.to_px(*this) + box_model().border.bottom.to_px(*this));
 
-        paint_border(context, Edge::Left, bordered_rect, CSS::PropertyID::BorderLeftStyle, style().border_left());
-        paint_border(context, Edge::Right, bordered_rect, CSS::PropertyID::BorderRightStyle, style().border_right());
-        paint_border(context, Edge::Top, bordered_rect, CSS::PropertyID::BorderTopStyle, style().border_top());
-        paint_border(context, Edge::Bottom, bordered_rect, CSS::PropertyID::BorderBottomStyle, style().border_bottom());
+        paint_border(context, Edge::Left, bordered_rect, style().border_left());
+        paint_border(context, Edge::Right, bordered_rect, style().border_right());
+        paint_border(context, Edge::Top, bordered_rect, style().border_top());
+        paint_border(context, Edge::Bottom, bordered_rect, style().border_bottom());
     }
 
     Layout::NodeWithStyleAndBoxModelMetrics::paint(context, phase);

+ 1 - 1
Libraries/LibWeb/Layout/Box.h

@@ -98,7 +98,7 @@ private:
         Bottom,
         Left,
     };
-    void paint_border(PaintContext&, Edge, const Gfx::FloatRect&, CSS::PropertyID style_property_id, const BorderData&);
+    void paint_border(PaintContext&, Edge, const Gfx::FloatRect&, const BorderData&);
 
     Gfx::FloatPoint m_offset;
     Gfx::FloatSize m_size;

+ 1 - 0
Libraries/LibWeb/Layout/LayoutStyle.h

@@ -41,6 +41,7 @@ public:
 struct BorderData {
 public:
     Color color { Color::Transparent };
+    CSS::LineStyle line_style { CSS::LineStyle::None };
     float width { 0 };
 };
 

+ 10 - 9
Libraries/LibWeb/Layout/Node.cpp

@@ -241,15 +241,16 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style)
     style.set_margin(specified_style.length_box(CSS::PropertyID::MarginLeft, CSS::PropertyID::MarginTop, CSS::PropertyID::MarginRight, CSS::PropertyID::MarginBottom));
     style.set_padding(specified_style.length_box(CSS::PropertyID::PaddingLeft, CSS::PropertyID::PaddingTop, CSS::PropertyID::PaddingRight, CSS::PropertyID::PaddingBottom));
 
-    style.border_left().width = specified_style.length_or_fallback(CSS::PropertyID::BorderLeftWidth, {}).resolved_or_zero(*this, 0).to_px(*this);
-    style.border_top().width = specified_style.length_or_fallback(CSS::PropertyID::BorderTopWidth, {}).resolved_or_zero(*this, 0).to_px(*this);
-    style.border_right().width = specified_style.length_or_fallback(CSS::PropertyID::BorderRightWidth, {}).resolved_or_zero(*this, 0).to_px(*this);
-    style.border_bottom().width = specified_style.length_or_fallback(CSS::PropertyID::BorderBottomWidth, {}).resolved_or_zero(*this, 0).to_px(*this);
-
-    style.border_left().color = specified_style.color_or_fallback(CSS::PropertyID::BorderLeftColor, document(), Color::Transparent);
-    style.border_top().color = specified_style.color_or_fallback(CSS::PropertyID::BorderTopColor, document(), Color::Transparent);
-    style.border_right().color = specified_style.color_or_fallback(CSS::PropertyID::BorderRightColor, document(), Color::Transparent);
-    style.border_bottom().color = specified_style.color_or_fallback(CSS::PropertyID::BorderBottomColor, document(), Color::Transparent);
+    auto do_border_style = [&](BorderData& border, CSS::PropertyID width_property, CSS::PropertyID color_property, CSS::PropertyID style_property) {
+        border.width = specified_style.length_or_fallback(width_property, {}).resolved_or_zero(*this, 0).to_px(*this);
+        border.color = specified_style.color_or_fallback(color_property, document(), Color::Transparent);
+        border.line_style = specified_style.line_style(style_property).value_or(CSS::LineStyle::None);
+    };
+
+    do_border_style(style.border_left(), CSS::PropertyID::BorderLeftWidth, CSS::PropertyID::BorderLeftColor, CSS::PropertyID::BorderLeftStyle);
+    do_border_style(style.border_top(), CSS::PropertyID::BorderTopWidth, CSS::PropertyID::BorderTopColor, CSS::PropertyID::BorderTopStyle);
+    do_border_style(style.border_right(), CSS::PropertyID::BorderRightWidth, CSS::PropertyID::BorderRightColor, CSS::PropertyID::BorderRightStyle);
+    do_border_style(style.border_bottom(), CSS::PropertyID::BorderBottomWidth, CSS::PropertyID::BorderBottomColor, CSS::PropertyID::BorderBottomStyle);
 }
 
 void Node::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned, unsigned)