mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 04:09:13 +00:00
LibWeb/CSS: Split up Parser.cpp
This file has been a pain to edit for a while, even with the previous splits. So, I've divided it up into 3 parts: - Parser.cpp has the "base" code. It's the algorithms and entry-points defined in the Syntax spec. - ValueParsing.cpp contains code for parsing single values, such as a length, or a color, or a calculation. - PropertyParsing.cpp contains code for parsing an entire property's value. A few of these sit in a grey area between being a property's value and a value in their own right, but the rule I've used is "is this useful outside of a single property and its shorthands?" This only moves code, with as few modifications as possible to make that work. I did add explicit instantiations for the template implementations as part of this, which revealed a few that are actually only compatible with a single type, so I'll clear those up in a subsequent commit.
This commit is contained in:
parent
97f7cb805f
commit
1413760047
Notes:
github-actions[bot]
2025-02-06 16:49:22 +00:00
Author: https://github.com/AtkinsSJ
Commit: 1413760047
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3464
Reviewed-by: https://github.com/ADKaster
7 changed files with 8500 additions and 8353 deletions
|
@ -100,11 +100,13 @@ set(SOURCES
|
||||||
CSS/Parser/MediaParsing.cpp
|
CSS/Parser/MediaParsing.cpp
|
||||||
CSS/Parser/Parser.cpp
|
CSS/Parser/Parser.cpp
|
||||||
CSS/Parser/ParsingContext.cpp
|
CSS/Parser/ParsingContext.cpp
|
||||||
|
CSS/Parser/PropertyParsing.cpp
|
||||||
CSS/Parser/RuleParsing.cpp
|
CSS/Parser/RuleParsing.cpp
|
||||||
CSS/Parser/SelectorParsing.cpp
|
CSS/Parser/SelectorParsing.cpp
|
||||||
CSS/Parser/Token.cpp
|
CSS/Parser/Token.cpp
|
||||||
CSS/Parser/Tokenizer.cpp
|
CSS/Parser/Tokenizer.cpp
|
||||||
CSS/Parser/Types.cpp
|
CSS/Parser/Types.cpp
|
||||||
|
CSS/Parser/ValueParsing.cpp
|
||||||
CSS/ParsedFontFace.cpp
|
CSS/ParsedFontFace.cpp
|
||||||
CSS/PreferredColorScheme.cpp
|
CSS/PreferredColorScheme.cpp
|
||||||
CSS/PreferredContrast.cpp
|
CSS/PreferredContrast.cpp
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020-2021, the SerenityOS developers.
|
* Copyright (c) 2020-2021, the SerenityOS developers.
|
||||||
* Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
|
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,7 @@
|
||||||
#include <AK/NonnullRawPtr.h>
|
#include <AK/NonnullRawPtr.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
|
#include <LibGC/Ptr.h>
|
||||||
#include <LibGfx/Font/UnicodeRange.h>
|
#include <LibGfx/Font/UnicodeRange.h>
|
||||||
#include <LibWeb/CSS/CSSStyleDeclaration.h>
|
#include <LibWeb/CSS/CSSStyleDeclaration.h>
|
||||||
#include <LibWeb/CSS/CSSStyleValue.h>
|
#include <LibWeb/CSS/CSSStyleValue.h>
|
||||||
|
@ -19,7 +20,6 @@
|
||||||
#include <LibWeb/CSS/ParsedFontFace.h>
|
#include <LibWeb/CSS/ParsedFontFace.h>
|
||||||
#include <LibWeb/CSS/Parser/ComponentValue.h>
|
#include <LibWeb/CSS/Parser/ComponentValue.h>
|
||||||
#include <LibWeb/CSS/Parser/Dimension.h>
|
#include <LibWeb/CSS/Parser/Dimension.h>
|
||||||
#include <LibWeb/CSS/Parser/ParsingContext.h>
|
|
||||||
#include <LibWeb/CSS/Parser/TokenStream.h>
|
#include <LibWeb/CSS/Parser/TokenStream.h>
|
||||||
#include <LibWeb/CSS/Parser/Tokenizer.h>
|
#include <LibWeb/CSS/Parser/Tokenizer.h>
|
||||||
#include <LibWeb/CSS/Parser/Types.h>
|
#include <LibWeb/CSS/Parser/Types.h>
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
#include <LibWeb/CSS/Ratio.h>
|
#include <LibWeb/CSS/Ratio.h>
|
||||||
#include <LibWeb/CSS/Selector.h>
|
#include <LibWeb/CSS/Selector.h>
|
||||||
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/AbstractImageStyleValue.h>
|
||||||
|
#include <LibWeb/CSS/StyleValues/BasicShapeStyleValue.h>
|
||||||
#include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/CalculatedStyleValue.h>
|
||||||
#include <LibWeb/CSS/Supports.h>
|
#include <LibWeb/CSS/Supports.h>
|
||||||
#include <LibWeb/Forward.h>
|
#include <LibWeb/Forward.h>
|
||||||
|
@ -58,11 +59,33 @@ struct NegateNode {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class Parser {
|
enum class ParsingMode {
|
||||||
public:
|
Normal,
|
||||||
static Parser create(ParsingContext const&, StringView input, StringView encoding = "utf-8"sv);
|
SVGPresentationAttribute, // See https://svgwg.org/svg2-draft/types.html#presentation-attribute-css-value
|
||||||
|
};
|
||||||
|
|
||||||
Parser(Parser&&);
|
struct ParsingParams {
|
||||||
|
explicit ParsingParams(ParsingMode = ParsingMode::Normal);
|
||||||
|
explicit ParsingParams(JS::Realm&, ParsingMode = ParsingMode::Normal);
|
||||||
|
explicit ParsingParams(JS::Realm&, URL::URL, ParsingMode = ParsingMode::Normal);
|
||||||
|
explicit ParsingParams(DOM::Document const&, URL::URL, ParsingMode = ParsingMode::Normal);
|
||||||
|
explicit ParsingParams(DOM::Document const&, ParsingMode = ParsingMode::Normal);
|
||||||
|
|
||||||
|
GC::Ptr<JS::Realm> realm;
|
||||||
|
GC::Ptr<DOM::Document const> document;
|
||||||
|
URL::URL url;
|
||||||
|
ParsingMode mode { ParsingMode::Normal };
|
||||||
|
};
|
||||||
|
|
||||||
|
// The very large CSS Parser implementation code is broken up among several .cpp files:
|
||||||
|
// Parser.cpp contains the core parser algorithms, defined in https://drafts.csswg.org/css-syntax
|
||||||
|
// Everything else is in different *Parsing.cpp files
|
||||||
|
class Parser {
|
||||||
|
AK_MAKE_NONCOPYABLE(Parser);
|
||||||
|
AK_MAKE_NONMOVABLE(Parser);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Parser create(ParsingParams const&, StringView input, StringView encoding = "utf-8"sv);
|
||||||
|
|
||||||
CSSStyleSheet* parse_as_css_stylesheet(Optional<URL::URL> location);
|
CSSStyleSheet* parse_as_css_stylesheet(Optional<URL::URL> location);
|
||||||
ElementInlineCSSStyleDeclaration* parse_as_style_attribute(DOM::Element&);
|
ElementInlineCSSStyleDeclaration* parse_as_style_attribute(DOM::Element&);
|
||||||
|
@ -95,12 +118,12 @@ public:
|
||||||
|
|
||||||
Vector<ComponentValue> parse_as_list_of_component_values();
|
Vector<ComponentValue> parse_as_list_of_component_values();
|
||||||
|
|
||||||
static NonnullRefPtr<CSSStyleValue> resolve_unresolved_style_value(ParsingContext const&, DOM::Element&, Optional<CSS::Selector::PseudoElement::Type>, PropertyID, UnresolvedStyleValue const&);
|
static NonnullRefPtr<CSSStyleValue> resolve_unresolved_style_value(ParsingParams const&, DOM::Element&, Optional<CSS::Selector::PseudoElement::Type>, PropertyID, UnresolvedStyleValue const&);
|
||||||
|
|
||||||
[[nodiscard]] LengthOrCalculated parse_as_sizes_attribute(DOM::Element const& element, HTML::HTMLImageElement const* img = nullptr);
|
[[nodiscard]] LengthOrCalculated parse_as_sizes_attribute(DOM::Element const& element, HTML::HTMLImageElement const* img = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Parser(ParsingContext const&, Vector<Token>);
|
Parser(ParsingParams const&, Vector<Token>);
|
||||||
|
|
||||||
enum class ParseError {
|
enum class ParseError {
|
||||||
IncludesIgnoredVendorPrefix,
|
IncludesIgnoredVendorPrefix,
|
||||||
|
@ -186,14 +209,10 @@ private:
|
||||||
[[nodiscard]] ComponentValue consume_a_component_value(TokenStream<T>&);
|
[[nodiscard]] ComponentValue consume_a_component_value(TokenStream<T>&);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void consume_a_component_value_and_do_nothing(TokenStream<T>&);
|
void consume_a_component_value_and_do_nothing(TokenStream<T>&);
|
||||||
template<typename T>
|
SimpleBlock consume_a_simple_block(TokenStream<Token>&);
|
||||||
SimpleBlock consume_a_simple_block(TokenStream<T>&);
|
void consume_a_simple_block_and_do_nothing(TokenStream<Token>&);
|
||||||
template<typename T>
|
Function consume_a_function(TokenStream<Token>&);
|
||||||
void consume_a_simple_block_and_do_nothing(TokenStream<T>&);
|
void consume_a_function_and_do_nothing(TokenStream<Token>&);
|
||||||
template<typename T>
|
|
||||||
Function consume_a_function(TokenStream<T>&);
|
|
||||||
template<typename T>
|
|
||||||
void consume_a_function_and_do_nothing(TokenStream<T>&);
|
|
||||||
// TODO: consume_a_unicode_range_value()
|
// TODO: consume_a_unicode_range_value()
|
||||||
|
|
||||||
Optional<GeneralEnclosed> parse_general_enclosed(TokenStream<ComponentValue>&);
|
Optional<GeneralEnclosed> parse_general_enclosed(TokenStream<ComponentValue>&);
|
||||||
|
@ -428,7 +447,6 @@ private:
|
||||||
bool substitute_attr_function(DOM::Element& element, FlyString const& property_name, Function const& attr_function, Vector<ComponentValue>& dest);
|
bool substitute_attr_function(DOM::Element& element, FlyString const& property_name, Function const& attr_function, Vector<ComponentValue>& dest);
|
||||||
|
|
||||||
static bool has_ignored_vendor_prefix(StringView);
|
static bool has_ignored_vendor_prefix(StringView);
|
||||||
static bool is_generic_font_family(Keyword);
|
|
||||||
|
|
||||||
struct PropertiesAndCustomProperties {
|
struct PropertiesAndCustomProperties {
|
||||||
Vector<StyleProperty> properties;
|
Vector<StyleProperty> properties;
|
||||||
|
@ -438,7 +456,17 @@ private:
|
||||||
PropertiesAndCustomProperties extract_properties(Vector<RuleOrListOfDeclarations> const&);
|
PropertiesAndCustomProperties extract_properties(Vector<RuleOrListOfDeclarations> const&);
|
||||||
void extract_property(Declaration const&, Parser::PropertiesAndCustomProperties&);
|
void extract_property(Declaration const&, Parser::PropertiesAndCustomProperties&);
|
||||||
|
|
||||||
ParsingContext m_context;
|
DOM::Document const* document() const;
|
||||||
|
HTML::Window const* window() const;
|
||||||
|
JS::Realm& realm() const;
|
||||||
|
bool in_quirks_mode() const;
|
||||||
|
bool is_parsing_svg_presentation_attribute() const;
|
||||||
|
URL::URL complete_url(StringView) const;
|
||||||
|
|
||||||
|
GC::Ptr<DOM::Document const> m_document;
|
||||||
|
GC::Ptr<JS::Realm> m_realm;
|
||||||
|
URL::URL m_url;
|
||||||
|
ParsingMode m_parsing_mode { ParsingMode::Normal };
|
||||||
|
|
||||||
Vector<Token> m_tokens;
|
Vector<Token> m_tokens;
|
||||||
TokenStream<Token> m_token_stream;
|
TokenStream<Token> m_token_stream;
|
||||||
|
@ -477,16 +505,16 @@ private:
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
|
||||||
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingContext const&, StringView, Optional<URL::URL> location = {});
|
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const&, StringView, Optional<URL::URL> location = {});
|
||||||
CSS::ElementInlineCSSStyleDeclaration* parse_css_style_attribute(CSS::Parser::ParsingContext const&, StringView, DOM::Element&);
|
CSS::ElementInlineCSSStyleDeclaration* parse_css_style_attribute(CSS::Parser::ParsingParams const&, StringView, DOM::Element&);
|
||||||
RefPtr<CSS::CSSStyleValue> parse_css_value(CSS::Parser::ParsingContext const&, StringView, CSS::PropertyID property_id = CSS::PropertyID::Invalid);
|
RefPtr<CSS::CSSStyleValue> parse_css_value(CSS::Parser::ParsingParams const&, StringView, CSS::PropertyID property_id = CSS::PropertyID::Invalid);
|
||||||
Optional<CSS::SelectorList> parse_selector(CSS::Parser::ParsingContext const&, StringView);
|
Optional<CSS::SelectorList> parse_selector(CSS::Parser::ParsingParams const&, StringView);
|
||||||
Optional<CSS::SelectorList> parse_selector_for_nested_style_rule(CSS::Parser::ParsingContext const&, StringView);
|
Optional<CSS::SelectorList> parse_selector_for_nested_style_rule(CSS::Parser::ParsingParams const&, StringView);
|
||||||
Optional<CSS::Selector::PseudoElement> parse_pseudo_element_selector(CSS::Parser::ParsingContext const&, StringView);
|
Optional<CSS::Selector::PseudoElement> parse_pseudo_element_selector(CSS::Parser::ParsingParams const&, StringView);
|
||||||
CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingContext const&, StringView);
|
CSS::CSSRule* parse_css_rule(CSS::Parser::ParsingParams const&, StringView);
|
||||||
RefPtr<CSS::MediaQuery> parse_media_query(CSS::Parser::ParsingContext const&, StringView);
|
RefPtr<CSS::MediaQuery> parse_media_query(CSS::Parser::ParsingParams const&, StringView);
|
||||||
Vector<NonnullRefPtr<CSS::MediaQuery>> parse_media_query_list(CSS::Parser::ParsingContext const&, StringView);
|
Vector<NonnullRefPtr<CSS::MediaQuery>> parse_media_query_list(CSS::Parser::ParsingParams const&, StringView);
|
||||||
RefPtr<CSS::Supports> parse_css_supports(CSS::Parser::ParsingContext const&, StringView);
|
RefPtr<CSS::Supports> parse_css_supports(CSS::Parser::ParsingParams const&, StringView);
|
||||||
Optional<CSS::StyleProperty> parse_css_supports_condition(CSS::Parser::ParsingContext const&, StringView);
|
Optional<CSS::StyleProperty> parse_css_supports_condition(CSS::Parser::ParsingParams const&, StringView);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
4348
Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp
Normal file
4348
Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -587,6 +587,103 @@ GC::Ptr<CSSPropertyRule> Parser::convert_to_property_rule(AtRule const& rule)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<T>& component_values)
|
||||||
|
{
|
||||||
|
// FIXME: Get this information from the system somehow?
|
||||||
|
// Format-name table: https://www.w3.org/TR/css-fonts-4/#font-format-definitions
|
||||||
|
auto font_format_is_supported = [](StringView name) {
|
||||||
|
// The spec requires us to treat opentype and truetype as synonymous.
|
||||||
|
if (name.is_one_of_ignoring_ascii_case("opentype"sv, "truetype"sv, "woff"sv, "woff2"sv))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<ParsedFontFace::Source> supported_sources;
|
||||||
|
|
||||||
|
auto list_of_source_token_lists = parse_a_comma_separated_list_of_component_values(component_values);
|
||||||
|
for (auto const& source_token_list : list_of_source_token_lists) {
|
||||||
|
TokenStream source_tokens { source_token_list };
|
||||||
|
source_tokens.discard_whitespace();
|
||||||
|
|
||||||
|
// <url> [ format(<font-format>)]?
|
||||||
|
// FIXME: Implement optional tech() function from CSS-Fonts-4.
|
||||||
|
if (auto maybe_url = parse_url_function(source_tokens); maybe_url.has_value()) {
|
||||||
|
auto url = maybe_url.release_value();
|
||||||
|
if (!url.is_valid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<FlyString> format;
|
||||||
|
|
||||||
|
source_tokens.discard_whitespace();
|
||||||
|
if (!source_tokens.has_next_token()) {
|
||||||
|
supported_sources.empend(move(url), format);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& maybe_function = source_tokens.consume_a_token();
|
||||||
|
if (!maybe_function.is_function()) {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (token after `url()` that isn't a function: {}); discarding.", maybe_function.to_debug_string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& function = maybe_function.function();
|
||||||
|
if (function.name.equals_ignoring_ascii_case("format"sv)) {
|
||||||
|
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name });
|
||||||
|
|
||||||
|
TokenStream format_tokens { function.value };
|
||||||
|
format_tokens.discard_whitespace();
|
||||||
|
auto const& format_name_token = format_tokens.consume_a_token();
|
||||||
|
StringView format_name;
|
||||||
|
if (format_name_token.is(Token::Type::Ident)) {
|
||||||
|
format_name = format_name_token.token().ident();
|
||||||
|
} else if (format_name_token.is(Token::Type::String)) {
|
||||||
|
format_name = format_name_token.token().string();
|
||||||
|
} else {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (`format()` parameter not an ident or string; is: {}); discarding.", format_name_token.to_debug_string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!font_format_is_supported(format_name)) {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src format({}) not supported; skipping.", format_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
format = FlyString::from_utf8(format_name).release_value_but_fixme_should_propagate_errors();
|
||||||
|
} else {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (unrecognized function token `{}`); discarding.", function.name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
source_tokens.discard_whitespace();
|
||||||
|
if (source_tokens.has_next_token()) {
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (extra token `{}`); discarding.", source_tokens.next_token().to_debug_string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
supported_sources.empend(move(url), format);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& first = source_tokens.consume_a_token();
|
||||||
|
if (first.is_function("local"sv)) {
|
||||||
|
if (first.function().value.is_empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
supported_sources.empend(first.function().value.first().to_string(), Optional<FlyString> {});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (failed to parse url from: {}); discarding.", first.to_debug_string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported_sources;
|
||||||
|
}
|
||||||
|
template Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<Token>& component_values);
|
||||||
|
template Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<ComponentValue>& component_values);
|
||||||
|
|
||||||
GC::Ptr<CSSFontFaceRule> Parser::convert_to_font_face_rule(AtRule const& rule)
|
GC::Ptr<CSSFontFaceRule> Parser::convert_to_font_face_rule(AtRule const& rule)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-fonts/#font-face-rule
|
// https://drafts.csswg.org/css-fonts/#font-face-rule
|
||||||
|
|
3932
Libraries/LibWeb/CSS/Parser/ValueParsing.cpp
Normal file
3932
Libraries/LibWeb/CSS/Parser/ValueParsing.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -8,10 +8,12 @@ source_set("Parser") {
|
||||||
"MediaParsing.cpp",
|
"MediaParsing.cpp",
|
||||||
"Parser.cpp",
|
"Parser.cpp",
|
||||||
"ParsingContext.cpp",
|
"ParsingContext.cpp",
|
||||||
|
"PropertyParsing.cpp",
|
||||||
"RuleParsing.cpp",
|
"RuleParsing.cpp",
|
||||||
"SelectorParsing.cpp",
|
"SelectorParsing.cpp",
|
||||||
"Token.cpp",
|
"Token.cpp",
|
||||||
"Tokenizer.cpp",
|
"Tokenizer.cpp",
|
||||||
"Types.cpp",
|
"Types.cpp",
|
||||||
|
"ValueParsing.cpp",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue