Skip to content

Commit b128514

Browse files
committed
LibWeb/CSS: Handle whitespace properly in transformation properties
We can no longer rely on the remaining token count, so these required significant rearranging.
1 parent 3341a52 commit b128514

File tree

2 files changed

+81
-76
lines changed

2 files changed

+81
-76
lines changed

Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp

Lines changed: 81 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,61 +2199,62 @@ RefPtr<StyleValue const> Parser::parse_shape_outside_value(TokenStream<Component
21992199
return StyleValueList::create({ basic_shape_value.release_nonnull(), shape_box_value.release_nonnull() }, StyleValueList::Separator::Space);
22002200
}
22012201

2202+
// https://drafts.csswg.org/css-transforms-2/#propdef-rotate
22022203
RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>& tokens)
22032204
{
2204-
// Value: none | <angle> | [ x | y | z | <number>{3} ] && <angle>
2205+
// none | <angle> | [ x | y | z | <number>{3} ] && <angle>
22052206

2206-
if (tokens.remaining_token_count() == 1) {
2207-
// "none"
2208-
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
2209-
return none;
2207+
// none
2208+
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
2209+
return none;
2210+
2211+
auto transaction = tokens.begin_transaction();
2212+
2213+
auto angle = parse_angle_value(tokens);
2214+
tokens.discard_whitespace();
22102215

2211-
// <angle>
2212-
if (auto angle = parse_angle_value(tokens))
2213-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate, { angle.release_nonnull() });
2216+
// <angle>
2217+
if (angle && !tokens.has_next_token()) {
2218+
transaction.commit();
2219+
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate, { angle.release_nonnull() });
22142220
}
22152221

22162222
auto parse_one_of_xyz = [&]() -> Optional<ComponentValue const&> {
2217-
auto transaction = tokens.begin_transaction();
2223+
auto xyz_transaction = tokens.begin_transaction();
2224+
tokens.discard_whitespace();
22182225
auto const& axis = tokens.consume_a_token();
22192226

22202227
if (axis.is_ident("x"sv) || axis.is_ident("y"sv) || axis.is_ident("z"sv)) {
2221-
transaction.commit();
2228+
xyz_transaction.commit();
22222229
return axis;
22232230
}
22242231

22252232
return {};
22262233
};
22272234

22282235
// [ x | y | z ] && <angle>
2229-
if (tokens.remaining_token_count() == 2) {
2230-
// Try parsing `x <angle>`
2231-
if (auto axis = parse_one_of_xyz(); axis.has_value()) {
2232-
if (auto angle = parse_angle_value(tokens); angle) {
2233-
if (axis->is_ident("x"sv))
2234-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateX, { angle.release_nonnull() });
2235-
if (axis->is_ident("y"sv))
2236-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateY, { angle.release_nonnull() });
2237-
if (axis->is_ident("z"sv))
2238-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateZ, { angle.release_nonnull() });
2239-
}
2240-
}
2236+
if (auto axis = parse_one_of_xyz(); axis.has_value()) {
2237+
tokens.discard_whitespace();
22412238

2242-
// Try parsing `<angle> x`
2243-
if (auto angle = parse_angle_value(tokens); angle) {
2244-
if (auto axis = parse_one_of_xyz(); axis.has_value()) {
2245-
if (axis->is_ident("x"sv))
2246-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateX, { angle.release_nonnull() });
2247-
if (axis->is_ident("y"sv))
2248-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateY, { angle.release_nonnull() });
2249-
if (axis->is_ident("z"sv))
2250-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateZ, { angle.release_nonnull() });
2251-
}
2239+
if (!angle)
2240+
angle = parse_angle_value(tokens);
2241+
2242+
if (angle) {
2243+
transaction.commit();
2244+
if (axis->is_ident("x"sv))
2245+
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateX, { angle.release_nonnull() });
2246+
if (axis->is_ident("y"sv))
2247+
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateY, { angle.release_nonnull() });
2248+
if (axis->is_ident("z"sv))
2249+
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::RotateZ, { angle.release_nonnull() });
2250+
VERIFY_NOT_REACHED();
22522251
}
2252+
2253+
return nullptr;
22532254
}
22542255

22552256
auto parse_three_numbers = [&]() -> Optional<StyleValueVector> {
2256-
auto transaction = tokens.begin_transaction();
2257+
auto numbers_transaction = tokens.begin_transaction();
22572258
StyleValueVector numbers;
22582259
for (size_t i = 0; i < 3; ++i) {
22592260
if (auto number = parse_number_value(tokens); number) {
@@ -2262,27 +2263,24 @@ RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>&
22622263
return {};
22632264
}
22642265
}
2265-
transaction.commit();
2266+
numbers_transaction.commit();
22662267
return numbers;
22672268
};
22682269

22692270
// <number>{3} && <angle>
2270-
if (tokens.remaining_token_count() == 4) {
2271-
// Try parsing <number>{3} <angle>
2272-
if (auto maybe_numbers = parse_three_numbers(); maybe_numbers.has_value()) {
2273-
if (auto angle = parse_angle_value(tokens); angle) {
2274-
auto numbers = maybe_numbers.release_value();
2275-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate3d, { numbers[0], numbers[1], numbers[2], angle.release_nonnull() });
2276-
}
2277-
}
2271+
if (auto maybe_numbers = parse_three_numbers(); maybe_numbers.has_value()) {
2272+
tokens.discard_whitespace();
22782273

2279-
// Try parsing <angle> <number>{3}
2280-
if (auto angle = parse_angle_value(tokens); angle) {
2281-
if (auto maybe_numbers = parse_three_numbers(); maybe_numbers.has_value()) {
2282-
auto numbers = maybe_numbers.release_value();
2283-
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate3d, { numbers[0], numbers[1], numbers[2], angle.release_nonnull() });
2284-
}
2274+
if (!angle)
2275+
angle = parse_angle_value(tokens);
2276+
2277+
if (angle) {
2278+
auto numbers = maybe_numbers.release_value();
2279+
transaction.commit();
2280+
return TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate3d, { numbers[0], numbers[1], numbers[2], angle.release_nonnull() });
22852281
}
2282+
2283+
return nullptr;
22862284
}
22872285

22882286
return nullptr;
@@ -4834,6 +4832,13 @@ RefPtr<StyleValue const> Parser::parse_touch_action_value(TokenStream<ComponentV
48344832
// https://www.w3.org/TR/css-transforms-1/#propdef-transform-origin
48354833
RefPtr<StyleValue const> Parser::parse_transform_origin_value(TokenStream<ComponentValue>& tokens)
48364834
{
4835+
// [ left | center | right | top | bottom | <length-percentage> ]
4836+
// |
4837+
// [ left | center | right | <length-percentage> ]
4838+
// [ top | center | bottom | <length-percentage> ] <length>?
4839+
// |
4840+
// [[ center | left | right ] && [ center | top | bottom ]] <length>?
4841+
48374842
enum class Axis {
48384843
None,
48394844
X,
@@ -4875,34 +4880,31 @@ RefPtr<StyleValue const> Parser::parse_transform_origin_value(TokenStream<Compon
48754880
};
48764881

48774882
auto transaction = tokens.begin_transaction();
4883+
tokens.discard_whitespace();
48784884

48794885
auto make_list = [&transaction](NonnullRefPtr<StyleValue const> const& x_value, NonnullRefPtr<StyleValue const> const& y_value, NonnullRefPtr<StyleValue const> const& z_value) -> NonnullRefPtr<StyleValueList> {
48804886
transaction.commit();
48814887
return StyleValueList::create(StyleValueVector { x_value, y_value, z_value }, StyleValueList::Separator::Space);
48824888
};
48834889

4884-
static StyleValue const& zero_value = LengthStyleValue::create(Length::make_px(0));
4890+
NonnullRefPtr<StyleValue const> const zero_value = LengthStyleValue::create(Length::make_px(0));
48854891

4886-
if (tokens.remaining_token_count() == 1) {
4887-
auto single_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
4888-
if (!single_value.has_value())
4889-
return nullptr;
4892+
auto first_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
4893+
if (!first_value.has_value())
4894+
return nullptr;
4895+
tokens.discard_whitespace();
4896+
if (!tokens.has_next_token()) {
48904897
// If only one value is specified, the second value is assumed to be center.
4891-
// FIXME: If one or two values are specified, the third value is assumed to be 0px.
4892-
switch (single_value->axis) {
4898+
switch (first_value->axis) {
48934899
case Axis::None:
48944900
case Axis::X:
4895-
return make_list(single_value->offset, KeywordStyleValue::create(Keyword::Center), zero_value);
4901+
return make_list(first_value->offset, KeywordStyleValue::create(Keyword::Center), zero_value);
48964902
case Axis::Y:
4897-
return make_list(KeywordStyleValue::create(Keyword::Center), single_value->offset, zero_value);
4903+
return make_list(KeywordStyleValue::create(Keyword::Center), first_value->offset, zero_value);
48984904
}
48994905
VERIFY_NOT_REACHED();
49004906
}
49014907

4902-
if (tokens.remaining_token_count() > 3)
4903-
return nullptr;
4904-
4905-
auto first_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
49064908
auto second_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
49074909
auto third_value = parse_length_value(tokens);
49084910

@@ -5040,20 +5042,23 @@ RefPtr<StyleValue const> Parser::parse_transition_property_value(TokenStream<Com
50405042
return StyleValueList::create(move(transition_properties), StyleValueList::Separator::Comma);
50415043
}
50425044

5045+
// https://drafts.csswg.org/css-transforms-2/#propdef-translate
50435046
RefPtr<StyleValue const> Parser::parse_translate_value(TokenStream<ComponentValue>& tokens)
50445047
{
5045-
if (tokens.remaining_token_count() == 1) {
5046-
// "none"
5047-
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
5048-
return none;
5049-
}
5048+
// none | <length-percentage> [ <length-percentage> <length>? ]?
5049+
5050+
// none
5051+
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
5052+
return none;
50505053

50515054
auto transaction = tokens.begin_transaction();
50525055

5056+
// <length-percentage> [ <length-percentage> <length>? ]?
50535057
auto maybe_x = parse_length_percentage_value(tokens);
50545058
if (!maybe_x)
50555059
return nullptr;
50565060

5061+
tokens.discard_whitespace();
50575062
if (!tokens.has_next_token()) {
50585063
transaction.commit();
50595064
return TransformationStyleValue::create(PropertyID::Translate, TransformFunction::Translate, { maybe_x.release_nonnull(), LengthStyleValue::create(Length::make_px(0)) });
@@ -5063,6 +5068,7 @@ RefPtr<StyleValue const> Parser::parse_translate_value(TokenStream<ComponentValu
50635068
if (!maybe_y)
50645069
return nullptr;
50655070

5071+
tokens.discard_whitespace();
50665072
if (!tokens.has_next_token()) {
50675073
transaction.commit();
50685074
return TransformationStyleValue::create(PropertyID::Translate, TransformFunction::Translate, { maybe_x.release_nonnull(), maybe_y.release_nonnull() });
@@ -5077,20 +5083,23 @@ RefPtr<StyleValue const> Parser::parse_translate_value(TokenStream<ComponentValu
50775083
return TransformationStyleValue::create(PropertyID::Translate, TransformFunction::Translate3d, { maybe_x.release_nonnull(), maybe_y.release_nonnull(), maybe_z.release_nonnull() });
50785084
}
50795085

5086+
// https://drafts.csswg.org/css-transforms-2/#propdef-scale
50805087
RefPtr<StyleValue const> Parser::parse_scale_value(TokenStream<ComponentValue>& tokens)
50815088
{
5082-
if (tokens.remaining_token_count() == 1) {
5083-
// "none"
5084-
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
5085-
return none;
5086-
}
5089+
// none | [ <number> | <percentage> ]{1,3}
5090+
5091+
// none
5092+
if (auto none = parse_all_as_single_keyword_value(tokens, Keyword::None))
5093+
return none;
50875094

50885095
auto transaction = tokens.begin_transaction();
50895096

5097+
// [ <number> | <percentage> ]{1,3}
50905098
auto maybe_x = parse_number_percentage_value(tokens);
50915099
if (!maybe_x)
50925100
return nullptr;
50935101

5102+
tokens.discard_whitespace();
50945103
if (!tokens.has_next_token()) {
50955104
transaction.commit();
50965105
return TransformationStyleValue::create(PropertyID::Scale, TransformFunction::Scale, { *maybe_x, *maybe_x });
@@ -5100,6 +5109,7 @@ RefPtr<StyleValue const> Parser::parse_scale_value(TokenStream<ComponentValue>&
51005109
if (!maybe_y)
51015110
return nullptr;
51025111

5112+
tokens.discard_whitespace();
51035113
if (!tokens.has_next_token()) {
51045114
transaction.commit();
51055115
return TransformationStyleValue::create(PropertyID::Scale, TransformFunction::Scale, { maybe_x.release_nonnull(), maybe_y.release_nonnull() });

Libraries/LibWeb/CSS/Properties.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,7 +3373,6 @@
33733373
"needs-layout-for-getcomputedstyle": true
33743374
},
33753375
"rotate": {
3376-
"strip-whitespace": true,
33773376
"animation-type": "custom",
33783377
"inherited": false,
33793378
"initial": "none",
@@ -3429,7 +3428,6 @@
34293428
]
34303429
},
34313430
"scale": {
3432-
"strip-whitespace": true,
34333431
"animation-type": "custom",
34343432
"inherited": false,
34353433
"initial": "none",
@@ -3814,7 +3812,6 @@
38143812
]
38153813
},
38163814
"transform": {
3817-
"strip-whitespace": true,
38183815
"animation-type": "custom",
38193816
"inherited": false,
38203817
"initial": "none",
@@ -3839,7 +3836,6 @@
38393836
]
38403837
},
38413838
"transform-origin": {
3842-
"strip-whitespace": true,
38433839
"affects-layout": false,
38443840
"animation-type": "by-computed-value",
38453841
"inherited": false,
@@ -3926,7 +3922,6 @@
39263922
]
39273923
},
39283924
"translate": {
3929-
"strip-whitespace": true,
39303925
"animation-type": "custom",
39313926
"inherited": false,
39323927
"initial": "none",

0 commit comments

Comments
 (0)