LibWeb/CSS: Add the text-rendering property

This commit is contained in:
Tim Ledbetter 2025-06-27 07:03:05 +01:00 committed by Sam Atkins
commit 68035a2b8d
Notes: github-actions[bot] 2025-06-27 15:53:08 +00:00
19 changed files with 106 additions and 10 deletions

View file

@ -792,6 +792,12 @@ TextOverflow ComputedProperties::text_overflow() const
return keyword_to_text_overflow(value.to_keyword()).release_value(); return keyword_to_text_overflow(value.to_keyword()).release_value();
} }
TextRendering ComputedProperties::text_rendering() const
{
auto const& value = property(PropertyID::TextRendering);
return keyword_to_text_rendering(value.to_keyword()).release_value();
}
PointerEvents ComputedProperties::pointer_events() const PointerEvents ComputedProperties::pointer_events() const
{ {
auto const& value = property(PropertyID::PointerEvents); auto const& value = property(PropertyID::PointerEvents);

View file

@ -83,6 +83,7 @@ public:
TextAlign text_align() const; TextAlign text_align() const;
TextJustify text_justify() const; TextJustify text_justify() const;
TextOverflow text_overflow() const; TextOverflow text_overflow() const;
TextRendering text_rendering() const;
Length border_spacing_horizontal(Layout::Node const&) const; Length border_spacing_horizontal(Layout::Node const&) const;
Length border_spacing_vertical(Layout::Node const&) const; Length border_spacing_vertical(Layout::Node const&) const;
CaptionSide caption_side() const; CaptionSide caption_side() const;

View file

@ -121,6 +121,7 @@ public:
static CSS::TextOverflow text_overflow() { return CSS::TextOverflow::Clip; } static CSS::TextOverflow text_overflow() { return CSS::TextOverflow::Clip; }
static CSS::LengthPercentage text_indent() { return CSS::Length::make_px(0); } static CSS::LengthPercentage text_indent() { return CSS::Length::make_px(0); }
static CSS::TextWrapMode text_wrap_mode() { return CSS::TextWrapMode::Wrap; } static CSS::TextWrapMode text_wrap_mode() { return CSS::TextWrapMode::Wrap; }
static CSS::TextRendering text_rendering() { return CSS::TextRendering::Auto; }
static CSS::Display display() { return CSS::Display { CSS::DisplayOutside::Inline, CSS::DisplayInside::Flow }; } static CSS::Display display() { return CSS::Display { CSS::DisplayOutside::Inline, CSS::DisplayInside::Flow }; }
static Color color() { return Color::Black; } static Color color() { return Color::Black; }
static Color stop_color() { return Color::Black; } static Color stop_color() { return Color::Black; }
@ -437,6 +438,7 @@ public:
CSS::TextJustify text_justify() const { return m_inherited.text_justify; } CSS::TextJustify text_justify() const { return m_inherited.text_justify; }
CSS::LengthPercentage const& text_indent() const { return m_inherited.text_indent; } CSS::LengthPercentage const& text_indent() const { return m_inherited.text_indent; }
CSS::TextWrapMode text_wrap_mode() const { return m_inherited.text_wrap_mode; } CSS::TextWrapMode text_wrap_mode() const { return m_inherited.text_wrap_mode; }
CSS::TextRendering text_rendering() const { return m_inherited.text_rendering; }
Vector<CSS::TextDecorationLine> const& text_decoration_line() const { return m_noninherited.text_decoration_line; } Vector<CSS::TextDecorationLine> const& text_decoration_line() const { return m_noninherited.text_decoration_line; }
CSS::LengthPercentage const& text_decoration_thickness() const { return m_noninherited.text_decoration_thickness; } CSS::LengthPercentage const& text_decoration_thickness() const { return m_noninherited.text_decoration_thickness; }
CSS::TextDecorationStyle text_decoration_style() const { return m_noninherited.text_decoration_style; } CSS::TextDecorationStyle text_decoration_style() const { return m_noninherited.text_decoration_style; }
@ -645,6 +647,7 @@ protected:
CSS::TextTransform text_transform { InitialValues::text_transform() }; CSS::TextTransform text_transform { InitialValues::text_transform() };
CSS::LengthPercentage text_indent { InitialValues::text_indent() }; CSS::LengthPercentage text_indent { InitialValues::text_indent() };
CSS::TextWrapMode text_wrap_mode { InitialValues::text_wrap_mode() }; CSS::TextWrapMode text_wrap_mode { InitialValues::text_wrap_mode() };
CSS::TextRendering text_rendering { InitialValues::text_rendering() };
CSS::WhiteSpaceCollapse white_space_collapse { InitialValues::white_space_collapse() }; CSS::WhiteSpaceCollapse white_space_collapse { InitialValues::white_space_collapse() };
CSS::WordBreak word_break { InitialValues::word_break() }; CSS::WordBreak word_break { InitialValues::word_break() };
CSS::LengthOrCalculated word_spacing { InitialValues::word_spacing() }; CSS::LengthOrCalculated word_spacing { InitialValues::word_spacing() };
@ -851,6 +854,7 @@ public:
void set_text_indent(CSS::LengthPercentage value) { m_inherited.text_indent = move(value); } void set_text_indent(CSS::LengthPercentage value) { m_inherited.text_indent = move(value); }
void set_text_wrap_mode(CSS::TextWrapMode value) { m_inherited.text_wrap_mode = value; } void set_text_wrap_mode(CSS::TextWrapMode value) { m_inherited.text_wrap_mode = value; }
void set_text_overflow(CSS::TextOverflow value) { m_noninherited.text_overflow = value; } void set_text_overflow(CSS::TextOverflow value) { m_noninherited.text_overflow = value; }
void set_text_rendering(CSS::TextRendering value) { m_inherited.text_rendering = value; }
void set_webkit_text_fill_color(Color value) { m_inherited.webkit_text_fill_color = value; } void set_webkit_text_fill_color(Color value) { m_inherited.webkit_text_fill_color = value; }
void set_position(CSS::Positioning position) { m_noninherited.position = position; } void set_position(CSS::Positioning position) { m_noninherited.position = position; }
void set_white_space_collapse(CSS::WhiteSpaceCollapse value) { m_inherited.white_space_collapse = value; } void set_white_space_collapse(CSS::WhiteSpaceCollapse value) { m_inherited.white_space_collapse = value; }

View file

@ -633,6 +633,12 @@
"clip", "clip",
"ellipsis" "ellipsis"
], ],
"text-rendering": [
"auto",
"optimizespeed",
"optimizelegibility",
"geometricprecision"
],
"text-transform": [ "text-transform": [
"capitalize", "capitalize",
"full-size-kana", "full-size-kana",

View file

@ -216,6 +216,7 @@
"full-size-kana", "full-size-kana",
"full-width", "full-width",
"fullscreen", "fullscreen",
"geometricprecision",
"grab", "grab",
"grabbing", "grabbing",
"grammar-error", "grammar-error",
@ -360,6 +361,7 @@
"on", "on",
"opaque", "opaque",
"open-quote", "open-quote",
"optimizelegibility",
"optimizequality", "optimizequality",
"optimizespeed", "optimizespeed",
"optional", "optional",

View file

@ -3003,6 +3003,15 @@
"text-overflow" "text-overflow"
] ]
}, },
"text-rendering": {
"affects-layout": false,
"animation-type": "discrete",
"inherited": true,
"initial": "auto",
"valid-types": [
"text-rendering"
]
},
"text-shadow": { "text-shadow": {
"affects-layout": false, "affects-layout": false,
"animation-type": "custom", "animation-type": "custom",

View file

@ -651,6 +651,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_text_align(computed_style.text_align()); computed_values.set_text_align(computed_style.text_align());
computed_values.set_text_justify(computed_style.text_justify()); computed_values.set_text_justify(computed_style.text_justify());
computed_values.set_text_overflow(computed_style.text_overflow()); computed_values.set_text_overflow(computed_style.text_overflow());
computed_values.set_text_rendering(computed_style.text_rendering());
if (auto text_indent = computed_style.length_percentage(CSS::PropertyID::TextIndent); text_indent.has_value()) if (auto text_indent = computed_style.length_percentage(CSS::PropertyID::TextIndent); text_indent.has_value())
computed_values.set_text_indent(text_indent.release_value()); computed_values.set_text_indent(text_indent.release_value());

View file

@ -76,6 +76,7 @@ static Array const attribute_style_properties {
NamedPropertyID(CSS::PropertyID::StrokeOpacity), NamedPropertyID(CSS::PropertyID::StrokeOpacity),
NamedPropertyID(CSS::PropertyID::StrokeWidth), NamedPropertyID(CSS::PropertyID::StrokeWidth),
NamedPropertyID(CSS::PropertyID::TextAnchor), NamedPropertyID(CSS::PropertyID::TextAnchor),
NamedPropertyID(CSS::PropertyID::TextRendering),
NamedPropertyID(CSS::PropertyID::TextOverflow), NamedPropertyID(CSS::PropertyID::TextOverflow),
NamedPropertyID(CSS::PropertyID::TransformOrigin), NamedPropertyID(CSS::PropertyID::TransformOrigin),
NamedPropertyID(CSS::PropertyID::UnicodeBidi), NamedPropertyID(CSS::PropertyID::UnicodeBidi),

View file

@ -56,6 +56,7 @@ All properties associated with getComputedStyle(document.body):
"text-decoration-line", "text-decoration-line",
"text-indent", "text-indent",
"text-justify", "text-justify",
"text-rendering",
"text-shadow", "text-shadow",
"text-transform", "text-transform",
"text-wrap-mode", "text-wrap-mode",

View file

@ -618,6 +618,8 @@ All supported properties and their default values exposed from CSSStylePropertie
'text-justify': 'auto' 'text-justify': 'auto'
'textOverflow': 'clip' 'textOverflow': 'clip'
'text-overflow': 'clip' 'text-overflow': 'clip'
'textRendering': 'auto'
'text-rendering': 'auto'
'textShadow': 'none' 'textShadow': 'none'
'text-shadow': 'none' 'text-shadow': 'none'
'textTransform': 'none' 'textTransform': 'none'

View file

@ -54,6 +54,7 @@ text-anchor: start
text-decoration-line: none text-decoration-line: none
text-indent: 0px text-indent: 0px
text-justify: auto text-justify: auto
text-rendering: auto
text-shadow: none text-shadow: none
text-transform: none text-transform: none
text-wrap-mode: wrap text-wrap-mode: wrap
@ -88,7 +89,7 @@ background-position-x: 0%
background-position-y: 0% background-position-y: 0%
background-repeat: repeat background-repeat: repeat
background-size: auto auto background-size: auto auto
block-size: 1350px block-size: 1365px
border-block-end-color: rgb(0, 0, 0) border-block-end-color: rgb(0, 0, 0)
border-block-end-style: none border-block-end-style: none
border-block-end-width: 0px border-block-end-width: 0px
@ -153,7 +154,7 @@ grid-row-start: auto
grid-template-areas: none grid-template-areas: none
grid-template-columns: none grid-template-columns: none
grid-template-rows: none grid-template-rows: none
height: 2325px height: 2340px
inline-size: 784px inline-size: 784px
inset-block-end: auto inset-block-end: auto
inset-block-start: auto inset-block-start: auto

View file

@ -1,8 +1,8 @@
Harness status: OK Harness status: OK
Found 236 tests Found 237 tests
230 Pass 231 Pass
6 Fail 6 Fail
Pass accent-color Pass accent-color
Pass border-collapse Pass border-collapse
@ -58,6 +58,7 @@ Pass text-anchor
Pass text-decoration-line Pass text-decoration-line
Pass text-indent Pass text-indent
Pass text-justify Pass text-justify
Pass text-rendering
Pass text-shadow Pass text-shadow
Pass text-transform Pass text-transform
Pass text-wrap-mode Pass text-wrap-mode

View file

@ -0,0 +1,7 @@
Harness status: OK
Found 2 tests
2 Pass
Pass e.style['text-rendering'] = "crispedges" should not set the property value
Pass e.style['text-rendering'] = "auto optimizespeed" should not set the property value

View file

@ -0,0 +1,9 @@
Harness status: OK
Found 4 tests
4 Pass
Pass e.style['text-rendering'] = "auto" should set the property value
Pass e.style['text-rendering'] = "optimizespeed" should set the property value
Pass e.style['text-rendering'] = "optimizelegibility" should set the property value
Pass e.style['text-rendering'] = "geometricprecision" should set the property value

View file

@ -1,8 +1,8 @@
Harness status: OK Harness status: OK
Found 42 tests Found 43 tests
38 Pass 39 Pass
4 Fail 4 Fail
Pass clip-path presentation attribute supported on an irrelevant element Pass clip-path presentation attribute supported on an irrelevant element
Pass clip-rule presentation attribute supported on an irrelevant element Pass clip-rule presentation attribute supported on an irrelevant element
@ -40,6 +40,7 @@ Pass stroke-width presentation attribute supported on an irrelevant element
Pass text-anchor presentation attribute supported on an irrelevant element Pass text-anchor presentation attribute supported on an irrelevant element
Fail text-decoration presentation attribute supported on an irrelevant element Fail text-decoration presentation attribute supported on an irrelevant element
Pass text-overflow presentation attribute supported on an irrelevant element Pass text-overflow presentation attribute supported on an irrelevant element
Pass text-rendering presentation attribute supported on an irrelevant element
Pass transform-origin presentation attribute supported on an irrelevant element Pass transform-origin presentation attribute supported on an irrelevant element
Pass unicode-bidi presentation attribute supported on an irrelevant element Pass unicode-bidi presentation attribute supported on an irrelevant element
Pass visibility presentation attribute supported on an irrelevant element Pass visibility presentation attribute supported on an irrelevant element

View file

@ -1,8 +1,8 @@
Harness status: OK Harness status: OK
Found 52 tests Found 53 tests
41 Pass 42 Pass
11 Fail 11 Fail
Pass clip-path presentation attribute supported on a relevant element Pass clip-path presentation attribute supported on a relevant element
Pass clip-rule presentation attribute supported on a relevant element Pass clip-rule presentation attribute supported on a relevant element
@ -46,6 +46,7 @@ Pass stroke-width presentation attribute supported on a relevant element
Pass text-anchor presentation attribute supported on a relevant element Pass text-anchor presentation attribute supported on a relevant element
Fail text-decoration presentation attribute supported on a relevant element Fail text-decoration presentation attribute supported on a relevant element
Pass text-overflow presentation attribute supported on a relevant element Pass text-overflow presentation attribute supported on a relevant element
Pass text-rendering presentation attribute supported on a relevant element
Pass transform-origin presentation attribute supported on a relevant element Pass transform-origin presentation attribute supported on a relevant element
Fail transform presentation attribute supported on a relevant element Fail transform presentation attribute supported on a relevant element
Pass unicode-bidi presentation attribute supported on a relevant element Pass unicode-bidi presentation attribute supported on a relevant element

View file

@ -1,8 +1,8 @@
Harness status: OK Harness status: OK
Found 42 tests Found 43 tests
38 Pass 39 Pass
4 Fail 4 Fail
Pass clip-path presentation attribute supported on an unknown SVG element Pass clip-path presentation attribute supported on an unknown SVG element
Pass clip-rule presentation attribute supported on an unknown SVG element Pass clip-rule presentation attribute supported on an unknown SVG element
@ -40,6 +40,7 @@ Pass stroke-width presentation attribute supported on an unknown SVG element
Pass text-anchor presentation attribute supported on an unknown SVG element Pass text-anchor presentation attribute supported on an unknown SVG element
Fail text-decoration presentation attribute supported on an unknown SVG element Fail text-decoration presentation attribute supported on an unknown SVG element
Pass text-overflow presentation attribute supported on an unknown SVG element Pass text-overflow presentation attribute supported on an unknown SVG element
Pass text-rendering presentation attribute supported on an unknown SVG element
Pass transform-origin presentation attribute supported on an unknown SVG element Pass transform-origin presentation attribute supported on an unknown SVG element
Pass unicode-bidi presentation attribute supported on an unknown SVG element Pass unicode-bidi presentation attribute supported on an unknown SVG element
Pass visibility presentation attribute supported on an unknown SVG element Pass visibility presentation attribute supported on an unknown SVG element

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
width="800px" height="800px">
<title>SVG Painting: parsing text-rendering with invalid values</title>
<metadata>
<h:link rel="help" href="https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty"/>
<h:meta name="assert" content="text-rendering supports only the grammar 'auto | optimizeSpeed | optimizeLegibility | geometricPrecision'."/>
</metadata>
<g id="target"></g>
<h:script src="../../../resources/testharness.js"/>
<h:script src="../../../resources/testharnessreport.js"/>
<h:script src="../../../css/support/parsing-testcommon.js"/>
<script><![CDATA[
test_invalid_value("text-rendering", "crispedges");
test_invalid_value("text-rendering", "auto optimizespeed");
]]></script>
</svg>

After

Width:  |  Height:  |  Size: 856 B

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:h="http://www.w3.org/1999/xhtml"
width="800px" height="800px">
<title>SVG Painting: parsing text-rendering with valid values</title>
<metadata>
<h:link rel="help" href="https://svgwg.org/svg2-draft/painting.html#TextRenderingProperty"/>
<h:meta name="assert" content="text-rendering supports the full grammar 'auto | optimizeSpeed | optimizeLegibility | geometricPrecision'."/>
</metadata>
<g id="target"></g>
<h:script src="../../../resources/testharness.js"/>
<h:script src="../../../resources/testharnessreport.js"/>
<h:script src="../../../css/support/parsing-testcommon.js"/>
<script><![CDATA[
test_valid_value("text-rendering", "auto");
test_valid_value("text-rendering", "optimizespeed");
test_valid_value("text-rendering", "optimizelegibility");
test_valid_value("text-rendering", "geometricprecision");
]]></script>
</svg>

After

Width:  |  Height:  |  Size: 955 B