|
@@ -41,6 +41,7 @@
|
|
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/ConicGradientStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/ConicGradientStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
|
|
|
|
+#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
|
|
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
|
|
@@ -4270,6 +4271,33 @@ RefPtr<StyleValue> Parser::parse_background_value(Vector<ComponentValue> const&
|
|
background_clip.release_nonnull());
|
|
background_clip.release_nonnull());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static Optional<PositionEdge> identifier_to_edge(ValueID identifier)
|
|
|
|
+{
|
|
|
|
+ switch (identifier) {
|
|
|
|
+ case ValueID::Top:
|
|
|
|
+ return PositionEdge::Top;
|
|
|
|
+ case ValueID::Bottom:
|
|
|
|
+ return PositionEdge::Bottom;
|
|
|
|
+ case ValueID::Left:
|
|
|
|
+ return PositionEdge::Left;
|
|
|
|
+ case ValueID::Right:
|
|
|
|
+ return PositionEdge::Right;
|
|
|
|
+ default:
|
|
|
|
+ return {};
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static Optional<LengthPercentage> style_value_to_length_percentage(auto value)
|
|
|
|
+{
|
|
|
|
+ if (value->is_percentage())
|
|
|
|
+ return LengthPercentage { value->as_percentage().percentage() };
|
|
|
|
+ if (value->has_length())
|
|
|
|
+ return LengthPercentage { value->to_length() };
|
|
|
|
+ if (value->is_calculated())
|
|
|
|
+ return LengthPercentage { value->as_calculated() };
|
|
|
|
+ return {};
|
|
|
|
+};
|
|
|
|
+
|
|
RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<ComponentValue>& tokens)
|
|
RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<ComponentValue>& tokens)
|
|
{
|
|
{
|
|
// NOTE: This *looks* like it parses a <position>, but it doesn't. From the spec:
|
|
// NOTE: This *looks* like it parses a <position>, but it doesn't. From the spec:
|
|
@@ -4281,20 +4309,6 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|
|
|
|
|
auto transaction = tokens.begin_transaction();
|
|
auto transaction = tokens.begin_transaction();
|
|
|
|
|
|
- auto to_edge = [](ValueID identifier) -> Optional<PositionEdge> {
|
|
|
|
- switch (identifier) {
|
|
|
|
- case ValueID::Top:
|
|
|
|
- return PositionEdge::Top;
|
|
|
|
- case ValueID::Bottom:
|
|
|
|
- return PositionEdge::Bottom;
|
|
|
|
- case ValueID::Left:
|
|
|
|
- return PositionEdge::Left;
|
|
|
|
- case ValueID::Right:
|
|
|
|
- return PositionEdge::Right;
|
|
|
|
- default:
|
|
|
|
- return {};
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
auto is_horizontal = [](ValueID identifier) -> bool {
|
|
auto is_horizontal = [](ValueID identifier) -> bool {
|
|
switch (identifier) {
|
|
switch (identifier) {
|
|
case ValueID::Left:
|
|
case ValueID::Left:
|
|
@@ -4328,16 +4342,6 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|
auto const center_offset = Percentage { 50 };
|
|
auto const center_offset = Percentage { 50 };
|
|
auto const zero_offset = Length::make_px(0);
|
|
auto const zero_offset = Length::make_px(0);
|
|
|
|
|
|
- auto value_to_length_percentage = [&](auto value) -> Optional<LengthPercentage> {
|
|
|
|
- if (value->is_percentage())
|
|
|
|
- return LengthPercentage { value->as_percentage().percentage() };
|
|
|
|
- if (value->has_length())
|
|
|
|
- return LengthPercentage { value->to_length() };
|
|
|
|
- if (value->is_calculated())
|
|
|
|
- return LengthPercentage { value->as_calculated() };
|
|
|
|
- return {};
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
while (tokens.has_next_token()) {
|
|
while (tokens.has_next_token()) {
|
|
// Check if we're done
|
|
// Check if we're done
|
|
auto seen_items = (horizontal.has_value() ? 1 : 0) + (vertical.has_value() ? 1 : 0) + (found_center ? 1 : 0);
|
|
auto seen_items = (horizontal.has_value() ? 1 : 0) + (vertical.has_value() ? 1 : 0) + (found_center ? 1 : 0);
|
|
@@ -4351,7 +4355,7 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|
tokens.next_token();
|
|
tokens.next_token();
|
|
auto value = maybe_value.release_nonnull();
|
|
auto value = maybe_value.release_nonnull();
|
|
|
|
|
|
- auto offset = value_to_length_percentage(value);
|
|
|
|
|
|
+ auto offset = style_value_to_length_percentage(value);
|
|
if (offset.has_value()) {
|
|
if (offset.has_value()) {
|
|
if (!horizontal.has_value()) {
|
|
if (!horizontal.has_value()) {
|
|
horizontal = EdgeOffset { PositionEdge::Left, *offset, false, true };
|
|
horizontal = EdgeOffset { PositionEdge::Left, *offset, false, true };
|
|
@@ -4369,7 +4373,7 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|
auto maybe_value = parse_css_value(token);
|
|
auto maybe_value = parse_css_value(token);
|
|
if (!maybe_value)
|
|
if (!maybe_value)
|
|
return zero_offset;
|
|
return zero_offset;
|
|
- auto offset = value_to_length_percentage(maybe_value.release_nonnull());
|
|
|
|
|
|
+ auto offset = style_value_to_length_percentage(maybe_value.release_nonnull());
|
|
if (offset.has_value()) {
|
|
if (offset.has_value()) {
|
|
offset_provided = true;
|
|
offset_provided = true;
|
|
tokens.next_token();
|
|
tokens.next_token();
|
|
@@ -4384,11 +4388,11 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|
if (is_horizontal(identifier)) {
|
|
if (is_horizontal(identifier)) {
|
|
bool offset_provided = false;
|
|
bool offset_provided = false;
|
|
auto offset = try_parse_offset(offset_provided);
|
|
auto offset = try_parse_offset(offset_provided);
|
|
- horizontal = EdgeOffset { *to_edge(identifier), offset, true, offset_provided };
|
|
|
|
|
|
+ horizontal = EdgeOffset { *identifier_to_edge(identifier), offset, true, offset_provided };
|
|
} else if (is_vertical(identifier)) {
|
|
} else if (is_vertical(identifier)) {
|
|
bool offset_provided = false;
|
|
bool offset_provided = false;
|
|
auto offset = try_parse_offset(offset_provided);
|
|
auto offset = try_parse_offset(offset_provided);
|
|
- vertical = EdgeOffset { *to_edge(identifier), offset, true, offset_provided };
|
|
|
|
|
|
+ vertical = EdgeOffset { *identifier_to_edge(identifier), offset, true, offset_provided };
|
|
} else if (identifier == ValueID::Center) {
|
|
} else if (identifier == ValueID::Center) {
|
|
found_center = true;
|
|
found_center = true;
|
|
} else {
|
|
} else {
|
|
@@ -4436,8 +4440,63 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
|
|
|
|
|
|
transaction.commit();
|
|
transaction.commit();
|
|
return PositionStyleValue::create(
|
|
return PositionStyleValue::create(
|
|
- horizontal->edge, horizontal->offset,
|
|
|
|
- vertical->edge, vertical->offset);
|
|
|
|
|
|
+ EdgeStyleValue::create(horizontal->edge, horizontal->offset),
|
|
|
|
+ EdgeStyleValue::create(vertical->edge, vertical->offset));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+RefPtr<StyleValue> Parser::parse_single_background_position_x_or_y_value(TokenStream<ComponentValue>& tokens, PropertyID property)
|
|
|
|
+{
|
|
|
|
+ PositionEdge relative_edge {};
|
|
|
|
+ if (property == PropertyID::BackgroundPositionX) {
|
|
|
|
+ // [ center | [ [ left | right | x-start | x-end ]? <length-percentage>? ]! ]#
|
|
|
|
+ relative_edge = PositionEdge::Left;
|
|
|
|
+ } else if (property == PropertyID::BackgroundPositionY) {
|
|
|
|
+ // [ center | [ [ top | bottom | y-start | y-end ]? <length-percentage>? ]! ]#
|
|
|
|
+ relative_edge = PositionEdge::Top;
|
|
|
|
+ } else {
|
|
|
|
+ VERIFY_NOT_REACHED();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ auto transaction = tokens.begin_transaction();
|
|
|
|
+ if (!tokens.has_next_token())
|
|
|
|
+ return {};
|
|
|
|
+
|
|
|
|
+ auto parse_value = [&](auto& token) -> RefPtr<StyleValue> {
|
|
|
|
+ auto maybe_value = parse_css_value(token);
|
|
|
|
+ if (!maybe_value || !property_accepts_value(property, *maybe_value))
|
|
|
|
+ return {};
|
|
|
|
+ return maybe_value.release_nonnull();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ auto value = parse_value(tokens.next_token());
|
|
|
|
+ if (value->has_identifier()) {
|
|
|
|
+ auto identifier = value->to_identifier();
|
|
|
|
+ if (identifier == ValueID::Center) {
|
|
|
|
+ transaction.commit();
|
|
|
|
+ return EdgeStyleValue::create(relative_edge, Percentage { 50 });
|
|
|
|
+ }
|
|
|
|
+ if (auto edge = identifier_to_edge(identifier); edge.has_value()) {
|
|
|
|
+ relative_edge = *edge;
|
|
|
|
+ } else {
|
|
|
|
+ return {};
|
|
|
|
+ }
|
|
|
|
+ if (tokens.has_next_token()) {
|
|
|
|
+ value = parse_value(tokens.peek_token());
|
|
|
|
+ if (!value) {
|
|
|
|
+ transaction.commit();
|
|
|
|
+ return EdgeStyleValue::create(relative_edge, Length::make_px(0));
|
|
|
|
+ }
|
|
|
|
+ tokens.next_token();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ auto offset = style_value_to_length_percentage(value);
|
|
|
|
+ if (offset.has_value()) {
|
|
|
|
+ transaction.commit();
|
|
|
|
+ return EdgeStyleValue::create(relative_edge, *offset);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return {};
|
|
}
|
|
}
|
|
|
|
|
|
RefPtr<StyleValue> Parser::parse_single_background_repeat_value(TokenStream<ComponentValue>& tokens)
|
|
RefPtr<StyleValue> Parser::parse_single_background_repeat_value(TokenStream<ComponentValue>& tokens)
|
|
@@ -6531,6 +6590,11 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
|
|
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this](auto& tokens) { return parse_single_background_position_value(tokens); }))
|
|
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this](auto& tokens) { return parse_single_background_position_value(tokens); }))
|
|
return parsed_value.release_nonnull();
|
|
return parsed_value.release_nonnull();
|
|
return ParseError::SyntaxError;
|
|
return ParseError::SyntaxError;
|
|
|
|
+ case PropertyID::BackgroundPositionX:
|
|
|
|
+ case PropertyID::BackgroundPositionY:
|
|
|
|
+ if (auto parsed_value = parse_comma_separated_value_list(component_values, [this, property_id](auto& tokens) { return parse_single_background_position_x_or_y_value(tokens, property_id); }))
|
|
|
|
+ return parsed_value.release_nonnull();
|
|
|
|
+ return ParseError::SyntaxError;
|
|
case PropertyID::BackgroundRepeat:
|
|
case PropertyID::BackgroundRepeat:
|
|
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this](auto& tokens) { return parse_single_background_repeat_value(tokens); }))
|
|
if (auto parsed_value = parse_comma_separated_value_list(component_values, [this](auto& tokens) { return parse_single_background_repeat_value(tokens); }))
|
|
return parsed_value.release_nonnull();
|
|
return parsed_value.release_nonnull();
|