summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Wilde <lukew@serenityos.org>2023-03-22 19:12:57 +0000
committerLinus Groh <mail@linusgroh.de>2023-03-23 21:00:43 +0000
commit31b507afbf74391d24490835c5581b6a00eb0d0f (patch)
tree7413c7d6e24a0f7eb1aa4aa3d6c6cd3f92daa295
parent4c3f1481ea15fb855e62843674ede79bdecfe91d (diff)
downloadserenity-31b507afbf74391d24490835c5581b6a00eb0d0f.zip
LibWeb: Introduce Performance Timeline and its Performance functions
-rw-r--r--Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp5
-rw-r--r--Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp2
-rw-r--r--Userland/Libraries/LibWeb/CMakeLists.txt3
-rw-r--r--Userland/Libraries/LibWeb/Forward.h4
-rw-r--r--Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp79
-rw-r--r--Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h16
-rw-r--r--Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp41
-rw-r--r--Userland/Libraries/LibWeb/HighResolutionTime/Performance.h5
-rw-r--r--Userland/Libraries/LibWeb/HighResolutionTime/Performance.idl11
-rw-r--r--Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.cpp34
-rw-r--r--Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.h33
-rw-r--r--Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.cpp31
-rw-r--r--Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.h56
-rw-r--r--Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.idl11
-rw-r--r--Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntryTuple.h50
-rw-r--r--Userland/Libraries/LibWeb/idl_files.cmake1
16 files changed, 381 insertions, 1 deletions
diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp
index 731941890e..1a63e2cf94 100644
--- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp
+++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp
@@ -44,6 +44,7 @@ static bool is_platform_object(Type const& type)
"NamedNodeMap"sv,
"Node"sv,
"Path2D"sv,
+ "PerformanceEntry"sv,
"Range"sv,
"ReadableStream"sv,
"Request"sv,
@@ -3145,6 +3146,7 @@ using namespace Web::Geometry;
using namespace Web::HighResolutionTime;
using namespace Web::HTML;
using namespace Web::IntersectionObserver;
+using namespace Web::PerformanceTimeline;
using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver;
using namespace Web::Selection;
@@ -3377,6 +3379,7 @@ using namespace Web::HighResolutionTime;
using namespace Web::HTML;
using namespace Web::IntersectionObserver;
using namespace Web::NavigationTiming;
+using namespace Web::PerformanceTimeline;
using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver;
using namespace Web::Selection;
@@ -3506,6 +3509,7 @@ using namespace Web::HighResolutionTime;
using namespace Web::HTML;
using namespace Web::IntersectionObserver;
using namespace Web::NavigationTiming;
+using namespace Web::PerformanceTimeline;
using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver;
using namespace Web::Selection;
@@ -3636,6 +3640,7 @@ using namespace Web::HighResolutionTime;
using namespace Web::HTML;
using namespace Web::IntersectionObserver;
using namespace Web::NavigationTiming;
+using namespace Web::PerformanceTimeline;
using namespace Web::RequestIdleCallback;
using namespace Web::ResizeObserver;
using namespace Web::Selection;
diff --git a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp
index 7844b16c60..e075b8a945 100644
--- a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp
+++ b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp
@@ -32,6 +32,7 @@
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HTML/WindowProxy.h>
#include <LibWeb/Namespace.h>
+#include <LibWeb/PerformanceTimeline/EntryTypes.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#include <LibWeb/SVG/AttributeNames.h>
#include <LibWeb/SVG/TagNames.h>
@@ -79,6 +80,7 @@ ErrorOr<void> initialize_main_thread_vm()
TRY(HTML::EventNames::initialize_strings());
TRY(HTML::TagNames::initialize_strings());
TRY(Namespace::initialize_strings());
+ TRY(PerformanceTimeline::EntryTypes::initialize_strings());
TRY(SVG::AttributeNames::initialize_strings());
TRY(SVG::TagNames::initialize_strings());
TRY(UIEvents::EventNames::initialize_strings());
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt
index 06602ba5de..50315e8ad7 100644
--- a/Userland/Libraries/LibWeb/CMakeLists.txt
+++ b/Userland/Libraries/LibWeb/CMakeLists.txt
@@ -371,6 +371,7 @@ set(SOURCES
Loader/ResourceLoader.cpp
MimeSniff/MimeType.cpp
Namespace.cpp
+ NavigationTiming/EntryNames.cpp
NavigationTiming/PerformanceTiming.cpp
Page/EditEventHandler.cpp
Page/EventHandler.cpp
@@ -400,6 +401,8 @@ set(SOURCES
Painting/ShadowPainting.cpp
Painting/StackingContext.cpp
Painting/TextPaintable.cpp
+ PerformanceTimeline/EntryTypes.cpp
+ PerformanceTimeline/PerformanceEntry.cpp
Platform/EventLoopPlugin.cpp
Platform/EventLoopPluginSerenity.cpp
Platform/FontPlugin.cpp
diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h
index d042d9ce7e..60d29430dd 100644
--- a/Userland/Libraries/LibWeb/Forward.h
+++ b/Userland/Libraries/LibWeb/Forward.h
@@ -387,6 +387,10 @@ struct BorderRadiiData;
struct LinearGradientData;
}
+namespace Web::PerformanceTimeline {
+class PerformanceEntry;
+}
+
namespace Web::Platform {
class Timer;
}
diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
index 1ea54ffa71..c5b85db129 100644
--- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
+++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.cpp
@@ -1,11 +1,13 @@
/*
* Copyright (c) 2022, Andrew Kaster <akaster@serenityos.org>
* Copyright (c) 2023, Linus Groh <linusg@serenityos.org>
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Base64.h>
+#include <AK/QuickSort.h>
#include <AK/String.h>
#include <AK/Utf8View.h>
#include <AK/Vector.h>
@@ -264,4 +266,81 @@ i32 WindowOrWorkerGlobalScopeMixin::run_timer_initialization_steps(TimerHandler
return id;
}
+// 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)
+{
+ // 1. Let result be an initially empty list.
+ Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>> result;
+
+ // 2. For each PerformanceEntry entry in buffer, run the following steps:
+ for (auto const& entry : buffer) {
+ // 1. If type is not null and if type is not identical to entry's entryType attribute, continue to next entry.
+ if (type.has_value() && type.value() != entry->entry_type())
+ continue;
+
+ // 2. If name is not null and if name is not identical to entry's name attribute, continue to next entry.
+ if (name.has_value() && name.value() != entry->name())
+ continue;
+
+ // 3. append entry to result.
+ TRY(result.try_append(entry));
+ }
+
+ // 3. Sort results's entries in chronological order with respect to startTime
+ quick_sort(result, [](auto const& left_entry, auto const& right_entry) {
+ return left_entry->start_time() < right_entry->start_time();
+ });
+
+ // 4. Return result.
+ return result;
+}
+
+// https://www.w3.org/TR/performance-timeline/#dfn-filter-buffer-map-by-name-and-type
+ErrorOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> WindowOrWorkerGlobalScopeMixin::filter_buffer_map_by_name_and_type(Optional<String> name, Optional<String> type) const
+{
+ // 1. Let result be an initially empty list.
+ Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>> result;
+
+ // 2. Let map be the performance entry buffer map associated with the relevant global object of this.
+ auto const& map = m_performance_entry_buffer_map;
+
+ // 3. Let tuple list be an empty list.
+ Vector<PerformanceTimeline::PerformanceEntryTuple const&> tuple_list;
+
+ // 4. If type is not null, append the result of getting the value of entry on map given type as key to tuple list.
+ // Otherwise, assign the result of get the values on map to tuple list.
+ if (type.has_value()) {
+ auto maybe_tuple = map.get(type.value());
+ if (maybe_tuple.has_value())
+ TRY(tuple_list.try_append(maybe_tuple.release_value()));
+ } else {
+ for (auto const& it : map)
+ TRY(tuple_list.try_append(it.value));
+ }
+
+ // 5. For each tuple in tuple list, run the following steps:
+ for (auto const& tuple : tuple_list) {
+ // 1. Let buffer be tuple's performance entry buffer.
+ auto const& buffer = tuple.performance_entry_buffer;
+
+ // 2. If tuple's availableFromTimeline is false, continue to the next tuple.
+ if (tuple.available_from_timeline == PerformanceTimeline::AvailableFromTimeline::No)
+ continue;
+
+ // 3. Let entries be the result of running filter buffer by name and type with buffer, name and type as inputs.
+ auto entries = TRY(filter_buffer_by_name_and_type(buffer, name, type));
+
+ // 4. For each entry in entries, append entry to result.
+ TRY(result.try_extend(entries));
+ }
+
+ // 6. Sort results's entries in chronological order with respect to startTime
+ quick_sort(result, [](auto const& left_entry, auto const& right_entry) {
+ return left_entry->start_time() < right_entry->start_time();
+ });
+
+ // 7. Return result.
+ return result;
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h
index 240015eb7c..c6c9133866 100644
--- a/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h
+++ b/Userland/Libraries/LibWeb/HTML/WindowOrWorkerGlobalScope.h
@@ -1,11 +1,13 @@
/*
* Copyright (c) 2023, Linus Groh <linusg@serenityos.org>
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
+#include <AK/FlyString.h>
#include <AK/Forward.h>
#include <AK/HashMap.h>
#include <AK/IDAllocator.h>
@@ -14,6 +16,8 @@
#include <LibWeb/Fetch/Request.h>
#include <LibWeb/Forward.h>
#include <LibWeb/HTML/MessagePort.h>
+#include <LibWeb/PerformanceTimeline/PerformanceEntry.h>
+#include <LibWeb/PerformanceTimeline/PerformanceEntryTuple.h>
namespace Web::HTML {
@@ -43,6 +47,8 @@ public:
void clear_timeout(i32);
void clear_interval(i32);
+ ErrorOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> filter_buffer_map_by_name_and_type(Optional<String> name, Optional<String> type) const;
+
protected:
void visit_edges(JS::Cell::Visitor&);
@@ -55,6 +61,16 @@ private:
IDAllocator m_timer_id_allocator;
HashMap<int, JS::NonnullGCPtr<Timer>> m_timers;
+
+ // https://www.w3.org/TR/performance-timeline/#performance-timeline
+ // Each global object has:
+ // FIXME: - a performance observer task queued flag
+ // FIXME: - a list of registered performance observer objects that is initially empty
+
+ // https://www.w3.org/TR/performance-timeline/#dfn-performance-entry-buffer-map
+ // a performance entry buffer map map, keyed on a DOMString, representing the entry type to which the buffer belongs. The map's value is the following tuple:
+ // NOTE: See the PerformanceEntryTuple struct above for the map's value tuple.
+ OrderedHashMap<FlyString, PerformanceTimeline::PerformanceEntryTuple> m_performance_entry_buffer_map;
};
}
diff --git a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp
index eaf62f55d7..d3fc604d06 100644
--- a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp
+++ b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -49,4 +50,44 @@ double Performance::time_origin() const
return static_cast<double>(m_timer.origin_time().to_milliseconds());
}
+// https://www.w3.org/TR/performance-timeline/#getentries-method
+WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> Performance::get_entries() const
+{
+ auto& realm = this->realm();
+ auto& vm = this->vm();
+ auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
+ VERIFY(window_or_worker);
+
+ // Returns a PerformanceEntryList object returned by the filter buffer map by name and type algorithm with name and
+ // type set to null.
+ return TRY_OR_THROW_OOM(vm, window_or_worker->filter_buffer_map_by_name_and_type(/* name= */ Optional<String> {}, /* type= */ Optional<String> {}));
+}
+
+// https://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbytype
+WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> Performance::get_entries_by_type(String const& type) const
+{
+ auto& realm = this->realm();
+ auto& vm = this->vm();
+ auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
+ VERIFY(window_or_worker);
+
+ // Returns a PerformanceEntryList object returned by filter buffer map by name and type algorithm with name set to null,
+ // and type set to the method's input type parameter.
+ return TRY_OR_THROW_OOM(vm, window_or_worker->filter_buffer_map_by_name_and_type(/* name= */ Optional<String> {}, type));
+}
+
+// https://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbyname
+WebIDL::ExceptionOr<Vector<JS::Handle<PerformanceTimeline::PerformanceEntry>>> Performance::get_entries_by_name(String const& name, Optional<String> type) const
+{
+ auto& realm = this->realm();
+ auto& vm = this->vm();
+ auto* window_or_worker = dynamic_cast<HTML::WindowOrWorkerGlobalScopeMixin*>(&realm.global_object());
+ VERIFY(window_or_worker);
+
+ // Returns a PerformanceEntryList object returned by filter buffer map by name and type algorithm with name set to the
+ // method input name parameter, and type set to null if optional entryType is omitted, or set to the method's input type
+ // parameter otherwise.
+ return TRY_OR_THROW_OOM(vm, window_or_worker->filter_buffer_map_by_name_and_type(name, type));
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h
index 77acba9900..8aa087c89a 100644
--- a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h
+++ b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -22,6 +23,10 @@ public:
JS::GCPtr<NavigationTiming::PerformanceTiming> timing();
+ 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_name(String const& name, Optional<String> type) const;
+
private:
explicit Performance(HTML::Window&);
diff --git a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.idl b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.idl
index 4f2bccf574..544026fb9b 100644
--- a/Userland/Libraries/LibWeb/HighResolutionTime/Performance.idl
+++ b/Userland/Libraries/LibWeb/HighResolutionTime/Performance.idl
@@ -1,12 +1,21 @@
#import <DOM/EventTarget.idl>
#import <HighResolutionTime/DOMHighResTimeStamp.idl>
#import <NavigationTiming/PerformanceTiming.idl>
+#import <PerformanceTimeline/PerformanceEntry.idl>
+
+// https://www.w3.org/TR/performance-timeline/#dom-performanceentrylist
+typedef sequence<PerformanceEntry> PerformanceEntryList;
// https://w3c.github.io/hr-time/#sec-performance
-[Exposed=(Window, Worker)]
+[Exposed=(Window, Worker), UseNewAKString]
interface Performance : EventTarget {
DOMHighResTimeStamp now();
readonly attribute DOMHighResTimeStamp timeOrigin;
readonly attribute PerformanceTiming timing;
+ // https://www.w3.org/TR/performance-timeline/#extensions-to-the-performance-interface
+ // "Performance Timeline" extensions to the Performance interface
+ PerformanceEntryList getEntries();
+ PerformanceEntryList getEntriesByType(DOMString type);
+ PerformanceEntryList getEntriesByName(DOMString name, optional DOMString type);
};
diff --git a/Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.cpp b/Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.cpp
new file mode 100644
index 0000000000..8478f623d8
--- /dev/null
+++ b/Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/PerformanceTimeline/EntryTypes.h>
+
+namespace Web::PerformanceTimeline::EntryTypes {
+
+#define __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(name) FlyString name;
+ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPES
+#undef __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE
+
+ErrorOr<void> initialize_strings()
+{
+ static bool s_initialized = false;
+ VERIFY(!s_initialized);
+
+#define __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(name) \
+ name = TRY(#name##_fly_string);
+ ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPES
+#undef __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE
+
+ // NOTE: Special cases for attributes with dashes in them.
+ first_input = TRY("first-input"_fly_string);
+ largest_contentful_paint = TRY("largest-contentful-paint"_fly_string);
+ layout_shift = TRY("layout-shift"_fly_string);
+
+ s_initialized = true;
+ return {};
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.h b/Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.h
new file mode 100644
index 0000000000..220fa611e0
--- /dev/null
+++ b/Userland/Libraries/LibWeb/PerformanceTimeline/EntryTypes.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/FlyString.h>
+
+namespace Web::PerformanceTimeline::EntryTypes {
+
+// https://w3c.github.io/timing-entrytypes-registry/#registry
+#define ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPES \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(element) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(event) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(first_input) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(largest_contentful_paint) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(layout_shift) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(longtask) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(mark) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(measure) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(navigation) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(resource) \
+ __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(paint)
+
+#define __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE(name) extern FlyString name;
+ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPES
+#undef __ENUMERATE_PERFORMANCE_TIMELINE_ENTRY_TYPE
+
+ErrorOr<void> initialize_strings();
+
+}
diff --git a/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.cpp b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.cpp
new file mode 100644
index 0000000000..ce9c8c1feb
--- /dev/null
+++ b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/Bindings/PerformanceEntryPrototype.h>
+#include <LibWeb/PerformanceTimeline/PerformanceEntry.h>
+
+namespace Web::PerformanceTimeline {
+
+PerformanceEntry::PerformanceEntry(JS::Realm& realm, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration)
+ : Bindings::PlatformObject(realm)
+ , m_name(name)
+ , m_start_time(start_time)
+ , m_duration(duration)
+{
+}
+
+PerformanceEntry::~PerformanceEntry() = default;
+
+JS::ThrowCompletionOr<void> PerformanceEntry::initialize(JS::Realm& realm)
+{
+ MUST_OR_THROW_OOM(Base::initialize(realm));
+ set_prototype(&Bindings::ensure_web_prototype<Bindings::PerformanceEntryPrototype>(realm, "PerformanceEntry"));
+
+ return {};
+}
+
+}
diff --git a/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.h b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.h
new file mode 100644
index 0000000000..b1c275d4e7
--- /dev/null
+++ b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/Bindings/PlatformObject.h>
+#include <LibWeb/HighResolutionTime/DOMHighResTimeStamp.h>
+
+namespace Web::PerformanceTimeline {
+
+enum class AvailableFromTimeline {
+ No,
+ Yes,
+};
+
+enum class ShouldAddEntry {
+ No,
+ Yes,
+};
+
+// https://www.w3.org/TR/performance-timeline/#dom-performanceentry
+class PerformanceEntry : public Bindings::PlatformObject {
+ WEB_PLATFORM_OBJECT(PerformanceEntry, Bindings::PlatformObject);
+
+public:
+ virtual ~PerformanceEntry();
+
+ // https://www.w3.org/TR/performance-timeline/#dom-performanceentry-entrytype
+ virtual FlyString const& entry_type() const = 0;
+
+ String const& name() const { return m_name; }
+ HighResolutionTime::DOMHighResTimeStamp start_time() const { return m_start_time; }
+ HighResolutionTime::DOMHighResTimeStamp duration() const { return m_duration; }
+
+ // https://w3c.github.io/timing-entrytypes-registry/#dfn-should-add-entry
+ virtual PerformanceTimeline::ShouldAddEntry should_add_entry() const = 0;
+
+protected:
+ PerformanceEntry(JS::Realm&, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration);
+ virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
+
+private:
+ // https://www.w3.org/TR/performance-timeline/#dom-performanceentry-name
+ String m_name;
+
+ // https://www.w3.org/TR/performance-timeline/#dom-performanceentry-starttime
+ HighResolutionTime::DOMHighResTimeStamp m_start_time { 0.0 };
+
+ // https://www.w3.org/TR/performance-timeline/#dom-performanceentry-duration
+ HighResolutionTime::DOMHighResTimeStamp m_duration { 0.0 };
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.idl b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.idl
new file mode 100644
index 0000000000..d612550ce6
--- /dev/null
+++ b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntry.idl
@@ -0,0 +1,11 @@
+#import <HighResolutionTime/DOMHighResTimeStamp.idl>
+
+// https://www.w3.org/TR/performance-timeline/#dom-performanceentry
+[Exposed=(Window,Worker), UseNewAKString]
+interface PerformanceEntry {
+ readonly attribute DOMString name;
+ readonly attribute DOMString entryType;
+ readonly attribute DOMHighResTimeStamp startTime;
+ readonly attribute DOMHighResTimeStamp duration;
+ [Default] object toJSON();
+};
diff --git a/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntryTuple.h b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntryTuple.h
new file mode 100644
index 0000000000..938cd6bf91
--- /dev/null
+++ b/Userland/Libraries/LibWeb/PerformanceTimeline/PerformanceEntryTuple.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/PerformanceTimeline/PerformanceEntry.h>
+
+namespace Web::PerformanceTimeline {
+
+// https://www.w3.org/TR/performance-timeline/#dfn-performance-entry-buffer-map
+struct PerformanceEntryTuple {
+ // https://www.w3.org/TR/performance-timeline/#dfn-performance-entry-buffer
+ // A performance entry buffer to store PerformanceEntry objects, that is initially empty.
+ Vector<JS::Handle<PerformanceEntry>> performance_entry_buffer;
+
+ // https://www.w3.org/TR/performance-timeline/#dfn-maxbuffersize
+ // An integer maxBufferSize, initialized to the registry value for this entry type.
+ // NOTE: The empty state represents Infinite size.
+ Optional<u64> max_buffer_size;
+
+ // https://www.w3.org/TR/performance-timeline/#dfn-availablefromtimeline
+ // A boolean availableFromTimeline, initialized to the registry value for this entry type.
+ AvailableFromTimeline available_from_timeline { AvailableFromTimeline::No };
+
+ // https://www.w3.org/TR/performance-timeline/#dfn-dropped-entries-count
+ // An integer dropped entries count that is initially 0.
+ u64 dropped_entries_count { 0 };
+
+ // https://www.w3.org/TR/performance-timeline/#dfn-determine-if-a-performance-entry-buffer-is-full
+ bool is_full()
+ {
+ // 1. Let num current entries be the size of tuple's performance entry buffer.
+ auto num_current_entries = performance_entry_buffer.size();
+
+ // 2. If num current entries is less than tuples's maxBufferSize, return false.
+ if (!max_buffer_size.has_value() || num_current_entries < max_buffer_size.value())
+ return false;
+
+ // 3. Increase tuple's dropped entries count by 1.
+ ++dropped_entries_count;
+
+ // 4. Return true.
+ return true;
+ }
+};
+
+}
diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake
index e84c90cb3b..126ff30302 100644
--- a/Userland/Libraries/LibWeb/idl_files.cmake
+++ b/Userland/Libraries/LibWeb/idl_files.cmake
@@ -172,6 +172,7 @@ libweb_js_bindings(HTML/WorkerNavigator)
libweb_js_bindings(HighResolutionTime/Performance)
libweb_js_bindings(IntersectionObserver/IntersectionObserver)
libweb_js_bindings(NavigationTiming/PerformanceTiming)
+libweb_js_bindings(PerformanceTimeline/PerformanceEntry)
libweb_js_bindings(RequestIdleCallback/IdleDeadline)
libweb_js_bindings(ResizeObserver/ResizeObserver)
libweb_js_bindings(Streams/ReadableStream)