mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 04:09:13 +00:00
LibWeb: Parse the transform-origin
z-value
This commit is contained in:
parent
a8d5758777
commit
68d3ddb1a7
Notes:
github-actions[bot]
2025-06-15 14:02:53 +00:00
Author: https://github.com/tcl3
Commit: 68d3ddb1a7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5085
10 changed files with 88 additions and 77 deletions
|
@ -656,15 +656,16 @@ TransformOrigin ComputedProperties::transform_origin() const
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const& value = property(PropertyID::TransformOrigin);
|
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 {};
|
return {};
|
||||||
auto const& list = value.as_value_list();
|
auto const& list = value.as_value_list();
|
||||||
|
|
||||||
auto x_value = length_percentage_with_keywords_resolved(list.values()[0]);
|
auto x_value = length_percentage_with_keywords_resolved(list.values()[0]);
|
||||||
auto y_value = length_percentage_with_keywords_resolved(list.values()[1]);
|
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 {};
|
||||||
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
|
Optional<Color> ComputedProperties::accent_color(Layout::NodeWithStyle const& node) const
|
||||||
|
|
|
@ -354,6 +354,7 @@ struct WhiteSpaceTrimData {
|
||||||
struct TransformOrigin {
|
struct TransformOrigin {
|
||||||
CSS::LengthPercentage x { Percentage(50) };
|
CSS::LengthPercentage x { Percentage(50) };
|
||||||
CSS::LengthPercentage y { Percentage(50) };
|
CSS::LengthPercentage y { Percentage(50) };
|
||||||
|
CSS::LengthPercentage z { Percentage(0) };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShadowData {
|
struct ShadowData {
|
||||||
|
|
|
@ -3806,7 +3806,6 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_value(TokenStream<ComponentV
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-transforms-1/#propdef-transform-origin
|
// 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)
|
RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
enum class Axis {
|
enum class Axis {
|
||||||
|
@ -3851,13 +3850,14 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<Com
|
||||||
|
|
||||||
auto transaction = tokens.begin_transaction();
|
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();
|
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()) {
|
static CSSStyleValue const& zero_value = LengthStyleValue::create(Length::make_px(0));
|
||||||
case 1: {
|
|
||||||
|
if (tokens.remaining_token_count() == 1) {
|
||||||
auto single_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
|
auto single_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
|
||||||
if (!single_value.has_value())
|
if (!single_value.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -3866,60 +3866,70 @@ RefPtr<CSSStyleValue const> Parser::parse_transform_origin_value(TokenStream<Com
|
||||||
switch (single_value->axis) {
|
switch (single_value->axis) {
|
||||||
case Axis::None:
|
case Axis::None:
|
||||||
case Axis::X:
|
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:
|
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();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
case 2: {
|
|
||||||
auto first_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
|
if (tokens.remaining_token_count() > 3)
|
||||||
auto second_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
|
return nullptr;
|
||||||
if (!first_value.has_value() || !second_value.has_value())
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (first_value->axis == Axis::X) {
|
||||||
|
x_value = first_value->offset;
|
||||||
|
} else if (first_value->axis == Axis::Y) {
|
||||||
|
y_value = first_value->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (second_value->axis == Axis::X) {
|
||||||
|
if (x_value)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
x_value = second_value->offset;
|
||||||
RefPtr<CSSStyleValue const> x_value;
|
// Put the other in Y since its axis can't have been X
|
||||||
RefPtr<CSSStyleValue const> y_value;
|
y_value = first_value->offset;
|
||||||
|
} else if (second_value->axis == Axis::Y) {
|
||||||
if (first_value->axis == Axis::X) {
|
if (y_value)
|
||||||
x_value = first_value->offset;
|
return nullptr;
|
||||||
} else if (first_value->axis == Axis::Y) {
|
y_value = second_value->offset;
|
||||||
y_value = first_value->offset;
|
// Put the other in X since its axis can't have been Y
|
||||||
}
|
x_value = first_value->offset;
|
||||||
|
} else {
|
||||||
if (second_value->axis == Axis::X) {
|
if (x_value) {
|
||||||
if (x_value)
|
VERIFY(!y_value);
|
||||||
return nullptr;
|
|
||||||
x_value = second_value->offset;
|
|
||||||
// Put the other in Y since its axis can't have been X
|
|
||||||
y_value = first_value->offset;
|
|
||||||
} else if (second_value->axis == Axis::Y) {
|
|
||||||
if (y_value)
|
|
||||||
return nullptr;
|
|
||||||
y_value = second_value->offset;
|
y_value = second_value->offset;
|
||||||
// Put the other in X since its axis can't have been Y
|
|
||||||
x_value = first_value->offset;
|
|
||||||
} else {
|
} else {
|
||||||
if (x_value) {
|
VERIFY(!x_value);
|
||||||
VERIFY(!y_value);
|
x_value = second_value->offset;
|
||||||
y_value = second_value->offset;
|
|
||||||
} else {
|
|
||||||
VERIFY(!x_value);
|
|
||||||
x_value = second_value->offset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 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>.
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
// 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).
|
||||||
|
// 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 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)
|
RefPtr<CSSStyleValue const> Parser::parse_transition_value(TokenStream<ComponentValue>& tokens)
|
||||||
|
|
|
@ -123,9 +123,9 @@ All supported properties and their default values exposed from CSSStylePropertie
|
||||||
'WebkitTransform': 'none'
|
'WebkitTransform': 'none'
|
||||||
'webkitTransform': 'none'
|
'webkitTransform': 'none'
|
||||||
'-webkit-transform': 'none'
|
'-webkit-transform': 'none'
|
||||||
'WebkitTransformOrigin': '50% 50%'
|
'WebkitTransformOrigin': '50% 50% 0px'
|
||||||
'webkitTransformOrigin': '50% 50%'
|
'webkitTransformOrigin': '50% 50% 0px'
|
||||||
'-webkit-transform-origin': '50% 50%'
|
'-webkit-transform-origin': '50% 50% 0px'
|
||||||
'WebkitTransition': 'all'
|
'WebkitTransition': 'all'
|
||||||
'webkitTransition': 'all'
|
'webkitTransition': 'all'
|
||||||
'-webkit-transition': 'all'
|
'-webkit-transition': 'all'
|
||||||
|
@ -630,8 +630,8 @@ All supported properties and their default values exposed from CSSStylePropertie
|
||||||
'transform': 'none'
|
'transform': 'none'
|
||||||
'transformBox': 'view-box'
|
'transformBox': 'view-box'
|
||||||
'transform-box': 'view-box'
|
'transform-box': 'view-box'
|
||||||
'transformOrigin': '50% 50%'
|
'transformOrigin': '50% 50% 0px'
|
||||||
'transform-origin': '50% 50%'
|
'transform-origin': '50% 50% 0px'
|
||||||
'transition': 'all'
|
'transition': 'all'
|
||||||
'transitionBehavior': 'normal'
|
'transitionBehavior': 'normal'
|
||||||
'transition-behavior': 'normal'
|
'transition-behavior': 'normal'
|
||||||
|
|
|
@ -150,8 +150,8 @@ text-indent: 'calc(2%)' -> '2%'
|
||||||
text-indent: 'calc(2% * var(--n))' -> 'calc(2 * 2%)'
|
text-indent: 'calc(2% * var(--n))' -> 'calc(2 * 2%)'
|
||||||
top: 'calc(2%)' -> '2%'
|
top: 'calc(2%)' -> '2%'
|
||||||
top: 'calc(2% * var(--n))' -> 'calc(2 * 2%)'
|
top: 'calc(2% * var(--n))' -> 'calc(2 * 2%)'
|
||||||
transform-origin: 'calc(2px) calc(2%)' -> '2px 2%'
|
transform-origin: 'calc(2px) calc(2%)' -> '2px 2% 0px'
|
||||||
transform-origin: 'calc(2px * var(--n)) calc(2% * var(--n))' -> '4px calc(2 * 2%)'
|
transform-origin: 'calc(2px * var(--n)) calc(2% * var(--n))' -> '4px calc(2 * 2%) 0px'
|
||||||
transition-delay: 'calc(2s)' -> '2s'
|
transition-delay: 'calc(2s)' -> '2s'
|
||||||
transition-delay: 'calc(2s * var(--n))' -> '4s'
|
transition-delay: 'calc(2s * var(--n))' -> '4s'
|
||||||
transition-duration: 'calc(2s)' -> '2s'
|
transition-duration: 'calc(2s)' -> '2s'
|
||||||
|
|
|
@ -221,7 +221,7 @@ top: auto
|
||||||
touch-action: auto
|
touch-action: auto
|
||||||
transform: none
|
transform: none
|
||||||
transform-box: view-box
|
transform-box: view-box
|
||||||
transform-origin: 50% 50%
|
transform-origin: 50% 50% 0px
|
||||||
transition-behavior: normal
|
transition-behavior: normal
|
||||||
transition-delay: 0s
|
transition-delay: 0s
|
||||||
transition-duration: 0s
|
transition-duration: 0s
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
center => center center
|
center => center center 0px
|
||||||
10px => 10px center
|
10px => 10px center 0px
|
||||||
25% => 25% center
|
25% => 25% center 0px
|
||||||
left 20% => left 20%
|
left 20% => left 20% 0px
|
||||||
20px bottom => 20px bottom
|
20px bottom => 20px bottom 0px
|
||||||
top right => right top
|
top right => right top 0px
|
||||||
"center" => (invalid)
|
"center" => (invalid)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Harness status: OK
|
Harness status: OK
|
||||||
|
|
||||||
Found 203 tests
|
Found 204 tests
|
||||||
|
|
||||||
199 Pass
|
200 Pass
|
||||||
4 Fail
|
4 Fail
|
||||||
Pass accent-color
|
Pass accent-color
|
||||||
Pass border-collapse
|
Pass border-collapse
|
||||||
|
@ -192,6 +192,7 @@ Pass top
|
||||||
Pass touch-action
|
Pass touch-action
|
||||||
Fail transform
|
Fail transform
|
||||||
Pass transform-box
|
Pass transform-box
|
||||||
|
Pass transform-origin
|
||||||
Pass transition-behavior
|
Pass transition-behavior
|
||||||
Pass transition-delay
|
Pass transition-delay
|
||||||
Pass transition-duration
|
Pass transition-duration
|
||||||
|
|
|
@ -2,13 +2,12 @@ Harness status: OK
|
||||||
|
|
||||||
Found 10 tests
|
Found 10 tests
|
||||||
|
|
||||||
8 Pass
|
10 Pass
|
||||||
2 Fail
|
|
||||||
Pass e.style['transform-origin'] = "1px 2px 3%" should not set the property value
|
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 left" should not set the property value
|
||||||
Pass e.style['transform-origin'] = "1px 2px 3px 4px" 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
|
Pass 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'] = "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'] = "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'] = "top bottom" should not set the property value
|
||||||
Pass e.style['transform-origin'] = "bottom 10% right 20%" should not set the property value
|
Pass e.style['transform-origin'] = "bottom 10% right 20%" should not set the property value
|
||||||
|
|
|
@ -2,8 +2,7 @@ Harness status: OK
|
||||||
|
|
||||||
Found 16 tests
|
Found 16 tests
|
||||||
|
|
||||||
12 Pass
|
16 Pass
|
||||||
4 Fail
|
|
||||||
Pass e.style['transform-origin'] = "left" should set the property value
|
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'] = "center" should set the property value
|
||||||
Pass e.style['transform-origin'] = "right" 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'] = "left center" should set the property value
|
||||||
Pass e.style['transform-origin'] = "center top" 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
|
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
|
Pass 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'] = "center left 6px" should set the property value
|
||||||
Pass e.style['transform-origin'] = "top center" 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
|
Pass 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'] = "-1px -2px -3px" should set the property value
|
Loading…
Add table
Add a link
Reference in a new issue