/* * Copyright (c) 2020-2021, the SerenityOS developers. * Copyright (c) 2021-2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Web::CSS::Parser { class PropertyDependencyNode; class Parser { public: static Parser create(ParsingContext const&, StringView input, StringView encoding = "utf-8"sv); Parser(Parser&&); CSSStyleSheet* parse_as_css_stylesheet(Optional location); ElementInlineCSSStyleDeclaration* parse_as_style_attribute(DOM::Element&); CSSRule* parse_as_css_rule(); Optional parse_as_supports_condition(); enum class SelectorParsingMode { Standard, // `` and `` // are handled with this parameter, not as separate functions. // https://drafts.csswg.org/selectors/#forgiving-selector Forgiving }; // Contrary to the name, these parse a comma-separated list of selectors, according to the spec. Optional parse_as_selector(SelectorParsingMode = SelectorParsingMode::Standard); Optional parse_as_relative_selector(SelectorParsingMode = SelectorParsingMode::Standard); Optional parse_as_pseudo_element_selector(); Vector> parse_as_media_query_list(); RefPtr parse_as_media_query(); RefPtr parse_as_supports(); RefPtr parse_as_css_value(PropertyID); Optional parse_as_component_value(); Vector parse_as_font_face_src(); static NonnullRefPtr resolve_unresolved_style_value(ParsingContext const&, DOM::Element&, Optional, PropertyID, UnresolvedStyleValue const&); [[nodiscard]] LengthOrCalculated parse_as_sizes_attribute(DOM::Element const& element, HTML::HTMLImageElement const* img = nullptr); private: Parser(ParsingContext const&, Vector); enum class ParseError { IncludesIgnoredVendorPrefix, InternalError, SyntaxError, }; template using ParseErrorOr = ErrorOr; // "Parse a stylesheet" is intended to be the normal parser entry point, for parsing stylesheets. struct ParsedStyleSheet { Optional location; Vector rules; }; template ParsedStyleSheet parse_a_stylesheet(TokenStream&, Optional location); // "Parse a stylesheet’s contents" is intended for use by the CSSStyleSheet replace() method, and similar, which parse text into the contents of an existing stylesheet. template Vector parse_a_stylesheets_contents(TokenStream&); // "Parse a block’s contents" is intended for parsing the contents of any block in CSS (including things like the style attribute), // and APIs such as the CSSStyleDeclaration cssText attribute. template Vector parse_a_blocks_contents(TokenStream&); // "Parse a rule" is intended for use by the CSSStyleSheet#insertRule method, and similar functions which might exist, which parse text into a single rule. template Optional parse_a_rule(TokenStream&); // "Parse a declaration" is used in @supports conditions. [CSS3-CONDITIONAL] template Optional parse_a_declaration(TokenStream&); // "Parse a component value" is for things that need to consume a single value, like the parsing rules for attr(). template Optional parse_a_component_value(TokenStream&); // "Parse a list of component values" is for the contents of presentational attributes, which parse text into a single declaration’s value, // or for parsing a stand-alone selector [SELECT] or list of Media Queries [MEDIAQ], as in Selectors API or the media HTML attribute. template Vector parse_a_list_of_component_values(TokenStream&); template Vector> parse_a_comma_separated_list_of_component_values(TokenStream&); enum class SelectorType { Standalone, Relative }; template ParseErrorOr parse_a_selector_list(TokenStream&, SelectorType, SelectorParsingMode = SelectorParsingMode::Standard); template Vector> parse_a_media_query_list(TokenStream&); template RefPtr parse_a_supports(TokenStream&); Optional parse_a_n_plus_b_pattern(TokenStream&); template [[nodiscard]] Vector consume_a_stylesheets_contents(TokenStream&); enum class Nested { No, Yes, }; template Optional consume_an_at_rule(TokenStream&, Nested nested = Nested::No); struct InvalidRuleError { }; template Variant consume_a_qualified_rule(TokenStream&, Optional stop_token = {}, Nested = Nested::No); template Vector consume_a_block(TokenStream&); template Vector consume_a_blocks_contents(TokenStream&); template Optional consume_a_declaration(TokenStream&, Nested = Nested::No); template void consume_the_remnants_of_a_bad_declaration(TokenStream&, Nested); template [[nodiscard]] Vector consume_a_list_of_component_values(TokenStream&, Optional stop_token = {}, Nested = Nested::No); template [[nodiscard]] ComponentValue consume_a_component_value(TokenStream&); template SimpleBlock consume_a_simple_block(TokenStream&); template Function consume_a_function(TokenStream&); // TODO: consume_a_unicode_range_value() Optional parse_general_enclosed(TokenStream&); template Vector parse_font_face_src(TokenStream&); enum class AllowBlankLayerName { No, Yes, }; Optional parse_layer_name(TokenStream&, AllowBlankLayerName); bool is_valid_in_the_current_context(Declaration const&) const; bool is_valid_in_the_current_context(AtRule const&) const; bool is_valid_in_the_current_context(QualifiedRule const&) const; GC::Ptr convert_to_rule(Rule const&, Nested); GC::Ptr convert_to_style_rule(QualifiedRule const&, Nested); GC::Ptr convert_to_font_face_rule(AtRule const&); GC::Ptr convert_to_keyframes_rule(AtRule const&); GC::Ptr convert_to_import_rule(AtRule const&); GC::Ptr convert_to_layer_rule(AtRule const&, Nested); GC::Ptr convert_to_media_rule(AtRule const&, Nested); GC::Ptr convert_to_namespace_rule(AtRule const&); GC::Ptr convert_to_supports_rule(AtRule const&, Nested); GC::Ptr convert_to_property_rule(AtRule const& rule); PropertyOwningCSSStyleDeclaration* convert_to_style_declaration(Vector const&); Optional convert_to_style_property(Declaration const&); Optional parse_dimension(ComponentValue const&); Optional parse_angle(TokenStream&); Optional parse_angle_percentage(TokenStream&); Optional parse_flex(TokenStream&); Optional parse_frequency(TokenStream&); Optional parse_frequency_percentage(TokenStream&); Optional parse_integer(TokenStream&); Optional parse_length(TokenStream&); Optional parse_length_percentage(TokenStream&); Optional parse_number(TokenStream&); Optional parse_number_percentage(TokenStream&); Optional parse_resolution(TokenStream&); Optional parse_time(TokenStream&); Optional parse_time_percentage(TokenStream&); Optional parse_source_size_value(TokenStream&); Optional parse_ratio(TokenStream&); Optional parse_unicode_range(TokenStream&); Optional parse_unicode_range(StringView); Vector parse_unicode_ranges(TokenStream&); Optional parse_grid_size(ComponentValue const&); Optional parse_fit_content(Vector const&); Optional parse_min_max(Vector const&); Optional parse_repeat(Vector const&); Optional parse_track_sizing_function(ComponentValue const&); Optional parse_url_function(TokenStream&); RefPtr parse_url_value(TokenStream&); Optional parse_shape_radius(TokenStream&); RefPtr parse_basic_shape_value(TokenStream&); template Optional> parse_color_stop_list(TokenStream& tokens, auto is_position, auto get_position); Optional> parse_linear_color_stop_list(TokenStream&); Optional> parse_angular_color_stop_list(TokenStream&); RefPtr parse_linear_gradient_function(TokenStream&); RefPtr parse_conic_gradient_function(TokenStream&); RefPtr parse_radial_gradient_function(TokenStream&); ParseErrorOr> parse_css_value(PropertyID, TokenStream&, Optional original_source_text = {}); RefPtr parse_css_value_for_property(PropertyID, TokenStream&); struct PropertyAndValue { PropertyID property; RefPtr style_value; }; Optional parse_css_value_for_properties(ReadonlySpan, TokenStream&); RefPtr parse_builtin_value(TokenStream&); RefPtr parse_calculated_value(ComponentValue const&); RefPtr parse_custom_ident_value(TokenStream&, std::initializer_list blacklist); // NOTE: Implemented in generated code. (GenerateCSSMathFunctions.cpp) OwnPtr parse_math_function(PropertyID, Function const&); OwnPtr parse_a_calc_function_node(Function const&); RefPtr parse_keyword_value(TokenStream&); RefPtr parse_hue_none_value(TokenStream&); RefPtr parse_solidus_and_alpha_value(TokenStream&); RefPtr parse_rgb_color_value(TokenStream&); RefPtr parse_hsl_color_value(TokenStream&); RefPtr parse_hwb_color_value(TokenStream&); Optional, 4>> parse_lab_like_color_value(TokenStream&, StringView); RefPtr parse_lab_color_value(TokenStream&); RefPtr parse_oklab_color_value(TokenStream&); Optional, 4>> parse_lch_like_color_value(TokenStream&, StringView); RefPtr parse_lch_color_value(TokenStream&); RefPtr parse_oklch_color_value(TokenStream&); RefPtr parse_color_function(TokenStream&); RefPtr parse_color_value(TokenStream&); RefPtr parse_counter_value(TokenStream&); enum class AllowReversed { No, Yes, }; RefPtr parse_counter_definitions_value(TokenStream&, AllowReversed, i32 default_value_if_not_reversed); RefPtr parse_rect_value(TokenStream&); RefPtr parse_ratio_value(TokenStream&); RefPtr parse_string_value(TokenStream&); RefPtr parse_image_value(TokenStream&); RefPtr parse_paint_value(TokenStream&); enum class PositionParsingMode { Normal, BackgroundPosition, }; RefPtr parse_position_value(TokenStream&, PositionParsingMode = PositionParsingMode::Normal); RefPtr parse_filter_value_list_value(TokenStream&); RefPtr parse_opentype_tag_value(TokenStream&); RefPtr parse_dimension_value(TokenStream&); RefPtr parse_angle_value(TokenStream&); RefPtr parse_angle_percentage_value(TokenStream&); RefPtr parse_flex_value(TokenStream&); RefPtr parse_frequency_value(TokenStream&); RefPtr parse_frequency_percentage_value(TokenStream&); RefPtr parse_integer_value(TokenStream&); RefPtr parse_length_value(TokenStream&); RefPtr parse_length_percentage_value(TokenStream&); RefPtr parse_number_value(TokenStream&); RefPtr parse_number_percentage_value(TokenStream& tokens); RefPtr parse_number_percentage_none_value(TokenStream& tokens); RefPtr parse_percentage_value(TokenStream& tokens); RefPtr parse_resolution_value(TokenStream&); RefPtr parse_time_value(TokenStream&); RefPtr parse_time_percentage_value(TokenStream&); template RefPtr parse_comma_separated_value_list(TokenStream&, ParseFunction); RefPtr parse_simple_comma_separated_value_list(PropertyID, TokenStream&); RefPtr parse_all_as_single_keyword_value(TokenStream&, Keyword); RefPtr parse_aspect_ratio_value(TokenStream&); RefPtr parse_background_value(TokenStream&); RefPtr parse_single_background_position_x_or_y_value(TokenStream&, PropertyID); RefPtr parse_single_background_repeat_value(TokenStream&); RefPtr parse_single_background_size_value(TokenStream&); RefPtr parse_border_value(PropertyID, TokenStream&); RefPtr parse_border_radius_value(TokenStream&); RefPtr parse_border_radius_shorthand_value(TokenStream&); RefPtr parse_columns_value(TokenStream&); RefPtr parse_content_value(TokenStream&); RefPtr parse_counter_increment_value(TokenStream&); RefPtr parse_counter_reset_value(TokenStream&); RefPtr parse_counter_set_value(TokenStream&); RefPtr parse_display_value(TokenStream&); RefPtr parse_flex_shorthand_value(TokenStream&); RefPtr parse_flex_flow_value(TokenStream&); RefPtr parse_font_value(TokenStream&); RefPtr parse_font_family_value(TokenStream&); RefPtr parse_font_language_override_value(TokenStream&); RefPtr parse_font_feature_settings_value(TokenStream&); RefPtr parse_font_variation_settings_value(TokenStream&); RefPtr parse_list_style_value(TokenStream&); RefPtr parse_math_depth_value(TokenStream&); RefPtr parse_overflow_value(TokenStream&); RefPtr parse_place_content_value(TokenStream&); RefPtr parse_place_items_value(TokenStream&); RefPtr parse_place_self_value(TokenStream&); RefPtr parse_quotes_value(TokenStream&); RefPtr parse_scrollbar_gutter_value(TokenStream&); enum class AllowInsetKeyword { No, Yes, }; RefPtr parse_shadow_value(TokenStream&, AllowInsetKeyword); RefPtr parse_single_shadow_value(TokenStream&, AllowInsetKeyword); RefPtr parse_text_decoration_value(TokenStream&); RefPtr parse_text_decoration_line_value(TokenStream&); RefPtr parse_rotate_value(TokenStream&); RefPtr parse_stroke_dasharray_value(TokenStream&); RefPtr parse_easing_value(TokenStream&); RefPtr parse_transform_value(TokenStream&); RefPtr parse_transform_origin_value(TokenStream&); RefPtr parse_transition_value(TokenStream&); RefPtr parse_translate_value(TokenStream&); RefPtr parse_grid_track_size_list(TokenStream&, bool allow_separate_line_name_blocks = false); RefPtr parse_grid_auto_track_sizes(TokenStream&); RefPtr parse_grid_auto_flow_value(TokenStream&); RefPtr parse_grid_track_size_list_shorthand_value(PropertyID, TokenStream&); RefPtr parse_grid_track_placement(TokenStream&); RefPtr parse_grid_track_placement_shorthand_value(PropertyID, TokenStream&); RefPtr parse_grid_template_areas_value(TokenStream&); RefPtr parse_grid_area_shorthand_value(TokenStream&); RefPtr parse_grid_shorthand_value(TokenStream&); OwnPtr parse_a_calculation(Vector const&); ParseErrorOr> parse_complex_selector(TokenStream&, SelectorType); ParseErrorOr> parse_compound_selector(TokenStream&); Optional parse_selector_combinator(TokenStream&); enum class AllowWildcardName { No, Yes, }; Optional parse_selector_qualified_name(TokenStream&, AllowWildcardName); ParseErrorOr parse_attribute_simple_selector(ComponentValue const&); ParseErrorOr parse_pseudo_simple_selector(TokenStream&); ParseErrorOr> parse_simple_selector(TokenStream&); NonnullRefPtr parse_media_query(TokenStream&); OwnPtr parse_media_condition(TokenStream&, MediaCondition::AllowOr allow_or); Optional parse_media_feature(TokenStream&); Optional parse_media_type(TokenStream&); OwnPtr parse_media_in_parens(TokenStream&); Optional parse_media_feature_value(MediaFeatureID, TokenStream&); OwnPtr parse_supports_condition(TokenStream&); Optional parse_supports_in_parens(TokenStream&); Optional parse_supports_feature(TokenStream&); NonnullRefPtr resolve_unresolved_style_value(DOM::Element&, Optional, PropertyID, UnresolvedStyleValue const&); bool expand_variables(DOM::Element&, Optional, FlyString const& property_name, HashMap>& dependencies, TokenStream& source, Vector& dest); bool expand_unresolved_values(DOM::Element&, FlyString const& property_name, TokenStream& source, Vector& dest); bool substitute_attr_function(DOM::Element& element, FlyString const& property_name, Function const& attr_function, Vector& dest); static bool has_ignored_vendor_prefix(StringView); static bool is_generic_font_family(Keyword); struct PropertiesAndCustomProperties { Vector properties; HashMap custom_properties; }; PropertiesAndCustomProperties extract_properties(Vector const&); void extract_property(Declaration const&, Parser::PropertiesAndCustomProperties&); ParsingContext m_context; Vector m_tokens; TokenStream m_token_stream; enum class ContextType { Unknown, Style, AtMedia, AtFontFace, AtKeyframes, Keyframe, AtSupports, SupportsCondition, AtLayer, AtProperty, }; static ContextType context_type_for_at_rule(FlyString const&); Vector m_rule_context; Vector m_pseudo_class_context; // Stack of pseudo-class functions we're currently inside }; } namespace Web { CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingContext const&, StringView, Optional location = {}); CSS::ElementInlineCSSStyleDeclaration* parse_css_style_attribute(CSS::Parser::ParsingContext const&, StringView, DOM::Element&); RefPtr parse_css_value(CSS::Parser::ParsingContext const&, StringView, CSS::PropertyID property_id = CSS::PropertyID::Invalid); Optional parse_selector(CSS::Parser::ParsingContext const&, StringView); Optional parse_selector_for_nested_style_rule(CSS::Parser::ParsingContext const&, StringView); Optional parse_pseudo_element_selector(CSS::Parser::ParsingContext const&, StringView); CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingContext const&, StringView); RefPtr parse_media_query(CSS::Parser::ParsingContext const&, StringView); Vector> parse_media_query_list(CSS::Parser::ParsingContext const&, StringView); RefPtr parse_css_supports(CSS::Parser::ParsingContext const&, StringView); Optional parse_css_supports_condition(CSS::Parser::ParsingContext const&, StringView); }