diff options
author | Luke Wilde <lukew@serenityos.org> | 2023-02-28 00:23:53 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-02-28 12:36:14 +0100 |
commit | 4d0277cd9a338d8fe29db8521ce0e632cae1ae1d (patch) | |
tree | c4d4515cea3e17eb2c5d3c6d1e3f3cdba8f92042 | |
parent | 5e422bdae03f1287e5ea3d7af80794e8aa25c919 (diff) | |
download | serenity-4d0277cd9a338d8fe29db8521ce0e632cae1ae1d.zip |
LibWeb: Implement navigator.{plugins,mimeTypes}
20 files changed, 767 insertions, 4 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index e2474811a0..105d2418e0 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -270,6 +270,8 @@ set(SOURCES HTML/MessageChannel.cpp HTML/MessageEvent.cpp HTML/MessagePort.cpp + HTML/MimeType.cpp + HTML/MimeTypeArray.cpp HTML/Navigator.cpp HTML/NavigatorID.cpp HTML/PageTransitionEvent.cpp @@ -281,6 +283,8 @@ set(SOURCES HTML/Parser/ListOfActiveFormattingElements.cpp HTML/Parser/StackOfOpenElements.cpp HTML/Path2D.cpp + HTML/Plugin.cpp + HTML/PluginArray.cpp HTML/PromiseRejectionEvent.cpp HTML/Scripting/ClassicScript.cpp HTML/Scripting/Environments.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index e9a9301129..243c34e27f 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -328,11 +328,15 @@ class Location; class MessageChannel; class MessageEvent; class MessagePort; +class MimeType; +class MimeTypeArray; struct NavigationParams; class Navigator; class Origin; class PageTransitionEvent; class Path2D; +class Plugin; +class PluginArray; struct PolicyContainer; class PromiseRejectionEvent; class WorkerDebugConsoleClient; diff --git a/Userland/Libraries/LibWeb/HTML/MimeType.cpp b/Userland/Libraries/LibWeb/HTML/MimeType.cpp new file mode 100644 index 0000000000..30e20dfc36 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/MimeType.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWeb/Bindings/Intrinsics.h> +#include <LibWeb/HTML/MimeType.h> +#include <LibWeb/HTML/Scripting/Environments.h> +#include <LibWeb/HTML/Window.h> + +namespace Web::HTML { + +MimeType::MimeType(JS::Realm& realm, String const& type) + : Bindings::PlatformObject(realm) + , m_type(type) +{ +} + +MimeType::~MimeType() = default; + +JS::ThrowCompletionOr<void> MimeType::initialize(JS::Realm& realm) +{ + MUST_OR_THROW_OOM(Base::initialize(realm)); + set_prototype(&Bindings::ensure_web_prototype<Bindings::MimeTypePrototype>(realm, "MimeType")); + + return {}; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#concept-mimetype-type +String const& MimeType::type() const +{ + // The MimeType interface's type getter steps are to return this's type. + return m_type; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-mimetype-description +JS::ThrowCompletionOr<String> MimeType::description() const +{ + // The MimeType interface's description getter steps are to return "Portable Document Format". + static String description_string = TRY_OR_THROW_OOM(vm(), String::from_utf8("Portable Document Format"sv)); + return description_string; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-mimetype-suffixes +String const& MimeType::suffixes() const +{ + // The MimeType interface's suffixes getter steps are to return "pdf". + static String suffixes_string = String::from_utf8_short_string("pdf"sv); + return suffixes_string; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-mimetype-enabledplugin +JS::NonnullGCPtr<Plugin> MimeType::enabled_plugin() const +{ + // The MimeType interface's enabledPlugin getter steps are to return this's relevant global object's PDF viewer plugin objects[0] (i.e., the generic "PDF Viewer" one). + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto plugin_objects = window.pdf_viewer_plugin_objects(); + + // NOTE: If a MimeType object was created, that means PDF viewer support is enabled, meaning there will be Plugin objects. + VERIFY(!plugin_objects.is_empty()); + return plugin_objects.first(); +} + +} diff --git a/Userland/Libraries/LibWeb/HTML/MimeType.h b/Userland/Libraries/LibWeb/HTML/MimeType.h new file mode 100644 index 0000000000..859e15dbf6 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/MimeType.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibWeb/Bindings/LegacyPlatformObject.h> + +namespace Web::HTML { + +// https://html.spec.whatwg.org/multipage/system-state.html#mimetype +class MimeType : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(MimeType, Bindings::PlatformObject); + +public: + virtual ~MimeType() override; + + String const& type() const; + JS::ThrowCompletionOr<String> description() const; + String const& suffixes() const; + JS::NonnullGCPtr<Plugin> enabled_plugin() const; + +private: + MimeType(JS::Realm&, String const& type); + + virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; + + // https://html.spec.whatwg.org/multipage/system-state.html#concept-mimetype-type + String m_type; +}; + +} diff --git a/Userland/Libraries/LibWeb/HTML/MimeType.idl b/Userland/Libraries/LibWeb/HTML/MimeType.idl new file mode 100644 index 0000000000..f5c4b26ccc --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/MimeType.idl @@ -0,0 +1,9 @@ +#import <HTML/Plugin.idl> + +[Exposed=Window, UseNewAKString] +interface MimeType { + readonly attribute DOMString type; + readonly attribute DOMString description; + readonly attribute DOMString suffixes; + readonly attribute Plugin enabledPlugin; +}; diff --git a/Userland/Libraries/LibWeb/HTML/MimeTypeArray.cpp b/Userland/Libraries/LibWeb/HTML/MimeTypeArray.cpp new file mode 100644 index 0000000000..7e9a823d54 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/MimeTypeArray.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWeb/Bindings/Intrinsics.h> +#include <LibWeb/HTML/MimeTypeArray.h> +#include <LibWeb/HTML/Scripting/Environments.h> +#include <LibWeb/HTML/Window.h> +#include <LibWeb/Page/Page.h> + +namespace Web::HTML { + +MimeTypeArray::MimeTypeArray(JS::Realm& realm) + : Bindings::LegacyPlatformObject(realm) +{ +} + +MimeTypeArray::~MimeTypeArray() = default; + +JS::ThrowCompletionOr<void> MimeTypeArray::initialize(JS::Realm& realm) +{ + MUST_OR_THROW_OOM(Base::initialize(realm)); + set_prototype(&Bindings::ensure_web_prototype<Bindings::MimeTypeArrayPrototype>(realm, "MimeTypeArray")); + + return {}; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewing-support:support-named-properties-2 +Vector<DeprecatedString> MimeTypeArray::supported_property_names() const +{ + // The MimeTypeArray interface supports named properties. If the user agent's PDF viewer supported is true, then they are the PDF viewer mime types. Otherwise, they are the empty list. + auto const& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + VERIFY(window.page()); + if (!window.page()->pdf_viewer_supported()) + return {}; + + // https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-mime-types + static Vector<DeprecatedString> mime_types = { + "application/pdf"sv, + "text/pdf"sv, + }; + + return mime_types; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewing-support:supports-indexed-properties-2 +bool MimeTypeArray::is_supported_property_index(u32 index) const +{ + // The MimeTypeArray interface supports indexed properties. The supported property indices are the indices of this's relevant global object's PDF viewer mime type objects. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + return index < window.pdf_viewer_mime_type_objects().size(); +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-mimetypearray-length +size_t MimeTypeArray::length() const +{ + // The MimeTypeArray interface's length getter steps are to return this's relevant global object's PDF viewer mime type objects's size. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + return window.pdf_viewer_mime_type_objects().size(); +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-mimetypearray-item +JS::GCPtr<MimeType> MimeTypeArray::item(u32 index) const +{ + // 1. Let mimeTypes be this's relevant global object's PDF viewer mime type objects. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto mime_types = window.pdf_viewer_mime_type_objects(); + + // 2. If index < mimeType's size, then return mimeTypes[index]. + if (index < mime_types.size()) + return mime_types[index]; + + // 3. Return null. + return nullptr; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-mimetypearray-nameditem +JS::GCPtr<MimeType> MimeTypeArray::named_item(String const& name) const +{ + // 1. For each MimeType mimeType of this's relevant global object's PDF viewer mime type objects: if mimeType's type is name, then return mimeType. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto mime_types = window.pdf_viewer_mime_type_objects(); + + for (auto& mime_type : mime_types) { + if (mime_type->type() == name) + return mime_type; + } + + // 2. Return null. + return nullptr; +} + +WebIDL::ExceptionOr<JS::Value> MimeTypeArray::item_value(size_t index) const +{ + auto return_value = item(index); + if (!return_value) + return JS::js_null(); + return return_value.ptr(); +} + +WebIDL::ExceptionOr<JS::Value> MimeTypeArray::named_item_value(DeprecatedFlyString const& name) const +{ + auto converted_name = TRY_OR_THROW_OOM(vm(), String::from_deprecated_string(name)); + auto return_value = named_item(converted_name); + if (!return_value) + return JS::js_null(); + return return_value.ptr(); +} + +} diff --git a/Userland/Libraries/LibWeb/HTML/MimeTypeArray.h b/Userland/Libraries/LibWeb/HTML/MimeTypeArray.h new file mode 100644 index 0000000000..368c13f46b --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/MimeTypeArray.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibWeb/Bindings/LegacyPlatformObject.h> + +namespace Web::HTML { + +// https://html.spec.whatwg.org/multipage/system-state.html#mimetypearray +class MimeTypeArray : public Bindings::LegacyPlatformObject { + WEB_PLATFORM_OBJECT(MimeTypeArray, Bindings::LegacyPlatformObject); + +public: + virtual ~MimeTypeArray() override; + + size_t length() const; + JS::GCPtr<MimeType> item(u32 index) const; + JS::GCPtr<MimeType> named_item(String const& name) const; + +private: + MimeTypeArray(JS::Realm&); + + virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; + + // ^Bindings::LegacyPlatformObject + virtual Vector<DeprecatedString> supported_property_names() const override; + virtual WebIDL::ExceptionOr<JS::Value> item_value(size_t index) const override; + virtual WebIDL::ExceptionOr<JS::Value> named_item_value(DeprecatedFlyString const& name) const override; + virtual bool is_supported_property_index(u32) const override; + + virtual bool supports_indexed_properties() const override { return true; } + virtual bool supports_named_properties() const override { return true; } + virtual bool has_indexed_property_setter() const override { return false; } + virtual bool has_named_property_setter() const override { return false; } + virtual bool has_named_property_deleter() const override { return false; } + virtual bool has_legacy_override_built_ins_interface_extended_attribute() const override { return false; } + virtual bool has_legacy_unenumerable_named_properties_interface_extended_attribute() const override { return true; } + virtual bool has_global_interface_extended_attribute() const override { return false; } + virtual bool indexed_property_setter_has_identifier() const override { return false; } + virtual bool named_property_setter_has_identifier() const override { return false; } + virtual bool named_property_deleter_has_identifier() const override { return false; } +}; + +} diff --git a/Userland/Libraries/LibWeb/HTML/MimeTypeArray.idl b/Userland/Libraries/LibWeb/HTML/MimeTypeArray.idl new file mode 100644 index 0000000000..80a5149ecb --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/MimeTypeArray.idl @@ -0,0 +1,8 @@ +#import <HTML/MimeType.idl> + +[Exposed=Window, LegacyUnenumerableNamedProperties, UseNewAKString] +interface MimeTypeArray { + readonly attribute unsigned long length; + getter MimeType? item(unsigned long index); + getter MimeType? namedItem(DOMString name); +}; diff --git a/Userland/Libraries/LibWeb/HTML/Navigator.cpp b/Userland/Libraries/LibWeb/HTML/Navigator.cpp index 67c8fb36af..4f538b5ed3 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigator.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigator.cpp @@ -39,7 +39,7 @@ JS::ThrowCompletionOr<void> Navigator::initialize(JS::Realm& realm) bool Navigator::pdf_viewer_enabled() const { // The NavigatorPlugins mixin's pdfViewerEnabled getter steps are to return the user agent's PDF viewer supported. - // NOTE: THe NavigatorPlugins mixin should only be exposed on the Window object. + // NOTE: The NavigatorPlugins mixin should only be exposed on the Window object. auto const& window = verify_cast<HTML::Window>(HTML::current_global_object()); return window.page()->pdf_viewer_supported(); } @@ -54,4 +54,25 @@ bool Navigator::webdriver() const return window.page()->is_webdriver_active(); } +void Navigator::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_mime_type_array); + visitor.visit(m_plugin_array); +} + +JS::ThrowCompletionOr<JS::NonnullGCPtr<MimeTypeArray>> Navigator::mime_types() +{ + if (!m_mime_type_array) + m_mime_type_array = TRY(heap().allocate<MimeTypeArray>(realm(), realm())); + return *m_mime_type_array; +} + +JS::ThrowCompletionOr<JS::NonnullGCPtr<PluginArray>> Navigator::plugins() +{ + if (!m_plugin_array) + m_plugin_array = TRY(heap().allocate<PluginArray>(realm(), realm())); + return *m_plugin_array; +} + } diff --git a/Userland/Libraries/LibWeb/HTML/Navigator.h b/Userland/Libraries/LibWeb/HTML/Navigator.h index 9d6123e5ff..0bb2332cf6 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigator.h +++ b/Userland/Libraries/LibWeb/HTML/Navigator.h @@ -7,10 +7,12 @@ #pragma once #include <LibWeb/Bindings/PlatformObject.h> +#include <LibWeb/HTML/MimeTypeArray.h> #include <LibWeb/HTML/NavigatorConcurrentHardware.h> #include <LibWeb/HTML/NavigatorID.h> #include <LibWeb/HTML/NavigatorLanguage.h> #include <LibWeb/HTML/NavigatorOnLine.h> +#include <LibWeb/HTML/PluginArray.h> namespace Web::HTML { @@ -35,17 +37,25 @@ public: // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-javaenabled bool java_enabled() const { return false; } - // https://html.spec.whatwg.org/multipage/system-state.html#dom-navigator-pdfviewerenabled bool pdf_viewer_enabled() const; bool webdriver() const; + JS::ThrowCompletionOr<JS::NonnullGCPtr<MimeTypeArray>> mime_types(); + JS::ThrowCompletionOr<JS::NonnullGCPtr<PluginArray>> plugins(); + virtual ~Navigator() override; +protected: + virtual void visit_edges(Cell::Visitor&) override; + private: explicit Navigator(JS::Realm&); virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; + + JS::GCPtr<PluginArray> m_plugin_array; + JS::GCPtr<MimeTypeArray> m_mime_type_array; }; } diff --git a/Userland/Libraries/LibWeb/HTML/Navigator.idl b/Userland/Libraries/LibWeb/HTML/Navigator.idl index 7d81a2cf40..4a96de9969 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigator.idl +++ b/Userland/Libraries/LibWeb/HTML/Navigator.idl @@ -1,7 +1,9 @@ +#import <HTML/MimeTypeArray.idl> #import <HTML/NavigatorID.idl> #import <HTML/NavigatorLanguage.idl> #import <HTML/NavigatorOnLine.idl> #import <HTML/NavigatorConcurrentHardware.idl> +#import <HTML/PluginArray.idl> // https://html.spec.whatwg.org/multipage/system-state.html#navigator [Exposed=Window] @@ -25,8 +27,8 @@ interface mixin NavigatorCookies { // https://html.spec.whatwg.org/multipage/system-state.html#navigatorplugins interface mixin NavigatorPlugins { - // FIXME: [SameObject] readonly attribute PluginArray plugins; - // FIXME: [SameObject] readonly attribute MimeTypeArray mimeTypes; + [SameObject] readonly attribute PluginArray plugins; + [SameObject] readonly attribute MimeTypeArray mimeTypes; boolean javaEnabled(); readonly attribute boolean pdfViewerEnabled; }; diff --git a/Userland/Libraries/LibWeb/HTML/Plugin.cpp b/Userland/Libraries/LibWeb/HTML/Plugin.cpp new file mode 100644 index 0000000000..4240a522c6 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/Plugin.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWeb/Bindings/Intrinsics.h> +#include <LibWeb/HTML/Plugin.h> +#include <LibWeb/HTML/Scripting/Environments.h> +#include <LibWeb/HTML/Window.h> +#include <LibWeb/Page/Page.h> + +namespace Web::HTML { + +Plugin::Plugin(JS::Realm& realm, String const& name) + : Bindings::LegacyPlatformObject(realm) + , m_name(name) +{ +} + +Plugin::~Plugin() = default; + +JS::ThrowCompletionOr<void> Plugin::initialize(JS::Realm& realm) +{ + MUST_OR_THROW_OOM(Base::initialize(realm)); + set_prototype(&Bindings::ensure_web_prototype<Bindings::PluginPrototype>(realm, "Plugin")); + + return {}; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-plugin-name +String const& Plugin::name() const +{ + // The Plugin interface's name getter steps are to return this's name. + return m_name; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-plugin-description +JS::ThrowCompletionOr<String> Plugin::description() const +{ + // The Plugin interface's description getter steps are to return "Portable Document Format". + static String description_string = TRY_OR_THROW_OOM(vm(), String::from_utf8("Portable Document Format"sv)); + return description_string; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-plugin-filename +JS::ThrowCompletionOr<String> Plugin::filename() const +{ + // The Plugin interface's filename getter steps are to return "internal-pdf-viewer". + static String filename_string = TRY_OR_THROW_OOM(vm(), String::from_utf8("internal-pdf-viewer"sv)); + return filename_string; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewing-support:support-named-properties-3 +Vector<DeprecatedString> Plugin::supported_property_names() const +{ + // The Plugin interface supports named properties. If the user agent's PDF viewer supported is true, then they are the PDF viewer mime types. Otherwise, they are the empty list. + auto const& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + VERIFY(window.page()); + if (!window.page()->pdf_viewer_supported()) + return {}; + + // https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-mime-types + static Vector<DeprecatedString> mime_types = { + "application/pdf"sv, + "text/pdf"sv, + }; + + return mime_types; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewing-support:supports-indexed-properties-3 +bool Plugin::is_supported_property_index(u32 index) const +{ + // The Plugin interface supports indexed properties. The supported property indices are the indices of this's relevant global object's PDF viewer mime type objects. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + return index < window.pdf_viewer_mime_type_objects().size(); +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-plugin-length +size_t Plugin::length() const +{ + // The Plugin interface's length getter steps are to return this's relevant global object's PDF viewer mime type objects's size. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + return window.pdf_viewer_mime_type_objects().size(); +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-plugin-item +JS::GCPtr<MimeType> Plugin::item(u32 index) const +{ + // 1. Let mimeTypes be this's relevant global object's PDF viewer mime type objects. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto mime_types = window.pdf_viewer_mime_type_objects(); + + // 2. If index < mimeType's size, then return mimeTypes[index]. + if (index < mime_types.size()) + return mime_types[index]; + + // 3. Return null. + return nullptr; +} + +JS::GCPtr<MimeType> Plugin::named_item(String const& name) const +{ + // 1. For each MimeType mimeType of this's relevant global object's PDF viewer mime type objects: if mimeType's type is name, then return mimeType. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto mime_types = window.pdf_viewer_mime_type_objects(); + + for (auto& mime_type : mime_types) { + if (mime_type->type() == name) + return mime_type; + } + + // 2. Return null. + return nullptr; +} + +WebIDL::ExceptionOr<JS::Value> Plugin::item_value(size_t index) const +{ + auto return_value = item(index); + if (!return_value) + return JS::js_null(); + return return_value.ptr(); +} + +WebIDL::ExceptionOr<JS::Value> Plugin::named_item_value(DeprecatedFlyString const& name) const +{ + auto converted_name = TRY_OR_THROW_OOM(vm(), String::from_deprecated_string(name)); + auto return_value = named_item(converted_name); + if (!return_value) + return JS::js_null(); + return return_value.ptr(); +} + +} diff --git a/Userland/Libraries/LibWeb/HTML/Plugin.h b/Userland/Libraries/LibWeb/HTML/Plugin.h new file mode 100644 index 0000000000..70bed1bae8 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/Plugin.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibWeb/Bindings/LegacyPlatformObject.h> + +namespace Web::HTML { + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-plugin +class Plugin : public Bindings::LegacyPlatformObject { + WEB_PLATFORM_OBJECT(Plugin, Bindings::LegacyPlatformObject); + +public: + virtual ~Plugin() override; + + String const& name() const; + JS::ThrowCompletionOr<String> description() const; + JS::ThrowCompletionOr<String> filename() const; + size_t length() const; + JS::GCPtr<MimeType> item(u32 index) const; + JS::GCPtr<MimeType> named_item(String const& name) const; + +private: + Plugin(JS::Realm&, String const& name); + + // https://html.spec.whatwg.org/multipage/system-state.html#concept-plugin-name + String m_name; + + virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; + + // ^Bindings::LegacyPlatformObject + virtual Vector<DeprecatedString> supported_property_names() const override; + virtual WebIDL::ExceptionOr<JS::Value> item_value(size_t index) const override; + virtual WebIDL::ExceptionOr<JS::Value> named_item_value(DeprecatedFlyString const& name) const override; + virtual bool is_supported_property_index(u32) const override; + + virtual bool supports_indexed_properties() const override { return true; } + virtual bool supports_named_properties() const override { return true; } + virtual bool has_indexed_property_setter() const override { return false; } + virtual bool has_named_property_setter() const override { return false; } + virtual bool has_named_property_deleter() const override { return false; } + virtual bool has_legacy_override_built_ins_interface_extended_attribute() const override { return false; } + virtual bool has_legacy_unenumerable_named_properties_interface_extended_attribute() const override { return true; } + virtual bool has_global_interface_extended_attribute() const override { return false; } + virtual bool indexed_property_setter_has_identifier() const override { return false; } + virtual bool named_property_setter_has_identifier() const override { return false; } + virtual bool named_property_deleter_has_identifier() const override { return false; } +}; + +} diff --git a/Userland/Libraries/LibWeb/HTML/Plugin.idl b/Userland/Libraries/LibWeb/HTML/Plugin.idl new file mode 100644 index 0000000000..b3d1591736 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/Plugin.idl @@ -0,0 +1,11 @@ +#import <HTML/MimeType.idl> + +[Exposed=Window, LegacyUnenumerableNamedProperties, UseNewAKString] +interface Plugin { + readonly attribute DOMString name; + readonly attribute DOMString description; + readonly attribute DOMString filename; + readonly attribute unsigned long length; + getter MimeType? item(unsigned long index); + getter MimeType? namedItem(DOMString name); +}; diff --git a/Userland/Libraries/LibWeb/HTML/PluginArray.cpp b/Userland/Libraries/LibWeb/HTML/PluginArray.cpp new file mode 100644 index 0000000000..c60699f47e --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/PluginArray.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibWeb/Bindings/Intrinsics.h> +#include <LibWeb/HTML/PluginArray.h> +#include <LibWeb/HTML/Scripting/Environments.h> +#include <LibWeb/HTML/Window.h> +#include <LibWeb/Page/Page.h> + +namespace Web::HTML { + +PluginArray::PluginArray(JS::Realm& realm) + : Bindings::LegacyPlatformObject(realm) +{ +} + +PluginArray::~PluginArray() = default; + +JS::ThrowCompletionOr<void> PluginArray::initialize(JS::Realm& realm) +{ + MUST_OR_THROW_OOM(Base::initialize(realm)); + set_prototype(&Bindings::ensure_web_prototype<Bindings::PluginArrayPrototype>(realm, "PluginArray")); + + return {}; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-pluginarray-refresh +void PluginArray::refresh() const +{ + // The PluginArray interface's refresh() method steps are to do nothing. +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewing-support:support-named-properties +Vector<DeprecatedString> PluginArray::supported_property_names() const +{ + // The PluginArray interface supports named properties. If the user agent's PDF viewer supported is true, then they are the PDF viewer plugin names. Otherwise, they are the empty list. + auto const& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + VERIFY(window.page()); + if (!window.page()->pdf_viewer_supported()) + return {}; + + // https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-plugin-names + static Vector<DeprecatedString> plugin_names = { + "PDF Viewer"sv, + "Chrome PDF Viewer"sv, + "Chromium PDF Viewer"sv, + "Microsoft Edge PDF Viewer"sv, + "WebKit built-in PDF"sv, + }; + + return plugin_names; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewing-support:supports-indexed-properties +bool PluginArray::is_supported_property_index(u32 index) const +{ + // The PluginArray interface supports indexed properties. The supported property indices are the indices of this's relevant global object's PDF viewer plugin objects. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + return index < window.pdf_viewer_plugin_objects().size(); +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-pluginarray-length +size_t PluginArray::length() const +{ + // The PluginArray interface's length getter steps are to return this's relevant global object's PDF viewer plugin objects's size. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + return window.pdf_viewer_plugin_objects().size(); +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-pluginarray-item +JS::GCPtr<Plugin> PluginArray::item(u32 index) const +{ + // 1. Let plugins be this's relevant global object's PDF viewer plugin objects. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto plugins = window.pdf_viewer_plugin_objects(); + + // 2. If index < plugins's size, then return plugins[index]. + if (index < plugins.size()) + return plugins[index]; + + // 3. Return null. + return nullptr; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#dom-pluginarray-nameditem +JS::GCPtr<Plugin> PluginArray::named_item(String const& name) const +{ + // 1. For each Plugin plugin of this's relevant global object's PDF viewer plugin objects: if plugin's name is name, then return plugin. + auto& window = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)); + auto plugins = window.pdf_viewer_plugin_objects(); + + for (auto& plugin : plugins) { + if (plugin->name() == name) + return plugin; + } + + // 2. Return null. + return nullptr; +} + +WebIDL::ExceptionOr<JS::Value> PluginArray::item_value(size_t index) const +{ + auto return_value = item(index); + if (!return_value) + return JS::js_null(); + return return_value.ptr(); +} + +WebIDL::ExceptionOr<JS::Value> PluginArray::named_item_value(DeprecatedFlyString const& name) const +{ + auto converted_name = TRY_OR_THROW_OOM(vm(), String::from_deprecated_string(name)); + auto return_value = named_item(converted_name); + if (!return_value) + return JS::js_null(); + return return_value.ptr(); +} + +} diff --git a/Userland/Libraries/LibWeb/HTML/PluginArray.h b/Userland/Libraries/LibWeb/HTML/PluginArray.h new file mode 100644 index 0000000000..f9c447e363 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/PluginArray.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <LibWeb/Bindings/LegacyPlatformObject.h> + +namespace Web::HTML { + +// https://html.spec.whatwg.org/multipage/system-state.html#pluginarray +class PluginArray : public Bindings::LegacyPlatformObject { + WEB_PLATFORM_OBJECT(PluginArray, Bindings::LegacyPlatformObject); + +public: + virtual ~PluginArray() override; + + void refresh() const; + size_t length() const; + JS::GCPtr<Plugin> item(u32 index) const; + JS::GCPtr<Plugin> named_item(String const& name) const; + +private: + PluginArray(JS::Realm&); + + virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override; + + // ^Bindings::LegacyPlatformObject + virtual Vector<DeprecatedString> supported_property_names() const override; + virtual WebIDL::ExceptionOr<JS::Value> item_value(size_t index) const override; + virtual WebIDL::ExceptionOr<JS::Value> named_item_value(DeprecatedFlyString const& name) const override; + virtual bool is_supported_property_index(u32) const override; + + virtual bool supports_indexed_properties() const override { return true; } + virtual bool supports_named_properties() const override { return true; } + virtual bool has_indexed_property_setter() const override { return false; } + virtual bool has_named_property_setter() const override { return false; } + virtual bool has_named_property_deleter() const override { return false; } + virtual bool has_legacy_override_built_ins_interface_extended_attribute() const override { return false; } + virtual bool has_legacy_unenumerable_named_properties_interface_extended_attribute() const override { return true; } + virtual bool has_global_interface_extended_attribute() const override { return false; } + virtual bool indexed_property_setter_has_identifier() const override { return false; } + virtual bool named_property_setter_has_identifier() const override { return false; } + virtual bool named_property_deleter_has_identifier() const override { return false; } +}; + +} diff --git a/Userland/Libraries/LibWeb/HTML/PluginArray.idl b/Userland/Libraries/LibWeb/HTML/PluginArray.idl new file mode 100644 index 0000000000..064ba80601 --- /dev/null +++ b/Userland/Libraries/LibWeb/HTML/PluginArray.idl @@ -0,0 +1,9 @@ +#import <HTML/Plugin.idl> + +[Exposed=Window, LegacyUnenumerableNamedProperties, UseNewAKString] +interface PluginArray { + undefined refresh(); + readonly attribute unsigned long length; + getter Plugin? item(unsigned long index); + getter Plugin? namedItem(DOMString name); +}; diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index acd0364e23..3507a81b3f 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -108,6 +108,10 @@ void Window::visit_edges(JS::Cell::Visitor& visitor) visitor.visit(m_navigator); for (auto& it : m_timers) visitor.visit(it.value.ptr()); + for (auto& plugin_object : m_pdf_viewer_plugin_objects) + visitor.visit(plugin_object); + for (auto& mime_type_object : m_pdf_viewer_mime_type_objects) + visitor.visit(mime_type_object); } Window::~Window() = default; @@ -1060,6 +1064,54 @@ HTML::BrowsingContext* Window::browsing_context() return m_associated_document->browsing_context(); } +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-plugin-objects +Vector<JS::NonnullGCPtr<Plugin>> Window::pdf_viewer_plugin_objects() +{ + // Each Window object has a PDF viewer plugin objects list. If the user agent's PDF viewer supported is false, then it is the empty list. + // Otherwise, it is a list containing five Plugin objects, whose names are, respectively: + // 0. "PDF Viewer" + // 1. "Chrome PDF Viewer" + // 2. "Chromium PDF Viewer" + // 3. "Microsoft Edge PDF Viewer" + // 4. "WebKit built-in PDF" + // The values of the above list form the PDF viewer plugin names list. https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-plugin-names + VERIFY(page()); + if (!page()->pdf_viewer_supported()) + return {}; + + if (m_pdf_viewer_plugin_objects.is_empty()) { + // FIXME: Remove the MUSTs and propagate the errors instead. + m_pdf_viewer_plugin_objects.append(realm().heap().allocate<Plugin>(realm(), realm(), MUST(String::from_utf8("PDF Viewer"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + m_pdf_viewer_plugin_objects.append(realm().heap().allocate<Plugin>(realm(), realm(), MUST(String::from_utf8("Chrome PDF Viewer"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + m_pdf_viewer_plugin_objects.append(realm().heap().allocate<Plugin>(realm(), realm(), MUST(String::from_utf8("Chromium PDF Viewer"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + m_pdf_viewer_plugin_objects.append(realm().heap().allocate<Plugin>(realm(), realm(), MUST(String::from_utf8("Microsoft Edge PDF Viewer"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + m_pdf_viewer_plugin_objects.append(realm().heap().allocate<Plugin>(realm(), realm(), MUST(String::from_utf8("WebKit built-in PDF"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + } + + return m_pdf_viewer_plugin_objects; +} + +// https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-mime-type-objects +Vector<JS::NonnullGCPtr<MimeType>> Window::pdf_viewer_mime_type_objects() +{ + // Each Window object has a PDF viewer mime type objects list. If the user agent's PDF viewer supported is false, then it is the empty list. + // Otherwise, it is a list containing two MimeType objects, whose types are, respectively: + // 0. "application/pdf" + // 1. "text/pdf" + // The values of the above list form the PDF viewer mime types list. https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-mime-types + VERIFY(page()); + if (!page()->pdf_viewer_supported()) + return {}; + + if (m_pdf_viewer_mime_type_objects.is_empty()) { + // FIXME: Remove the MUSTs and propagate the errors instead. + m_pdf_viewer_mime_type_objects.append(realm().heap().allocate<MimeType>(realm(), realm(), MUST(String::from_utf8("application/pdf"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + m_pdf_viewer_mime_type_objects.append(realm().heap().allocate<MimeType>(realm(), realm(), MUST(String::from_utf8("text/pdf"sv))).release_allocated_value_but_fixme_should_propagate_errors()); + } + + return m_pdf_viewer_mime_type_objects; +} + void Window::initialize_web_interfaces(Badge<WindowEnvironmentSettingsObject>) { auto& realm = this->realm(); diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index 9a1d8c85da..42d88fb31b 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -20,6 +20,8 @@ #include <LibWeb/HTML/AnimationFrameCallbackDriver.h> #include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h> #include <LibWeb/HTML/GlobalEventHandlers.h> +#include <LibWeb/HTML/MimeType.h> +#include <LibWeb/HTML/Plugin.h> #include <LibWeb/HTML/Scripting/ImportMap.h> #include <LibWeb/HTML/WindowEventHandlers.h> @@ -137,6 +139,9 @@ public: void initialize_web_interfaces(Badge<WindowEnvironmentSettingsObject>); + Vector<JS::NonnullGCPtr<Plugin>> pdf_viewer_plugin_objects(); + Vector<JS::NonnullGCPtr<MimeType>> pdf_viewer_mime_type_objects(); + private: explicit Window(JS::Realm&); @@ -184,6 +189,12 @@ private: // https://w3c.github.io/requestidlecallback/#dfn-idle-callback-identifier u32 m_idle_callback_identifier = 0; + // https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-plugin-objects + Vector<JS::NonnullGCPtr<Plugin>> m_pdf_viewer_plugin_objects; + + // https://html.spec.whatwg.org/multipage/system-state.html#pdf-viewer-mime-type-objects + Vector<JS::NonnullGCPtr<MimeType>> m_pdf_viewer_mime_type_objects; + public: HTML::Origin origin() const; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index fa1488d4b7..e394258a7d 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -152,9 +152,13 @@ libweb_js_bindings(HTML/Location) libweb_js_bindings(HTML/MessageChannel) libweb_js_bindings(HTML/MessageEvent) libweb_js_bindings(HTML/MessagePort) +libweb_js_bindings(HTML/MimeType) +libweb_js_bindings(HTML/MimeTypeArray) libweb_js_bindings(HTML/Navigator) libweb_js_bindings(HTML/PageTransitionEvent) libweb_js_bindings(HTML/Path2D) +libweb_js_bindings(HTML/Plugin) +libweb_js_bindings(HTML/PluginArray) libweb_js_bindings(HTML/PromiseRejectionEvent) libweb_js_bindings(HTML/Storage) libweb_js_bindings(HTML/SubmitEvent) |