mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
LibWeb: Validate literal numeric values at parse time
This brings a couple of advantages: - Previously we relied on the caller validating the parsed value was in bounds after the fact - this was usually fine but there are a couple of places that it was forgotten (see the tests added in this commit), requiring the bounds to be passed as arguments makes us consider the desired range more explicitly. - In a future commit we will use the passed bounds as the clamping bounds for computed values, removing the need for the existing `ValueParsingContext` based method we have at the moment. - Generating code is easier with this approach
This commit is contained in:
Notes:
github-actions[bot]
2026-04-22 13:25:26 +00:00
Author: https://github.com/Calme1709 Commit: https://github.com/LadybirdBrowser/ladybird/commit/76250ba1420 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8959 Reviewed-by: https://github.com/AtkinsSJ ✅
@@ -13,7 +13,16 @@ namespace Web::CSS {
|
||||
struct NumericRange {
|
||||
double min;
|
||||
double max;
|
||||
|
||||
bool contains(double value) const { return value >= min && value <= max; }
|
||||
};
|
||||
|
||||
using NumericRangesByValueType = HashMap<ValueType, NumericRange>;
|
||||
|
||||
constexpr NumericRange infinite_range = { AK::NumericLimits<float>::lowest(), AK::NumericLimits<float>::max() };
|
||||
constexpr NumericRange non_negative_range = { 0, AK::NumericLimits<float>::max() };
|
||||
|
||||
constexpr NumericRange infinite_integer_range = { AK::NumericLimits<i32>::min(), AK::NumericLimits<i32>::max() };
|
||||
constexpr NumericRange non_negative_integer_range = { 0, AK::NumericLimits<i32>::max() };
|
||||
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
||||
return CounterStyleSystemStyleValue::create(system.release_value());
|
||||
|
||||
if (keyword_value->to_keyword() == Keyword::Fixed) {
|
||||
auto integer_value = parse_integer_value(tokens);
|
||||
auto integer_value = parse_integer_value(tokens, infinite_integer_range);
|
||||
|
||||
return CounterStyleSystemStyleValue::create_fixed(integer_value);
|
||||
}
|
||||
@@ -200,7 +200,7 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
||||
if (auto keyword_value = parse_keyword_value(tokens); keyword_value && keyword_value->to_keyword() == Keyword::Infinite)
|
||||
return keyword_value;
|
||||
|
||||
if (auto integer_value = parse_integer_value(tokens); integer_value)
|
||||
if (auto integer_value = parse_integer_value(tokens, infinite_integer_range); integer_value)
|
||||
return integer_value;
|
||||
|
||||
return nullptr;
|
||||
@@ -317,7 +317,7 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
||||
return StyleValueList::create({ first.release_nonnull(), second.release_nonnull() }, StyleValueList::Separator::Space);
|
||||
}
|
||||
case DescriptorMetadata::ValueType::Length:
|
||||
return parse_length_value(tokens);
|
||||
return parse_length_value(tokens, infinite_range);
|
||||
case DescriptorMetadata::ValueType::OptionalDeclarationValue: {
|
||||
tokens.discard_whitespace();
|
||||
|
||||
@@ -340,18 +340,11 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
||||
return value.release_nonnull();
|
||||
|
||||
// <length [0,∞]>{1,2}
|
||||
if (auto first_length = parse_length_value(tokens)) {
|
||||
if (first_length->is_length() && first_length->as_length().raw_value() < 0)
|
||||
return nullptr;
|
||||
|
||||
if (auto first_length = parse_length_value(tokens, non_negative_range)) {
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (auto second_length = parse_length_value(tokens)) {
|
||||
if (second_length->is_length() && second_length->as_length().raw_value() < 0)
|
||||
return nullptr;
|
||||
|
||||
if (auto second_length = parse_length_value(tokens, non_negative_range))
|
||||
return StyleValueList::create(StyleValueVector { first_length.release_nonnull(), second_length.release_nonnull() }, StyleValueList::Separator::Space);
|
||||
}
|
||||
|
||||
return first_length.release_nonnull();
|
||||
}
|
||||
@@ -392,13 +385,12 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_descriptor_v
|
||||
return page_size ? page_size.release_nonnull() : orientation.release_nonnull();
|
||||
}
|
||||
case DescriptorMetadata::ValueType::PositivePercentage: {
|
||||
if (auto percentage_value = parse_percentage_value(tokens)) {
|
||||
if (percentage_value->is_percentage()) {
|
||||
if (percentage_value->as_percentage().raw_value() < 0)
|
||||
return nullptr;
|
||||
if (auto percentage_value = parse_percentage_value(tokens, non_negative_range)) {
|
||||
if (percentage_value->is_percentage())
|
||||
return percentage_value.release_nonnull();
|
||||
}
|
||||
// All calculations in descriptors must be resolvable at parse-time.
|
||||
|
||||
// FIXME: Support relative lengths within calcs here (i.e. by absolutizing and clamping rather
|
||||
// than rejecting anything that doesn't resolve at parse time)
|
||||
if (percentage_value->is_calculated()) {
|
||||
auto percentage = percentage_value->as_calculated().resolve_percentage({});
|
||||
if (percentage.has_value() && percentage->value() >= 0)
|
||||
|
||||
@@ -117,7 +117,7 @@ Optional<Vector<ColorStopListElement>> Parser::parse_linear_color_stop_list(Toke
|
||||
// <linear-color-stop> , [ <linear-color-hint>? , <linear-color-stop> ]#
|
||||
return parse_color_stop_list(
|
||||
tokens,
|
||||
[&](auto& it) { return parse_length_percentage_value(it); });
|
||||
[&](auto& it) { return parse_length_percentage_value(it, infinite_range, infinite_range); });
|
||||
}
|
||||
|
||||
Optional<Vector<ColorStopListElement>> Parser::parse_angular_color_stop_list(TokenStream<ComponentValue>& tokens)
|
||||
@@ -138,7 +138,7 @@ Optional<Vector<ColorStopListElement>> Parser::parse_angular_color_stop_list(Tok
|
||||
}
|
||||
}
|
||||
|
||||
return parse_angle_percentage_value(it);
|
||||
return parse_angle_percentage_value(it, infinite_range, infinite_range);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ RefPtr<LinearGradientStyleValue const> Parser::parse_linear_gradient_function(To
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto const& first_param = tokens.next_token();
|
||||
if (auto maybe_angle = parse_angle_value(tokens)) {
|
||||
if (auto maybe_angle = parse_angle_value(tokens, infinite_range)) {
|
||||
gradient_direction = maybe_angle.release_nonnull();
|
||||
} else if (first_param.is(Token::Type::Number) && first_param.token().number_value() == 0) {
|
||||
// <zero>
|
||||
@@ -327,7 +327,7 @@ RefPtr<ConicGradientStyleValue const> Parser::parse_conic_gradient_function(Toke
|
||||
// from [ <angle> | <zero> ]
|
||||
if (from_angle || at_position)
|
||||
return nullptr;
|
||||
if (auto maybe_angle = parse_angle_value(tokens)) {
|
||||
if (auto maybe_angle = parse_angle_value(tokens, infinite_range)) {
|
||||
from_angle = maybe_angle.release_nonnull();
|
||||
} else if (auto peek_token = tokens.next_token(); peek_token.is(Token::Type::Number) && peek_token.token().number_value() == 0) {
|
||||
tokens.discard_a_token(); // 0
|
||||
|
||||
@@ -510,7 +510,7 @@ Optional<MediaFeatureValue> Parser::parse_media_feature_value(MediaFeatureID med
|
||||
if (media_feature_accepts_type(media_feature, MediaFeatureValueType::Boolean)) {
|
||||
auto transaction = tokens.begin_transaction();
|
||||
tokens.discard_whitespace();
|
||||
if (auto integer = parse_integer_value(tokens)) {
|
||||
if (auto integer = parse_integer_value(tokens, infinite_integer_range)) {
|
||||
if (integer->is_calculated() || first_is_one_of(integer->as_integer().integer(), 0, 1)) {
|
||||
transaction.commit();
|
||||
return MediaFeatureValue(MediaFeatureValue::Type::Integer, integer.release_nonnull());
|
||||
@@ -521,7 +521,7 @@ Optional<MediaFeatureValue> Parser::parse_media_feature_value(MediaFeatureID med
|
||||
// Integer
|
||||
if (media_feature_accepts_type(media_feature, MediaFeatureValueType::Integer)) {
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto integer = parse_integer_value(tokens)) {
|
||||
if (auto integer = parse_integer_value(tokens, infinite_integer_range)) {
|
||||
transaction.commit();
|
||||
return MediaFeatureValue(MediaFeatureValue::Type::Integer, integer.release_nonnull());
|
||||
}
|
||||
@@ -531,7 +531,7 @@ Optional<MediaFeatureValue> Parser::parse_media_feature_value(MediaFeatureID med
|
||||
if (media_feature_accepts_type(media_feature, MediaFeatureValueType::Length)) {
|
||||
auto transaction = tokens.begin_transaction();
|
||||
tokens.discard_whitespace();
|
||||
if (auto length = parse_length_value(tokens)) {
|
||||
if (auto length = parse_length_value(tokens, infinite_range)) {
|
||||
transaction.commit();
|
||||
return MediaFeatureValue(MediaFeatureValue::Type::Length, length.release_nonnull());
|
||||
}
|
||||
@@ -571,7 +571,7 @@ Optional<MediaFeatureValue> Parser::parse_media_feature_value(MediaFeatureID med
|
||||
if (media_feature_accepts_type(media_feature, MediaFeatureValueType::Resolution)) {
|
||||
auto transaction = tokens.begin_transaction();
|
||||
tokens.discard_whitespace();
|
||||
if (auto resolution = parse_resolution_value(tokens)) {
|
||||
if (auto resolution = parse_resolution_value(tokens, infinite_range)) {
|
||||
transaction.commit();
|
||||
return MediaFeatureValue(MediaFeatureValue::Type::Resolution, resolution.release_nonnull());
|
||||
}
|
||||
|
||||
@@ -1876,13 +1876,12 @@ RefPtr<StyleValue const> Parser::parse_source_size_value(TokenStream<ComponentVa
|
||||
return KeywordStyleValue::create(Keyword::Auto);
|
||||
}
|
||||
|
||||
if (auto parsed = parse_length_value(tokens)) {
|
||||
// https://html.spec.whatwg.org/multipage/images.html#valid-source-size-list
|
||||
// "A <source-size-value> that is a <length> must not be negative,
|
||||
// and must not use CSS functions other than the math functions."
|
||||
if (parsed->is_length() && parsed->as_length().length().raw_value() < 0)
|
||||
return {};
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/images.html#valid-source-size-list
|
||||
// "A <source-size-value> that is a <length> must not be negative,
|
||||
// and must not use CSS functions other than the math functions."
|
||||
if (auto parsed = parse_length_value(tokens, non_negative_range)) {
|
||||
// FIXME: It seems odd that we disallow infinite calculated values here rather than clamping as we do for all
|
||||
// other values - is this correct?
|
||||
if (parsed->is_calculated()) {
|
||||
// https://drafts.csswg.org/css-values-4/#calc-range
|
||||
// "the value resulting from a top-level calculation must be
|
||||
|
||||
@@ -458,21 +458,22 @@ private:
|
||||
|
||||
RefPtr<StyleValue const> parse_anchor(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_anchor_size(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_angle_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_angle_percentage_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_flex_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_frequency_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_frequency_percentage_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_integer_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_length_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_length_percentage_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_number_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_number_percentage_value(TokenStream<ComponentValue>& tokens);
|
||||
RefPtr<StyleValue const> parse_angle_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_angle_percentage_value(TokenStream<ComponentValue>&, NumericRange const& accepted_angle_range, NumericRange const& accepted_percentage_range);
|
||||
RefPtr<StyleValue const> parse_flex_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_frequency_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_frequency_percentage_value(TokenStream<ComponentValue>&, NumericRange const& accepted_frequency_range, NumericRange const& accepted_percentage_range);
|
||||
RefPtr<StyleValue const> parse_integer_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_length_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_length_percentage_value(TokenStream<ComponentValue>&, NumericRange const& accepted_length_range, NumericRange const& accepted_percentage_range);
|
||||
RefPtr<StyleValue const> parse_number_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_number_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_number_range, NumericRange const& accepted_percentage_range);
|
||||
RefPtr<StyleValue const> parse_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_resolution_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_time_value(TokenStream<ComponentValue>&, NumericRange const& accepted_range);
|
||||
RefPtr<StyleValue const> parse_time_percentage_value(TokenStream<ComponentValue>&, NumericRange const& accepted_time_range, NumericRange const& accepted_percentage_range);
|
||||
|
||||
RefPtr<StyleValue const> parse_number_percentage_none_value(TokenStream<ComponentValue>& tokens);
|
||||
RefPtr<StyleValue const> parse_percentage_value(TokenStream<ComponentValue>& tokens);
|
||||
RefPtr<StyleValue const> parse_resolution_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_time_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<StyleValue const> parse_time_percentage_value(TokenStream<ComponentValue>&);
|
||||
|
||||
RefPtr<StyleValue const> parse_view_timeline_inset_value(TokenStream<ComponentValue>&);
|
||||
RefPtr<ScrollFunctionStyleValue const> parse_scroll_function_value(TokenStream<ComponentValue>&);
|
||||
|
||||
@@ -270,197 +270,93 @@ Optional<Parser::PropertyAndValue> Parser::parse_css_value_for_properties(Readon
|
||||
// <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()) {
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto value = parse_integer_value(tokens)) {
|
||||
if ((value->is_integer() && property_accepts_integer(*property, value->as_integer().integer())) || !value->is_integer()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
if (auto value = parse_integer_value(tokens, property_accepted_ranges_by_value_type(*property).get(ValueType::Integer).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Number); property.has_value()) {
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto value = parse_number_value(tokens)) {
|
||||
if ((value->is_number() && property_accepts_number(*property, value->as_number().number())) || !value->is_number()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
if (auto value = parse_number_value(tokens, property_accepted_ranges_by_value_type(*property).get(ValueType::Number).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Angle); property.has_value()) {
|
||||
auto const& valid_ranges = property_accepted_ranges_by_value_type(*property);
|
||||
auto const& angle_range = valid_ranges.get(ValueType::Angle).value();
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (property_resolves_percentages_relative_to(*property) == ValueType::Angle) {
|
||||
if (auto value = parse_angle_percentage_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_angle() && property_accepts_angle(*property, value->as_angle().angle())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_percentage() && property_accepts_percentage(*property, value->as_percentage().percentage())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto value = parse_angle_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
if (auto value = parse_angle_percentage_value(tokens, angle_range, valid_ranges.get(ValueType::Percentage).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_angle() && property_accepts_angle(*property, value->as_angle().angle())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = parse_angle_value(tokens, angle_range))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Flex); property.has_value()) {
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto value = parse_flex_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_flex() && property_accepts_flex(*property, value->as_flex().flex())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
if (auto value = parse_flex_value(tokens, property_accepted_ranges_by_value_type(*property).get(ValueType::Flex).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Frequency); property.has_value()) {
|
||||
auto const& valid_ranges = property_accepted_ranges_by_value_type(*property);
|
||||
auto const& frequency_range = valid_ranges.get(ValueType::Frequency).value();
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (property_resolves_percentages_relative_to(*property) == ValueType::Frequency) {
|
||||
if (auto value = parse_frequency_percentage_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_frequency() && property_accepts_frequency(*property, value->as_frequency().frequency())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_percentage() && property_accepts_percentage(*property, value->as_percentage().percentage())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto value = parse_frequency_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
if (auto value = parse_frequency_percentage_value(tokens, frequency_range, valid_ranges.get(ValueType::Percentage).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_frequency() && property_accepts_frequency(*property, value->as_frequency().frequency())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = parse_frequency_value(tokens, frequency_range))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto parsed = parse_for_type(ValueType::FitContent); parsed.has_value())
|
||||
return parsed.release_value();
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Length); property.has_value()) {
|
||||
auto const& valid_ranges = property_accepted_ranges_by_value_type(*property);
|
||||
auto const& length_range = valid_ranges.get(ValueType::Length).value();
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (property_resolves_percentages_relative_to(*property) == ValueType::Length) {
|
||||
if (auto value = parse_length_percentage_value(tokens)) {
|
||||
if (value->is_calculated() || value->is_anchor_size()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_length() && property_accepts_length(*property, value->as_length().length())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_percentage() && property_accepts_percentage(*property, value->as_percentage().percentage())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto value = parse_length_value(tokens)) {
|
||||
if (value->is_calculated() || value->is_anchor_size()) {
|
||||
transaction.commit();
|
||||
if (auto value = parse_length_percentage_value(tokens, length_range, valid_ranges.get(ValueType::Percentage).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_length() && property_accepts_length(*property, value->as_length().length())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = parse_length_value(tokens, length_range))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Resolution); property.has_value()) {
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto value = parse_resolution_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_resolution() && property_accepts_resolution(*property, value->as_resolution().resolution())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = parse_resolution_value(tokens, property_accepted_ranges_by_value_type(*property).get(ValueType::Resolution).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Time); property.has_value()) {
|
||||
auto const& valid_ranges = property_accepted_ranges_by_value_type(*property);
|
||||
auto const& time_range = valid_ranges.get(ValueType::Time).value();
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (property_resolves_percentages_relative_to(*property) == ValueType::Time) {
|
||||
if (auto value = parse_time_percentage_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_time() && property_accepts_time(*property, value->as_time().time())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_percentage() && property_accepts_percentage(*property, value->as_percentage().percentage())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto value = parse_time_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
if (auto value = parse_time_percentage_value(tokens, time_range, valid_ranges.get(ValueType::Percentage).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_time() && property_accepts_time(*property, value->as_time().time())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = parse_time_value(tokens, time_range))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
// <percentage> is checked after the <foo-percentage> types.
|
||||
if (auto property = any_property_accepts_type(property_ids, ValueType::Percentage); property.has_value()) {
|
||||
auto context_guard = push_temporary_value_parsing_context(*property);
|
||||
auto transaction = tokens.begin_transaction();
|
||||
if (auto value = parse_percentage_value(tokens)) {
|
||||
if (value->is_calculated()) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
if (value->is_percentage() && property_accepts_percentage(*property, value->as_percentage().percentage())) {
|
||||
transaction.commit();
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = parse_percentage_value(tokens, property_accepted_ranges_by_value_type(*property).get(ValueType::Percentage).value()))
|
||||
return PropertyAndValue { *property, value };
|
||||
}
|
||||
|
||||
if (auto parsed = parse_for_type(ValueType::Paint); parsed.has_value())
|
||||
@@ -991,7 +887,7 @@ RefPtr<StyleValue const> Parser::parse_counter_definitions_value(TokenStream<Com
|
||||
tokens.discard_whitespace();
|
||||
|
||||
// <integer>?
|
||||
definition.value = parse_integer_value(tokens);
|
||||
definition.value = parse_integer_value(tokens, infinite_integer_range);
|
||||
if (!definition.value && !definition.is_reversed)
|
||||
definition.value = IntegerStyleValue::create(default_value_if_not_reversed);
|
||||
|
||||
@@ -1079,9 +975,9 @@ RefPtr<StyleValue const> Parser::parse_cursor_value(TokenStream<ComponentValue>&
|
||||
|
||||
if (part_tokens.has_next_token()) {
|
||||
// <number>{2}, which are the x and y coordinates of the hotspot
|
||||
auto x = parse_number_value(part_tokens);
|
||||
auto x = parse_number_value(part_tokens, infinite_range);
|
||||
part_tokens.discard_whitespace();
|
||||
auto y = parse_number_value(part_tokens);
|
||||
auto y = parse_number_value(part_tokens, infinite_range);
|
||||
part_tokens.discard_whitespace();
|
||||
if (!x || !y || part_tokens.has_next_token())
|
||||
return nullptr;
|
||||
@@ -1467,7 +1363,7 @@ RefPtr<StyleValue const> Parser::parse_single_background_position_x_or_y_value(T
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
value = parse_length_percentage_value(tokens);
|
||||
value = parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!value) {
|
||||
transaction.commit();
|
||||
return EdgeStyleValue::create(relative_edge, {});
|
||||
@@ -1735,14 +1631,10 @@ RefPtr<StyleValue const> Parser::parse_border_image_slice_value(TokenStream<Comp
|
||||
|
||||
Vector<ValueComparingNonnullRefPtr<StyleValue const>> number_percentages;
|
||||
while (number_percentages.size() <= 4 && tokens.has_next_token()) {
|
||||
auto number_percentage = parse_number_percentage_value(tokens);
|
||||
auto number_percentage = parse_number_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
if (!number_percentage)
|
||||
break;
|
||||
|
||||
if (number_percentage->is_number() && !property_accepts_number(PropertyID::BorderImageSlice, number_percentage->as_number().number()))
|
||||
return nullptr;
|
||||
if (number_percentage->is_percentage() && !property_accepts_percentage(PropertyID::BorderImageSlice, number_percentage->as_percentage().percentage()))
|
||||
return nullptr;
|
||||
number_percentages.append(number_percentage.release_nonnull());
|
||||
tokens.discard_whitespace();
|
||||
}
|
||||
@@ -1804,7 +1696,7 @@ RefPtr<StyleValue const> Parser::parse_border_radius_value(TokenStream<Component
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
tokens.discard_whitespace();
|
||||
auto horizontal = parse_length_percentage_value(tokens);
|
||||
auto horizontal = parse_length_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (tokens.next_token().is_delim('/')) {
|
||||
@@ -1812,7 +1704,7 @@ RefPtr<StyleValue const> Parser::parse_border_radius_value(TokenStream<Component
|
||||
tokens.discard_whitespace();
|
||||
}
|
||||
|
||||
auto vertical = parse_length_percentage_value(tokens);
|
||||
auto vertical = parse_length_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
if (horizontal && vertical) {
|
||||
transaction.commit();
|
||||
return BorderRadiusStyleValue::create(horizontal.release_nonnull(), vertical.release_nonnull());
|
||||
@@ -1960,7 +1852,7 @@ RefPtr<StyleValue const> Parser::parse_single_shadow_value(TokenStream<Component
|
||||
}
|
||||
|
||||
auto const& token = tokens.next_token();
|
||||
if (auto maybe_offset_x = parse_length_value(tokens); maybe_offset_x) {
|
||||
if (auto maybe_offset_x = parse_length_value(tokens, infinite_range); maybe_offset_x) {
|
||||
// horizontal offset
|
||||
if (offset_x)
|
||||
return nullptr;
|
||||
@@ -1970,7 +1862,7 @@ RefPtr<StyleValue const> Parser::parse_single_shadow_value(TokenStream<Component
|
||||
tokens.discard_whitespace();
|
||||
if (!tokens.has_next_token())
|
||||
return nullptr;
|
||||
auto maybe_offset_y = parse_length_value(tokens);
|
||||
auto maybe_offset_y = parse_length_value(tokens, infinite_range);
|
||||
if (!maybe_offset_y)
|
||||
return nullptr;
|
||||
offset_y = maybe_offset_y;
|
||||
@@ -1981,21 +1873,17 @@ RefPtr<StyleValue const> Parser::parse_single_shadow_value(TokenStream<Component
|
||||
break;
|
||||
|
||||
m_value_context.append(SpecialContext::ShadowBlurRadius);
|
||||
auto maybe_blur_radius = parse_length_value(tokens);
|
||||
auto maybe_blur_radius = parse_length_value(tokens, non_negative_range);
|
||||
m_value_context.take_last();
|
||||
if (!maybe_blur_radius)
|
||||
continue;
|
||||
blur_radius = maybe_blur_radius;
|
||||
if (blur_radius->is_length() && blur_radius->as_length().raw_value() < 0)
|
||||
return nullptr;
|
||||
if (blur_radius->is_percentage() && blur_radius->as_percentage().raw_value() < 0)
|
||||
return nullptr;
|
||||
|
||||
// spread distance (optional)
|
||||
tokens.discard_whitespace();
|
||||
if (!tokens.has_next_token())
|
||||
break;
|
||||
auto maybe_spread_distance = parse_length_value(tokens);
|
||||
auto maybe_spread_distance = parse_length_value(tokens, infinite_range);
|
||||
if (!maybe_spread_distance)
|
||||
continue;
|
||||
|
||||
@@ -2100,7 +1988,7 @@ RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>&
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
auto angle = parse_angle_value(tokens);
|
||||
auto angle = parse_angle_value(tokens, infinite_range);
|
||||
tokens.discard_whitespace();
|
||||
|
||||
// <angle>
|
||||
@@ -2127,7 +2015,7 @@ RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>&
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (!angle)
|
||||
angle = parse_angle_value(tokens);
|
||||
angle = parse_angle_value(tokens, infinite_range);
|
||||
|
||||
if (angle) {
|
||||
transaction.commit();
|
||||
@@ -2147,7 +2035,7 @@ RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>&
|
||||
auto numbers_transaction = tokens.begin_transaction();
|
||||
StyleValueVector numbers;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (auto number = parse_number_value(tokens); number) {
|
||||
if (auto number = parse_number_value(tokens, infinite_range); number) {
|
||||
numbers.append(number.release_nonnull());
|
||||
} else {
|
||||
return {};
|
||||
@@ -2162,7 +2050,7 @@ RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>&
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (!angle)
|
||||
angle = parse_angle_value(tokens);
|
||||
angle = parse_angle_value(tokens, infinite_range);
|
||||
|
||||
if (angle) {
|
||||
auto numbers = maybe_numbers.release_value();
|
||||
@@ -2190,20 +2078,16 @@ RefPtr<StyleValue const> Parser::parse_stroke_dasharray_value(TokenStream<Compon
|
||||
tokens.discard_whitespace();
|
||||
|
||||
// A <dasharray> is a list of comma and/or white space separated <number> or <length-percentage> values. A <number> value represents a value in user units.
|
||||
auto value = parse_number_value(tokens);
|
||||
if (value && value->is_number() && value->as_number().number() < 0)
|
||||
return {};
|
||||
// If any value in the list is negative, the <dasharray> value is invalid.
|
||||
auto value = parse_number_value(tokens, non_negative_range);
|
||||
|
||||
if (value) {
|
||||
dashes.append(value.release_nonnull());
|
||||
} else {
|
||||
auto value = parse_length_percentage_value(tokens);
|
||||
auto value = parse_length_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
if (!value)
|
||||
return {};
|
||||
if (value->is_percentage() && value->as_percentage().raw_value() < 0)
|
||||
return {};
|
||||
if (value->is_length() && value->as_length().raw_value() < 0)
|
||||
return {};
|
||||
|
||||
dashes.append(value.release_nonnull());
|
||||
}
|
||||
|
||||
@@ -2864,9 +2748,7 @@ RefPtr<StyleValue const> Parser::parse_font_feature_settings_value(TokenStream<C
|
||||
tag_tokens.discard_whitespace();
|
||||
RefPtr<StyleValue const> value;
|
||||
if (tag_tokens.has_next_token()) {
|
||||
if (auto integer = parse_integer_value(tag_tokens)) {
|
||||
if (integer->is_integer() && integer->as_integer().integer() < 0)
|
||||
return nullptr;
|
||||
if (auto integer = parse_integer_value(tag_tokens, non_negative_integer_range)) {
|
||||
value = integer;
|
||||
} else {
|
||||
// A value of on is synonymous with 1 and off is synonymous with 0.
|
||||
@@ -2919,7 +2801,7 @@ RefPtr<StyleValue const> Parser::parse_font_variation_settings_value(TokenStream
|
||||
tag_tokens.discard_whitespace();
|
||||
auto opentype_tag = parse_opentype_tag_value(tag_tokens);
|
||||
tag_tokens.discard_whitespace();
|
||||
auto number = parse_number_value(tag_tokens);
|
||||
auto number = parse_number_value(tag_tokens, infinite_range);
|
||||
tag_tokens.discard_whitespace();
|
||||
|
||||
if (!opentype_tag || !number || tag_tokens.has_next_token())
|
||||
@@ -3423,7 +3305,7 @@ RefPtr<StyleValue const> Parser::parse_math_depth_value(TokenStream<ComponentVal
|
||||
|
||||
auto add_tokens = TokenStream { function.value };
|
||||
add_tokens.discard_whitespace();
|
||||
if (auto integer_value = parse_integer_value(add_tokens)) {
|
||||
if (auto integer_value = parse_integer_value(add_tokens, infinite_integer_range)) {
|
||||
add_tokens.discard_whitespace();
|
||||
if (add_tokens.has_next_token())
|
||||
return nullptr;
|
||||
@@ -3435,7 +3317,7 @@ RefPtr<StyleValue const> Parser::parse_math_depth_value(TokenStream<ComponentVal
|
||||
}
|
||||
|
||||
// <integer>
|
||||
if (auto integer_value = parse_integer_value(tokens)) {
|
||||
if (auto integer_value = parse_integer_value(tokens, infinite_integer_range)) {
|
||||
transaction.commit();
|
||||
return integer_value;
|
||||
}
|
||||
@@ -3449,7 +3331,7 @@ RefPtr<StyleValue const> Parser::parse_overflow_clip_margin_value(TokenStream<Co
|
||||
// <visual-box> || <length [0,∞]>
|
||||
// FIXME: Implement the <visual-box> part of this.
|
||||
|
||||
if (auto length = parse_length_value(tokens)) {
|
||||
if (auto length = parse_length_value(tokens, non_negative_range)) {
|
||||
return length.release_nonnull();
|
||||
}
|
||||
|
||||
@@ -4265,7 +4147,7 @@ RefPtr<StyleValue const> Parser::parse_text_indent_value(TokenStream<ComponentVa
|
||||
|
||||
while (tokens.has_next_token()) {
|
||||
if (!length_percentage) {
|
||||
if (auto parsed = parse_length_percentage_value(tokens)) {
|
||||
if (auto parsed = parse_length_percentage_value(tokens, infinite_range, infinite_range)) {
|
||||
length_percentage = parsed.release_nonnull();
|
||||
tokens.discard_whitespace();
|
||||
continue;
|
||||
@@ -4494,7 +4376,7 @@ RefPtr<StyleValue const> Parser::parse_transform_origin_value(TokenStream<Compon
|
||||
}
|
||||
|
||||
auto second_value = to_axis_offset(parse_css_value_for_property(PropertyID::TransformOrigin, tokens));
|
||||
auto third_value = parse_length_value(tokens);
|
||||
auto third_value = parse_length_value(tokens, infinite_range);
|
||||
|
||||
if (!first_value.has_value() || !second_value.has_value())
|
||||
return nullptr;
|
||||
@@ -4615,7 +4497,7 @@ RefPtr<StyleValue const> Parser::parse_translate_value(TokenStream<ComponentValu
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
// <length-percentage> [ <length-percentage> <length>? ]?
|
||||
auto maybe_x = parse_length_percentage_value(tokens);
|
||||
auto maybe_x = parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_x)
|
||||
return nullptr;
|
||||
|
||||
@@ -4625,7 +4507,7 @@ RefPtr<StyleValue const> Parser::parse_translate_value(TokenStream<ComponentValu
|
||||
return TransformationStyleValue::create(PropertyID::Translate, TransformFunction::Translate, { maybe_x.release_nonnull(), LengthStyleValue::create(Length::make_px(0)) });
|
||||
}
|
||||
|
||||
auto maybe_y = parse_length_percentage_value(tokens);
|
||||
auto maybe_y = parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_y)
|
||||
return nullptr;
|
||||
|
||||
@@ -4636,7 +4518,7 @@ RefPtr<StyleValue const> Parser::parse_translate_value(TokenStream<ComponentValu
|
||||
}
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(SpecialContext::TranslateZArgument);
|
||||
auto maybe_z = parse_length_value(tokens);
|
||||
auto maybe_z = parse_length_value(tokens, infinite_range);
|
||||
if (!maybe_z)
|
||||
return nullptr;
|
||||
|
||||
@@ -4656,7 +4538,7 @@ RefPtr<StyleValue const> Parser::parse_scale_value(TokenStream<ComponentValue>&
|
||||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
// [ <number> | <percentage> ]{1,3}
|
||||
auto maybe_x = parse_number_percentage_value(tokens);
|
||||
auto maybe_x = parse_number_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_x)
|
||||
return nullptr;
|
||||
|
||||
@@ -4666,7 +4548,7 @@ RefPtr<StyleValue const> Parser::parse_scale_value(TokenStream<ComponentValue>&
|
||||
return TransformationStyleValue::create(PropertyID::Scale, TransformFunction::Scale, { *maybe_x, *maybe_x });
|
||||
}
|
||||
|
||||
auto maybe_y = parse_number_percentage_value(tokens);
|
||||
auto maybe_y = parse_number_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_y)
|
||||
return nullptr;
|
||||
|
||||
@@ -4676,7 +4558,7 @@ RefPtr<StyleValue const> Parser::parse_scale_value(TokenStream<ComponentValue>&
|
||||
return TransformationStyleValue::create(PropertyID::Scale, TransformFunction::Scale, { maybe_x.release_nonnull(), maybe_y.release_nonnull() });
|
||||
}
|
||||
|
||||
auto maybe_z = parse_number_percentage_value(tokens);
|
||||
auto maybe_z = parse_number_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_z)
|
||||
return nullptr;
|
||||
|
||||
@@ -5494,11 +5376,10 @@ RefPtr<StyleValue const> Parser::parse_filter_value_list_value(TokenStream<Compo
|
||||
return FilterOperation::Blur { LengthStyleValue::create(Length::make_px(0)) };
|
||||
|
||||
// Negative values are not allowed.
|
||||
auto blur_radius = parse_length_value(tokens);
|
||||
auto blur_radius = parse_length_value(tokens, non_negative_range);
|
||||
tokens.discard_whitespace();
|
||||
if (!blur_radius || (blur_radius->is_length() && blur_radius->as_length().raw_value() < 0))
|
||||
if (!blur_radius)
|
||||
return {};
|
||||
|
||||
return if_no_more_tokens_return(FilterOperation::Blur { blur_radius.release_nonnull() });
|
||||
} else if (filter_token == FilterToken::DropShadow) {
|
||||
if (!tokens.has_next_token())
|
||||
@@ -5510,18 +5391,18 @@ RefPtr<StyleValue const> Parser::parse_filter_value_list_value(TokenStream<Compo
|
||||
RefPtr<StyleValue const> maybe_radius;
|
||||
auto maybe_color = parse_color_value(tokens);
|
||||
tokens.discard_whitespace();
|
||||
auto x_offset = parse_length_value(tokens);
|
||||
auto x_offset = parse_length_value(tokens, infinite_range);
|
||||
tokens.discard_whitespace();
|
||||
if (!x_offset || !tokens.has_next_token())
|
||||
return {};
|
||||
|
||||
auto y_offset = parse_length_value(tokens);
|
||||
auto y_offset = parse_length_value(tokens, infinite_range);
|
||||
tokens.discard_whitespace();
|
||||
if (!y_offset)
|
||||
return {};
|
||||
|
||||
if (tokens.has_next_token()) {
|
||||
maybe_radius = parse_length_value(tokens);
|
||||
maybe_radius = parse_length_value(tokens, infinite_range);
|
||||
tokens.discard_whitespace();
|
||||
if (!maybe_color && (!maybe_radius || tokens.has_next_token())) {
|
||||
maybe_color = parse_color_value(tokens);
|
||||
@@ -5550,7 +5431,7 @@ RefPtr<StyleValue const> Parser::parse_filter_value_list_value(TokenStream<Compo
|
||||
return {};
|
||||
}
|
||||
|
||||
if (auto angle = parse_angle_value(tokens))
|
||||
if (auto angle = parse_angle_value(tokens, infinite_range))
|
||||
return if_no_more_tokens_return(FilterOperation::HueRotate { angle.release_nonnull() });
|
||||
|
||||
return {};
|
||||
@@ -5582,18 +5463,12 @@ RefPtr<StyleValue const> Parser::parse_filter_value_list_value(TokenStream<Compo
|
||||
if (!tokens.has_next_token())
|
||||
return FilterOperation::Color { filter_token_to_operation(filter_token), NumberStyleValue::create(1) };
|
||||
|
||||
auto amount = parse_number_percentage_value(tokens);
|
||||
// Negative values are not allowed.
|
||||
auto amount = parse_number_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
|
||||
if (!amount)
|
||||
return {};
|
||||
|
||||
// Negative values are not allowed.
|
||||
if (amount->is_percentage() && amount->as_percentage().percentage().value() < 0)
|
||||
return {};
|
||||
|
||||
if (amount->is_number() && amount->as_number().number() < 0)
|
||||
return {};
|
||||
|
||||
// Values of amount over 100% are allowed but UAs must clamp the values to 1.
|
||||
// NB: Only for grayscale(), invert(), opacity() and sepia() functions
|
||||
if (first_is_one_of(filter_token, FilterToken::Grayscale, FilterToken::Invert, FilterToken::Opacity, FilterToken::Sepia)) {
|
||||
|
||||
@@ -578,12 +578,12 @@ RefPtr<UnicodeRangeStyleValue const> Parser::parse_unicode_range_value(TokenStre
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_integer_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_integer_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto const& peek_token = tokens.next_token();
|
||||
if (peek_token.is(Token::Type::Number) && peek_token.token().is_integer()) {
|
||||
if (peek_token.is(Token::Type::Number) && peek_token.token().is_integer() && accepted_range.contains(peek_token.token().to_integer())) {
|
||||
tokens.discard_a_token(); // integer
|
||||
return IntegerStyleValue::create(peek_token.token().to_integer());
|
||||
}
|
||||
@@ -599,12 +599,12 @@ RefPtr<StyleValue const> Parser::parse_integer_value(TokenStream<ComponentValue>
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_number_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_number_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto const& peek_token = tokens.next_token();
|
||||
if (peek_token.is(Token::Type::Number)) {
|
||||
if (peek_token.is(Token::Type::Number) && accepted_range.contains(peek_token.token().number_value())) {
|
||||
tokens.discard_a_token(); // number
|
||||
return NumberStyleValue::create(peek_token.token().number_value());
|
||||
}
|
||||
@@ -620,12 +620,12 @@ RefPtr<StyleValue const> Parser::parse_number_value(TokenStream<ComponentValue>&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_number_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_number_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_number_range, NumericRange const& accepted_percentage_range)
|
||||
{
|
||||
// Parses [<percentage> | <number>] (which is equivalent to [<alpha-value>])
|
||||
if (auto value = parse_number_value(tokens))
|
||||
if (auto value = parse_number_value(tokens, accepted_number_range))
|
||||
return value;
|
||||
if (auto value = parse_percentage_value(tokens))
|
||||
if (auto value = parse_percentage_value(tokens, accepted_percentage_range))
|
||||
return value;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -633,9 +633,9 @@ RefPtr<StyleValue const> Parser::parse_number_percentage_value(TokenStream<Compo
|
||||
RefPtr<StyleValue const> Parser::parse_number_percentage_none_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// Parses [<percentage> | <number> | none] (which is equivalent to [<alpha-value> | none])
|
||||
if (auto value = parse_number_value(tokens))
|
||||
if (auto value = parse_number_value(tokens, infinite_range))
|
||||
return value;
|
||||
if (auto value = parse_percentage_value(tokens))
|
||||
if (auto value = parse_percentage_value(tokens, infinite_range))
|
||||
return value;
|
||||
|
||||
if (tokens.next_token().is_ident("none"sv)) {
|
||||
@@ -646,12 +646,12 @@ RefPtr<StyleValue const> Parser::parse_number_percentage_none_value(TokenStream<
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto const& peek_token = tokens.next_token();
|
||||
if (peek_token.is(Token::Type::Percentage)) {
|
||||
if (peek_token.is(Token::Type::Percentage) && accepted_range.contains(peek_token.token().percentage())) {
|
||||
tokens.discard_a_token(); // percentage
|
||||
return PercentageStyleValue::create(Percentage(peek_token.token().percentage()));
|
||||
}
|
||||
@@ -702,7 +702,7 @@ RefPtr<StyleValue const> Parser::parse_anchor(TokenStream<ComponentValue>& token
|
||||
anchor_side_value = parse_keyword_value(argument_tokens);
|
||||
if (!anchor_side_value) {
|
||||
// FIXME: Only percentages are allowed here, but we parse a length-percentage so that calc values are handled.
|
||||
anchor_side_value = parse_length_percentage_value(argument_tokens);
|
||||
anchor_side_value = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range);
|
||||
if (!anchor_side_value)
|
||||
return {};
|
||||
|
||||
@@ -716,7 +716,7 @@ RefPtr<StyleValue const> Parser::parse_anchor(TokenStream<ComponentValue>& token
|
||||
if (argument_tokens.next_token().is(Token::Type::Comma)) {
|
||||
argument_tokens.discard_a_token();
|
||||
argument_tokens.discard_whitespace();
|
||||
fallback_value = parse_length_percentage_value(argument_tokens);
|
||||
fallback_value = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range);
|
||||
if (!fallback_value)
|
||||
fallback_value = parse_anchor(argument_tokens);
|
||||
if (!fallback_value)
|
||||
@@ -850,7 +850,7 @@ RefPtr<StyleValue const> Parser::parse_anchor_size(TokenStream<ComponentValue>&
|
||||
// FIXME: Nested anchor sizes should actually be handled by parse_length_percentage()
|
||||
if (auto nested_anchor_size = parse_anchor_size(argument_tokens))
|
||||
fallback_value = nested_anchor_size.release_nonnull();
|
||||
else if (auto length_percentage = parse_length_percentage_value(argument_tokens))
|
||||
else if (auto length_percentage = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range))
|
||||
fallback_value = length_percentage.release_nonnull();
|
||||
|
||||
if (!fallback_value && comma_present)
|
||||
@@ -864,7 +864,7 @@ RefPtr<StyleValue const> Parser::parse_anchor_size(TokenStream<ComponentValue>&
|
||||
return AnchorSizeStyleValue::create(anchor_name, anchor_size, fallback_value);
|
||||
}
|
||||
|
||||
static RefPtr<AngleStyleValue const> parse_literal_angle_value(TokenStream<ComponentValue>& tokens, bool is_parsing_svg_presentation_attribute)
|
||||
static RefPtr<AngleStyleValue const> parse_literal_angle_value(TokenStream<ComponentValue>& tokens, bool is_parsing_svg_presentation_attribute, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
@@ -872,8 +872,13 @@ static RefPtr<AngleStyleValue const> parse_literal_angle_value(TokenStream<Compo
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto& dimension_token = tokens.consume_a_token().token();
|
||||
if (auto angle_type = string_to_angle_unit(dimension_token.dimension_unit()); angle_type.has_value()) {
|
||||
Angle angle { dimension_token.dimension_value(), angle_type.release_value() };
|
||||
|
||||
if (!accepted_range.contains(angle.to_degrees()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return AngleStyleValue::create(Angle { (dimension_token.dimension_value()), angle_type.release_value() });
|
||||
return AngleStyleValue::create(move(angle));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -883,26 +888,30 @@ static RefPtr<AngleStyleValue const> parse_literal_angle_value(TokenStream<Compo
|
||||
// FIXME: How should these numbers be interpreted? https://github.com/w3c/svgwg/issues/792
|
||||
// For now: Convert to an angle in degrees.
|
||||
if (tokens.next_token().is(Token::Type::Number) && is_parsing_svg_presentation_attribute) {
|
||||
auto numeric_value = tokens.consume_a_token().token().number_value();
|
||||
return AngleStyleValue::create(Angle::make_degrees(numeric_value));
|
||||
auto angle = Angle::make_degrees(tokens.consume_a_token().token().number_value());
|
||||
|
||||
if (!accepted_range.contains(angle.to_degrees()))
|
||||
return nullptr;
|
||||
|
||||
return AngleStyleValue::create(move(angle));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static RefPtr<PercentageStyleValue const> parse_literal_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
static RefPtr<PercentageStyleValue const> parse_literal_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (tokens.next_token().is(Token::Type::Percentage))
|
||||
if (tokens.next_token().is(Token::Type::Percentage) && accepted_range.contains(tokens.next_token().token().percentage()))
|
||||
return PercentageStyleValue::create(Percentage { tokens.consume_a_token().token().percentage() });
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_angle_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_angle_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
if (auto literal_angle = parse_literal_angle_value(tokens, is_parsing_svg_presentation_attribute()))
|
||||
if (auto literal_angle = parse_literal_angle_value(tokens, is_parsing_svg_presentation_attribute(), accepted_range))
|
||||
return literal_angle;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
@@ -913,12 +922,12 @@ RefPtr<StyleValue const> Parser::parse_angle_value(TokenStream<ComponentValue>&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_angle_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_angle_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_angle_range, NumericRange const& accepted_percentage_range)
|
||||
{
|
||||
if (auto literal_angle = parse_literal_angle_value(tokens, is_parsing_svg_presentation_attribute()))
|
||||
if (auto literal_angle = parse_literal_angle_value(tokens, is_parsing_svg_presentation_attribute(), accepted_angle_range))
|
||||
return literal_angle;
|
||||
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens))
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens, accepted_percentage_range))
|
||||
return literal_percentage;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
@@ -929,7 +938,7 @@ RefPtr<StyleValue const> Parser::parse_angle_percentage_value(TokenStream<Compon
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_flex_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_flex_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
@@ -937,8 +946,13 @@ RefPtr<StyleValue const> Parser::parse_flex_value(TokenStream<ComponentValue>& t
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto& dimension_token = tokens.consume_a_token().token();
|
||||
if (auto flex_type = string_to_flex_unit(dimension_token.dimension_unit()); flex_type.has_value()) {
|
||||
Flex flex { (dimension_token.dimension_value()), flex_type.release_value() };
|
||||
|
||||
if (!accepted_range.contains(flex.to_fr()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return FlexStyleValue::create(Flex { (dimension_token.dimension_value()), flex_type.release_value() });
|
||||
return FlexStyleValue::create(move(flex));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -951,7 +965,7 @@ RefPtr<StyleValue const> Parser::parse_flex_value(TokenStream<ComponentValue>& t
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static RefPtr<FrequencyStyleValue const> parse_literal_frequency_value(TokenStream<ComponentValue>& tokens)
|
||||
static RefPtr<FrequencyStyleValue const> parse_literal_frequency_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
@@ -959,17 +973,22 @@ static RefPtr<FrequencyStyleValue const> parse_literal_frequency_value(TokenStre
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto& dimension_token = tokens.consume_a_token().token();
|
||||
if (auto frequency_type = string_to_frequency_unit(dimension_token.dimension_unit()); frequency_type.has_value()) {
|
||||
Frequency frequency { dimension_token.dimension_value(), frequency_type.release_value() };
|
||||
|
||||
if (!accepted_range.contains(frequency.to_hertz()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return FrequencyStyleValue::create(Frequency { (dimension_token.dimension_value()), frequency_type.release_value() });
|
||||
return FrequencyStyleValue::create(move(frequency));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_frequency_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_frequency_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
if (auto literal_frequency = parse_literal_frequency_value(tokens))
|
||||
if (auto literal_frequency = parse_literal_frequency_value(tokens, accepted_range))
|
||||
return literal_frequency;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
@@ -980,12 +999,12 @@ RefPtr<StyleValue const> Parser::parse_frequency_value(TokenStream<ComponentValu
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_frequency_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_frequency_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_frequency_range, NumericRange const& accepted_percentage_range)
|
||||
{
|
||||
if (auto literal_frequency = parse_literal_frequency_value(tokens))
|
||||
if (auto literal_frequency = parse_literal_frequency_value(tokens, accepted_frequency_range))
|
||||
return literal_frequency;
|
||||
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens))
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens, accepted_percentage_range))
|
||||
return literal_percentage;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
@@ -996,7 +1015,7 @@ RefPtr<StyleValue const> Parser::parse_frequency_percentage_value(TokenStream<Co
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static RefPtr<LengthStyleValue const> parse_literal_length_value(TokenStream<ComponentValue>& tokens, bool context_allows_quirky_length, bool is_parsing_svg_presentation_attribute)
|
||||
static RefPtr<LengthStyleValue const> parse_literal_length_value(TokenStream<ComponentValue>& tokens, bool context_allows_quirky_length, bool is_parsing_svg_presentation_attribute, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
@@ -1004,8 +1023,18 @@ static RefPtr<LengthStyleValue const> parse_literal_length_value(TokenStream<Com
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto const& dimension_token = tokens.consume_a_token().token();
|
||||
if (auto length_type = string_to_length_unit(dimension_token.dimension_unit()); length_type.has_value()) {
|
||||
Length length { dimension_token.dimension_value(), length_type.release_value() };
|
||||
|
||||
// NB: Since we can't convert font/viewport relative lengths to their canonical units at parse time it
|
||||
// doesn't make sense to have non-zero/non-infinite bounds for lengths
|
||||
VERIFY(accepted_range.min == AK::NumericLimits<float>::lowest() || accepted_range.min == 0);
|
||||
VERIFY(accepted_range.max == AK::NumericLimits<float>::max() || accepted_range.max == 0);
|
||||
|
||||
if (!accepted_range.contains(length.raw_value()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return LengthStyleValue::create(Length { (dimension_token.dimension_value()), length_type.release_value() });
|
||||
return LengthStyleValue::create(length);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1014,12 +1043,20 @@ static RefPtr<LengthStyleValue const> parse_literal_length_value(TokenStream<Com
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto numeric_value = tokens.consume_a_token().token().number_value();
|
||||
if (numeric_value == 0) {
|
||||
if (!accepted_range.contains(0))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return LengthStyleValue::create(Length::make_px(0));
|
||||
}
|
||||
if (context_allows_quirky_length) {
|
||||
auto nearest_value = CSSPixels::nearest_value_for(numeric_value);
|
||||
|
||||
if (!accepted_range.contains(nearest_value.to_double()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return LengthStyleValue::create(Length::make_px(CSSPixels::nearest_value_for(numeric_value)));
|
||||
return LengthStyleValue::create(Length::make_px(nearest_value));
|
||||
}
|
||||
|
||||
// https://svgwg.org/svg2-draft/types.html#presentation-attribute-css-value
|
||||
@@ -1027,17 +1064,22 @@ static RefPtr<LengthStyleValue const> parse_literal_length_value(TokenStream<Com
|
||||
// FIXME: How should these numbers be interpreted? https://github.com/w3c/svgwg/issues/792
|
||||
// For now: Convert to a length in pixels.
|
||||
if (is_parsing_svg_presentation_attribute) {
|
||||
auto nearest_value = CSSPixels::nearest_value_for(numeric_value);
|
||||
|
||||
if (!accepted_range.contains(nearest_value.to_double()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return LengthStyleValue::create(Length::make_px(CSSPixels::nearest_value_for(numeric_value)));
|
||||
return LengthStyleValue::create(Length::make_px(nearest_value));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_length_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_length_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
if (auto literal_length = parse_literal_length_value(tokens, context_allows_quirky_length(), is_parsing_svg_presentation_attribute()))
|
||||
if (auto literal_length = parse_literal_length_value(tokens, context_allows_quirky_length(), is_parsing_svg_presentation_attribute(), accepted_range))
|
||||
return literal_length;
|
||||
|
||||
if (tokens.next_token().is_function("anchor-size"sv))
|
||||
@@ -1051,12 +1093,12 @@ RefPtr<StyleValue const> Parser::parse_length_value(TokenStream<ComponentValue>&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_length_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_length_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_length_range, NumericRange const& accepted_percentage_range)
|
||||
{
|
||||
if (auto literal_length = parse_literal_length_value(tokens, context_allows_quirky_length(), is_parsing_svg_presentation_attribute()))
|
||||
if (auto literal_length = parse_literal_length_value(tokens, context_allows_quirky_length(), is_parsing_svg_presentation_attribute(), accepted_length_range))
|
||||
return literal_length;
|
||||
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens))
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens, accepted_percentage_range))
|
||||
return literal_percentage;
|
||||
|
||||
if (tokens.next_token().is_function("anchor-size"sv))
|
||||
@@ -1070,21 +1112,24 @@ RefPtr<StyleValue const> Parser::parse_length_percentage_value(TokenStream<Compo
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_resolution_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_resolution_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (tokens.next_token().is(Token::Type::Dimension)) {
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto& dimension_token = tokens.consume_a_token().token();
|
||||
// The allowed range of <resolution> values always excludes negative values, in addition to any explicit
|
||||
// ranges that might be specified.
|
||||
// https://drafts.csswg.org/css-values-4/#resolution
|
||||
if (dimension_token.dimension_value() < 0)
|
||||
return nullptr;
|
||||
if (auto resolution_type = string_to_resolution_unit(dimension_token.dimension_unit()); resolution_type.has_value()) {
|
||||
Resolution resolution { dimension_token.dimension_value(), resolution_type.release_value() };
|
||||
|
||||
// The allowed range of <resolution> values always excludes negative values, in addition to any explicit
|
||||
// ranges that might be specified.
|
||||
// https://drafts.csswg.org/css-values-4/#resolution
|
||||
if (dimension_token.dimension_value() < 0 || !accepted_range.contains(resolution.to_dots_per_pixel()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return ResolutionStyleValue::create(Resolution { (dimension_token.dimension_value()), resolution_type.release_value() });
|
||||
return ResolutionStyleValue::create(move(resolution));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1097,7 +1142,7 @@ RefPtr<StyleValue const> Parser::parse_resolution_value(TokenStream<ComponentVal
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static RefPtr<TimeStyleValue const> parse_literal_time_value(TokenStream<ComponentValue>& tokens)
|
||||
static RefPtr<TimeStyleValue const> parse_literal_time_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
tokens.discard_whitespace();
|
||||
|
||||
@@ -1105,17 +1150,22 @@ static RefPtr<TimeStyleValue const> parse_literal_time_value(TokenStream<Compone
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto const& dimension_token = tokens.consume_a_token().token();
|
||||
if (auto time_type = string_to_time_unit(dimension_token.dimension_unit()); time_type.has_value()) {
|
||||
Time time { dimension_token.dimension_value(), time_type.release_value() };
|
||||
|
||||
if (!accepted_range.contains(time.to_seconds()))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return TimeStyleValue::create(Time { (dimension_token.dimension_value()), time_type.release_value() });
|
||||
return TimeStyleValue::create(move(time));
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_time_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_time_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_range)
|
||||
{
|
||||
if (auto literal_time = parse_literal_time_value(tokens))
|
||||
if (auto literal_time = parse_literal_time_value(tokens, accepted_range))
|
||||
return literal_time;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
@@ -1126,12 +1176,12 @@ RefPtr<StyleValue const> Parser::parse_time_value(TokenStream<ComponentValue>& t
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<StyleValue const> Parser::parse_time_percentage_value(TokenStream<ComponentValue>& tokens)
|
||||
RefPtr<StyleValue const> Parser::parse_time_percentage_value(TokenStream<ComponentValue>& tokens, NumericRange const& accepted_time_range, NumericRange const& accepted_percentage_range)
|
||||
{
|
||||
if (auto literal_time = parse_literal_time_value(tokens))
|
||||
if (auto literal_time = parse_literal_time_value(tokens, accepted_time_range))
|
||||
return literal_time;
|
||||
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens))
|
||||
if (auto literal_percentage = parse_literal_percentage_value(tokens, accepted_percentage_range))
|
||||
return literal_percentage;
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
@@ -1159,7 +1209,7 @@ RefPtr<StyleValue const> Parser::parse_view_timeline_inset_value(TokenStream<Com
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto length_percentage = parse_length_percentage_value(tokens)) {
|
||||
if (auto length_percentage = parse_length_percentage_value(tokens, infinite_range, infinite_range)) {
|
||||
inset_values.append(length_percentage.release_nonnull());
|
||||
continue;
|
||||
}
|
||||
@@ -1343,7 +1393,7 @@ RefPtr<StyleValue const> Parser::parse_rect_value(TokenStream<ComponentValue>& t
|
||||
(void)argument_tokens.consume_a_token(); // `auto`
|
||||
params.append(KeywordStyleValue::create(Keyword::Auto));
|
||||
} else {
|
||||
auto maybe_length = parse_length_value(argument_tokens);
|
||||
auto maybe_length = parse_length_value(argument_tokens, infinite_range);
|
||||
if (!maybe_length)
|
||||
return nullptr;
|
||||
|
||||
@@ -1389,9 +1439,9 @@ RefPtr<StyleValue const> Parser::parse_hue_none_value(TokenStream<ComponentValue
|
||||
// Parses [<hue> | none]
|
||||
// <hue> = <number> | <angle>
|
||||
|
||||
if (auto angle = parse_angle_value(tokens))
|
||||
if (auto angle = parse_angle_value(tokens, infinite_range))
|
||||
return angle;
|
||||
if (auto number = parse_number_value(tokens))
|
||||
if (auto number = parse_number_value(tokens, infinite_range))
|
||||
return number;
|
||||
if (tokens.next_token().is_ident("none"sv)) {
|
||||
tokens.discard_a_token(); // keyword none
|
||||
@@ -1474,7 +1524,7 @@ RefPtr<StyleValue const> Parser::parse_rgb_color_value(TokenStream<ComponentValu
|
||||
inner_tokens.discard_a_token(); // comma
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
green = parse_number_percentage_value(inner_tokens);
|
||||
green = parse_number_percentage_value(inner_tokens, infinite_range, infinite_range);
|
||||
if (!green)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
@@ -1483,7 +1533,7 @@ RefPtr<StyleValue const> Parser::parse_rgb_color_value(TokenStream<ComponentValu
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
blue = parse_number_percentage_value(inner_tokens);
|
||||
blue = parse_number_percentage_value(inner_tokens, infinite_range, infinite_range);
|
||||
if (!blue)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
@@ -1494,7 +1544,7 @@ RefPtr<StyleValue const> Parser::parse_rgb_color_value(TokenStream<ComponentValu
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
alpha = parse_number_percentage_value(inner_tokens);
|
||||
alpha = parse_number_percentage_value(inner_tokens, infinite_range, infinite_range);
|
||||
|
||||
if (!alpha)
|
||||
return {};
|
||||
@@ -1596,7 +1646,7 @@ RefPtr<StyleValue const> Parser::parse_hsl_color_value(TokenStream<ComponentValu
|
||||
(void)inner_tokens.consume_a_token(); // comma
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
s = parse_percentage_value(inner_tokens);
|
||||
s = parse_percentage_value(inner_tokens, infinite_range);
|
||||
if (!s)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
@@ -1605,7 +1655,7 @@ RefPtr<StyleValue const> Parser::parse_hsl_color_value(TokenStream<ComponentValu
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
l = parse_percentage_value(inner_tokens);
|
||||
l = parse_percentage_value(inner_tokens, infinite_range);
|
||||
if (!l)
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
@@ -1616,7 +1666,7 @@ RefPtr<StyleValue const> Parser::parse_hsl_color_value(TokenStream<ComponentValu
|
||||
return {};
|
||||
inner_tokens.discard_whitespace();
|
||||
|
||||
alpha = parse_number_percentage_value(inner_tokens);
|
||||
alpha = parse_number_percentage_value(inner_tokens, infinite_range, infinite_range);
|
||||
// The parser has consumed a comma, so the alpha value is now required
|
||||
if (!alpha)
|
||||
return {};
|
||||
@@ -2014,21 +2064,16 @@ RefPtr<StyleValue const> Parser::parse_color_mix_function(TokenStream<ComponentV
|
||||
{
|
||||
auto parse_component = [this](TokenStream<ComponentValue>& function_tokens) -> Optional<ColorMixStyleValue::ColorMixComponent> {
|
||||
function_tokens.discard_whitespace();
|
||||
auto percentage_style_value = parse_percentage_value(function_tokens);
|
||||
auto percentage_style_value = parse_percentage_value(function_tokens, { .min = 0, .max = 100 });
|
||||
function_tokens.discard_whitespace();
|
||||
auto color_style_value = parse_color_value(function_tokens);
|
||||
if (!color_style_value)
|
||||
return {};
|
||||
function_tokens.discard_whitespace();
|
||||
if (!percentage_style_value) {
|
||||
percentage_style_value = parse_percentage_value(function_tokens);
|
||||
percentage_style_value = parse_percentage_value(function_tokens, { .min = 0, .max = 100 });
|
||||
function_tokens.discard_whitespace();
|
||||
}
|
||||
if (percentage_style_value && !percentage_style_value->is_calculated()) {
|
||||
auto percentage = percentage_style_value->as_percentage().percentage().value();
|
||||
if (percentage < 0 || percentage > 100)
|
||||
return {};
|
||||
}
|
||||
return ColorMixStyleValue::ColorMixComponent {
|
||||
.color = color_style_value.release_nonnull(),
|
||||
.percentage = move(percentage_style_value),
|
||||
@@ -2303,7 +2348,7 @@ RefPtr<StyleValue const> Parser::parse_corner_shape_value(TokenStream<ComponentV
|
||||
return SuperellipseStyleValue::create(NumberStyleValue::create(AK::Infinity<double>));
|
||||
}
|
||||
|
||||
if (auto number_value = parse_number_value(function_tokens); number_value) {
|
||||
if (auto number_value = parse_number_value(function_tokens, infinite_range); number_value) {
|
||||
function_tokens.discard_whitespace();
|
||||
|
||||
if (function_tokens.has_next_token())
|
||||
@@ -2548,13 +2593,10 @@ RefPtr<StyleValue const> Parser::parse_nonnegative_integer_symbol_pair_value(Tok
|
||||
RefPtr<StyleValue const> symbol;
|
||||
|
||||
while (tokens.has_next_token()) {
|
||||
if (auto integer_value = parse_integer_value(tokens)) {
|
||||
if (auto integer_value = parse_integer_value(tokens, non_negative_integer_range)) {
|
||||
if (integer)
|
||||
return nullptr;
|
||||
|
||||
if (integer_value->is_integer() && integer_value->as_integer().integer() < 0)
|
||||
return nullptr;
|
||||
|
||||
integer = integer_value;
|
||||
tokens.discard_whitespace();
|
||||
continue;
|
||||
@@ -2589,9 +2631,9 @@ RefPtr<StyleValue const> Parser::parse_ratio_value(TokenStream<ComponentValue>&
|
||||
auto scope_guard = push_temporary_value_parsing_context(SpecialContext::RatioComponent);
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto numerator = parse_number_value(tokens);
|
||||
auto numerator = parse_number_value(tokens, non_negative_range);
|
||||
|
||||
if (!numerator || (numerator->is_number() && numerator->as_number().number() < 0))
|
||||
if (!numerator)
|
||||
return nullptr;
|
||||
|
||||
tokens.discard_whitespace();
|
||||
@@ -2600,8 +2642,8 @@ RefPtr<StyleValue const> Parser::parse_ratio_value(TokenStream<ComponentValue>&
|
||||
tokens.discard_a_token();
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto denominator = parse_number_value(tokens);
|
||||
if (!denominator || (denominator->is_number() && denominator->as_number().number() < 0))
|
||||
auto denominator = parse_number_value(tokens, non_negative_range);
|
||||
if (!denominator)
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
@@ -2775,7 +2817,7 @@ RefPtr<PositionStyleValue const> Parser::parse_position_value(TokenStream<Compon
|
||||
}
|
||||
|
||||
// [ <length-percentage> ]
|
||||
if (auto maybe_percentage = parse_length_percentage_value(tokens)) {
|
||||
if (auto maybe_percentage = parse_length_percentage_value(tokens, infinite_range, infinite_range)) {
|
||||
transaction.commit();
|
||||
return PositionStyleValue::create(EdgeStyleValue::create({}, maybe_percentage), EdgeStyleValue::create(PositionEdge::Center, {}));
|
||||
}
|
||||
@@ -2834,7 +2876,7 @@ RefPtr<PositionStyleValue const> Parser::parse_position_value(TokenStream<Compon
|
||||
return EdgeStyleValue::create(position, {});
|
||||
}
|
||||
|
||||
auto maybe_length = parse_length_percentage_value(tokens);
|
||||
auto maybe_length = parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_length)
|
||||
return nullptr;
|
||||
|
||||
@@ -2872,7 +2914,7 @@ RefPtr<PositionStyleValue const> Parser::parse_position_value(TokenStream<Compon
|
||||
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto maybe_length = parse_length_percentage_value(tokens);
|
||||
auto maybe_length = parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (!maybe_length)
|
||||
return {};
|
||||
|
||||
@@ -2932,7 +2974,7 @@ RefPtr<PositionStyleValue const> Parser::parse_position_value(TokenStream<Compon
|
||||
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto maybe_length = parse_length_percentage_value(tokens);
|
||||
auto maybe_length = parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
if (maybe_length) {
|
||||
// 'center' cannot be followed by a <length-percentage>
|
||||
if (maybe_position.value() == PositionEdge::Center && maybe_length)
|
||||
@@ -3050,17 +3092,17 @@ RefPtr<StyleValue const> Parser::parse_easing_value(TokenStream<ComponentValue>&
|
||||
RefPtr<StyleValue const> first_input;
|
||||
RefPtr<StyleValue const> second_input;
|
||||
|
||||
if (auto maybe_output = parse_number_value(argument_tokens))
|
||||
if (auto maybe_output = parse_number_value(argument_tokens, infinite_range))
|
||||
output = maybe_output;
|
||||
|
||||
if (auto maybe_first_input = parse_percentage_value(argument_tokens)) {
|
||||
if (auto maybe_first_input = parse_percentage_value(argument_tokens, infinite_range)) {
|
||||
first_input = maybe_first_input;
|
||||
if (auto maybe_second_input = parse_percentage_value(argument_tokens)) {
|
||||
if (auto maybe_second_input = parse_percentage_value(argument_tokens, infinite_range)) {
|
||||
second_input = maybe_second_input;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto maybe_output = parse_number_value(argument_tokens)) {
|
||||
if (auto maybe_output = parse_number_value(argument_tokens, infinite_range)) {
|
||||
if (output)
|
||||
return nullptr;
|
||||
output = maybe_output;
|
||||
@@ -3090,24 +3132,20 @@ RefPtr<StyleValue const> Parser::parse_easing_value(TokenStream<ComponentValue>&
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto parse_argument = [this, &comma_separated_arguments](auto index) {
|
||||
auto parse_argument = [this, &comma_separated_arguments](auto index, NumericRange accepted_range) {
|
||||
TokenStream<ComponentValue> argument_tokens { comma_separated_arguments[index] };
|
||||
return parse_number_value(argument_tokens);
|
||||
return parse_number_value(argument_tokens, accepted_range);
|
||||
};
|
||||
|
||||
m_value_context.append(SpecialContext::CubicBezierFunctionXCoordinate);
|
||||
auto x1 = parse_argument(0);
|
||||
auto x2 = parse_argument(2);
|
||||
auto x1 = parse_argument(0, { .min = 0, .max = 1 });
|
||||
auto x2 = parse_argument(2, { .min = 0, .max = 1 });
|
||||
m_value_context.take_last();
|
||||
|
||||
auto y1 = parse_argument(1);
|
||||
auto y2 = parse_argument(3);
|
||||
auto y1 = parse_argument(1, infinite_range);
|
||||
auto y2 = parse_argument(3, infinite_range);
|
||||
if (!x1 || !y1 || !x2 || !y2)
|
||||
return nullptr;
|
||||
if (x1->is_number() && (x1->as_number().number() < 0.0 || x1->as_number().number() > 1.0))
|
||||
return nullptr;
|
||||
if (x2->is_number() && (x2->as_number().number() < 0.0 || x2->as_number().number() > 1.0))
|
||||
return nullptr;
|
||||
|
||||
EasingStyleValue::CubicBezier bezier {
|
||||
x1.release_nonnull(),
|
||||
@@ -3155,24 +3193,18 @@ RefPtr<StyleValue const> Parser::parse_easing_value(TokenStream<ComponentValue>&
|
||||
|
||||
auto const& intervals_argument = comma_separated_arguments[0][0];
|
||||
auto intervals_token = TokenStream<ComponentValue>::of_single_token(intervals_argument);
|
||||
m_value_context.append(position == StepPosition::JumpNone ? SpecialContext::StepsIntervalsJumpNone : SpecialContext::StepsIntervalsNormal);
|
||||
auto intervals = parse_integer_value(intervals_token);
|
||||
m_value_context.take_last();
|
||||
if (!intervals)
|
||||
return nullptr;
|
||||
|
||||
// Perform extra validation
|
||||
// https://drafts.csswg.org/css-easing/#step-easing-functions
|
||||
// If the <step-position> is jump-none, the <integer> must be at least 2, or the function is invalid.
|
||||
// Otherwise, the <integer> must be at least 1, or the function is invalid.
|
||||
if (intervals->is_integer()) {
|
||||
if (position == StepPosition::JumpNone) {
|
||||
if (intervals->as_integer().integer() <= 1)
|
||||
return nullptr;
|
||||
} else if (intervals->as_integer().integer() <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
m_value_context.append(position == StepPosition::JumpNone ? SpecialContext::StepsIntervalsJumpNone : SpecialContext::StepsIntervalsNormal);
|
||||
double min_internals = position == StepPosition::JumpNone ? 2 : 1;
|
||||
auto intervals = parse_integer_value(intervals_token, NumericRange { .min = min_internals, .max = AK::NumericLimits<i32>::max() });
|
||||
m_value_context.take_last();
|
||||
|
||||
if (!intervals)
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return EasingStyleValue::create(EasingStyleValue::Steps { intervals.release_nonnull(), position });
|
||||
@@ -3366,13 +3398,9 @@ RefPtr<BorderRadiusRectStyleValue const> Parser::parse_border_radius_rect_value(
|
||||
continue;
|
||||
}
|
||||
|
||||
auto maybe_dimension = parse_length_percentage_value(tokens);
|
||||
auto maybe_dimension = parse_length_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
if (!maybe_dimension)
|
||||
return nullptr;
|
||||
if (maybe_dimension->is_length() && maybe_dimension->as_length().length().raw_value() < 0)
|
||||
return nullptr;
|
||||
if (maybe_dimension->is_percentage() && maybe_dimension->as_percentage().percentage().value() < 0)
|
||||
return nullptr;
|
||||
if (reading_vertical) {
|
||||
vertical_radii.append(maybe_dimension.release_nonnull());
|
||||
} else {
|
||||
@@ -3429,16 +3457,10 @@ RefPtr<RadialSizeStyleValue const> Parser::parse_radial_size(TokenStream<Compone
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(SpecialContext::RadialSizeLengthPercentage);
|
||||
|
||||
auto length_percentage_value = parse_length_percentage_value(tokens);
|
||||
auto length_percentage_value = parse_length_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
if (!length_percentage_value)
|
||||
return nullptr;
|
||||
|
||||
if (length_percentage_value->is_length() && length_percentage_value->as_length().length().raw_value() < 0)
|
||||
return nullptr;
|
||||
|
||||
if (length_percentage_value->is_percentage() && length_percentage_value->as_percentage().percentage().value() < 0)
|
||||
return nullptr;
|
||||
|
||||
length_percentage_transaction.commit();
|
||||
return length_percentage_value;
|
||||
};
|
||||
@@ -3487,7 +3509,7 @@ RefPtr<FitContentStyleValue const> Parser::parse_fit_content_value(TokenStream<C
|
||||
return nullptr;
|
||||
TokenStream argument_tokens { function.value };
|
||||
argument_tokens.discard_whitespace();
|
||||
auto length_percentage_value = parse_length_percentage_value(argument_tokens);
|
||||
auto length_percentage_value = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range);
|
||||
if (!length_percentage_value)
|
||||
return nullptr;
|
||||
argument_tokens.discard_whitespace();
|
||||
@@ -3515,14 +3537,7 @@ RefPtr<StyleValue const> Parser::parse_font_style_value(TokenStream<ComponentVal
|
||||
|
||||
if (tokens.has_next_token() && keyword_value->to_keyword() == Keyword::Oblique) {
|
||||
auto context_guard = push_temporary_value_parsing_context(SpecialContext::FontStyleAngle);
|
||||
if (auto angle_value = parse_angle_value(tokens)) {
|
||||
if (angle_value->is_angle()) {
|
||||
auto angle = angle_value->as_angle().angle();
|
||||
auto angle_degrees = angle.to_degrees();
|
||||
if (angle_degrees < -90 || angle_degrees > 90)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (auto angle_value = parse_angle_value(tokens, { .min = -90, .max = 90 })) {
|
||||
transaction.commit();
|
||||
return FontStyleStyleValue::create(font_style.release_value(), angle_value);
|
||||
}
|
||||
@@ -3886,22 +3901,22 @@ RefPtr<StyleValue const> Parser::parse_basic_shape_value(TokenStream<ComponentVa
|
||||
// The four <length-percentage>s define the position of the top, right, bottom, and left edges of a rectangle.
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto top = parse_length_percentage_value(arguments_tokens);
|
||||
auto top = parse_length_percentage_value(arguments_tokens, infinite_range, infinite_range);
|
||||
if (!top)
|
||||
return nullptr;
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto right = parse_length_percentage_value(arguments_tokens);
|
||||
auto right = parse_length_percentage_value(arguments_tokens, infinite_range, infinite_range);
|
||||
if (!right)
|
||||
right = top;
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto bottom = parse_length_percentage_value(arguments_tokens);
|
||||
auto bottom = parse_length_percentage_value(arguments_tokens, infinite_range, infinite_range);
|
||||
if (!bottom)
|
||||
bottom = top;
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto left = parse_length_percentage_value(arguments_tokens);
|
||||
auto left = parse_length_percentage_value(arguments_tokens, infinite_range, infinite_range);
|
||||
if (!left)
|
||||
left = right;
|
||||
|
||||
@@ -3932,22 +3947,22 @@ RefPtr<StyleValue const> Parser::parse_basic_shape_value(TokenStream<ComponentVa
|
||||
auto arguments_tokens = TokenStream { component_value.function().value };
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto x = parse_length_percentage_value(arguments_tokens);
|
||||
auto x = parse_length_percentage_value(arguments_tokens, infinite_range, infinite_range);
|
||||
if (!x)
|
||||
return nullptr;
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto y = parse_length_percentage_value(arguments_tokens);
|
||||
auto y = parse_length_percentage_value(arguments_tokens, infinite_range, infinite_range);
|
||||
if (!y)
|
||||
return nullptr;
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto width = parse_length_percentage_value(arguments_tokens);
|
||||
auto width = parse_length_percentage_value(arguments_tokens, non_negative_range, non_negative_range);
|
||||
if (!width)
|
||||
return nullptr;
|
||||
|
||||
arguments_tokens.discard_whitespace();
|
||||
auto height = parse_length_percentage_value(arguments_tokens);
|
||||
auto height = parse_length_percentage_value(arguments_tokens, non_negative_range, non_negative_range);
|
||||
if (!height)
|
||||
return nullptr;
|
||||
|
||||
@@ -3969,13 +3984,6 @@ RefPtr<StyleValue const> Parser::parse_basic_shape_value(TokenStream<ComponentVa
|
||||
if (arguments_tokens.has_next_token())
|
||||
return nullptr;
|
||||
|
||||
// Negative width or height is invalid.
|
||||
if ((width->is_length() && width->as_length().raw_value() < 0)
|
||||
|| (width->is_percentage() && width->as_percentage().raw_value() < 0)
|
||||
|| (height->is_length() && height->as_length().raw_value() < 0)
|
||||
|| (height->is_percentage() && height->as_percentage().raw_value() < 0))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return BasicShapeStyleValue::create(Xywh { x.release_nonnull(), y.release_nonnull(), width.release_nonnull(), height.release_nonnull(), border_radius });
|
||||
}
|
||||
@@ -3986,7 +3994,7 @@ RefPtr<StyleValue const> Parser::parse_basic_shape_value(TokenStream<ComponentVa
|
||||
|
||||
auto parse_length_percentage_or_auto = [this](TokenStream<ComponentValue>& tokens) -> RefPtr<StyleValue const> {
|
||||
tokens.discard_whitespace();
|
||||
if (auto value = parse_length_percentage_value(tokens); value)
|
||||
if (auto value = parse_length_percentage_value(tokens, infinite_range, infinite_range); value)
|
||||
return value;
|
||||
if (tokens.consume_a_token().is_ident("auto"sv))
|
||||
return KeywordStyleValue::create(Keyword::Auto);
|
||||
@@ -4117,12 +4125,12 @@ RefPtr<StyleValue const> Parser::parse_basic_shape_value(TokenStream<ComponentVa
|
||||
TokenStream argument_tokens { argument };
|
||||
|
||||
argument_tokens.discard_whitespace();
|
||||
auto x_pos = parse_length_percentage_value(argument_tokens);
|
||||
auto x_pos = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range);
|
||||
if (!x_pos)
|
||||
return nullptr;
|
||||
|
||||
argument_tokens.discard_whitespace();
|
||||
auto y_pos = parse_length_percentage_value(argument_tokens);
|
||||
auto y_pos = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range);
|
||||
if (!y_pos)
|
||||
return nullptr;
|
||||
|
||||
@@ -4246,15 +4254,13 @@ RefPtr<RandomValueSharingStyleValue const> Parser::parse_random_value_sharing(To
|
||||
tokens.discard_whitespace();
|
||||
|
||||
auto context_guard = push_temporary_value_parsing_context(SpecialContext::RandomValueSharingFixedValue);
|
||||
if (auto fixed_value = parse_number_value(tokens)) {
|
||||
// NB: Fixed values have to be less than one and numbers serialize with six digits of precision
|
||||
if (auto fixed_value = parse_number_value(tokens, { .min = 0, .max = 0.999999 })) {
|
||||
tokens.discard_whitespace();
|
||||
|
||||
if (tokens.has_next_token())
|
||||
return nullptr;
|
||||
|
||||
if (fixed_value->is_number() && (fixed_value->as_number().number() < 0 || fixed_value->as_number().number() >= 1))
|
||||
return nullptr;
|
||||
|
||||
transaction.commit();
|
||||
return RandomValueSharingStyleValue::create_fixed(fixed_value.release_nonnull());
|
||||
}
|
||||
@@ -4341,12 +4347,8 @@ Optional<GridSize> Parser::parse_grid_track_breadth(TokenStream<ComponentValue>&
|
||||
if (auto inflexible_breadth = parse_grid_inflexible_breadth(tokens); inflexible_breadth.has_value())
|
||||
return inflexible_breadth;
|
||||
|
||||
if (auto flex_value = parse_flex_value(tokens)) {
|
||||
if (flex_value->is_flex() && flex_value->as_flex().raw_value() < 0)
|
||||
return {};
|
||||
|
||||
if (auto flex_value = parse_flex_value(tokens, non_negative_range))
|
||||
return GridSize(flex_value.release_nonnull());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -4387,13 +4389,9 @@ RefPtr<StyleValue const> Parser::parse_grid_fixed_breadth(TokenStream<ComponentV
|
||||
// <fixed-breadth> = <length-percentage [0,∞]>
|
||||
|
||||
auto transaction = tokens.begin_transaction();
|
||||
auto length_percentage = parse_length_percentage_value(tokens);
|
||||
auto length_percentage = parse_length_percentage_value(tokens, non_negative_range, non_negative_range);
|
||||
if (!length_percentage)
|
||||
return {};
|
||||
if (length_percentage->is_length() && length_percentage->as_length().raw_value() < 0)
|
||||
return {};
|
||||
if (length_percentage->is_percentage() && length_percentage->as_percentage().raw_value() < 0)
|
||||
return {};
|
||||
transaction.commit();
|
||||
return length_percentage;
|
||||
}
|
||||
@@ -4560,8 +4558,8 @@ Optional<GridRepeat> Parser::parse_grid_track_repeat(TokenStream<ComponentValue>
|
||||
GridRepeatTypeParser parse_repeat_type = [this](TokenStream<ComponentValue>& tokens) -> Optional<GridRepeatParams> {
|
||||
auto context_guard = push_temporary_value_parsing_context(SpecialContext::GridTrackRepeatCount);
|
||||
|
||||
auto maybe_integer = parse_integer_value(tokens);
|
||||
if (!maybe_integer || (maybe_integer->is_integer() && maybe_integer->as_integer().integer() < 1))
|
||||
auto maybe_integer = parse_integer_value(tokens, { .min = 1, .max = NumericLimits<i32>::max() });
|
||||
if (!maybe_integer)
|
||||
return {};
|
||||
|
||||
return GridRepeatParams { GridRepeatType::Fixed, maybe_integer };
|
||||
@@ -4604,8 +4602,8 @@ Optional<GridRepeat> Parser::parse_grid_fixed_repeat(TokenStream<ComponentValue>
|
||||
GridRepeatTypeParser parse_repeat_type = [this](TokenStream<ComponentValue>& tokens) -> Optional<GridRepeatParams> {
|
||||
auto context_guard = push_temporary_value_parsing_context(SpecialContext::GridTrackRepeatCount);
|
||||
|
||||
auto maybe_integer = parse_integer_value(tokens);
|
||||
if (!maybe_integer || (maybe_integer->is_integer() && maybe_integer->as_integer().integer() < 1))
|
||||
auto maybe_integer = parse_integer_value(tokens, { .min = 1, .max = NumericLimits<i32>::max() });
|
||||
if (!maybe_integer)
|
||||
return {};
|
||||
|
||||
return GridRepeatParams { GridRepeatType::Fixed, maybe_integer };
|
||||
@@ -4829,7 +4827,7 @@ RefPtr<GridTrackPlacementStyleValue const> Parser::parse_grid_track_placement(To
|
||||
|
||||
// FIXME: Use the correct value parsing context here to clamp calculated values (note the non-contiguous valid
|
||||
// range for integers for non-span)
|
||||
if (auto maybe_parsed_integer = parse_integer_value(tokens)) {
|
||||
if (auto maybe_parsed_integer = parse_integer_value(tokens, infinite_integer_range)) {
|
||||
if (parsed_integer)
|
||||
return nullptr;
|
||||
|
||||
@@ -5385,7 +5383,7 @@ OwnPtr<BooleanExpression> Parser::parse_if_condition(TokenStream<ComponentValue>
|
||||
RefPtr<StyleValue const> Parser::parse_opacity_value_value(TokenStream<ComponentValue>& tokens)
|
||||
{
|
||||
// <opacity-value> = <number> | <percentage>
|
||||
if (auto value = parse_number_percentage_value(tokens))
|
||||
if (auto value = parse_number_percentage_value(tokens, infinite_range, infinite_range))
|
||||
return OpacityValueStyleValue::create(value.release_nonnull());
|
||||
|
||||
return nullptr;
|
||||
@@ -5687,7 +5685,7 @@ RefPtr<StyleValue const> Parser::parse_transform_function_value(TokenStream<Comp
|
||||
switch (function_metadata.parameters[argument_index].type) {
|
||||
case TransformFunctionParameterType::Angle: {
|
||||
// These are `<angle> | <zero>` in the spec, so we have to check for both kinds.
|
||||
if (auto angle_value = parse_angle_value(argument_tokens)) {
|
||||
if (auto angle_value = parse_angle_value(argument_tokens, infinite_range)) {
|
||||
values.append(angle_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
@@ -5700,7 +5698,7 @@ RefPtr<StyleValue const> Parser::parse_transform_function_value(TokenStream<Comp
|
||||
}
|
||||
case TransformFunctionParameterType::Length:
|
||||
case TransformFunctionParameterType::LengthNone: {
|
||||
if (auto length_value = parse_length_value(argument_tokens)) {
|
||||
if (auto length_value = parse_length_value(argument_tokens, infinite_range)) {
|
||||
values.append(length_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
@@ -5714,21 +5712,21 @@ RefPtr<StyleValue const> Parser::parse_transform_function_value(TokenStream<Comp
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::LengthPercentage: {
|
||||
if (auto length_percentage_value = parse_length_percentage_value(argument_tokens)) {
|
||||
if (auto length_percentage_value = parse_length_percentage_value(argument_tokens, infinite_range, infinite_range)) {
|
||||
values.append(length_percentage_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::Number: {
|
||||
if (auto number_value = parse_number_value(argument_tokens)) {
|
||||
if (auto number_value = parse_number_value(argument_tokens, infinite_range)) {
|
||||
values.append(number_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
case TransformFunctionParameterType::NumberPercentage: {
|
||||
if (auto number_percentage_value = parse_number_percentage_value(argument_tokens)) {
|
||||
if (auto number_percentage_value = parse_number_percentage_value(argument_tokens, infinite_range, infinite_range)) {
|
||||
values.append(number_percentage_value.release_nonnull());
|
||||
break;
|
||||
}
|
||||
@@ -5774,9 +5772,9 @@ RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<C
|
||||
case ValueType::AnchorSize:
|
||||
return parse_anchor_size(tokens);
|
||||
case ValueType::Angle:
|
||||
return parse_angle_value(tokens);
|
||||
return parse_angle_value(tokens, infinite_range);
|
||||
case ValueType::AnglePercentage:
|
||||
return parse_angle_percentage_value(tokens);
|
||||
return parse_angle_percentage_value(tokens, infinite_range, infinite_range);
|
||||
case ValueType::BackgroundPosition:
|
||||
return parse_position_value(tokens, PositionParsingMode::BackgroundPosition);
|
||||
case ValueType::BasicShape:
|
||||
@@ -5801,7 +5799,7 @@ RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<C
|
||||
case ValueType::FitContent:
|
||||
return parse_fit_content_value(tokens);
|
||||
case ValueType::Flex:
|
||||
return parse_flex_value(tokens);
|
||||
return parse_flex_value(tokens, infinite_range);
|
||||
case ValueType::FontStyle:
|
||||
return parse_font_style_value(tokens);
|
||||
case ValueType::FontVariantAlternates:
|
||||
@@ -5813,19 +5811,19 @@ RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<C
|
||||
case ValueType::FontVariantNumeric:
|
||||
return parse_font_variant_numeric_value(tokens);
|
||||
case ValueType::Frequency:
|
||||
return parse_frequency_value(tokens);
|
||||
return parse_frequency_value(tokens, infinite_range);
|
||||
case ValueType::FrequencyPercentage:
|
||||
return parse_frequency_percentage_value(tokens);
|
||||
return parse_frequency_percentage_value(tokens, infinite_range, infinite_range);
|
||||
case ValueType::Image:
|
||||
return parse_image_value(tokens);
|
||||
case ValueType::Integer:
|
||||
return parse_integer_value(tokens);
|
||||
return parse_integer_value(tokens, infinite_integer_range);
|
||||
case ValueType::Length:
|
||||
return parse_length_value(tokens);
|
||||
return parse_length_value(tokens, infinite_range);
|
||||
case ValueType::LengthPercentage:
|
||||
return parse_length_percentage_value(tokens);
|
||||
return parse_length_percentage_value(tokens, infinite_range, infinite_range);
|
||||
case ValueType::Number:
|
||||
return parse_number_value(tokens);
|
||||
return parse_number_value(tokens, infinite_range);
|
||||
case ValueType::OpacityValue:
|
||||
return parse_opacity_value_value(tokens);
|
||||
case ValueType::OpentypeTag:
|
||||
@@ -5833,7 +5831,7 @@ RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<C
|
||||
case ValueType::Paint:
|
||||
return parse_paint_value(tokens);
|
||||
case ValueType::Percentage:
|
||||
return parse_percentage_value(tokens);
|
||||
return parse_percentage_value(tokens, infinite_range);
|
||||
case ValueType::Position:
|
||||
return parse_position_value(tokens);
|
||||
case ValueType::Ratio:
|
||||
@@ -5841,15 +5839,15 @@ RefPtr<StyleValue const> Parser::parse_value(ValueType value_type, TokenStream<C
|
||||
case ValueType::Rect:
|
||||
return parse_rect_value(tokens);
|
||||
case ValueType::Resolution:
|
||||
return parse_resolution_value(tokens);
|
||||
return parse_resolution_value(tokens, infinite_range);
|
||||
case ValueType::ScrollFunction:
|
||||
return parse_scroll_function_value(tokens);
|
||||
case ValueType::String:
|
||||
return parse_string_value(tokens);
|
||||
case ValueType::Time:
|
||||
return parse_time_value(tokens);
|
||||
return parse_time_value(tokens, infinite_range);
|
||||
case ValueType::TimePercentage:
|
||||
return parse_time_percentage_value(tokens);
|
||||
return parse_time_percentage_value(tokens, infinite_range, infinite_range);
|
||||
case ValueType::TransformFunction:
|
||||
return parse_transform_function_value(tokens);
|
||||
case ValueType::TransformList:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#foo { }
|
||||
@@ -0,0 +1 @@
|
||||
#foo { }
|
||||
@@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<style>
|
||||
#foo {
|
||||
border-top-left-radius: -1px;
|
||||
border-top-right-radius: 1px -1px;
|
||||
border-bottom-right-radius: -1px 1px;
|
||||
border-bottom-left-radius: -1px -1px;
|
||||
}
|
||||
</style>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
println(document.styleSheets[0].cssRules[0].cssText);
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<style>
|
||||
#foo {
|
||||
overflow-clip-margin: -1px;
|
||||
}
|
||||
</style>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
println(document.styleSheets[0].cssRules[0].cssText);
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user