diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index 6ec0f4293be..55619eee7b0 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -32,6 +32,8 @@ pointer-events: auto quotes: auto stroke: none stroke-linecap: butt +stroke-linejoin: miter +stroke-miterlimit: 4 stroke-opacity: 1 stroke-width: 1px tab-size: 8 @@ -121,7 +123,7 @@ grid-row-start: auto grid-template-areas: none grid-template-columns: auto grid-template-rows: auto -height: 2091px +height: 2125px inline-size: auto inset-block-end: auto inset-block-start: auto diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index ad27ce2c7dd..4ab7abd6157 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -149,6 +149,8 @@ public: static CSS::FillRule fill_rule() { return CSS::FillRule::Nonzero; } static CSS::ClipRule clip_rule() { return CSS::ClipRule::Nonzero; } static CSS::StrokeLinecap stroke_linecap() { return CSS::StrokeLinecap::Butt; } + static CSS::StrokeLinejoin stroke_linejoin() { return CSS::StrokeLinejoin::Miter; } + static float stroke_miterlimit() { return 4.0f; } static float stroke_opacity() { return 1.0f; } static float stop_opacity() { return 1.0f; } static CSS::TextAnchor text_anchor() { return CSS::TextAnchor::Start; } @@ -473,6 +475,8 @@ public: Optional const& stroke() const { return m_inherited.stroke; } float fill_opacity() const { return m_inherited.fill_opacity; } CSS::StrokeLinecap stroke_linecap() const { return m_inherited.stroke_linecap; } + CSS::StrokeLinejoin stroke_linejoin() const { return m_inherited.stroke_linejoin; } + NumberOrCalculated stroke_miterlimit() const { return m_inherited.stroke_miterlimit; } float stroke_opacity() const { return m_inherited.stroke_opacity; } LengthPercentage const& stroke_width() const { return m_inherited.stroke_width; } Color stop_color() const { return m_noninherited.stop_color; } @@ -569,6 +573,8 @@ protected: Optional stroke; float fill_opacity { InitialValues::fill_opacity() }; CSS::StrokeLinecap stroke_linecap { InitialValues::stroke_linecap() }; + CSS::StrokeLinejoin stroke_linejoin { InitialValues::stroke_linejoin() }; + NumberOrCalculated stroke_miterlimit { InitialValues::stroke_miterlimit() }; float stroke_opacity { InitialValues::stroke_opacity() }; LengthPercentage stroke_width { Length::make_px(1) }; CSS::TextAnchor text_anchor { InitialValues::text_anchor() }; @@ -813,6 +819,8 @@ public: void set_fill_rule(CSS::FillRule value) { m_inherited.fill_rule = value; } void set_fill_opacity(float value) { m_inherited.fill_opacity = value; } void set_stroke_linecap(CSS::StrokeLinecap value) { m_inherited.stroke_linecap = value; } + void set_stroke_linejoin(CSS::StrokeLinejoin value) { m_inherited.stroke_linejoin = value; } + void set_stroke_miterlimit(NumberOrCalculated value) { m_inherited.stroke_miterlimit = value; } void set_stroke_opacity(float value) { m_inherited.stroke_opacity = value; } void set_stroke_width(LengthPercentage value) { m_inherited.stroke_width = value; } void set_stop_color(Color value) { m_noninherited.stop_color = value; } diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json index c4127a92c83..e98d8ce3ed9 100644 --- a/Userland/Libraries/LibWeb/CSS/Enums.json +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -422,6 +422,11 @@ "square", "round" ], + "stroke-linejoin": [ + "miter", + "round", + "bevel" + ], "text-align": [ "center", "justify", diff --git a/Userland/Libraries/LibWeb/CSS/Keywords.json b/Userland/Libraries/LibWeb/CSS/Keywords.json index 52497552f98..3959149c659 100644 --- a/Userland/Libraries/LibWeb/CSS/Keywords.json +++ b/Userland/Libraries/LibWeb/CSS/Keywords.json @@ -79,6 +79,7 @@ "background", "backwards", "baseline", + "bevel", "bidi-override", "blink", "block", @@ -251,6 +252,7 @@ "middle", "min-content", "minimal-ui", + "miter", "monospace", "more", "move", diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 6d6bcd4d75f..0ce6a9a6f37 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -2414,6 +2414,24 @@ "stroke-linecap" ] }, + "stroke-linejoin": { + "affects-layout": false, + "animation-type": "discrete", + "inherited": true, + "initial": "miter", + "valid-types": [ + "stroke-linejoin" + ] + }, + "stroke-miterlimit": { + "affects-layout": false, + "animation-type": "by-computed-value", + "inherited": true, + "initial": "4", + "valid-types": [ + "number [0,∞]" + ] + }, "stroke-opacity": { "affects-layout": false, "animation-type": "by-computed-value", diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index dfdfe377a77..3732b84c7c0 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -326,6 +326,25 @@ Optional StyleProperties::stroke_linecap() const return keyword_to_stroke_linecap(value->to_keyword()); } +Optional StyleProperties::stroke_linejoin() const +{ + auto value = property(CSS::PropertyID::StrokeLinejoin); + return keyword_to_stroke_linejoin(value->to_keyword()); +} + +NumberOrCalculated StyleProperties::stroke_miterlimit() const +{ + auto value = property(CSS::PropertyID::StrokeMiterlimit); + + if (value->is_math()) { + auto const& math_value = value->as_math(); + VERIFY(math_value.resolves_to_number()); + return NumberOrCalculated { math_value }; + } + + return NumberOrCalculated { value->as_number().number() }; +} + float StyleProperties::stroke_opacity() const { auto value = property(CSS::PropertyID::StrokeOpacity); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index d7184631464..811e8dba07b 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -180,6 +180,8 @@ public: float stop_opacity() const; float fill_opacity() const; Optional stroke_linecap() const; + Optional stroke_linejoin() const; + NumberOrCalculated stroke_miterlimit() const; float stroke_opacity() const; Optional fill_rule() const; Optional clip_rule() const; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 5af49f68478..49372e5711b 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -849,6 +849,11 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) computed_values.set_fill_opacity(computed_style.fill_opacity()); if (auto stroke_linecap = computed_style.stroke_linecap(); stroke_linecap.has_value()) computed_values.set_stroke_linecap(stroke_linecap.value()); + if (auto stroke_linejoin = computed_style.stroke_linejoin(); stroke_linejoin.has_value()) + computed_values.set_stroke_linejoin(stroke_linejoin.value()); + + computed_values.set_stroke_miterlimit(computed_style.stroke_miterlimit()); + computed_values.set_stroke_opacity(computed_style.stroke_opacity()); computed_values.set_stop_opacity(computed_style.stop_opacity()); diff --git a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp index 1128a46b5f1..d55ff339bc7 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp @@ -150,6 +150,8 @@ void SVGGraphicsElement::apply_presentational_hints(CSS::StyleProperties& style) // FIXME: The `stroke` attribute and CSS `stroke` property are not the same! But our support is limited enough that they are equivalent for now. NamedPropertyID(CSS::PropertyID::Stroke), NamedPropertyID(CSS::PropertyID::StrokeLinecap), + NamedPropertyID(CSS::PropertyID::StrokeLinejoin), + NamedPropertyID(CSS::PropertyID::StrokeMiterlimit), NamedPropertyID(CSS::PropertyID::StrokeWidth), NamedPropertyID(CSS::PropertyID::FillRule), NamedPropertyID(CSS::PropertyID::FillOpacity), @@ -242,6 +244,20 @@ Optional SVGGraphicsElement::stroke_linecap() const return layout_node()->computed_values().stroke_linecap(); } +Optional SVGGraphicsElement::stroke_linejoin() const +{ + if (!layout_node()) + return {}; + return layout_node()->computed_values().stroke_linejoin(); +} + +Optional SVGGraphicsElement::stroke_miterlimit() const +{ + if (!layout_node()) + return {}; + return layout_node()->computed_values().stroke_miterlimit(); +} + Optional SVGGraphicsElement::stroke_opacity() const { if (!layout_node()) diff --git a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h index 198188e19f2..678c1824460 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h @@ -39,6 +39,8 @@ public: Optional stroke_width() const; Optional fill_opacity() const; Optional stroke_linecap() const; + Optional stroke_linejoin() const; + Optional stroke_miterlimit() const; Optional stroke_opacity() const; Optional fill_rule() const; Optional clip_rule() const;