diff options
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibWeb/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Attribute.cpp | 24 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Attribute.h | 37 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Attribute.idl | 12 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Element.cpp | 12 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/DOM/Element.h | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/Forward.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.cpp | 38 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.h | 8 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp | 4 |
10 files changed, 102 insertions, 42 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 2f407f7703..f16da893c3 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -54,6 +54,8 @@ set(SOURCES Cookie/ParsedCookie.cpp DOM/AbortController.cpp DOM/AbortSignal.cpp + DOM/Attribute.cpp + DOM/Attribute.idl DOM/CharacterData.cpp DOM/CharacterData.idl DOM/Comment.cpp @@ -366,6 +368,7 @@ libweb_js_wrapper(CSS/MediaQueryListEvent) libweb_js_wrapper(CSS/Screen) libweb_js_wrapper(CSS/StyleSheet) libweb_js_wrapper(CSS/StyleSheetList) +libweb_js_wrapper(DOM/Attribute) libweb_js_wrapper(DOM/AbortController) libweb_js_wrapper(DOM/AbortSignal) libweb_js_wrapper(DOM/CharacterData) diff --git a/Userland/Libraries/LibWeb/DOM/Attribute.cpp b/Userland/Libraries/LibWeb/DOM/Attribute.cpp new file mode 100644 index 0000000000..996a80a404 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/Attribute.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2021, Tim Flynn <trflynn89@pm.me> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWeb/DOM/Attribute.h> +#include <LibWeb/DOM/Document.h> + +namespace Web::DOM { + +NonnullRefPtr<Attribute> Attribute::create(Document& document, FlyString local_name, String value) +{ + return adopt_ref(*new Attribute(document, move(local_name), move(value))); +} + +Attribute::Attribute(Document& document, FlyString local_name, String value) + : Node(document, NodeType::ATTRIBUTE_NODE) + , m_qualified_name(move(local_name), {}, {}) + , m_value(move(value)) +{ +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/Attribute.h b/Userland/Libraries/LibWeb/DOM/Attribute.h index 5261a5bf7d..0a9dfd97b9 100644 --- a/Userland/Libraries/LibWeb/DOM/Attribute.h +++ b/Userland/Libraries/LibWeb/DOM/Attribute.h @@ -7,25 +7,42 @@ #pragma once #include <AK/FlyString.h> +#include <LibWeb/DOM/Node.h> +#include <LibWeb/QualifiedName.h> namespace Web::DOM { -class Attribute { +// https://dom.spec.whatwg.org/#attr +class Attribute final : public Node { public: - Attribute(const FlyString& name, const String& value) - : m_name(name) - , m_value(value) - { - } + using WrapperType = Bindings::AttributeWrapper; - const FlyString& name() const { return m_name; } - const String& value() const { return m_value; } + static NonnullRefPtr<Attribute> create(Document&, FlyString local_name, String value); - void set_value(const String& value) { m_value = value; } + virtual ~Attribute() override = default; + + virtual FlyString node_name() const override { return name(); } + + FlyString const& namespace_uri() const { return m_qualified_name.namespace_(); } + FlyString const& prefix() const { return m_qualified_name.prefix(); } + FlyString const& local_name() const { return m_qualified_name.local_name(); } + String const& name() const { return m_qualified_name.as_string(); } + + String const& value() const { return m_value; } + void set_value(String value) { m_value = move(value); } + + Element const* owner_element() const { return m_owner_element; } + void set_owner_element(Element const* owner_element) { m_owner_element = owner_element; } + + // Always returns true: https://dom.spec.whatwg.org/#dom-attr-specified + constexpr bool specified() const { return true; } private: - FlyString m_name; + Attribute(Document&, FlyString local_name, String value); + + QualifiedName m_qualified_name; String m_value; + Element const* m_owner_element { nullptr }; }; } diff --git a/Userland/Libraries/LibWeb/DOM/Attribute.idl b/Userland/Libraries/LibWeb/DOM/Attribute.idl new file mode 100644 index 0000000000..8b15866a3f --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/Attribute.idl @@ -0,0 +1,12 @@ +[Exposed=Window] +interface Attribute : Node { + readonly attribute DOMString? namespaceURI; + readonly attribute DOMString? prefix; + readonly attribute DOMString localName; + readonly attribute DOMString name; + [CEReactions] attribute DOMString value; + + readonly attribute Element? ownerElement; + + readonly attribute boolean specified; +}; diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index bed9e07cfe..e6ea910150 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -49,8 +49,8 @@ Element::~Element() Attribute* Element::find_attribute(const FlyString& name) { for (auto& attribute : m_attributes) { - if (attribute.name() == name) - return &attribute; + if (attribute->name() == name) + return attribute; } return nullptr; } @@ -58,8 +58,8 @@ Attribute* Element::find_attribute(const FlyString& name) const Attribute* Element::find_attribute(const FlyString& name) const { for (auto& attribute : m_attributes) { - if (attribute.name() == name) - return &attribute; + if (attribute->name() == name) + return attribute; } return nullptr; } @@ -82,7 +82,7 @@ ExceptionOr<void> Element::set_attribute(const FlyString& name, const String& va if (auto* attribute = find_attribute(name)) attribute->set_value(value); else - m_attributes.empend(name, value); + m_attributes.append(Attribute::create(document(), name, value)); parse_attribute(name, value); return {}; @@ -92,7 +92,7 @@ void Element::remove_attribute(const FlyString& name) { CSS::StyleInvalidator style_invalidator(document()); - m_attributes.remove_first_matching([&](auto& attribute) { return attribute.name() == name; }); + m_attributes.remove_first_matching([&](auto& attribute) { return attribute->name() == name; }); } bool Element::has_class(const FlyString& class_name, CaseSensitivity case_sensitivity) const diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index d23c640280..cc829ff53d 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -67,7 +67,7 @@ public: void for_each_attribute(Callback callback) const { for (auto& attribute : m_attributes) - callback(attribute.name(), attribute.value()); + callback(attribute->name(), attribute->value()); } bool has_class(const FlyString&, CaseSensitivity = CaseSensitivity::CaseSensitive) const; @@ -132,7 +132,7 @@ private: QualifiedName m_qualified_name; String m_html_uppercased_qualified_name; - Vector<Attribute> m_attributes; + Vector<NonnullRefPtr<Attribute>> m_attributes; RefPtr<CSS::CSSStyleDeclaration> m_inline_style; diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index ab862c7c11..2f3dd779dd 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -71,6 +71,7 @@ class UnsetStyleValue; namespace Web::DOM { class AbortController; class AbortSignal; +class Attribute; class CharacterData; class Comment; class CustomEvent; @@ -290,6 +291,7 @@ class URLSearchParamsIterator; namespace Web::Bindings { class AbortControllerWrapper; class AbortSignalWrapper; +class AttributeWrapper; class CanvasRenderingContext2DWrapper; class CharacterDataWrapper; class CloseEventWrapper; diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.cpp index 460e0a3872..f0c5c524b1 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.cpp @@ -9,6 +9,8 @@ #include <AK/StringView.h> #include <AK/Utf8View.h> #include <LibTextCodec/Decoder.h> +#include <LibWeb/DOM/Attribute.h> +#include <LibWeb/DOM/Document.h> #include <LibWeb/HTML/Parser/HTMLEncodingDetection.h> #include <ctype.h> @@ -94,7 +96,7 @@ Optional<String> extract_character_encoding_from_meta_element(String const& stri return TextCodec::get_standardized_encoding(encoding); } -Optional<DOM::Attribute> prescan_get_attribute(const ByteBuffer& input, size_t& position) +RefPtr<DOM::Attribute> prescan_get_attribute(DOM::Document& document, const ByteBuffer& input, size_t& position) { if (!prescan_skip_whitespace_and_slashes(input, position)) return {}; @@ -109,7 +111,7 @@ Optional<DOM::Attribute> prescan_get_attribute(const ByteBuffer& input, size_t& } else if (input[position] == '\t' || input[position] == '\n' || input[position] == '\f' || input[position] == '\r' || input[position] == ' ') goto spaces; else if (input[position] == '/' || input[position] == '>') - return DOM::Attribute(attribute_name.to_string(), ""); + return DOM::Attribute::create(document, attribute_name.to_string(), ""); else attribute_name.append_as_lowercase(input[position]); ++position; @@ -121,7 +123,7 @@ spaces: if (!prescan_skip_whitespace_and_slashes(input, position)) return {}; if (input[position] != '=') - return DOM::Attribute(attribute_name.to_string(), ""); + return DOM::Attribute::create(document, attribute_name.to_string(), ""); ++position; value: @@ -134,13 +136,13 @@ value: ++position; for (; !prescan_should_abort(input, position); ++position) { if (input[position] == quote_character) - return DOM::Attribute(attribute_name.to_string(), attribute_value.to_string()); + return DOM::Attribute::create(document, attribute_name.to_string(), attribute_value.to_string()); else attribute_value.append_as_lowercase(input[position]); } return {}; } else if (input[position] == '>') - return DOM::Attribute(attribute_name.to_string(), ""); + return DOM::Attribute::create(document, attribute_name.to_string(), ""); else attribute_value.append_as_lowercase(input[position]); @@ -150,7 +152,7 @@ value: for (; !prescan_should_abort(input, position); ++position) { if (input[position] == '\t' || input[position] == '\n' || input[position] == '\f' || input[position] == '\r' || input[position] == ' ' || input[position] == '>') - return DOM::Attribute(attribute_name.to_string(), attribute_value.to_string()); + return DOM::Attribute::create(document, attribute_name.to_string(), attribute_value.to_string()); else attribute_value.append_as_lowercase(input[position]); } @@ -158,7 +160,7 @@ value: } // https://html.spec.whatwg.org/multipage/parsing.html#prescan-a-byte-stream-to-determine-its-encoding -Optional<String> run_prescan_byte_stream_algorithm(const ByteBuffer& input) +Optional<String> run_prescan_byte_stream_algorithm(DOM::Document& document, const ByteBuffer& input) { // https://html.spec.whatwg.org/multipage/parsing.html#prescan-a-byte-stream-to-determine-its-encoding @@ -194,24 +196,24 @@ Optional<String> run_prescan_byte_stream_algorithm(const ByteBuffer& input) Optional<String> charset {}; while (true) { - auto attribute = prescan_get_attribute(input, position); - if (!attribute.has_value()) + auto attribute = prescan_get_attribute(document, input, position); + if (!attribute) break; - if (attribute_list.contains_slow(attribute.value().name())) + if (attribute_list.contains_slow(attribute->name())) continue; - auto& attribute_name = attribute.value().name(); - attribute_list.append(attribute.value().name()); + auto& attribute_name = attribute->name(); + attribute_list.append(attribute->name()); if (attribute_name == "http-equiv") { - got_pragma = attribute.value().value() == "content-type"; + got_pragma = attribute->value() == "content-type"; } else if (attribute_name == "content") { - auto encoding = extract_character_encoding_from_meta_element(attribute.value().value()); + auto encoding = extract_character_encoding_from_meta_element(attribute->value()); if (encoding.has_value() && !charset.has_value()) { charset = encoding.value(); need_pragma = true; } } else if (attribute_name == "charset") { - auto maybe_charset = TextCodec::get_standardized_encoding(attribute.value().value()); + auto maybe_charset = TextCodec::get_standardized_encoding(attribute->value()); if (maybe_charset.has_value()) { charset = Optional<String> { maybe_charset }; need_pragma = { false }; @@ -231,7 +233,7 @@ Optional<String> run_prescan_byte_stream_algorithm(const ByteBuffer& input) && ((input[position + 1] == '/' && isalpha(input[position + 2])) || isalpha(input[position + 1]))) { position += 2; prescan_skip_whitespace_and_slashes(input, position); - while (prescan_get_attribute(input, position).has_value()) { }; + while (prescan_get_attribute(document, input, position)) { }; } else if (!prescan_should_abort(input, position + 1) && input[position] == '<' && (input[position + 1] == '!' || input[position + 1] == '/' || input[position + 1] == '?')) { position += 2; while (input[position] != '>') { @@ -247,7 +249,7 @@ Optional<String> run_prescan_byte_stream_algorithm(const ByteBuffer& input) } // https://html.spec.whatwg.org/multipage/parsing.html#determining-the-character-encoding -String run_encoding_sniffing_algorithm(const ByteBuffer& input) +String run_encoding_sniffing_algorithm(DOM::Document& document, const ByteBuffer& input) { if (input.size() >= 2) { if (input[0] == 0xFE && input[1] == 0xFF) { @@ -265,7 +267,7 @@ String run_encoding_sniffing_algorithm(const ByteBuffer& input) // at any later step in this algorithm. // FIXME: If the transport layer specifies a character encoding, and it is supported. - auto optional_encoding = run_prescan_byte_stream_algorithm(input); + auto optional_encoding = run_prescan_byte_stream_algorithm(document, input); if (optional_encoding.has_value()) { return optional_encoding.value(); } diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.h b/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.h index 4d9a1e9ab2..52784e8d7c 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.h +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLEncodingDetection.h @@ -8,7 +8,7 @@ #include <AK/Optional.h> #include <AK/String.h> -#include <LibWeb/DOM/Attribute.h> +#include <LibWeb/Forward.h> namespace Web::HTML { @@ -16,8 +16,8 @@ bool prescan_should_abort(const ByteBuffer& input, const size_t& position); bool prescan_is_whitespace_or_slash(const u8& byte); bool prescan_skip_whitespace_and_slashes(const ByteBuffer& input, size_t& position); Optional<String> extract_character_encoding_from_meta_element(String const&); -Optional<DOM::Attribute> prescan_get_attribute(const ByteBuffer& input, size_t& position); -Optional<String> run_prescan_byte_stream_algorithm(const ByteBuffer& input); -String run_encoding_sniffing_algorithm(const ByteBuffer& input); +RefPtr<DOM::Attribute> prescan_get_attribute(DOM::Document&, const ByteBuffer& input, size_t& position); +Optional<String> run_prescan_byte_stream_algorithm(DOM::Document&, const ByteBuffer& input); +String run_encoding_sniffing_algorithm(DOM::Document&, const ByteBuffer& input); } diff --git a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp index d9fc29f64b..1a7ada5a10 100644 --- a/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp +++ b/Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp @@ -2810,7 +2810,7 @@ void HTMLParser::handle_in_frameset(HTMLToken& token) } if (token.is_end_of_file()) { - //FIXME: If the current node is not the root html element, then this is a parse error. + // FIXME: If the current node is not the root html element, then this is a parse error. stop_parsing(); return; @@ -3162,7 +3162,7 @@ NonnullOwnPtr<HTMLParser> HTMLParser::create_with_uncertain_encoding(DOM::Docume { if (document.has_encoding()) return make<HTMLParser>(document, input, document.encoding().value()); - auto encoding = run_encoding_sniffing_algorithm(input); + auto encoding = run_encoding_sniffing_algorithm(document, input); dbgln("The encoding sniffing algorithm returned encoding '{}'", encoding); return make<HTMLParser>(document, input, encoding); } |