summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-07-18 17:12:23 +0100
committerAndreas Kling <kling@serenityos.org>2021-07-22 23:09:01 +0200
commit6e0376361a58db1fba7ba400cf2498668094a7aa (patch)
tree7b128a3ac2f16bd8dda29e546ccf39ffa766c08b /Userland/Libraries
parent57d34f196602b7d6d6327815762249b4b5b7a6f4 (diff)
downloadserenity-6e0376361a58db1fba7ba400cf2498668094a7aa.zip
LibWeb: Expose StyleValue parsing method in CSS Parser
Now that StyleResolver is going to deal with StyleComponentValueRules, it will need to be able to parse those into StyleValues, using `parse_css_value()`. Also added StyleValue::is_builtin_or_dynamic(), which returns true for values that are valid anywhere - things like `initial` and `inherit`, along with `var()`, `attr()` and `calc()` - which we want to test for easily.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp146
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h20
-rw-r--r--Userland/Libraries/LibWeb/CSS/StyleValue.h5
3 files changed, 116 insertions, 55 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index beb13f4560..e1ec171571 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -1271,17 +1271,36 @@ Optional<float> Parser::try_parse_float(StringView string)
return is_negative ? -value : value;
}
-RefPtr<StyleValue> Parser::parse_single_css_value(PropertyID property_id, StyleComponentValueRule const& component_value)
+RefPtr<StyleValue> Parser::parse_keyword_or_custom_value(ParsingContext const&, StyleComponentValueRule const& component_value)
{
- dbgln_if(CSS_PARSER_TRACE, "Parser::parse_single_css_value '{}'", component_value.to_debug_string());
- // FIXME: This is mostly copied from the old, deprecated parser. It is probably not to spec.
+ if (component_value.is(Token::Type::Ident)) {
+ auto ident = component_value.token().ident();
+ if (ident.equals_ignoring_case("inherit"))
+ return InheritStyleValue::create();
+ if (ident.equals_ignoring_case("initial"))
+ return InitialStyleValue::create();
+ if (ident.equals_ignoring_case("auto"))
+ return LengthStyleValue::create(Length::make_auto());
+ // FIXME: Implement `unset` keyword
+ }
- auto takes_integer_value = [](PropertyID property_id) -> bool {
- return property_id == PropertyID::ZIndex
- || property_id == PropertyID::FontWeight
- || property_id == PropertyID::Custom;
- };
+ if (component_value.is_function() && component_value.function().name().equals_ignoring_case("var")) {
+ // FIXME: Handle fallback value as second parameter
+ // https://www.w3.org/TR/css-variables-1/#using-variables
+ if (!component_value.function().values().is_empty()) {
+ auto& property_name_token = component_value.function().values().first();
+ if (property_name_token.is(Token::Type::Ident))
+ return CustomStyleValue::create(property_name_token.token().ident());
+ else
+ dbgln("First argument to var() function was not an ident: '{}'", property_name_token.to_debug_string());
+ }
+ }
+ return {};
+}
+
+RefPtr<StyleValue> Parser::parse_length_value(ParsingContext const& context, StyleComponentValueRule const& component_value)
+{
auto parse_length = [&]() -> Optional<Length> {
Length::Type type = Length::Type::Undefined;
Optional<float> numeric_value;
@@ -1320,7 +1339,7 @@ RefPtr<StyleValue> Parser::parse_single_css_value(PropertyID property_id, StyleC
type = Length::Type::In;
} else if (unit_string.equals_ignoring_case("Q")) {
type = Length::Type::Q;
- } else if (m_context.in_quirks_mode()) {
+ } else if (context.in_quirks_mode()) {
type = Length::Type::Px;
}
@@ -1330,10 +1349,14 @@ RefPtr<StyleValue> Parser::parse_single_css_value(PropertyID property_id, StyleC
if (value_string == "0") {
type = Length::Type::Px;
numeric_value = 0;
- } else if (m_context.in_quirks_mode()) {
+ } else if (context.in_quirks_mode()) {
type = Length::Type::Px;
numeric_value = try_parse_float(value_string);
}
+ } else if (component_value.is(Token::Type::Percentage)) {
+ type = Length::Type::Percentage;
+ auto value_string = component_value.token().m_value.string_view();
+ numeric_value = try_parse_float(value_string);
}
if (!numeric_value.has_value())
@@ -1342,53 +1365,46 @@ RefPtr<StyleValue> Parser::parse_single_css_value(PropertyID property_id, StyleC
return Length(numeric_value.value(), type);
};
- if (takes_integer_value(property_id) && component_value.is(Token::Type::Number)) {
- auto number = component_value.token();
- if (number.m_number_type == Token::NumberType::Integer) {
- return LengthStyleValue::create(Length::make_px(number.integer()));
- }
- }
-
- if (component_value.is(Token::Type::Dimension) || component_value.is(Token::Type::Number)) {
+ if (component_value.is(Token::Type::Dimension) || component_value.is(Token::Type::Number) || component_value.is(Token::Type::Percentage)) {
auto length = parse_length();
if (length.has_value())
return LengthStyleValue::create(length.value());
-
- auto value_string = component_value.token().m_value.string_view();
- auto float_number = try_parse_float(value_string);
- if (float_number.has_value())
- return NumericStyleValue::create(float_number.value());
- return nullptr;
}
- if (component_value.is(Token::Type::Ident)) {
- auto ident = component_value.token().ident();
- if (ident.equals_ignoring_case("inherit"))
- return InheritStyleValue::create();
- if (ident.equals_ignoring_case("initial"))
- return InitialStyleValue::create();
- if (ident.equals_ignoring_case("auto"))
- return LengthStyleValue::create(Length::make_auto());
- }
+ return {};
+}
- if (component_value.is_function() && component_value.function().name().equals_ignoring_case("var")) {
- // FIXME: Handle fallback value as second parameter
- // https://www.w3.org/TR/css-variables-1/#using-variables
- if (!component_value.function().values().is_empty()) {
- auto& property_name_token = component_value.function().values().first();
- if (property_name_token.is(Token::Type::Ident))
- return CustomStyleValue::create(property_name_token.token().ident());
- else
- dbgln("First argument to var() function was not an ident: '{}'", property_name_token.to_debug_string());
+RefPtr<StyleValue> Parser::parse_numeric_value(ParsingContext const&, StyleComponentValueRule const& component_value)
+{
+ if (component_value.is(Token::Type::Number)) {
+ auto number = component_value.token();
+ if (number.m_number_type == Token::NumberType::Integer) {
+ // FIXME: This seems wrong, but it's how the old parser did things, as well as it
+ // whitelisting ZIndex, FontWeight and Custom PropertyIDs to allow this.
+ return LengthStyleValue::create(Length::make_px(number.integer()));
+ } else {
+ auto float_value = try_parse_float(number.m_value.string_view());
+ if (float_value.has_value())
+ return NumericStyleValue::create(float_value.value());
}
}
+ return {};
+}
+
+RefPtr<StyleValue> Parser::parse_identifier_value(ParsingContext const&, StyleComponentValueRule const& component_value)
+{
if (component_value.is(Token::Type::Ident)) {
auto value_id = value_id_from_string(component_value.token().ident());
if (value_id != ValueID::Invalid)
return IdentifierStyleValue::create(value_id);
}
+ return {};
+}
+
+RefPtr<StyleValue> Parser::parse_color_value(ParsingContext const&, StyleComponentValueRule const& component_value)
+{
auto parse_css_color = [&]() -> Optional<Color> {
if (component_value.is(Token::Type::Ident) && component_value.token().ident().equals_ignoring_case("transparent"))
return Color::from_rgba(0x00000000);
@@ -1408,6 +1424,11 @@ RefPtr<StyleValue> Parser::parse_single_css_value(PropertyID property_id, StyleC
if (color.has_value())
return ColorStyleValue::create(color.value());
+ return {};
+}
+
+RefPtr<StyleValue> Parser::parse_string_value(ParsingContext const&, StyleComponentValueRule const& component_value)
+{
if (component_value.is(Token::Type::String))
return StringStyleValue::create(component_value.token().string());
@@ -1438,11 +1459,50 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S
return {};
if (component_values.size() == 1)
- return parse_single_css_value(property_id, component_values.first());
+ return parse_css_value(m_context, property_id, component_values.first());
return ValueListStyleValue::create(move(component_values));
}
+RefPtr<StyleValue> Parser::parse_css_value(ParsingContext const& context, PropertyID property_id, StyleComponentValueRule const& component_value)
+{
+ dbgln_if(CSS_PARSER_TRACE, "Parser::parse_css_value '{}'", component_value.to_debug_string());
+
+ // FIXME: Figure out if we still need takes_integer_value, and if so, move this information
+ // into Properties.json.
+ auto takes_integer_value = [](PropertyID property_id) -> bool {
+ return property_id == PropertyID::ZIndex
+ || property_id == PropertyID::FontWeight
+ || property_id == PropertyID::Custom;
+ };
+ if (takes_integer_value(property_id) && component_value.is(Token::Type::Number)) {
+ auto number = component_value.token();
+ if (number.m_number_type == Token::NumberType::Integer) {
+ return LengthStyleValue::create(Length::make_px(number.integer()));
+ }
+ }
+
+ if (auto keyword_or_custom = parse_keyword_or_custom_value(context, component_value))
+ return keyword_or_custom;
+
+ if (auto length = parse_length_value(context, component_value))
+ return length;
+
+ if (auto numeric = parse_numeric_value(context, component_value))
+ return numeric;
+
+ if (auto identifier = parse_identifier_value(context, component_value))
+ return identifier;
+
+ if (auto color = parse_color_value(context, component_value))
+ return color;
+
+ if (auto string = parse_string_value(context, component_value))
+ return string;
+
+ return {};
+}
+
Optional<Selector::SimpleSelector::NthChildPattern> Parser::parse_nth_child_pattern(TokenStream<StyleComponentValueRule>& values)
{
dbgln_if(CSS_PARSER_TRACE, "Parser::parse_nth_child_pattern");
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
index 6e8b82e927..fc0d6fed2b 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
@@ -19,6 +19,7 @@
#include <LibWeb/CSS/Parser/StyleRule.h>
#include <LibWeb/CSS/Parser/Tokenizer.h>
#include <LibWeb/CSS/Selector.h>
+#include <LibWeb/CSS/StyleValue.h>
namespace Web::CSS {
@@ -26,7 +27,6 @@ class CSSStyleSheet;
class CSSRule;
class CSSStyleRule;
struct StyleProperty;
-class StyleValue;
enum class PropertyID;
class ParsingContext {
@@ -127,16 +127,7 @@ public:
NonnullRefPtrVector<Selector> parse_a_relative_selector(TokenStream<T>&);
RefPtr<StyleValue> parse_css_value(PropertyID, TokenStream<StyleComponentValueRule>&);
-
- // FIXME: https://drafts.csswg.org/css-backgrounds-3/
- static Optional<String> as_valid_background_repeat(String input) { return input; }
- static Optional<String> as_valid_background_attachment(String input) { return input; }
- static Optional<String> as_valid_background_position(String input) { return input; }
- static Optional<String> as_valid_background_clip(String input) { return input; }
- static Optional<String> as_valid_background_origin(String input) { return input; }
- static Optional<String> as_valid_background_size(String input) { return input; }
- static Optional<String> as_valid_border_style(String input) { return input; }
- static Optional<String> as_valid_border_image_repeat(String input) { return input; }
+ static RefPtr<StyleValue> parse_css_value(ParsingContext const&, PropertyID, StyleComponentValueRule const&);
private:
[[nodiscard]] NonnullRefPtrVector<StyleRule> consume_a_list_of_rules(bool top_level);
@@ -177,7 +168,12 @@ private:
static Optional<float> try_parse_float(StringView string);
- RefPtr<StyleValue> parse_single_css_value(PropertyID, StyleComponentValueRule const&);
+ static RefPtr<StyleValue> parse_keyword_or_custom_value(ParsingContext const&, StyleComponentValueRule const&);
+ static RefPtr<StyleValue> parse_length_value(ParsingContext const&, StyleComponentValueRule const&);
+ static RefPtr<StyleValue> parse_numeric_value(ParsingContext const&, StyleComponentValueRule const&);
+ static RefPtr<StyleValue> parse_identifier_value(ParsingContext const&, StyleComponentValueRule const&);
+ static RefPtr<StyleValue> parse_color_value(ParsingContext const&, StyleComponentValueRule const&);
+ static RefPtr<StyleValue> parse_string_value(ParsingContext const&, StyleComponentValueRule const&);
ParsingContext m_context;
diff --git a/Userland/Libraries/LibWeb/CSS/StyleValue.h b/Userland/Libraries/LibWeb/CSS/StyleValue.h
index 8f7e0fc06b..ab73ffe788 100644
--- a/Userland/Libraries/LibWeb/CSS/StyleValue.h
+++ b/Userland/Libraries/LibWeb/CSS/StyleValue.h
@@ -239,6 +239,11 @@ public:
bool is_numeric() const { return type() == Type::Numeric; }
bool is_value_list() const { return type() == Type::ValueList; }
+ bool is_builtin_or_dynamic() const
+ {
+ return is_inherit() || is_initial() || is_custom_property();
+ }
+
virtual String to_string() const = 0;
virtual Length to_length() const { return Length::make_auto(); }
virtual Color to_color(const DOM::Document&) const { return {}; }