mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWeb/CSS: Replace Parser "current property" with a stack of contexts
`current_property_id()` is insufficient to determine if a quirk is allowed. For example, unitless lengths are allowed in certain properties, but NOT if they are inside a calc() or other function. It's also incorrect when we are parsing a longhand inside a shorthand. So instead, replace that with a stack of value-parsing contexts. For now, this is either properties or CSS functions, but in future can be expanded to include media features and other places. This lets us disallow quirks inside functions, like we're supposed to. It also lays the groundwork for being able to more easily determine what type a percentage inside a calculation should become, as this is based on the same stack of contexts.
This commit is contained in:
parent
619df0bc2c
commit
bc00ef8314
Notes:
github-actions[bot]
2025-01-13 11:00:39 +00:00
Author: https://github.com/AtkinsSJ
Commit: bc00ef8314
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3198
4 changed files with 196 additions and 76 deletions
|
@ -150,6 +150,8 @@ RefPtr<CSSStyleValue> Parser::parse_linear_gradient_function(TokenStream<Compone
|
||||||
gradient_type = GradientType::WebKit;
|
gradient_type = GradientType::WebKit;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_name });
|
||||||
|
|
||||||
function_name = consume_if_starts_with(function_name, "repeating-"sv, [&] {
|
function_name = consume_if_starts_with(function_name, "repeating-"sv, [&] {
|
||||||
repeating_gradient = GradientRepeating::Yes;
|
repeating_gradient = GradientRepeating::Yes;
|
||||||
});
|
});
|
||||||
|
@ -274,6 +276,7 @@ RefPtr<CSSStyleValue> Parser::parse_conic_gradient_function(TokenStream<Componen
|
||||||
GradientRepeating repeating_gradient = GradientRepeating::No;
|
GradientRepeating repeating_gradient = GradientRepeating::No;
|
||||||
|
|
||||||
auto function_name = component_value.function().name.bytes_as_string_view();
|
auto function_name = component_value.function().name.bytes_as_string_view();
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_name });
|
||||||
|
|
||||||
function_name = consume_if_starts_with(function_name, "repeating-"sv, [&] {
|
function_name = consume_if_starts_with(function_name, "repeating-"sv, [&] {
|
||||||
repeating_gradient = GradientRepeating::Yes;
|
repeating_gradient = GradientRepeating::Yes;
|
||||||
|
@ -384,6 +387,7 @@ RefPtr<CSSStyleValue> Parser::parse_radial_gradient_function(TokenStream<Compone
|
||||||
auto repeating_gradient = GradientRepeating::No;
|
auto repeating_gradient = GradientRepeating::No;
|
||||||
|
|
||||||
auto function_name = component_value.function().name.bytes_as_string_view();
|
auto function_name = component_value.function().name.bytes_as_string_view();
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_name });
|
||||||
|
|
||||||
function_name = consume_if_starts_with(function_name, "repeating-"sv, [&] {
|
function_name = consume_if_starts_with(function_name, "repeating-"sv, [&] {
|
||||||
repeating_gradient = GradientRepeating::Yes;
|
repeating_gradient = GradientRepeating::Yes;
|
||||||
|
|
|
@ -1935,6 +1935,8 @@ RefPtr<CalculatedStyleValue> Parser::parse_calculated_value(ComponentValue const
|
||||||
|
|
||||||
OwnPtr<CalculationNode> Parser::parse_a_calc_function_node(Function const& function)
|
OwnPtr<CalculationNode> Parser::parse_a_calc_function_node(Function const& function)
|
||||||
{
|
{
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
|
||||||
|
|
||||||
if (function.name.equals_ignoring_ascii_case("calc"sv))
|
if (function.name.equals_ignoring_ascii_case("calc"sv))
|
||||||
return parse_a_calculation(function.value);
|
return parse_a_calculation(function.value);
|
||||||
|
|
||||||
|
@ -1976,13 +1978,9 @@ Optional<Dimension> Parser::parse_dimension(ComponentValue const& component_valu
|
||||||
auto numeric_value = component_value.token().number_value();
|
auto numeric_value = component_value.token().number_value();
|
||||||
if (numeric_value == 0)
|
if (numeric_value == 0)
|
||||||
return Length::make_px(0);
|
return Length::make_px(0);
|
||||||
if (m_context.in_quirks_mode() && property_has_quirk(m_context.current_property_id(), Quirk::UnitlessLength)) {
|
|
||||||
// https://quirks.spec.whatwg.org/#quirky-length-value
|
if (context_allows_quirky_length())
|
||||||
// FIXME: Disallow quirk when inside a CSS sub-expression (like `calc()`)
|
|
||||||
// "The <quirky-length> value must not be supported in arguments to CSS expressions other than the rect()
|
|
||||||
// expression, and must not be supported in the supports() static method of the CSS interface."
|
|
||||||
return Length::make_px(CSSPixels::nearest_value_for(numeric_value));
|
return Length::make_px(CSSPixels::nearest_value_for(numeric_value));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -2663,6 +2661,38 @@ RefPtr<CSSStyleValue> Parser::parse_frequency_percentage_value(TokenStream<Compo
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Parser::context_allows_quirky_length() const
|
||||||
|
{
|
||||||
|
if (!m_context.in_quirks_mode())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-values-4/#deprecated-quirky-length
|
||||||
|
// "When CSS is being parsed in quirks mode, <quirky-length> is a type of <length> that is only valid in certain properties:"
|
||||||
|
// (NOTE: List skipped for brevity; quirks data is assigned in Properties.json)
|
||||||
|
// "It is not valid in properties that include or reference these properties, such as the background shorthand,
|
||||||
|
// or inside functional notations such as calc(), except that they must be allowed in rect() in the clip property."
|
||||||
|
|
||||||
|
// So, it must be allowed in the top-level ValueParsingContext, and then not disallowed by any child contexts.
|
||||||
|
|
||||||
|
Optional<PropertyID> top_level_property;
|
||||||
|
if (!m_value_context.is_empty()) {
|
||||||
|
top_level_property = m_value_context.first().visit(
|
||||||
|
[](PropertyID const& property_id) -> Optional<PropertyID> { return property_id; },
|
||||||
|
[](auto const&) -> Optional<PropertyID> { return OptionalNone {}; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unitless_length_allowed = top_level_property.has_value() && property_has_quirk(top_level_property.value(), Quirk::UnitlessLength);
|
||||||
|
for (auto i = 1u; i < m_value_context.size() && unitless_length_allowed; i++) {
|
||||||
|
unitless_length_allowed = m_value_context[i].visit(
|
||||||
|
[](PropertyID const& property_id) { return property_has_quirk(property_id, Quirk::UnitlessLength); },
|
||||||
|
[top_level_property](Parser::FunctionContext const& function_context) {
|
||||||
|
return function_context.name == "rect"sv && top_level_property == PropertyID::Clip;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return unitless_length_allowed;
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<CSSStyleValue> Parser::parse_length_value(TokenStream<ComponentValue>& tokens)
|
RefPtr<CSSStyleValue> Parser::parse_length_value(TokenStream<ComponentValue>& tokens)
|
||||||
{
|
{
|
||||||
if (tokens.next_token().is(Token::Type::Dimension)) {
|
if (tokens.next_token().is(Token::Type::Dimension)) {
|
||||||
|
@ -2682,11 +2712,7 @@ RefPtr<CSSStyleValue> Parser::parse_length_value(TokenStream<ComponentValue>& to
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
return LengthStyleValue::create(Length::make_px(0));
|
return LengthStyleValue::create(Length::make_px(0));
|
||||||
}
|
}
|
||||||
if (m_context.in_quirks_mode() && property_has_quirk(m_context.current_property_id(), Quirk::UnitlessLength)) {
|
if (context_allows_quirky_length()) {
|
||||||
// https://quirks.spec.whatwg.org/#quirky-length-value
|
|
||||||
// FIXME: Disallow quirk when inside a CSS sub-expression (like `calc()`)
|
|
||||||
// "The <quirky-length> value must not be supported in arguments to CSS expressions other than the rect()
|
|
||||||
// expression, and must not be supported in the supports() static method of the CSS interface."
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
return LengthStyleValue::create(Length::make_px(CSSPixels::nearest_value_for(numeric_value)));
|
return LengthStyleValue::create(Length::make_px(CSSPixels::nearest_value_for(numeric_value)));
|
||||||
}
|
}
|
||||||
|
@ -2733,11 +2759,7 @@ RefPtr<CSSStyleValue> Parser::parse_length_percentage_value(TokenStream<Componen
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
return LengthStyleValue::create(Length::make_px(0));
|
return LengthStyleValue::create(Length::make_px(0));
|
||||||
}
|
}
|
||||||
if (m_context.in_quirks_mode() && property_has_quirk(m_context.current_property_id(), Quirk::UnitlessLength)) {
|
if (context_allows_quirky_length()) {
|
||||||
// https://quirks.spec.whatwg.org/#quirky-length-value
|
|
||||||
// FIXME: Disallow quirk when inside a CSS sub-expression (like `calc()`)
|
|
||||||
// "The <quirky-length> value must not be supported in arguments to CSS expressions other than the rect()
|
|
||||||
// expression, and must not be supported in the supports() static method of the CSS interface."
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
return LengthStyleValue::create(Length::make_px(CSSPixels::nearest_value_for(numeric_value)));
|
return LengthStyleValue::create(Length::make_px(CSSPixels::nearest_value_for(numeric_value)));
|
||||||
}
|
}
|
||||||
|
@ -2853,6 +2875,8 @@ RefPtr<CSSStyleValue> Parser::parse_rect_value(TokenStream<ComponentValue>& toke
|
||||||
if (!function_token.is_function("rect"sv))
|
if (!function_token.is_function("rect"sv))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { "rect"sv });
|
||||||
|
|
||||||
Vector<Length, 4> params;
|
Vector<Length, 4> params;
|
||||||
auto argument_tokens = TokenStream { function_token.function().value };
|
auto argument_tokens = TokenStream { function_token.function().value };
|
||||||
|
|
||||||
|
@ -2988,6 +3012,8 @@ RefPtr<CSSStyleValue> Parser::parse_rgb_color_value(TokenStream<ComponentValue>&
|
||||||
if (!function_token.is_function("rgb"sv) && !function_token.is_function("rgba"sv))
|
if (!function_token.is_function("rgb"sv) && !function_token.is_function("rgba"sv))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.function().name });
|
||||||
|
|
||||||
RefPtr<CSSStyleValue> red;
|
RefPtr<CSSStyleValue> red;
|
||||||
RefPtr<CSSStyleValue> green;
|
RefPtr<CSSStyleValue> green;
|
||||||
RefPtr<CSSStyleValue> blue;
|
RefPtr<CSSStyleValue> blue;
|
||||||
|
@ -3110,6 +3136,8 @@ RefPtr<CSSStyleValue> Parser::parse_hsl_color_value(TokenStream<ComponentValue>&
|
||||||
if (!function_token.is_function("hsl"sv) && !function_token.is_function("hsla"sv))
|
if (!function_token.is_function("hsl"sv) && !function_token.is_function("hsla"sv))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.function().name });
|
||||||
|
|
||||||
RefPtr<CSSStyleValue> h;
|
RefPtr<CSSStyleValue> h;
|
||||||
RefPtr<CSSStyleValue> s;
|
RefPtr<CSSStyleValue> s;
|
||||||
RefPtr<CSSStyleValue> l;
|
RefPtr<CSSStyleValue> l;
|
||||||
|
@ -3211,6 +3239,8 @@ RefPtr<CSSStyleValue> Parser::parse_hwb_color_value(TokenStream<ComponentValue>&
|
||||||
if (!function_token.is_function("hwb"sv))
|
if (!function_token.is_function("hwb"sv))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.function().name });
|
||||||
|
|
||||||
RefPtr<CSSStyleValue> h;
|
RefPtr<CSSStyleValue> h;
|
||||||
RefPtr<CSSStyleValue> w;
|
RefPtr<CSSStyleValue> w;
|
||||||
RefPtr<CSSStyleValue> b;
|
RefPtr<CSSStyleValue> b;
|
||||||
|
@ -3444,6 +3474,8 @@ RefPtr<CSSStyleValue> Parser::parse_color_function(TokenStream<ComponentValue>&
|
||||||
if (!function_token.is_function("color"sv))
|
if (!function_token.is_function("color"sv))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.function().name });
|
||||||
|
|
||||||
auto inner_tokens = TokenStream { function_token.function().value };
|
auto inner_tokens = TokenStream { function_token.function().value };
|
||||||
inner_tokens.discard_whitespace();
|
inner_tokens.discard_whitespace();
|
||||||
|
|
||||||
|
@ -3579,66 +3611,89 @@ RefPtr<CSSStyleValue> Parser::parse_color_value(TokenStream<ComponentValue>& tok
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk
|
// https://drafts.csswg.org/css-color-4/#quirky-color
|
||||||
if (m_context.in_quirks_mode() && property_has_quirk(m_context.current_property_id(), Quirk::HashlessHexColor)) {
|
if (m_context.in_quirks_mode()) {
|
||||||
// The value of a quirky color is obtained from the possible component values using the following algorithm,
|
// "When CSS is being parsed in quirks mode, <quirky-color> is a type of <color> that is only valid in certain properties:"
|
||||||
// aborting on the first step that returns a value:
|
// (NOTE: List skipped for brevity; quirks data is assigned in Properties.json)
|
||||||
|
// "It is not valid in properties that include or reference these properties, such as the background shorthand,
|
||||||
|
// or inside functional notations such as color-mix()"
|
||||||
|
|
||||||
// 1. Let cv be the component value.
|
bool quirky_color_allowed = false;
|
||||||
auto const& cv = component_value;
|
if (!m_value_context.is_empty()) {
|
||||||
String serialization;
|
quirky_color_allowed = m_value_context.first().visit(
|
||||||
// 2. If cv is a <number-token> or a <dimension-token>, follow these substeps:
|
[](PropertyID const& property_id) { return property_has_quirk(property_id, Quirk::HashlessHexColor); },
|
||||||
if (cv.is(Token::Type::Number) || cv.is(Token::Type::Dimension)) {
|
[](FunctionContext const&) { return false; });
|
||||||
// 1. If cv’s type flag is not "integer", return an error.
|
}
|
||||||
// This means that values that happen to use scientific notation, e.g., 5e5e5e, will fail to parse.
|
for (auto i = 1u; i < m_value_context.size() && quirky_color_allowed; i++) {
|
||||||
if (!cv.token().number().is_integer())
|
quirky_color_allowed = m_value_context[i].visit(
|
||||||
return {};
|
[](PropertyID const& property_id) { return property_has_quirk(property_id, Quirk::UnitlessLength); },
|
||||||
|
[](FunctionContext const&) {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (quirky_color_allowed) {
|
||||||
|
// NOTE: This algorithm is no longer in the spec, since the concept got moved and renamed. However, it works,
|
||||||
|
// and so we might as well keep using it.
|
||||||
|
|
||||||
// 2. If cv’s value is less than zero, return an error.
|
// The value of a quirky color is obtained from the possible component values using the following algorithm,
|
||||||
auto value = cv.is(Token::Type::Number) ? cv.token().to_integer() : cv.token().dimension_value_int();
|
// aborting on the first step that returns a value:
|
||||||
if (value < 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// 3. Let serialization be the serialization of cv’s value, as a base-ten integer using digits 0-9 (U+0030 to U+0039) in the shortest form possible.
|
// 1. Let cv be the component value.
|
||||||
StringBuilder serialization_builder;
|
auto const& cv = component_value;
|
||||||
serialization_builder.appendff("{}", value);
|
String serialization;
|
||||||
|
// 2. If cv is a <number-token> or a <dimension-token>, follow these substeps:
|
||||||
|
if (cv.is(Token::Type::Number) || cv.is(Token::Type::Dimension)) {
|
||||||
|
// 1. If cv’s type flag is not "integer", return an error.
|
||||||
|
// This means that values that happen to use scientific notation, e.g., 5e5e5e, will fail to parse.
|
||||||
|
if (!cv.token().number().is_integer())
|
||||||
|
return {};
|
||||||
|
|
||||||
// 4. If cv is a <dimension-token>, append the unit to serialization.
|
// 2. If cv’s value is less than zero, return an error.
|
||||||
if (cv.is(Token::Type::Dimension))
|
auto value = cv.is(Token::Type::Number) ? cv.token().to_integer() : cv.token().dimension_value_int();
|
||||||
serialization_builder.append(cv.token().dimension_unit());
|
if (value < 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
// 5. If serialization consists of fewer than six characters, prepend zeros (U+0030) so that it becomes six characters.
|
// 3. Let serialization be the serialization of cv’s value, as a base-ten integer using digits 0-9 (U+0030 to U+0039) in the shortest form possible.
|
||||||
serialization = MUST(serialization_builder.to_string());
|
StringBuilder serialization_builder;
|
||||||
if (serialization_builder.length() < 6) {
|
serialization_builder.appendff("{}", value);
|
||||||
StringBuilder builder;
|
|
||||||
for (size_t i = 0; i < (6 - serialization_builder.length()); i++)
|
// 4. If cv is a <dimension-token>, append the unit to serialization.
|
||||||
builder.append('0');
|
if (cv.is(Token::Type::Dimension))
|
||||||
builder.append(serialization_builder.string_view());
|
serialization_builder.append(cv.token().dimension_unit());
|
||||||
serialization = MUST(builder.to_string());
|
|
||||||
|
// 5. If serialization consists of fewer than six characters, prepend zeros (U+0030) so that it becomes six characters.
|
||||||
|
serialization = MUST(serialization_builder.to_string());
|
||||||
|
if (serialization_builder.length() < 6) {
|
||||||
|
StringBuilder builder;
|
||||||
|
for (size_t i = 0; i < (6 - serialization_builder.length()); i++)
|
||||||
|
builder.append('0');
|
||||||
|
builder.append(serialization_builder.string_view());
|
||||||
|
serialization = MUST(builder.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// 3. Otherwise, cv is an <ident-token>; let serialization be cv’s value.
|
||||||
// 3. Otherwise, cv is an <ident-token>; let serialization be cv’s value.
|
else {
|
||||||
else {
|
if (!cv.is(Token::Type::Ident))
|
||||||
if (!cv.is(Token::Type::Ident))
|
return {};
|
||||||
|
serialization = cv.token().ident().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. If serialization does not consist of three or six characters, return an error.
|
||||||
|
if (serialization.bytes().size() != 3 && serialization.bytes().size() != 6)
|
||||||
return {};
|
return {};
|
||||||
serialization = cv.token().ident().to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. If serialization does not consist of three or six characters, return an error.
|
// 5. If serialization contains any characters not in the range [0-9A-Fa-f] (U+0030 to U+0039, U+0041 to U+0046, U+0061 to U+0066), return an error.
|
||||||
if (serialization.bytes().size() != 3 && serialization.bytes().size() != 6)
|
for (auto c : serialization.bytes_as_string_view()) {
|
||||||
return {};
|
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')))
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// 5. If serialization contains any characters not in the range [0-9A-Fa-f] (U+0030 to U+0039, U+0041 to U+0046, U+0061 to U+0066), return an error.
|
// 6. Return the concatenation of "#" (U+0023) and serialization.
|
||||||
for (auto c : serialization.bytes_as_string_view()) {
|
auto color = Color::from_string(MUST(String::formatted("#{}", serialization)));
|
||||||
if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')))
|
if (color.has_value()) {
|
||||||
return {};
|
transaction.commit();
|
||||||
}
|
return CSSColorValue::create_from_color(color.release_value());
|
||||||
|
}
|
||||||
// 6. Return the concatenation of "#" (U+0023) and serialization.
|
|
||||||
auto color = Color::from_string(MUST(String::formatted("#{}", serialization)));
|
|
||||||
if (color.has_value()) {
|
|
||||||
transaction.commit();
|
|
||||||
return CSSColorValue::create_from_color(color.release_value());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3759,6 +3814,8 @@ RefPtr<CSSStyleValue> Parser::parse_counter_value(TokenStream<ComponentValue>& t
|
||||||
if (token.is_function("counter"sv)) {
|
if (token.is_function("counter"sv)) {
|
||||||
// counter() = counter( <counter-name>, <counter-style>? )
|
// counter() = counter( <counter-name>, <counter-style>? )
|
||||||
auto& function = token.function();
|
auto& function = token.function();
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
|
||||||
|
|
||||||
TokenStream function_tokens { function.value };
|
TokenStream function_tokens { function.value };
|
||||||
auto function_values = parse_a_comma_separated_list_of_component_values(function_tokens);
|
auto function_values = parse_a_comma_separated_list_of_component_values(function_tokens);
|
||||||
if (function_values.is_empty() || function_values.size() > 2)
|
if (function_values.is_empty() || function_values.size() > 2)
|
||||||
|
@ -3787,6 +3844,8 @@ RefPtr<CSSStyleValue> Parser::parse_counter_value(TokenStream<ComponentValue>& t
|
||||||
if (token.is_function("counters"sv)) {
|
if (token.is_function("counters"sv)) {
|
||||||
// counters() = counters( <counter-name>, <string>, <counter-style>? )
|
// counters() = counters( <counter-name>, <string>, <counter-style>? )
|
||||||
auto& function = token.function();
|
auto& function = token.function();
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
|
||||||
|
|
||||||
TokenStream function_tokens { function.value };
|
TokenStream function_tokens { function.value };
|
||||||
auto function_values = parse_a_comma_separated_list_of_component_values(function_tokens);
|
auto function_values = parse_a_comma_separated_list_of_component_values(function_tokens);
|
||||||
if (function_values.size() < 2 || function_values.size() > 3)
|
if (function_values.size() < 2 || function_values.size() > 3)
|
||||||
|
@ -5649,6 +5708,8 @@ RefPtr<CSSStyleValue> Parser::parse_filter_value_list_value(TokenStream<Componen
|
||||||
auto filter_token = parse_filter_function_name(token.function().name);
|
auto filter_token = parse_filter_function_name(token.function().name);
|
||||||
if (!filter_token.has_value())
|
if (!filter_token.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { token.function().name });
|
||||||
auto filter_function = parse_filter_function(*filter_token, token.function().value);
|
auto filter_function = parse_filter_function(*filter_token, token.function().value);
|
||||||
if (!filter_function.has_value())
|
if (!filter_function.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -6654,6 +6715,8 @@ Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<T>& compo
|
||||||
|
|
||||||
auto const& function = maybe_function.function();
|
auto const& function = maybe_function.function();
|
||||||
if (function.name.equals_ignoring_ascii_case("format"sv)) {
|
if (function.name.equals_ignoring_ascii_case("format"sv)) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
|
||||||
|
|
||||||
TokenStream format_tokens { function.value };
|
TokenStream format_tokens { function.value };
|
||||||
format_tokens.discard_whitespace();
|
format_tokens.discard_whitespace();
|
||||||
auto const& format_name_token = format_tokens.consume_a_token();
|
auto const& format_name_token = format_tokens.consume_a_token();
|
||||||
|
@ -6815,6 +6878,8 @@ RefPtr<CSSStyleValue> Parser::parse_math_depth_value(TokenStream<ComponentValue>
|
||||||
|
|
||||||
// add(<integer>)
|
// add(<integer>)
|
||||||
if (token.is_function("add"sv)) {
|
if (token.is_function("add"sv)) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { token.function().name });
|
||||||
|
|
||||||
auto add_tokens = TokenStream { token.function().value };
|
auto add_tokens = TokenStream { token.function().value };
|
||||||
add_tokens.discard_whitespace();
|
add_tokens.discard_whitespace();
|
||||||
auto const& integer_token = add_tokens.consume_a_token();
|
auto const& integer_token = add_tokens.consume_a_token();
|
||||||
|
@ -7105,6 +7170,8 @@ RefPtr<CSSStyleValue> Parser::parse_easing_value(TokenStream<ComponentValue>& to
|
||||||
argument.remove_all_matching([](auto& value) { return value.is(Token::Type::Whitespace); });
|
argument.remove_all_matching([](auto& value) { return value.is(Token::Type::Whitespace); });
|
||||||
|
|
||||||
auto name = part.function().name;
|
auto name = part.function().name;
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { name });
|
||||||
|
|
||||||
if (name.equals_ignoring_ascii_case("linear"sv)) {
|
if (name.equals_ignoring_ascii_case("linear"sv)) {
|
||||||
// linear() = linear( [ <number> && <percentage>{0,2} ]# )
|
// linear() = linear( [ <number> && <percentage>{0,2} ]# )
|
||||||
Vector<EasingStyleValue::Linear::Stop> stops;
|
Vector<EasingStyleValue::Linear::Stop> stops;
|
||||||
|
@ -7255,6 +7322,9 @@ RefPtr<CSSStyleValue> Parser::parse_transform_value(TokenStream<ComponentValue>&
|
||||||
auto maybe_function = transform_function_from_string(part.function().name);
|
auto maybe_function = transform_function_from_string(part.function().name);
|
||||||
if (!maybe_function.has_value())
|
if (!maybe_function.has_value())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { part.function().name });
|
||||||
|
|
||||||
auto function = maybe_function.release_value();
|
auto function = maybe_function.release_value();
|
||||||
auto function_metadata = transform_function_metadata(function);
|
auto function_metadata = transform_function_metadata(function);
|
||||||
|
|
||||||
|
@ -7783,6 +7853,8 @@ Optional<CSS::ExplicitGridTrack> Parser::parse_track_sizing_function(ComponentVa
|
||||||
{
|
{
|
||||||
if (token.is_function()) {
|
if (token.is_function()) {
|
||||||
auto const& function_token = token.function();
|
auto const& function_token = token.function();
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.name });
|
||||||
|
|
||||||
if (function_token.name.equals_ignoring_ascii_case("repeat"sv)) {
|
if (function_token.name.equals_ignoring_ascii_case("repeat"sv)) {
|
||||||
auto maybe_repeat = parse_repeat(function_token.value);
|
auto maybe_repeat = parse_repeat(function_token.value);
|
||||||
if (maybe_repeat.has_value())
|
if (maybe_repeat.has_value())
|
||||||
|
@ -8398,7 +8470,8 @@ bool block_contains_var_or_attr(SimpleBlock const& block)
|
||||||
|
|
||||||
Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(PropertyID property_id, TokenStream<ComponentValue>& unprocessed_tokens, Optional<String> original_source_text)
|
Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue>> Parser::parse_css_value(PropertyID property_id, TokenStream<ComponentValue>& unprocessed_tokens, Optional<String> original_source_text)
|
||||||
{
|
{
|
||||||
m_context.set_current_property_id(property_id);
|
auto context_guard = push_temporary_value_parsing_context(property_id);
|
||||||
|
|
||||||
Vector<ComponentValue> component_values;
|
Vector<ComponentValue> component_values;
|
||||||
bool contains_var_or_attr = false;
|
bool contains_var_or_attr = false;
|
||||||
bool const property_accepts_custom_ident = property_accepts_type(property_id, ValueType::CustomIdent);
|
bool const property_accepts_custom_ident = property_accepts_type(property_id, ValueType::CustomIdent);
|
||||||
|
@ -8824,6 +8897,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
auto& peek_token = tokens.next_token();
|
auto& peek_token = tokens.next_token();
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::EasingFunction); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::EasingFunction); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_easing_function = parse_easing_value(tokens))
|
if (auto maybe_easing_function = parse_easing_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_easing_function };
|
return PropertyAndValue { *property, maybe_easing_function };
|
||||||
}
|
}
|
||||||
|
@ -8841,68 +8915,82 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
|
|
||||||
// Custom idents
|
// Custom idents
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::CustomIdent); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::CustomIdent); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto custom_ident = parse_custom_ident_value(tokens, {}))
|
if (auto custom_ident = parse_custom_ident_value(tokens, {}))
|
||||||
return PropertyAndValue { *property, custom_ident };
|
return PropertyAndValue { *property, custom_ident };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Color); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Color); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_color = parse_color_value(tokens))
|
if (auto maybe_color = parse_color_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_color };
|
return PropertyAndValue { *property, maybe_color };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Counter); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Counter); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_counter = parse_counter_value(tokens))
|
if (auto maybe_counter = parse_counter_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_counter };
|
return PropertyAndValue { *property, maybe_counter };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Image); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Image); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_image = parse_image_value(tokens))
|
if (auto maybe_image = parse_image_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_image };
|
return PropertyAndValue { *property, maybe_image };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Position); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Position); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_position = parse_position_value(tokens))
|
if (auto maybe_position = parse_position_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_position };
|
return PropertyAndValue { *property, maybe_position };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::BackgroundPosition); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::BackgroundPosition); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_position = parse_position_value(tokens, PositionParsingMode::BackgroundPosition))
|
if (auto maybe_position = parse_position_value(tokens, PositionParsingMode::BackgroundPosition))
|
||||||
return PropertyAndValue { *property, maybe_position };
|
return PropertyAndValue { *property, maybe_position };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::BasicShape); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::BasicShape); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_basic_shape = parse_basic_shape_value(tokens))
|
if (auto maybe_basic_shape = parse_basic_shape_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_basic_shape };
|
return PropertyAndValue { *property, maybe_basic_shape };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Ratio); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Ratio); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_ratio = parse_ratio_value(tokens))
|
if (auto maybe_ratio = parse_ratio_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_ratio };
|
return PropertyAndValue { *property, maybe_ratio };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::OpenTypeTag); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::OpenTypeTag); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_rect = parse_opentype_tag_value(tokens))
|
if (auto maybe_rect = parse_opentype_tag_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_rect };
|
return PropertyAndValue { *property, maybe_rect };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Rect); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Rect); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto maybe_rect = parse_rect_value(tokens))
|
if (auto maybe_rect = parse_rect_value(tokens))
|
||||||
return PropertyAndValue { *property, maybe_rect };
|
return PropertyAndValue { *property, maybe_rect };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peek_token.is(Token::Type::String)) {
|
if (peek_token.is(Token::Type::String)) {
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::String); property.has_value())
|
if (auto property = any_property_accepts_type(property_ids, ValueType::String); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
return PropertyAndValue { *property, StringStyleValue::create(tokens.consume_a_token().token().string()) };
|
return PropertyAndValue { *property, StringStyleValue::create(tokens.consume_a_token().token().string()) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Url); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Url); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto url = parse_url_value(tokens))
|
if (auto url = parse_url_value(tokens))
|
||||||
return PropertyAndValue { *property, url };
|
return PropertyAndValue { *property, url };
|
||||||
}
|
}
|
||||||
|
|
||||||
// <integer>/<number> come before <length>, so that 0 is not interpreted as a <length> in case both are allowed.
|
// <integer>/<number> come before <length>, so that 0 is not interpreted as a <length> in case both are allowed.
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Integer); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Integer); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto value = parse_integer_value(tokens)) {
|
if (auto value = parse_integer_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
return PropertyAndValue { *property, value };
|
return PropertyAndValue { *property, value };
|
||||||
|
@ -8912,6 +9000,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Number); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Number); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto value = parse_number_value(tokens)) {
|
if (auto value = parse_number_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
return PropertyAndValue { *property, value };
|
return PropertyAndValue { *property, value };
|
||||||
|
@ -8921,6 +9010,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (property_accepts_type(*property, ValueType::Percentage)) {
|
if (property_accepts_type(*property, ValueType::Percentage)) {
|
||||||
if (auto value = parse_angle_percentage_value(tokens)) {
|
if (auto value = parse_angle_percentage_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
|
@ -8940,6 +9030,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Flex); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Flex); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto value = parse_flex_value(tokens)) {
|
if (auto value = parse_flex_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
return PropertyAndValue { *property, value };
|
return PropertyAndValue { *property, value };
|
||||||
|
@ -8949,6 +9040,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (property_accepts_type(*property, ValueType::Percentage)) {
|
if (property_accepts_type(*property, ValueType::Percentage)) {
|
||||||
if (auto value = parse_frequency_percentage_value(tokens)) {
|
if (auto value = parse_frequency_percentage_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
|
@ -8968,6 +9060,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (property_accepts_type(*property, ValueType::Percentage)) {
|
if (property_accepts_type(*property, ValueType::Percentage)) {
|
||||||
if (auto value = parse_length_percentage_value(tokens)) {
|
if (auto value = parse_length_percentage_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
|
@ -8987,6 +9080,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Resolution); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Resolution); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto value = parse_resolution_value(tokens)) {
|
if (auto value = parse_resolution_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
return PropertyAndValue { *property, value };
|
return PropertyAndValue { *property, value };
|
||||||
|
@ -8996,6 +9090,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (property_accepts_type(*property, ValueType::Percentage)) {
|
if (property_accepts_type(*property, ValueType::Percentage)) {
|
||||||
if (auto value = parse_time_percentage_value(tokens)) {
|
if (auto value = parse_time_percentage_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
|
@ -9016,6 +9111,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
|
|
||||||
// <percentage> is checked after the <foo-percentage> types.
|
// <percentage> is checked after the <foo-percentage> types.
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto value = parse_percentage_value(tokens)) {
|
if (auto value = parse_percentage_value(tokens)) {
|
||||||
if (value->is_calculated())
|
if (value->is_calculated())
|
||||||
return PropertyAndValue { *property, value };
|
return PropertyAndValue { *property, value };
|
||||||
|
@ -9025,6 +9121,7 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Paint); property.has_value()) {
|
if (auto property = any_property_accepts_type(property_ids, ValueType::Paint); property.has_value()) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||||
if (auto value = parse_paint_value(tokens))
|
if (auto value = parse_paint_value(tokens))
|
||||||
return PropertyAndValue { *property, value.release_nonnull() };
|
return PropertyAndValue { *property, value.release_nonnull() };
|
||||||
}
|
}
|
||||||
|
@ -9245,8 +9342,19 @@ OwnPtr<CalculationNode> Parser::convert_to_calculation_node(CalcParsing::Node co
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component_value->is(Token::Type::Percentage)) {
|
if (component_value->is(Token::Type::Percentage)) {
|
||||||
// FIXME: Figure this out in non-property contexts
|
Optional<ValueType> percentage_resolved_type;
|
||||||
auto percentage_resolved_type = property_resolves_percentages_relative_to(m_context.current_property_id());
|
for (auto const& value_context : m_value_context.in_reverse()) {
|
||||||
|
percentage_resolved_type = value_context.visit(
|
||||||
|
[](PropertyID property_id) -> Optional<ValueType> {
|
||||||
|
return property_resolves_percentages_relative_to(property_id);
|
||||||
|
},
|
||||||
|
[](FunctionContext const&) -> Optional<ValueType> {
|
||||||
|
// FIXME: Some functions provide this. The spec mentions `media-progress()` as an example.
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
if (percentage_resolved_type.has_value())
|
||||||
|
break;
|
||||||
|
}
|
||||||
return NumericCalculationNode::create(Percentage { component_value->token().percentage() }, percentage_resolved_type);
|
return NumericCalculationNode::create(Percentage { component_value->token().percentage() }, percentage_resolved_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -443,6 +443,18 @@ private:
|
||||||
Vector<Token> m_tokens;
|
Vector<Token> m_tokens;
|
||||||
TokenStream<Token> m_token_stream;
|
TokenStream<Token> m_token_stream;
|
||||||
|
|
||||||
|
struct FunctionContext {
|
||||||
|
StringView name;
|
||||||
|
};
|
||||||
|
using ValueParsingContext = Variant<PropertyID, FunctionContext>;
|
||||||
|
Vector<ValueParsingContext> m_value_context;
|
||||||
|
auto push_temporary_value_parsing_context(ValueParsingContext&& context)
|
||||||
|
{
|
||||||
|
m_value_context.append(context);
|
||||||
|
return ScopeGuard { [&] { m_value_context.take_last(); } };
|
||||||
|
}
|
||||||
|
bool context_allows_quirky_length() const;
|
||||||
|
|
||||||
enum class ContextType {
|
enum class ContextType {
|
||||||
Unknown,
|
Unknown,
|
||||||
Style,
|
Style,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020-2021, the SerenityOS developers.
|
* Copyright (c) 2020-2021, the SerenityOS developers.
|
||||||
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
|
* Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -34,9 +34,6 @@ public:
|
||||||
HTML::Window const* window() const;
|
HTML::Window const* window() const;
|
||||||
URL::URL complete_url(StringView) const;
|
URL::URL complete_url(StringView) const;
|
||||||
|
|
||||||
PropertyID current_property_id() const { return m_current_property_id; }
|
|
||||||
void set_current_property_id(PropertyID property_id) { m_current_property_id = property_id; }
|
|
||||||
|
|
||||||
JS::Realm& realm() const
|
JS::Realm& realm() const
|
||||||
{
|
{
|
||||||
VERIFY(m_realm);
|
VERIFY(m_realm);
|
||||||
|
@ -46,7 +43,6 @@ public:
|
||||||
private:
|
private:
|
||||||
GC::Ptr<JS::Realm> m_realm;
|
GC::Ptr<JS::Realm> m_realm;
|
||||||
GC::Ptr<DOM::Document const> m_document;
|
GC::Ptr<DOM::Document const> m_document;
|
||||||
PropertyID m_current_property_id { PropertyID::Invalid };
|
|
||||||
URL::URL m_url;
|
URL::URL m_url;
|
||||||
Mode m_mode { Mode::Normal };
|
Mode m_mode { Mode::Normal };
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue