mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:17:45 +00:00
LibWeb: Implement performance.mark and performance.clearMarks
This commit is contained in:
parent
89ebef9730
commit
cbe0901706
13 changed files with 341 additions and 0 deletions
|
@ -45,6 +45,7 @@ static bool is_platform_object(Type const& type)
|
||||||
"Node"sv,
|
"Node"sv,
|
||||||
"Path2D"sv,
|
"Path2D"sv,
|
||||||
"PerformanceEntry"sv,
|
"PerformanceEntry"sv,
|
||||||
|
"PerformanceMark"sv,
|
||||||
"Range"sv,
|
"Range"sv,
|
||||||
"ReadableStream"sv,
|
"ReadableStream"sv,
|
||||||
"Request"sv,
|
"Request"sv,
|
||||||
|
@ -3152,6 +3153,7 @@ using namespace Web::ResizeObserver;
|
||||||
using namespace Web::Selection;
|
using namespace Web::Selection;
|
||||||
using namespace Web::Streams;
|
using namespace Web::Streams;
|
||||||
using namespace Web::UIEvents;
|
using namespace Web::UIEvents;
|
||||||
|
using namespace Web::UserTiming;
|
||||||
using namespace Web::URL;
|
using namespace Web::URL;
|
||||||
using namespace Web::XHR;
|
using namespace Web::XHR;
|
||||||
using namespace Web::WebAssembly;
|
using namespace Web::WebAssembly;
|
||||||
|
@ -3387,6 +3389,7 @@ using namespace Web::Streams;
|
||||||
using namespace Web::SVG;
|
using namespace Web::SVG;
|
||||||
using namespace Web::UIEvents;
|
using namespace Web::UIEvents;
|
||||||
using namespace Web::URL;
|
using namespace Web::URL;
|
||||||
|
using namespace Web::UserTiming;
|
||||||
using namespace Web::WebSockets;
|
using namespace Web::WebSockets;
|
||||||
using namespace Web::XHR;
|
using namespace Web::XHR;
|
||||||
using namespace Web::WebAssembly;
|
using namespace Web::WebAssembly;
|
||||||
|
@ -3516,6 +3519,7 @@ using namespace Web::Selection;
|
||||||
using namespace Web::XHR;
|
using namespace Web::XHR;
|
||||||
using namespace Web::UIEvents;
|
using namespace Web::UIEvents;
|
||||||
using namespace Web::URL;
|
using namespace Web::URL;
|
||||||
|
using namespace Web::UserTiming;
|
||||||
using namespace Web::WebGL;
|
using namespace Web::WebGL;
|
||||||
using namespace Web::WebIDL;
|
using namespace Web::WebIDL;
|
||||||
|
|
||||||
|
@ -3648,6 +3652,7 @@ using namespace Web::Streams;
|
||||||
using namespace Web::SVG;
|
using namespace Web::SVG;
|
||||||
using namespace Web::UIEvents;
|
using namespace Web::UIEvents;
|
||||||
using namespace Web::URL;
|
using namespace Web::URL;
|
||||||
|
using namespace Web::UserTiming;
|
||||||
using namespace Web::WebSockets;
|
using namespace Web::WebSockets;
|
||||||
using namespace Web::XHR;
|
using namespace Web::XHR;
|
||||||
using namespace Web::WebGL;
|
using namespace Web::WebGL;
|
||||||
|
|
|
@ -448,6 +448,7 @@ set(SOURCES
|
||||||
URL/URL.cpp
|
URL/URL.cpp
|
||||||
URL/URLSearchParams.cpp
|
URL/URLSearchParams.cpp
|
||||||
URL/URLSearchParamsIterator.cpp
|
URL/URLSearchParamsIterator.cpp
|
||||||
|
UserTiming/PerformanceMark.cpp
|
||||||
WebAssembly/Instance.cpp
|
WebAssembly/Instance.cpp
|
||||||
WebAssembly/Memory.cpp
|
WebAssembly/Memory.cpp
|
||||||
WebAssembly/Module.cpp
|
WebAssembly/Module.cpp
|
||||||
|
|
|
@ -519,6 +519,10 @@ class URLSearchParams;
|
||||||
class URLSearchParamsIterator;
|
class URLSearchParamsIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Web::UserTiming {
|
||||||
|
class PerformanceMark;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Web::Bindings {
|
namespace Web::Bindings {
|
||||||
class Intrinsics;
|
class Intrinsics;
|
||||||
class OptionConstructor;
|
class OptionConstructor;
|
||||||
|
|
|
@ -747,6 +747,7 @@ WebIDL::ExceptionOr<void> Window::initialize_web_interfaces(Badge<WindowEnvironm
|
||||||
Object::set_prototype(&Bindings::ensure_web_prototype<Bindings::WindowPrototype>(realm, "Window"));
|
Object::set_prototype(&Bindings::ensure_web_prototype<Bindings::WindowPrototype>(realm, "Window"));
|
||||||
|
|
||||||
MUST_OR_THROW_OOM(Bindings::WindowGlobalMixin::initialize(realm, *this));
|
MUST_OR_THROW_OOM(Bindings::WindowGlobalMixin::initialize(realm, *this));
|
||||||
|
MUST_OR_THROW_OOM(WindowOrWorkerGlobalScopeMixin::initialize(realm));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <LibWeb/HTML/Window.h>
|
#include <LibWeb/HTML/Window.h>
|
||||||
#include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
|
#include <LibWeb/HTML/WindowOrWorkerGlobalScope.h>
|
||||||
#include <LibWeb/Infra/Base64.h>
|
#include <LibWeb/Infra/Base64.h>
|
||||||
|
#include <LibWeb/PerformanceTimeline/EntryTypes.h>
|
||||||
|
#include <LibWeb/UserTiming/PerformanceMark.h>
|
||||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||||
#include <LibWeb/WebIDL/DOMException.h>
|
#include <LibWeb/WebIDL/DOMException.h>
|
||||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
|
@ -32,6 +34,27 @@ namespace Web::HTML {
|
||||||
|
|
||||||
WindowOrWorkerGlobalScopeMixin::~WindowOrWorkerGlobalScopeMixin() = default;
|
WindowOrWorkerGlobalScopeMixin::~WindowOrWorkerGlobalScopeMixin() = default;
|
||||||
|
|
||||||
|
// Please keep these in alphabetical order based on the entry type :^)
|
||||||
|
#define ENUMERATE_SUPPORTED_PERFORMANCE_ENTRY_TYPES \
|
||||||
|
__ENUMERATE_SUPPORTED_PERFORMANCE_ENTRY_TYPES(PerformanceTimeline::EntryTypes::mark, UserTiming::PerformanceMark)
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<void> WindowOrWorkerGlobalScopeMixin::initialize(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
|
#define __ENUMERATE_SUPPORTED_PERFORMANCE_ENTRY_TYPES(entry_type, cpp_class) \
|
||||||
|
TRY_OR_THROW_OOM(vm, m_performance_entry_buffer_map.try_set(entry_type, PerformanceTimeline::PerformanceEntryTuple { \
|
||||||
|
.performance_entry_buffer = {}, \
|
||||||
|
.max_buffer_size = cpp_class::max_buffer_size(), \
|
||||||
|
.available_from_timeline = cpp_class::available_from_timeline(), \
|
||||||
|
.dropped_entries_count = 0, \
|
||||||
|
}));
|
||||||
|
ENUMERATE_SUPPORTED_PERFORMANCE_ENTRY_TYPES
|
||||||
|
#undef __ENUMERATE_SUPPORTED_PERFORMANCE_ENTRY_TYPES
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void WindowOrWorkerGlobalScopeMixin::visit_edges(JS::Cell::Visitor& visitor)
|
void WindowOrWorkerGlobalScopeMixin::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
{
|
{
|
||||||
for (auto& it : m_timers)
|
for (auto& it : m_timers)
|
||||||
|
@ -266,6 +289,72 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. https://www.w3.org/TR/performance-timeline/#dfn-relevant-performance-entry-tuple
|
||||||
|
PerformanceTimeline::PerformanceEntryTuple& WindowOrWorkerGlobalScopeMixin::relevant_performance_entry_tuple(FlyString const& entry_type)
|
||||||
|
{
|
||||||
|
// 1. Let map be the performance entry buffer map associated with globalObject.
|
||||||
|
// 2. Return the result of getting the value of an entry from map, given entryType as the key.
|
||||||
|
auto tuple = m_performance_entry_buffer_map.get(entry_type);
|
||||||
|
|
||||||
|
// This shouldn't be called with entry types that aren't in `ENUMERATE_SUPPORTED_PERFORMANCE_ENTRY_TYPES`.
|
||||||
|
VERIFY(tuple.has_value());
|
||||||
|
return tuple.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/performance-timeline/#dfn-queue-a-performanceentry
|
||||||
|
WebIDL::ExceptionOr<void> WindowOrWorkerGlobalScopeMixin::queue_performance_entry(JS::NonnullGCPtr<PerformanceTimeline::PerformanceEntry> new_entry)
|
||||||
|
{
|
||||||
|
auto& vm = new_entry->vm();
|
||||||
|
|
||||||
|
// FIXME: 1. Let interested observers be an initially empty set of PerformanceObserver objects.
|
||||||
|
|
||||||
|
// 2. Let entryType be newEntry’s entryType value.
|
||||||
|
auto const& entry_type = new_entry->entry_type();
|
||||||
|
|
||||||
|
// 3. Let relevantGlobal be newEntry's relevant global object.
|
||||||
|
// NOTE: Already is `this`.
|
||||||
|
|
||||||
|
// FIXME: 4. For each registered performance observer regObs in relevantGlobal's list of registered performance observer
|
||||||
|
// objects:
|
||||||
|
// 1. If regObs's options list contains a PerformanceObserverInit options whose entryTypes member includes entryType
|
||||||
|
// or whose type member equals to entryType:
|
||||||
|
// 1. If should add entry with newEntry and options returns true, append regObs's observer to interested observers.
|
||||||
|
|
||||||
|
// FIXME: 5. For each observer in interested observers:
|
||||||
|
// 1. Append newEntry to observer's observer buffer.
|
||||||
|
|
||||||
|
// 6. Let tuple be the relevant performance entry tuple of entryType and relevantGlobal.
|
||||||
|
auto& tuple = relevant_performance_entry_tuple(entry_type);
|
||||||
|
|
||||||
|
// 7. Let isBufferFull be the return value of the determine if a performance entry buffer is full algorithm with tuple
|
||||||
|
// as input.
|
||||||
|
bool is_buffer_full = tuple.is_full();
|
||||||
|
|
||||||
|
// 8. Let shouldAdd be the result of should add entry with newEntry as input.
|
||||||
|
auto should_add = new_entry->should_add_entry();
|
||||||
|
|
||||||
|
// 9. If isBufferFull is false and shouldAdd is true, append newEntry to tuple's performance entry buffer.
|
||||||
|
if (!is_buffer_full && should_add == PerformanceTimeline::ShouldAddEntry::Yes)
|
||||||
|
TRY_OR_THROW_OOM(vm, tuple.performance_entry_buffer.try_append(JS::make_handle(new_entry)));
|
||||||
|
|
||||||
|
// FIXME: 10. Queue the PerformanceObserver task with relevantGlobal as input.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowOrWorkerGlobalScopeMixin::clear_performance_entry_buffer(Badge<HighResolutionTime::Performance>, FlyString const& entry_type)
|
||||||
|
{
|
||||||
|
auto& tuple = relevant_performance_entry_tuple(entry_type);
|
||||||
|
tuple.performance_entry_buffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowOrWorkerGlobalScopeMixin::remove_entries_from_performance_entry_buffer(Badge<HighResolutionTime::Performance>, FlyString const& entry_type, String entry_name)
|
||||||
|
{
|
||||||
|
auto& tuple = relevant_performance_entry_tuple(entry_type);
|
||||||
|
tuple.performance_entry_buffer.remove_all_matching([&entry_name](JS::Handle<PerformanceTimeline::PerformanceEntry> const& entry) {
|
||||||
|
return entry->name() == entry_name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/performance-timeline/#dfn-filter-buffer-by-name-and-type
|
// https://www.w3.org/TR/performance-timeline/#dfn-filter-buffer-by-name-and-type
|
||||||
static ErrorOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> filter_buffer_by_name_and_type(Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>> const& buffer, Optional<String> name, Optional<String> type)
|
static ErrorOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> filter_buffer_by_name_and_type(Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>> const& buffer, Optional<String> name, Optional<String> type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,9 +47,15 @@ public:
|
||||||
void clear_timeout(i32);
|
void clear_timeout(i32);
|
||||||
void clear_interval(i32);
|
void clear_interval(i32);
|
||||||
|
|
||||||
|
PerformanceTimeline::PerformanceEntryTuple& relevant_performance_entry_tuple(FlyString const& entry_type);
|
||||||
|
WebIDL::ExceptionOr<void> queue_performance_entry(JS::NonnullGCPtr<PerformanceTimeline::PerformanceEntry> new_entry);
|
||||||
|
void clear_performance_entry_buffer(Badge<HighResolutionTime::Performance>, FlyString const& entry_type);
|
||||||
|
void remove_entries_from_performance_entry_buffer(Badge<HighResolutionTime::Performance>, FlyString const& entry_type, String entry_name);
|
||||||
|
|
||||||
ErrorOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> filter_buffer_map_by_name_and_type(Optional<String> name, Optional<String> type) const;
|
ErrorOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> filter_buffer_map_by_name_and_type(Optional<String> name, Optional<String> type) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
JS::ThrowCompletionOr<void> initialize(JS::Realm&);
|
||||||
void visit_edges(JS::Cell::Visitor&);
|
void visit_edges(JS::Cell::Visitor&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <LibWeb/HTML/Window.h>
|
#include <LibWeb/HTML/Window.h>
|
||||||
#include <LibWeb/HighResolutionTime/Performance.h>
|
#include <LibWeb/HighResolutionTime/Performance.h>
|
||||||
#include <LibWeb/NavigationTiming/PerformanceTiming.h>
|
#include <LibWeb/NavigationTiming/PerformanceTiming.h>
|
||||||
|
#include <LibWeb/PerformanceTimeline/EntryTypes.h>
|
||||||
|
|
||||||
namespace Web::HighResolutionTime {
|
namespace Web::HighResolutionTime {
|
||||||
|
|
||||||
|
@ -50,6 +51,44 @@ double Performance::time_origin() const
|
||||||
return static_cast<double>(m_timer.origin_time().to_milliseconds());
|
return static_cast<double>(m_timer.origin_time().to_milliseconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#mark-method
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<UserTiming::PerformanceMark>> Performance::mark(String const& mark_name, UserTiming::PerformanceMarkOptions const& mark_options)
|
||||||
|
{
|
||||||
|
auto& realm = this->realm();
|
||||||
|
|
||||||
|
// 1. Run the PerformanceMark constructor and let entry be the newly created object.
|
||||||
|
auto entry = TRY(UserTiming::PerformanceMark::construct_impl(realm, mark_name, mark_options));
|
||||||
|
|
||||||
|
// 2. Queue entry.
|
||||||
|
auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
|
||||||
|
VERIFY(window_or_worker);
|
||||||
|
TRY(window_or_worker->queue_performance_entry(entry));
|
||||||
|
|
||||||
|
// 3. Add entry to the performance entry buffer.
|
||||||
|
// FIXME: This seems to be a holdover from moving to the `queue` structure for PerformanceObserver, as this would cause a double append.
|
||||||
|
|
||||||
|
// 4. Return entry.
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Performance::clear_marks(Optional<String> mark_name)
|
||||||
|
{
|
||||||
|
auto& realm = this->realm();
|
||||||
|
auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
|
||||||
|
VERIFY(window_or_worker);
|
||||||
|
|
||||||
|
// 1. If markName is omitted, remove all PerformanceMark objects from the performance entry buffer.
|
||||||
|
if (!mark_name.has_value()) {
|
||||||
|
window_or_worker->clear_performance_entry_buffer({}, PerformanceTimeline::EntryTypes::mark);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Otherwise, remove all PerformanceMark objects listed in the performance entry buffer whose name is markName.
|
||||||
|
window_or_worker->remove_entries_from_performance_entry_buffer({}, PerformanceTimeline::EntryTypes::mark, mark_name.value());
|
||||||
|
|
||||||
|
// 3. Return undefined.
|
||||||
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/performance-timeline/#getentries-method
|
// https://www.w3.org/TR/performance-timeline/#getentries-method
|
||||||
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> Performance::get_entries() const
|
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> Performance::get_entries() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <LibCore/ElapsedTimer.h>
|
#include <LibCore/ElapsedTimer.h>
|
||||||
#include <LibWeb/DOM/EventTarget.h>
|
#include <LibWeb/DOM/EventTarget.h>
|
||||||
|
#include <LibWeb/UserTiming/PerformanceMark.h>
|
||||||
|
|
||||||
namespace Web::HighResolutionTime {
|
namespace Web::HighResolutionTime {
|
||||||
|
|
||||||
|
@ -23,6 +24,9 @@ public:
|
||||||
|
|
||||||
JS::GCPtr<NavigationTiming::PerformanceTiming> timing();
|
JS::GCPtr<NavigationTiming::PerformanceTiming> timing();
|
||||||
|
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<UserTiming::PerformanceMark>> mark(String const& mark_name, UserTiming::PerformanceMarkOptions const& mark_options = {});
|
||||||
|
void clear_marks(Optional<String> mark_name);
|
||||||
|
|
||||||
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> get_entries() const;
|
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> get_entries() const;
|
||||||
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> get_entries_by_type(String const& type) const;
|
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> get_entries_by_type(String const& type) const;
|
||||||
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> get_entries_by_name(String const& name, Optional<String> type) const;
|
WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> get_entries_by_name(String const& name, Optional<String> type) const;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#import <HighResolutionTime/DOMHighResTimeStamp.idl>
|
#import <HighResolutionTime/DOMHighResTimeStamp.idl>
|
||||||
#import <NavigationTiming/PerformanceTiming.idl>
|
#import <NavigationTiming/PerformanceTiming.idl>
|
||||||
#import <PerformanceTimeline/PerformanceEntry.idl>
|
#import <PerformanceTimeline/PerformanceEntry.idl>
|
||||||
|
#import <UserTiming/PerformanceMark.idl>
|
||||||
|
|
||||||
// https://www.w3.org/TR/performance-timeline/#dom-performanceentrylist
|
// https://www.w3.org/TR/performance-timeline/#dom-performanceentrylist
|
||||||
typedef sequence<PerformanceEntry> PerformanceEntryList;
|
typedef sequence<PerformanceEntry> PerformanceEntryList;
|
||||||
|
@ -13,6 +14,14 @@ interface Performance : EventTarget {
|
||||||
readonly attribute DOMHighResTimeStamp timeOrigin;
|
readonly attribute DOMHighResTimeStamp timeOrigin;
|
||||||
|
|
||||||
readonly attribute PerformanceTiming timing;
|
readonly attribute PerformanceTiming timing;
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#extensions-performance-interface
|
||||||
|
// "User Timing" extensions to the Performance interface
|
||||||
|
PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions = {});
|
||||||
|
undefined clearMarks(optional DOMString markName);
|
||||||
|
// FIXME: PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions = {}, optional DOMString endMark);
|
||||||
|
// FIXME: undefined clearMeasures(optional DOMString measureName);
|
||||||
|
|
||||||
// https://www.w3.org/TR/performance-timeline/#extensions-to-the-performance-interface
|
// https://www.w3.org/TR/performance-timeline/#extensions-to-the-performance-interface
|
||||||
// "Performance Timeline" extensions to the Performance interface
|
// "Performance Timeline" extensions to the Performance interface
|
||||||
PerformanceEntryList getEntries();
|
PerformanceEntryList getEntries();
|
||||||
|
|
113
Userland/Libraries/LibWeb/UserTiming/PerformanceMark.cpp
Normal file
113
Userland/Libraries/LibWeb/UserTiming/PerformanceMark.cpp
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
|
#include <LibWeb/Bindings/PerformanceMarkPrototype.h>
|
||||||
|
#include <LibWeb/HTML/StructuredSerialize.h>
|
||||||
|
#include <LibWeb/HTML/Window.h>
|
||||||
|
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
|
||||||
|
#include <LibWeb/NavigationTiming/EntryNames.h>
|
||||||
|
#include <LibWeb/PerformanceTimeline/EntryTypes.h>
|
||||||
|
#include <LibWeb/UserTiming/PerformanceMark.h>
|
||||||
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
|
|
||||||
|
namespace Web::UserTiming {
|
||||||
|
|
||||||
|
PerformanceMark::PerformanceMark(JS::Realm& realm, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration, JS::Value detail)
|
||||||
|
: PerformanceTimeline::PerformanceEntry(realm, name, start_time, duration)
|
||||||
|
, m_detail(detail)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PerformanceMark::~PerformanceMark() = default;
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#dfn-performancemark-constructor
|
||||||
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<PerformanceMark>> PerformanceMark::construct_impl(JS::Realm& realm, String const& mark_name, Web::UserTiming::PerformanceMarkOptions const& mark_options)
|
||||||
|
{
|
||||||
|
auto& current_global_object = realm.global_object();
|
||||||
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
|
// 1. If the current global object is a Window object and markName uses the same name as a read only attribute in the PerformanceTiming interface, throw a SyntaxError.
|
||||||
|
if (is<HTML::Window>(current_global_object)) {
|
||||||
|
bool matched = false;
|
||||||
|
|
||||||
|
#define __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME(name) \
|
||||||
|
if (mark_name == NavigationTiming::EntryNames::name) \
|
||||||
|
matched = true;
|
||||||
|
ENUMERATE_NAVIGATION_TIMING_ENTRY_NAMES
|
||||||
|
#undef __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME
|
||||||
|
|
||||||
|
if (matched)
|
||||||
|
return WebIDL::SyntaxError::create(realm, DeprecatedString::formatted("'{}' markName cannot be used in a Window context because it is part of the PerformanceTiming interface", mark_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Step 2 (creating the entry) is done after determining values, as we set the values once during creation and never change them after.
|
||||||
|
|
||||||
|
// 3. Set entry's name attribute to markName.
|
||||||
|
auto const& name = mark_name;
|
||||||
|
|
||||||
|
// 4. Set entry's entryType attribute to DOMString "mark".
|
||||||
|
// NOTE: Already done via the `entry_type` virtual function.
|
||||||
|
|
||||||
|
// 5. Set entry's startTime attribute as follows:
|
||||||
|
HighResolutionTime::DOMHighResTimeStamp start_time { 0.0 };
|
||||||
|
|
||||||
|
// 1. If markOptions's startTime member is present, then:
|
||||||
|
if (mark_options.start_time.has_value()) {
|
||||||
|
// 1. If markOptions's startTime is negative, throw a TypeError.
|
||||||
|
if (mark_options.start_time.value() < 0.0)
|
||||||
|
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "startTime cannot be negative"sv };
|
||||||
|
|
||||||
|
// 2. Otherwise, set entry's startTime to the value of markOptions's startTime.
|
||||||
|
start_time = mark_options.start_time.value();
|
||||||
|
}
|
||||||
|
// 2. Otherwise, set it to the value that would be returned by the Performance object's now() method.
|
||||||
|
else {
|
||||||
|
// FIXME: Performance#now doesn't currently use TimeOrigin's functions, update this and Performance#now to match Performance#now's specification.
|
||||||
|
start_time = HighResolutionTime::unsafe_shared_current_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Set entry's duration attribute to 0.
|
||||||
|
constexpr HighResolutionTime::DOMHighResTimeStamp duration = 0.0;
|
||||||
|
|
||||||
|
// 7. If markOptions's detail is null, set entry's detail to null.
|
||||||
|
JS::Value detail;
|
||||||
|
if (mark_options.detail.is_null()) {
|
||||||
|
detail = JS::js_null();
|
||||||
|
}
|
||||||
|
// 8. Otherwise:
|
||||||
|
else {
|
||||||
|
// 1. Let record be the result of calling the StructuredSerialize algorithm on markOptions's detail.
|
||||||
|
auto record = TRY(HTML::structured_serialize(vm, mark_options.detail));
|
||||||
|
|
||||||
|
// 2. Set entry's detail to the result of calling the StructuredDeserialize algorithm on record and the current realm.
|
||||||
|
detail = TRY(HTML::structured_deserialize(vm, record, realm, Optional<HTML::SerializationMemory> {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Create a new PerformanceMark object (entry) with the current global object's realm.
|
||||||
|
return MUST_OR_THROW_OOM(realm.heap().allocate<PerformanceMark>(realm, realm, name, start_time, duration, detail));
|
||||||
|
}
|
||||||
|
|
||||||
|
FlyString const& PerformanceMark::entry_type() const
|
||||||
|
{
|
||||||
|
return PerformanceTimeline::EntryTypes::mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<void> PerformanceMark::initialize(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
MUST_OR_THROW_OOM(Base::initialize(realm));
|
||||||
|
set_prototype(&Bindings::ensure_web_prototype<Bindings::PerformanceMarkPrototype>(realm, "PerformanceMark"));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PerformanceMark::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
Userland/Libraries/LibWeb/UserTiming/PerformanceMark.h
Normal file
55
Userland/Libraries/LibWeb/UserTiming/PerformanceMark.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibWeb/PerformanceTimeline/PerformanceEntry.h>
|
||||||
|
|
||||||
|
namespace Web::UserTiming {
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#ref-for-dom-performancemarkoptions-1
|
||||||
|
struct PerformanceMarkOptions {
|
||||||
|
JS::Value detail { JS::js_null() };
|
||||||
|
Optional<HighResolutionTime::DOMHighResTimeStamp> start_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#dom-performancemark
|
||||||
|
class PerformanceMark final : public PerformanceTimeline::PerformanceEntry {
|
||||||
|
WEB_PLATFORM_OBJECT(PerformanceMark, PerformanceTimeline::PerformanceEntry);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~PerformanceMark();
|
||||||
|
|
||||||
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<PerformanceMark>> construct_impl(JS::Realm&, String const& mark_name, PerformanceMarkOptions const& mark_options = {});
|
||||||
|
|
||||||
|
// NOTE: These three functions are answered by the registry for the given entry type.
|
||||||
|
// https://w3c.github.io/timing-entrytypes-registry/#registry
|
||||||
|
|
||||||
|
// https://w3c.github.io/timing-entrytypes-registry/#dfn-availablefromtimeline
|
||||||
|
static PerformanceTimeline::AvailableFromTimeline available_from_timeline() { return PerformanceTimeline::AvailableFromTimeline::Yes; }
|
||||||
|
|
||||||
|
// https://w3c.github.io/timing-entrytypes-registry/#dfn-maxbuffersize
|
||||||
|
// NOTE: The empty state represents Infinite size.
|
||||||
|
static Optional<u64> max_buffer_size() { return OptionalNone {}; }
|
||||||
|
|
||||||
|
// https://w3c.github.io/timing-entrytypes-registry/#dfn-should-add-entry
|
||||||
|
virtual PerformanceTimeline::ShouldAddEntry should_add_entry() const override { return PerformanceTimeline::ShouldAddEntry::Yes; }
|
||||||
|
|
||||||
|
virtual FlyString const& entry_type() const override;
|
||||||
|
|
||||||
|
JS::Value detail() const { return m_detail; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PerformanceMark(JS::Realm&, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration, JS::Value detail);
|
||||||
|
|
||||||
|
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
||||||
|
virtual void visit_edges(JS::Cell::Visitor&) override;
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#dom-performancemark-detail
|
||||||
|
JS::Value m_detail { JS::js_null() };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
14
Userland/Libraries/LibWeb/UserTiming/PerformanceMark.idl
Normal file
14
Userland/Libraries/LibWeb/UserTiming/PerformanceMark.idl
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#import <PerformanceTimeline/PerformanceEntry.idl>
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#dom-performancemark
|
||||||
|
[Exposed=(Window,Worker), UseNewAKString]
|
||||||
|
interface PerformanceMark : PerformanceEntry {
|
||||||
|
constructor(DOMString markName, optional PerformanceMarkOptions markOptions = {});
|
||||||
|
readonly attribute any detail;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://w3c.github.io/user-timing/#ref-for-dom-performancemarkoptions-1
|
||||||
|
dictionary PerformanceMarkOptions {
|
||||||
|
any detail;
|
||||||
|
DOMHighResTimeStamp startTime;
|
||||||
|
};
|
|
@ -201,6 +201,7 @@ libweb_js_bindings(UIEvents/UIEvent)
|
||||||
libweb_js_bindings(UIEvents/WheelEvent)
|
libweb_js_bindings(UIEvents/WheelEvent)
|
||||||
libweb_js_bindings(URL/URL)
|
libweb_js_bindings(URL/URL)
|
||||||
libweb_js_bindings(URL/URLSearchParams ITERABLE)
|
libweb_js_bindings(URL/URLSearchParams ITERABLE)
|
||||||
|
libweb_js_bindings(UserTiming/PerformanceMark)
|
||||||
libweb_js_bindings(WebAssembly/Instance)
|
libweb_js_bindings(WebAssembly/Instance)
|
||||||
libweb_js_bindings(WebAssembly/Memory)
|
libweb_js_bindings(WebAssembly/Memory)
|
||||||
libweb_js_bindings(WebAssembly/Module)
|
libweb_js_bindings(WebAssembly/Module)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue