LibWeb: Return absolutized computed value for outline width property

This commit is contained in:
Tim Ledbetter 2025-04-04 23:56:09 +01:00 committed by Andreas Kling
parent b05b9378ed
commit 32812f5db0
Notes: github-actions[bot] 2025-04-05 10:55:27 +00:00
7 changed files with 100 additions and 32 deletions

View file

@ -960,6 +960,10 @@ RefPtr<CSSStyleValue const> CSSStyleProperties::style_value_for_computed_propert
auto border_top_width = layout_node.computed_values().border_top();
return LengthStyleValue::create(Length::make_px(border_top_width.width));
}
case PropertyID::OutlineWidth: {
auto outline_width = layout_node.computed_values().outline_width();
return LengthStyleValue::create(outline_width);
}
case PropertyID::WebkitTextFillColor:
return CSSColorValue::create_from_color(layout_node.computed_values().webkit_text_fill_color(), ColorSyntax::Modern);
case PropertyID::Invalid:

View file

@ -728,6 +728,29 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_transition_delay(transition_delay.resolve_time({ .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) }).value());
}
auto resolve_border_width = [&](CSS::PropertyID width_property) -> CSSPixels {
auto const& value = computed_style.property(width_property);
if (value.is_calculated())
return max(CSSPixels { 0 },
value.as_calculated().resolve_length({ .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) })->to_px(*this));
if (value.is_length())
return value.as_length().length().to_px(*this);
if (value.is_keyword()) {
// https://www.w3.org/TR/css-backgrounds-3/#valdef-line-width-thin
switch (value.to_keyword()) {
case CSS::Keyword::Thin:
return 1;
case CSS::Keyword::Medium:
return 3;
case CSS::Keyword::Thick:
return 5;
default:
VERIFY_NOT_REACHED();
}
}
VERIFY_NOT_REACHED();
};
auto do_border_style = [&](CSS::BorderData& border, CSS::PropertyID width_property, CSS::PropertyID color_property, CSS::PropertyID style_property) {
// FIXME: The default border color value is `currentcolor`, but since we can't resolve that easily,
// we just manually grab the value from `color`. This makes it dependent on `color` being
@ -743,30 +766,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
if (border.line_style == CSS::LineStyle::None || border.line_style == CSS::LineStyle::Hidden) {
border.width = 0;
} else {
auto resolve_border_width = [&]() -> CSSPixels {
auto const& value = computed_style.property(width_property);
if (value.is_calculated())
return max(CSSPixels { 0 },
value.as_calculated().resolve_length({ .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) })->to_px(*this));
if (value.is_length())
return value.as_length().length().to_px(*this);
if (value.is_keyword()) {
// https://www.w3.org/TR/css-backgrounds-3/#valdef-line-width-thin
switch (value.to_keyword()) {
case CSS::Keyword::Thin:
return 1;
case CSS::Keyword::Medium:
return 3;
case CSS::Keyword::Thick:
return 5;
default:
VERIFY_NOT_REACHED();
}
}
VERIFY_NOT_REACHED();
};
border.width = snap_a_length_as_a_border_width(document().page().client().device_pixels_per_css_pixel(), resolve_border_width());
border.width = snap_a_length_as_a_border_width(document().page().client().device_pixels_per_css_pixel(), resolve_border_width(width_property));
}
};
@ -780,8 +780,13 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
if (auto const& outline_offset = computed_style.property(CSS::PropertyID::OutlineOffset); outline_offset.is_length())
computed_values.set_outline_offset(outline_offset.as_length().length());
computed_values.set_outline_style(computed_style.outline_style());
if (auto const& outline_width = computed_style.property(CSS::PropertyID::OutlineWidth); outline_width.is_length())
computed_values.set_outline_width(outline_width.as_length().length());
CSSPixels resolved_outline_width = 0;
if (computed_values.outline_style() != CSS::OutlineStyle::None)
resolved_outline_width = max(CSSPixels { 0 }, resolve_border_width(CSS::PropertyID::OutlineWidth));
auto snapped_outline_width = snap_a_length_as_a_border_width(document().page().client().device_pixels_per_css_pixel(), resolved_outline_width);
computed_values.set_outline_width(CSS::Length::make_px(snapped_outline_width));
computed_values.set_grid_auto_columns(computed_style.grid_auto_columns());
computed_values.set_grid_auto_rows(computed_style.grid_auto_rows());

View file

@ -496,15 +496,15 @@ All supported properties and their default values exposed from CSSStylePropertie
'object-position': '50% 50%'
'opacity': '1'
'order': '0'
'outline': 'rgb(0, 0, 0) none medium'
'outline': 'rgb(0, 0, 0) none 0px'
'outlineColor': 'rgb(0, 0, 0)'
'outline-color': 'rgb(0, 0, 0)'
'outlineOffset': '0px'
'outline-offset': '0px'
'outlineStyle': 'none'
'outline-style': 'none'
'outlineWidth': 'medium'
'outline-width': 'medium'
'outlineWidth': '0px'
'outline-width': '0px'
'overflow': 'visible'
'overflowX': 'visible'
'overflow-x': 'visible'

View file

@ -116,8 +116,8 @@ order: 'calc(2)' -> '2'
order: 'calc(2 * var(--n))' -> '4'
outline-offset: 'calc(2px)' -> '2px'
outline-offset: 'calc(2px * var(--n))' -> '4px'
outline-width: 'calc(2px)' -> '2px'
outline-width: 'calc(2px * var(--n))' -> '4px'
outline-width: 'calc(2px)' -> '0px'
outline-width: 'calc(2px * var(--n))' -> '0px'
padding-bottom: 'calc(2px)' -> '2px'
padding-bottom: 'calc(2px * var(--n))' -> '4px'
padding-left: 'calc(2%)' -> '15.6875px'

View file

@ -186,7 +186,7 @@ order: 0
outline-color: rgb(0, 0, 0)
outline-offset: 0px
outline-style: none
outline-width: medium
outline-width: 0px
overflow-x: visible
overflow-y: visible
padding-block-end: 0px

View file

@ -0,0 +1,14 @@
Harness status: OK
Found 9 tests
9 Pass
Pass Property outline-width value '2.5px'
Pass Property outline-width value '10px'
Pass Property outline-width value '0.5em'
Pass Property outline-width value 'calc(10px + 0.5em)'
Pass Property outline-width value 'calc(10px - 0.5em)'
Pass Property outline-width value 'thin'
Pass Property outline-width value 'medium'
Pass Property outline-width value 'thick'
Pass outline-width is 0 when outline-style is none

View file

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS UI Level 3: getComputedStyle().outlineWidth</title>
<link rel="help" href="https://drafts.csswg.org/css-ui-3/#outline-width">
<meta name="assert" content="outline-width computed value is absolute length, 0 if the outline style is none.">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/computed-testcommon.js"></script>
</head>
<body>
<style>
#target {
font-size: 40px;
border-style: dotted; /* Avoid border-*-width computed style 0 */
border-top-width: thin;
border-right-width: medium;
border-bottom-width: thick;
outline-style: dotted; /* Avoid outline-width computed style 0 */
}
</style>
<div id="target"></div>
<script>
test_computed_value("outline-width", "2.5px", "2px");
test_computed_value("outline-width", "10px");
test_computed_value("outline-width", "0.5em", "20px");
test_computed_value("outline-width", "calc(10px + 0.5em)", "30px");
test_computed_value("outline-width", "calc(10px - 0.5em)", "0px");
test_computed_value("outline-width", "thin", getComputedStyle(target).borderTopWidth);
test_computed_value("outline-width", "medium", getComputedStyle(target).borderRightWidth);
test_computed_value("outline-width", "thick", getComputedStyle(target).borderBottomWidth);
test(() => {
target.style['outline-width'] = '10px';
target.style['outline-style'] = 'none';
assert_equals(getComputedStyle(target)['outline-width'], '0px');
target.style['outline-style'] = '';
}, 'outline-width is 0 when outline-style is none');
</script>
</body>
</html>