From d30ae92b82d997bc4db407c563c88f90d8260093 Mon Sep 17 00:00:00 2001 From: Noah Bright Date: Sun, 22 Sep 2024 15:12:55 -0400 Subject: [PATCH] LibWeb: Define PerformanceEventTiming https://www.w3.org/TR/event-timing/#sec-performance-event-timing Add idl, header and stubs for PerformanceEventTiming interface. Two missing `PerformanceEntry` types that have come up in issues are the `first-input` and the `event` entryTypes. Those are both this. Also, because both of those are this same interface, the static methods from the parent class are difficult to implement because of instance-specific details. Might either need subclasses or to edit the parent and also everything that inherits from it :/ --- .../BindingsGenerator/IDLGenerators.cpp | 1 + .../Text/expected/all-window-properties.txt | 1 + Userland/Libraries/LibWeb/CMakeLists.txt | 1 + .../EventTiming/PerformanceEventTiming.cpp | 125 ++++++++++++++++++ .../EventTiming/PerformanceEventTiming.h | 66 +++++++++ .../EventTiming/PerformanceEventTiming.idl | 18 +++ Userland/Libraries/LibWeb/Forward.h | 4 + Userland/Libraries/LibWeb/idl_files.cmake | 1 + 8 files changed, 217 insertions(+) create mode 100644 Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.cpp create mode 100644 Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.h create mode 100644 Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.idl diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 29ebb28cd7a..6f8f5d2e823 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -4190,6 +4190,7 @@ static void generate_using_namespace_definitions(SourceGenerator& generator) using namespace Web::DOMURL; using namespace Web::Encoding; using namespace Web::EntriesAPI; + using namespace Web::EventTiming; using namespace Web::Fetch; using namespace Web::FileAPI; using namespace Web::Geometry; diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 8fa706e12ad..e4484c041c2 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -243,6 +243,7 @@ PageTransitionEvent Path2D Performance PerformanceEntry +PerformanceEventTiming PerformanceMark PerformanceMeasure PerformanceNavigation diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 15eb9bc2b56..d68a98f17ed 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -219,6 +219,7 @@ set(SOURCES Encoding/TextDecoder.cpp Encoding/TextEncoder.cpp EntriesAPI/FileSystemEntry.cpp + EventTiming/PerformanceEventTiming.cpp Fetch/Body.cpp Fetch/BodyInit.cpp Fetch/Enums.cpp diff --git a/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.cpp b/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.cpp new file mode 100644 index 00000000000..4380c88dba7 --- /dev/null +++ b/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024, Noah Bright + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace Web::EventTiming { + +JS_DEFINE_ALLOCATOR(PerformanceEventTiming); + +// https://www.w3.org/TR/event-timing/#sec-init-event-timing +PerformanceEventTiming::PerformanceEventTiming(JS::Realm& realm, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration, + DOM::Event const& event, HighResolutionTime::DOMHighResTimeStamp processing_start, unsigned long long interaction_id) + : PerformanceTimeline::PerformanceEntry(realm, name, start_time, duration) + , m_entry_type(PerformanceTimeline::EntryTypes::event) + , m_start_time(event.time_stamp()) + , m_processing_start(processing_start) + , m_cancelable(event.cancelable()) + , m_interaction_id(interaction_id) + +{ +} + +PerformanceEventTiming::~PerformanceEventTiming() = default; + +FlyString const& PerformanceEventTiming::entry_type() const +{ + return m_entry_type; +} + +HighResolutionTime::DOMHighResTimeStamp PerformanceEventTiming::processing_end() const +{ + dbgln("FIXME: Implement PeformanceEventTiming processing_end()"); + return 0; +} + +HighResolutionTime::DOMHighResTimeStamp PerformanceEventTiming::processing_start() const +{ + dbgln("FIXME: Implement PeformanceEventTiming processing_start()"); + return 0; +} + +bool PerformanceEventTiming::cancelable() const +{ + return m_cancelable; +} + +JS::ThrowCompletionOr> PerformanceEventTiming::target() +{ + dbgln("FIXME: Implement PerformanceEventTiming::PeformanceEventTiming target()"); + return nullptr; +} + +unsigned long long PerformanceEventTiming::interaction_id() +{ + dbgln("FIXME: Implement PeformanceEventTiming interaction_id()"); + return 0; +} + +// https://www.w3.org/TR/event-timing/#sec-should-add-performanceeventtiming +PerformanceTimeline::ShouldAddEntry PerformanceEventTiming::should_add_performance_event_timing() const +{ + dbgln("FIXME: Implement PeformanceEventTiming should_add_performance_event_timing()"); + // 1. If entry’s entryType attribute value equals to "first-input", return true. + if (entry_type() == "first-input") + return PerformanceTimeline::ShouldAddEntry::Yes; + + // 2. Assert that entry’s entryType attribute value equals "event". + VERIFY(entry_type() == "event"); + + // FIXME: 3. Let minDuration be computed as follows: + // FIXME: 3.1. If options is not present or if options’s durationThreshold is not present, let minDuration be 104. + // FIXME: 3.2. Otherwise, let minDuration be the maximum between 16 and options’s durationThreshold value. + + // FIXME: 4. If entry’s duration attribute value is greater than or equal to minDuration, return true. + + // 5. Otherwise, return false. + return PerformanceTimeline::ShouldAddEntry::No; +} + +// https://w3c.github.io/timing-entrytypes-registry/#dfn-availablefromtimeline +// FIXME: the output here depends on the type of the object instance, but this function is static +// the commented out if statement won't compile +PerformanceTimeline::AvailableFromTimeline PerformanceEventTiming::available_from_timeline() +{ + dbgln("FIXME: Implement PeformanceEventTiming available_from_timeline()"); + // if (entry_type() == "first-input") + return PerformanceTimeline::AvailableFromTimeline::Yes; +} + +// https://w3c.github.io/timing-entrytypes-registry/#dfn-maxbuffersize +// FIXME: Same issue as available_from_timeline() above +Optional PerformanceEventTiming::max_buffer_size() +{ + dbgln("FIXME: Implement PeformanceEventTiming max_buffer_size()"); + if (true) //(entry_type() == "first-input") + return 1; + // else return 150; +} + +// https://w3c.github.io/timing-entrytypes-registry/#dfn-should-add-entry +PerformanceTimeline::ShouldAddEntry PerformanceEventTiming::should_add_entry(Optional) const +{ + return should_add_performance_event_timing(); +} + +void PerformanceEventTiming::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(PerformanceEventTiming); +} + +void PerformanceEventTiming::visit_edges(JS::Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_event_target); +} + +} diff --git a/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.h b/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.h new file mode 100644 index 00000000000..d0f06341915 --- /dev/null +++ b/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, Noah Bright + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::EventTiming { + +// https://www.w3.org/TR/event-timing/#sec-performance-event-timing +class PerformanceEventTiming final : public PerformanceTimeline::PerformanceEntry { + WEB_PLATFORM_OBJECT(PerformanceEventTiming, PerformanceTimeline::PerformanceEntry); + JS_DECLARE_ALLOCATOR(PerformanceEventTiming); + +public: + virtual ~PerformanceEventTiming(); + + HighResolutionTime::DOMHighResTimeStamp processing_start() const; + HighResolutionTime::DOMHighResTimeStamp processing_end() const; + bool cancelable() const; + JS::ThrowCompletionOr> target(); + unsigned long long interaction_id(); + + // from the registry: + // https://w3c.github.io/timing-entrytypes-registry/#dfn-availablefromtimeline + static PerformanceTimeline::AvailableFromTimeline available_from_timeline(); + // https://w3c.github.io/timing-entrytypes-registry/#dfn-maxbuffersize + static Optional max_buffer_size(); + // https://w3c.github.io/timing-entrytypes-registry/#dfn-should-add-entry + virtual PerformanceTimeline::ShouldAddEntry should_add_entry(Optional = {}) const override; + + virtual FlyString const& entry_type() const override; + +private: + PerformanceEventTiming(JS::Realm& realm, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration, + DOM::Event const& event, HighResolutionTime::DOMHighResTimeStamp processing_start, unsigned long long interaction_id); + + // m_entry_type defined here for both "event"s and "first-input"s + // this is the only PerformanceEntry that has two event types it could represent + // That complicates implementing the registry functions if they remain static + FlyString m_entry_type; + JS::GCPtr m_event_target; + HighResolutionTime::DOMHighResTimeStamp m_start_time; + HighResolutionTime::DOMHighResTimeStamp m_processing_start; + bool m_cancelable; + unsigned long long m_interaction_id; + + static WebIDL::ExceptionOr> construct_impl(DOM::Event const&, HighResolutionTime::DOMHighResTimeStamp, unsigned long long); + virtual void initialize(JS::Realm&) override; + + PerformanceTimeline::ShouldAddEntry should_add_performance_event_timing() const; + + virtual void visit_edges(JS::Cell::Visitor&) override; + + // FIXME: remaining algorithms described in this spec: + // https://www.w3.org/TR/event-timing/#sec-increasing-interaction-count + // https://www.w3.org/TR/event-timing/#sec-computing-interactionid + // https://www.w3.org/TR/event-timing/#sec-fin-event-timing + // https://www.w3.org/TR/event-timing/#sec-dispatch-pending +}; +} diff --git a/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.idl b/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.idl new file mode 100644 index 00000000000..7a0350cb36c --- /dev/null +++ b/Userland/Libraries/LibWeb/EventTiming/PerformanceEventTiming.idl @@ -0,0 +1,18 @@ +#import + +// https://www.w3.org/TR/event-timing/#sec-performance-event-timing +[Exposed=Window] +interface PerformanceEventTiming : PerformanceEntry { + readonly attribute DOMHighResTimeStamp processingStart; + readonly attribute DOMHighResTimeStamp processingEnd; + readonly attribute boolean cancelable; + readonly attribute Node? target; + readonly attribute unsigned long long interactionId; + [Default] object toJSON(); +}; + + +// Potential fixme: This spec has some more IDLs +// https://www.w3.org/TR/event-timing/#sec-event-counts +// https://www.w3.org/TR/event-timing/#sec-extensions +// https://www.w3.org/TR/event-timing/#sec-modifications-perf-timeline diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 454d0f92f58..703b8102610 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -307,6 +307,10 @@ namespace Web::EntriesAPI { class FileSystemEntry; } +namespace Web::EventTiming { +class PerformanceEventTiming; +} + namespace Web::Fetch { class BodyMixin; class Headers; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 2e1f8feb0de..14b5086932f 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -82,6 +82,7 @@ libweb_js_bindings(DOMURL/URLSearchParams ITERABLE) libweb_js_bindings(Encoding/TextDecoder) libweb_js_bindings(Encoding/TextEncoder) libweb_js_bindings(EntriesAPI/FileSystemEntry) +libweb_js_bindings(EventTiming/PerformanceEventTiming) libweb_js_bindings(Fetch/Headers ITERABLE) libweb_js_bindings(Fetch/Request) libweb_js_bindings(Fetch/Response)