summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorMacDue <macdue@dueutil.tech>2023-04-03 00:04:00 +0100
committerAndreas Kling <kling@serenityos.org>2023-04-03 07:10:33 +0200
commitbed55ac6696466723d5067b748f05651e5d1521c (patch)
treecd4a3fe56090b6bb68fe965e559554b04e04da67 /Userland
parent2a659693bc54e2c473f71c3ac89905bd9384d8b9 (diff)
downloadserenity-bed55ac6696466723d5067b748f05651e5d1521c.zip
LibWeb: Parse and plumb background-position-x/y
This parses the new background-position-x/y longhands and properly hooks up them up. This requires converting PositionStyleValue to just contain two EdgeStyleValues so that it can be easily expanded into the longhands.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp124
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h1
-rw-r--r--Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp3
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleComputer.cpp14
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp16
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h20
-rw-r--r--Userland/Libraries/LibWeb/Layout/Node.cpp24
7 files changed, 135 insertions, 67 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index afde36f313..d513f66b17 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -41,6 +41,7 @@
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
#include <LibWeb/CSS/StyleValues/ConicGradientStyleValue.h>
#include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
+#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
#include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
@@ -4270,6 +4271,33 @@ RefPtr<StyleValue> Parser::parse_background_value(Vector<ComponentValue> const&
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)
{
// 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 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 {
switch (identifier) {
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 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()) {
// Check if we're done
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();
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 (!horizontal.has_value()) {
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);
if (!maybe_value)
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()) {
offset_provided = true;
tokens.next_token();
@@ -4384,11 +4388,11 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
if (is_horizontal(identifier)) {
bool offset_provided = false;
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)) {
bool offset_provided = false;
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) {
found_center = true;
} else {
@@ -4436,8 +4440,63 @@ RefPtr<StyleValue> Parser::parse_single_background_position_value(TokenStream<Co
transaction.commit();
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)
@@ -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); }))
return parsed_value.release_nonnull();
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:
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();
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
index c9e27c2efe..f3a45863f2 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
@@ -294,6 +294,7 @@ private:
RefPtr<StyleValue> parse_filter_value_list_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_background_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_single_background_position_value(TokenStream<ComponentValue>&);
+ RefPtr<StyleValue> parse_single_background_position_x_or_y_value(TokenStream<ComponentValue>&, PropertyID);
RefPtr<StyleValue> parse_single_background_repeat_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue> parse_single_background_size_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue> parse_border_value(Vector<ComponentValue> const&);
diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp
index 87f76868ca..76cef8fcb6 100644
--- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp
+++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp
@@ -19,6 +19,7 @@
#include <LibWeb/CSS/StyleValues/BorderStyleValue.h>
#include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
#include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
+#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
@@ -195,7 +196,7 @@ RefPtr<StyleValue const> ResolvedCSSStyleDeclaration::style_value_for_property(L
return BackgroundStyleValue::create(
value_or_default(maybe_background_color, InitialStyleValue::the()),
value_or_default(maybe_background_image, IdentifierStyleValue::create(CSS::ValueID::None)),
- value_or_default(maybe_background_position, PositionStyleValue::create(PositionEdge::Left, Length::make_px(0), PositionEdge::Top, Length::make_px(0))),
+ value_or_default(maybe_background_position, PositionStyleValue::create(EdgeStyleValue::create(PositionEdge::Left, Length::make_px(0)), EdgeStyleValue::create(PositionEdge::Top, Length::make_px(0)))),
value_or_default(maybe_background_size, IdentifierStyleValue::create(CSS::ValueID::Auto)),
value_or_default(maybe_background_repeat, BackgroundRepeatStyleValue::create(CSS::Repeat::Repeat, CSS::Repeat::Repeat)),
value_or_default(maybe_background_attachment, IdentifierStyleValue::create(CSS::ValueID::Scroll)),
diff --git a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
index da5e080303..335559bceb 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp
@@ -43,6 +43,7 @@
#include <LibWeb/CSS/StyleValues/NumericStyleValue.h>
#include <LibWeb/CSS/StyleValues/OverflowStyleValue.h>
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
+#include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
#include <LibWeb/CSS/StyleValues/TextDecorationStyleValue.h>
#include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
@@ -454,6 +455,19 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
return;
}
+ if (property_id == CSS::PropertyID::BackgroundPosition) {
+ if (value.is_position()) {
+ auto const& position = value.as_position();
+ style.set_property(CSS::PropertyID::BackgroundPositionX, position.edge_x());
+ style.set_property(CSS::PropertyID::BackgroundPositionY, position.edge_y());
+ return;
+ }
+
+ style.set_property(CSS::PropertyID::BackgroundPositionX, value);
+ style.set_property(CSS::PropertyID::BackgroundPositionY, value);
+ return;
+ }
+
if (property_id == CSS::PropertyID::Margin) {
if (value.is_value_list()) {
auto const& values_list = value.as_value_list();
diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp
index 543c13de31..71cb93bbc0 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp
+++ b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.cpp
@@ -13,21 +13,7 @@ namespace Web::CSS {
ErrorOr<String> PositionStyleValue::to_string() const
{
- auto to_string = [](PositionEdge edge) {
- switch (edge) {
- case PositionEdge::Left:
- return "left";
- case PositionEdge::Right:
- return "right";
- case PositionEdge::Top:
- return "top";
- case PositionEdge::Bottom:
- return "bottom";
- }
- VERIFY_NOT_REACHED();
- };
-
- return String::formatted("{} {} {} {}", to_string(m_properties.edge_x), TRY(m_properties.offset_x.to_string()), to_string(m_properties.edge_y), TRY(m_properties.offset_y.to_string()));
+ return String::formatted("{} {}", TRY(m_properties.edge_x->to_string()), TRY(m_properties.edge_y->to_string()));
}
}
diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h
index 39efe318ff..028a75d079 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h
+++ b/Userland/Libraries/LibWeb/CSS/StyleValues/PositionStyleValue.h
@@ -17,33 +17,29 @@ namespace Web::CSS {
class PositionStyleValue final : public StyleValueWithDefaultOperators<PositionStyleValue> {
public:
- static ValueComparingNonnullRefPtr<PositionStyleValue> create(PositionEdge edge_x, LengthPercentage const& offset_x, PositionEdge edge_y, LengthPercentage const& offset_y)
+ static ValueComparingNonnullRefPtr<PositionStyleValue> create(ValueComparingNonnullRefPtr<StyleValue> egde_x, ValueComparingNonnullRefPtr<StyleValue> edge_y)
{
- return adopt_ref(*new PositionStyleValue(edge_x, offset_x, edge_y, offset_y));
+ return adopt_ref(*new PositionStyleValue(move(egde_x), move(edge_y)));
}
virtual ~PositionStyleValue() override = default;
- PositionEdge edge_x() const { return m_properties.edge_x; }
- LengthPercentage const& offset_x() const { return m_properties.offset_x; }
- PositionEdge edge_y() const { return m_properties.edge_y; }
- LengthPercentage const& offset_y() const { return m_properties.offset_y; }
+ ValueComparingNonnullRefPtr<StyleValue> edge_x() const { return m_properties.edge_x; }
+ ValueComparingNonnullRefPtr<StyleValue> edge_y() const { return m_properties.edge_y; }
virtual ErrorOr<String> to_string() const override;
bool properties_equal(PositionStyleValue const& other) const { return m_properties == other.m_properties; }
private:
- PositionStyleValue(PositionEdge edge_x, LengthPercentage const& offset_x, PositionEdge edge_y, LengthPercentage const& offset_y)
+ PositionStyleValue(ValueComparingNonnullRefPtr<StyleValue> edge_x, ValueComparingNonnullRefPtr<StyleValue> edge_y)
: StyleValueWithDefaultOperators(Type::Position)
- , m_properties { .edge_x = edge_x, .offset_x = offset_x, .edge_y = edge_y, .offset_y = offset_y }
+ , m_properties { .edge_x = edge_x, .edge_y = edge_y }
{
}
struct Properties {
- PositionEdge edge_x;
- LengthPercentage offset_x;
- PositionEdge edge_y;
- LengthPercentage offset_y;
+ ValueComparingNonnullRefPtr<StyleValue> edge_x;
+ ValueComparingNonnullRefPtr<StyleValue> edge_y;
bool operator==(Properties const&) const = default;
} m_properties;
};
diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp
index 5faf73ebde..d40e6656df 100644
--- a/Userland/Libraries/LibWeb/Layout/Node.cpp
+++ b/Userland/Libraries/LibWeb/Layout/Node.cpp
@@ -9,7 +9,7 @@
#include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
#include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
#include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h>
-#include <LibWeb/CSS/StyleValues/PositionStyleValue.h>
+#include <LibWeb/CSS/StyleValues/EdgeStyleValue.h>
#include <LibWeb/CSS/StyleValues/StyleValueList.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/Dump.h>
@@ -293,7 +293,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
auto clips = computed_style.property(CSS::PropertyID::BackgroundClip);
auto images = computed_style.property(CSS::PropertyID::BackgroundImage);
auto origins = computed_style.property(CSS::PropertyID::BackgroundOrigin);
- auto positions = computed_style.property(CSS::PropertyID::BackgroundPosition);
+ auto x_positions = computed_style.property(CSS::PropertyID::BackgroundPositionX);
+ auto y_positions = computed_style.property(CSS::PropertyID::BackgroundPositionY);
auto repeats = computed_style.property(CSS::PropertyID::BackgroundRepeat);
auto sizes = computed_style.property(CSS::PropertyID::BackgroundSize);
@@ -315,7 +316,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
layer_count = max(layer_count, count_layers(clips));
layer_count = max(layer_count, count_layers(images));
layer_count = max(layer_count, count_layers(origins));
- layer_count = max(layer_count, count_layers(positions));
+ layer_count = max(layer_count, count_layers(x_positions));
+ layer_count = max(layer_count, count_layers(y_positions));
layer_count = max(layer_count, count_layers(repeats));
layer_count = max(layer_count, count_layers(sizes));
@@ -369,14 +371,18 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
layer.clip = as_box(clip_value->to_identifier());
}
- if (auto position_value = value_for_layer(positions, layer_index); position_value && position_value->is_position()) {
- auto& position = position_value->as_position();
- layer.position_edge_x = position.edge_x();
- layer.position_edge_y = position.edge_y();
- layer.position_offset_x = position.offset_x();
- layer.position_offset_y = position.offset_y();
+ if (auto position_value = value_for_layer(x_positions, layer_index); position_value && position_value->is_edge()) {
+ auto& position = position_value->as_edge();
+ layer.position_edge_x = position.edge();
+ layer.position_offset_x = position.offset();
}
+ if (auto position_value = value_for_layer(y_positions, layer_index); position_value && position_value->is_edge()) {
+ auto& position = position_value->as_edge();
+ layer.position_edge_y = position.edge();
+ layer.position_offset_y = position.offset();
+ };
+
if (auto size_value = value_for_layer(sizes, layer_index); size_value) {
if (size_value->is_background_size()) {
auto& size = size_value->as_background_size();