LibWeb: Parse the transform-origin z-value

This commit is contained in:
Tim Ledbetter 2025-06-14 00:52:42 +01:00 committed by Alexander Kalenik
commit 68d3ddb1a7
Notes: github-actions[bot] 2025-06-15 14:02:53 +00:00
10 changed files with 88 additions and 77 deletions

View file

@ -656,15 +656,16 @@ TransformOrigin ComputedProperties::transform_origin() const
};
auto const& value = property(PropertyID::TransformOrigin);
if (!value.is_value_list() || value.as_value_list().size() != 2)
if (!value.is_value_list() || value.as_value_list().size() != 3)
return {};
auto const& list = value.as_value_list();
auto x_value = length_percentage_with_keywords_resolved(list.values()[0]);
auto y_value = length_percentage_with_keywords_resolved(list.values()[1]);
if (!x_value.has_value() || !y_value.has_value())
auto z_value = length_percentage_for_style_value(list.values()[2]);
if (!x_value.has_value() || !y_value.has_value() || !z_value.has_value())
return {};
return { x_value.value(), y_value.value() };
return { x_value.value(), y_value.value(), z_value.value() };
}
Optional<Color> ComputedProperties::accent_color(Layout::NodeWithStyle const& node) const

View file

@ -354,6 +354,7 @@ struct WhiteSpaceTrimData {
struct TransformOrigin {
CSS::LengthPercentage x { Percentage(50) };
CSS::LengthPercentage y { Percentage(50) };
CSS::LengthPercentage z { Percentage(0) };
};
struct ShadowData {

View file

@ -3806,7 +3806,6 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_value(TokenStream<ComponentV
}
// https://www.w3.org/TR/css-transforms-1/#propdef-transform-origin
// FIXME: This only supports a 2D position
RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<ComponentValue>& tokens)
{
enum class Axis {
@ -3851,13 +3850,14 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<Com
auto transaction = tokens.begin_transaction();
auto make_list = [&transaction](NonnullRefPtr<CSSStyleValue const> const& x_value, NonnullRefPtr<CSSStyleValue const> const& y_value) -> NonnullRefPtr<StyleValueList> {
auto make_list = [&transaction](NonnullRefPtr<CSSStyleValue const> const& x_value, NonnullRefPtr<CSSStyleValue const> const& y_value, NonnullRefPtr<CSSStyleValue const> const& z_value) -> NonnullRefPtr<StyleValueList> {
transaction.commit();
return StyleValueList::create(StyleValueVector { x_value, y_value }, StyleValueList::Separator::Space);
return StyleValueList::create(StyleValueVector { x_value, y_value, z_value }, StyleValueList::Separator::Space);
};
switch (tokens.remaining_token_count()) {
case 1: {
static CSSStyleValue const& zero_value = LengthStyleValue::create(Length::make_px(0));
if (tokens.remaining_token_count() == 1) {
auto single_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
if (!single_value.has_value())
return nullptr;
@ -3866,18 +3866,31 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<Com
switch (single_value->axis) {
case Axis::None:
case Axis::X:
return make_list(single_value->offset, CSSKeywordValue::create(Keyword::Center));
return make_list(single_value->offset, CSSKeywordValue::create(Keyword::Center), zero_value);
case Axis::Y:
return make_list(CSSKeywordValue::create(Keyword::Center), single_value->offset);
return make_list(CSSKeywordValue::create(Keyword::Center), single_value->offset, zero_value);
}
VERIFY_NOT_REACHED();
}
case 2: {
if (tokens.remaining_token_count() > 3)
return nullptr;
auto first_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
auto second_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
auto third_value = parse_length_value(tokens);
if ((first_value->offset->is_length() || first_value->offset->is_percentage()) && second_value->axis == Axis::X)
return nullptr;
if ((second_value->offset->is_length() || second_value->offset->is_percentage()) && first_value->axis == Axis::Y)
return nullptr;
if (!first_value.has_value() || !second_value.has_value())
return nullptr;
if (!third_value)
third_value = zero_value;
RefPtr<CSSStyleValue const> x_value;
RefPtr<CSSStyleValue const> y_value;
@ -3910,16 +3923,13 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<Com
}
// If two or more values are defined and either no value is a keyword, or the only used keyword is center,
// then the first value represents the horizontal position (or offset) and the second represents the vertical position (or offset).
// FIXME: A third value always represents the Z position (or offset) and must be of type <length>.
// A third value always represents the Z position (or offset) and must be of type <length>.
if (first_value->axis == Axis::None && second_value->axis == Axis::None) {
x_value = first_value->offset;
y_value = second_value->offset;
}
return make_list(x_value.release_nonnull(), y_value.release_nonnull());
}
}
return nullptr;
return make_list(x_value.release_nonnull(), y_value.release_nonnull(), third_value.release_nonnull());
}
RefPtr<CSSStyleValue const> Parser::parse_transition_value(TokenStream<ComponentValue>& tokens)

View file

@ -123,9 +123,9 @@ All supported properties and their default values exposed from CSSStylePropertie
'WebkitTransform': 'none'
'webkitTransform': 'none'
'-webkit-transform': 'none'
'WebkitTransformOrigin': '50% 50%'
'webkitTransformOrigin': '50% 50%'
'-webkit-transform-origin': '50% 50%'
'WebkitTransformOrigin': '50% 50% 0px'
'webkitTransformOrigin': '50% 50% 0px'
'-webkit-transform-origin': '50% 50% 0px'
'WebkitTransition': 'all'
'webkitTransition': 'all'
'-webkit-transition': 'all'
@ -630,8 +630,8 @@ All supported properties and their default values exposed from CSSStylePropertie
'transform': 'none'
'transformBox': 'view-box'
'transform-box': 'view-box'
'transformOrigin': '50% 50%'
'transform-origin': '50% 50%'
'transformOrigin': '50% 50% 0px'
'transform-origin': '50% 50% 0px'
'transition': 'all'
'transitionBehavior': 'normal'
'transition-behavior': 'normal'

View file

@ -150,8 +150,8 @@ text-indent: 'calc(2%)' -> '2%'
text-indent: 'calc(2% * var(--n))' -> 'calc(2 * 2%)'
top: 'calc(2%)' -> '2%'
top: 'calc(2% * var(--n))' -> 'calc(2 * 2%)'
transform-origin: 'calc(2px) calc(2%)' -> '2px 2%'
transform-origin: 'calc(2px * var(--n)) calc(2% * var(--n))' -> '4px calc(2 * 2%)'
transform-origin: 'calc(2px) calc(2%)' -> '2px 2% 0px'
transform-origin: 'calc(2px * var(--n)) calc(2% * var(--n))' -> '4px calc(2 * 2%) 0px'
transition-delay: 'calc(2s)' -> '2s'
transition-delay: 'calc(2s * var(--n))' -> '4s'
transition-duration: 'calc(2s)' -> '2s'

View file

@ -221,7 +221,7 @@ top: auto
touch-action: auto
transform: none
transform-box: view-box
transform-origin: 50% 50%
transform-origin: 50% 50% 0px
transition-behavior: normal
transition-delay: 0s
transition-duration: 0s

View file

@ -1,7 +1,7 @@
center => center center
10px => 10px center
25% => 25% center
left 20% => left 20%
20px bottom => 20px bottom
top right => right top
center => center center 0px
10px => 10px center 0px
25% => 25% center 0px
left 20% => left 20% 0px
20px bottom => 20px bottom 0px
top right => right top 0px
"center" => (invalid)

View file

@ -1,8 +1,8 @@
Harness status: OK
Found 203 tests
Found 204 tests
199 Pass
200 Pass
4 Fail
Pass accent-color
Pass border-collapse
@ -192,6 +192,7 @@ Pass top
Pass touch-action
Fail transform
Pass transform-box
Pass transform-origin
Pass transition-behavior
Pass transition-delay
Pass transition-duration

View file

@ -2,13 +2,12 @@ Harness status: OK
Found 10 tests
8 Pass
2 Fail
10 Pass
Pass e.style['transform-origin'] = "1px 2px 3%" should not set the property value
Pass e.style['transform-origin'] = "1px 2px left" should not set the property value
Pass e.style['transform-origin'] = "1px 2px 3px 4px" should not set the property value
Fail e.style['transform-origin'] = "1px left" should not set the property value
Fail e.style['transform-origin'] = "top 1px" should not set the property value
Pass e.style['transform-origin'] = "1px left" should not set the property value
Pass e.style['transform-origin'] = "top 1px" should not set the property value
Pass e.style['transform-origin'] = "right left" should not set the property value
Pass e.style['transform-origin'] = "top bottom" should not set the property value
Pass e.style['transform-origin'] = "bottom 10% right 20%" should not set the property value

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 16 tests
12 Pass
4 Fail
16 Pass
Pass e.style['transform-origin'] = "left" should set the property value
Pass e.style['transform-origin'] = "center" should set the property value
Pass e.style['transform-origin'] = "right" should set the property value
@ -15,8 +14,8 @@ Pass e.style['transform-origin'] = "-4%" should set the property value
Pass e.style['transform-origin'] = "left center" should set the property value
Pass e.style['transform-origin'] = "center top" should set the property value
Pass e.style['transform-origin'] = "right -4%" should set the property value
Fail e.style['transform-origin'] = "-1px bottom 5px" should set the property value
Fail e.style['transform-origin'] = "center left 6px" should set the property value
Pass e.style['transform-origin'] = "-1px bottom 5px" should set the property value
Pass e.style['transform-origin'] = "center left 6px" should set the property value
Pass e.style['transform-origin'] = "top center" should set the property value
Fail e.style['transform-origin'] = "bottom right 7px" should set the property value
Fail e.style['transform-origin'] = "-1px -2px -3px" should set the property value
Pass e.style['transform-origin'] = "bottom right 7px" should set the property value
Pass e.style['transform-origin'] = "-1px -2px -3px" should set the property value