Skip to content

Commit

Permalink
LibWeb: Implement "get time origin timestamp" AO
Browse files Browse the repository at this point in the history
  • Loading branch information
tcl3 committed Jan 23, 2025
1 parent b4ebade commit c6313b1
Show file tree
Hide file tree
Showing 16 changed files with 215 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ EnvironmentSettingsSnapshot::EnvironmentSettingsSnapshot(NonnullOwnPtr<JS::Execu
, m_url(serialized_settings.api_base_url)
, m_origin(serialized_settings.origin)
, m_policy_container(serialized_settings.policy_container)
, m_time_origin(serialized_settings.time_origin)
{
// Why can't we put these in the init list? grandparent class members are strange it seems
this->id = serialized_settings.id;
this->creation_url = serialized_settings.creation_url;
this->top_level_creation_url = serialized_settings.top_level_creation_url;
this->top_level_creation_url = serialized_settings.top_level_creation_url;
}

// Out of line to ensure this class has a key function
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LibWeb/HTML/Scripting/EnvironmentSettingsSnapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ class EnvironmentSettingsSnapshot final
URL::Origin origin() const override { return m_origin; }
PolicyContainer policy_container() const override { return m_policy_container; }
CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const override { return CanUseCrossOriginIsolatedAPIs::No; }
double time_origin() const override { return m_time_origin; }

private:
String m_api_url_character_encoding;
URL::URL m_url;
URL::Origin m_origin;
HTML::PolicyContainer m_policy_container;
double m_time_origin { 0 };
};

}
3 changes: 3 additions & 0 deletions Libraries/LibWeb/HTML/Scripting/Environments.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ struct EnvironmentSettingsObject : public Environment {
// https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-cross-origin-isolated-capability
virtual CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const = 0;

// https://html.spec.whatwg.org/multipage/webappapis.html#concept-settings-object-time-origin
virtual double time_origin() const = 0;

URL::URL parse_url(StringView);
URL::URL encoding_parse_url(StringView);
Optional<String> encoding_parse_and_serialize_url(StringView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ ErrorOr<void> encode(Encoder& encoder, Web::HTML::SerializedEnvironmentSettingsO
TRY(encoder.encode(object.origin));
TRY(encoder.encode(object.policy_container));
TRY(encoder.encode(object.cross_origin_isolated_capability));
TRY(encoder.encode(object.time_origin));

return {};
}
Expand All @@ -40,6 +41,7 @@ ErrorOr<Web::HTML::SerializedEnvironmentSettingsObject> decode(Decoder& decoder)
object.origin = TRY(decoder.decode<URL::Origin>());
object.policy_container = TRY(decoder.decode<Web::HTML::PolicyContainer>());
object.cross_origin_isolated_capability = TRY(decoder.decode<Web::HTML::CanUseCrossOriginIsolatedAPIs>());
object.time_origin = TRY(decoder.decode<double>());

return object;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct SerializedEnvironmentSettingsObject {
URL::Origin origin;
PolicyContainer policy_container;
CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability;
double time_origin;
};

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ PolicyContainer WindowEnvironmentSettingsObject::policy_container() const
return m_window->associated_document().policy_container();
}

// https://html.spec.whatwg.org/multipage/nav-history-apis.html#script-settings-for-window-objects:concept-settings-object-time-origin
double WindowEnvironmentSettingsObject::time_origin() const
{
// Return window's associated Document's load timing info's navigation start time.
return m_window->associated_document().load_timing_info().navigation_start_time;
}

// https://html.spec.whatwg.org/multipage/window-object.html#script-settings-for-window-objects:concept-settings-object-cross-origin-isolated-capability
CanUseCrossOriginIsolatedAPIs WindowEnvironmentSettingsObject::cross_origin_isolated_capability() const
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class WindowEnvironmentSettingsObject final : public EnvironmentSettingsObject {
virtual URL::Origin origin() const override;
virtual PolicyContainer policy_container() const override;
virtual CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const override;
virtual double time_origin() const override;

private:
WindowEnvironmentSettingsObject(Window&, NonnullOwnPtr<JS::ExecutionContext>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ GC_DEFINE_ALLOCATOR(WorkerEnvironmentSettingsObject);
// https://html.spec.whatwg.org/multipage/workers.html#set-up-a-worker-environment-settings-object
GC::Ref<WorkerEnvironmentSettingsObject> WorkerEnvironmentSettingsObject::setup(GC::Ref<Page> page, NonnullOwnPtr<JS::ExecutionContext> execution_context, SerializedEnvironmentSettingsObject const& outside_settings, HighResolutionTime::DOMHighResTimeStamp unsafe_worker_creation_time)
{
(void)unsafe_worker_creation_time;

// 1. Let inherited origin be outside settings's origin.
auto inherited_origin = outside_settings.origin;

Expand All @@ -32,7 +30,7 @@ GC::Ref<WorkerEnvironmentSettingsObject> WorkerEnvironmentSettingsObject::setup(

// 4. Let settings object be a new environment settings object whose algorithms are defined as follows:
// NOTE: See the functions defined for this class.
auto settings_object = realm->create<WorkerEnvironmentSettingsObject>(move(execution_context), worker);
auto settings_object = realm->create<WorkerEnvironmentSettingsObject>(move(execution_context), worker, unsafe_worker_creation_time);
settings_object->target_browsing_context = nullptr;
settings_object->m_origin = move(inherited_origin);

Expand Down Expand Up @@ -80,6 +78,12 @@ CanUseCrossOriginIsolatedAPIs WorkerEnvironmentSettingsObject::cross_origin_isol
return CanUseCrossOriginIsolatedAPIs::No;
}

double WorkerEnvironmentSettingsObject::time_origin() const
{
// Return the result of coarsening unsafeWorkerCreationTime with worker global scope's cross-origin isolated capability.
return HighResolutionTime::coarsen_time(m_unsafe_worker_creation_time, cross_origin_isolated_capability() == CanUseCrossOriginIsolatedAPIs::Yes);
}

void WorkerEnvironmentSettingsObject::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ class WorkerEnvironmentSettingsObject final
GC_DECLARE_ALLOCATOR(WorkerEnvironmentSettingsObject);

public:
WorkerEnvironmentSettingsObject(NonnullOwnPtr<JS::ExecutionContext> execution_context, GC::Ref<WorkerGlobalScope> global_scope)
WorkerEnvironmentSettingsObject(NonnullOwnPtr<JS::ExecutionContext> execution_context, GC::Ref<WorkerGlobalScope> global_scope, HighResolutionTime::DOMHighResTimeStamp unsafe_worker_creation_time)
: EnvironmentSettingsObject(move(execution_context))
, m_global_scope(global_scope)
, m_unsafe_worker_creation_time(unsafe_worker_creation_time)
{
}

Expand All @@ -34,6 +35,7 @@ class WorkerEnvironmentSettingsObject final
URL::Origin origin() const override;
PolicyContainer policy_container() const override;
CanUseCrossOriginIsolatedAPIs cross_origin_isolated_capability() const override;
double time_origin() const override;

private:
virtual void visit_edges(JS::Cell::Visitor&) override;
Expand All @@ -42,6 +44,8 @@ class WorkerEnvironmentSettingsObject final
URL::Origin m_origin;

GC::Ref<WorkerGlobalScope> m_global_scope;

HighResolutionTime::DOMHighResTimeStamp m_unsafe_worker_creation_time { 0 };
};

}
33 changes: 20 additions & 13 deletions Libraries/LibWeb/HighResolutionTime/TimeOrigin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,15 @@

namespace Web::HighResolutionTime {

// https://w3c.github.io/hr-time/#dfn-get-time-origin-timestamp
DOMHighResTimeStamp get_time_origin_timestamp(JS::Object const& global)
// https://w3c.github.io/hr-time/#dfn-estimated-monotonic-time-of-the-unix-epoch
DOMHighResTimeStamp estimated_monotonic_time_of_the_unix_epoch()
{
(void)global;

// To get time origin timestamp, given a global object global, run the following steps, which return a duration:
// FIXME: 1. Let timeOrigin be global's relevant settings object's time origin.
auto time_origin = 0;

// Each group of environment settings objects that could possibly communicate in any way
// has an estimated monotonic time of the Unix epoch, a moment on the monotonic clock,
// whose value is initialized by the following steps:

// !. Let wall time be the wall clock's unsafe current time.
struct timeval tv;
gettimeofday(&tv, nullptr);
auto wall_time = tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
// 1. Let wall time be the wall clock's unsafe current time.
auto wall_time = wall_clock_unsafe_current_time();

// 2. Let monotonic time be the monotonic clock's unsafe current time.
auto monotonic_time = unsafe_shared_current_time();
Expand All @@ -37,9 +29,18 @@ DOMHighResTimeStamp get_time_origin_timestamp(JS::Object const& global)

// 4. Initialize the estimated monotonic time of the Unix epoch to the result of calling coarsen time with epoch time
auto estimated_monotonic_time = coarsen_time(epoch_time);
return estimated_monotonic_time;
}

// https://w3c.github.io/hr-time/#dfn-get-time-origin-timestamp
DOMHighResTimeStamp get_time_origin_timestamp(JS::Object const& global)
{
// To get time origin timestamp, given a global object global, run the following steps, which return a duration:
// 1. Let timeOrigin be global's relevant settings object's time origin.
auto time_origin = HTML::relevant_principal_settings_object(global).time_origin();

// 2. Return the duration from the estimated monotonic time of the Unix epoch to timeOrigin.
return estimated_monotonic_time - time_origin;
return estimated_monotonic_time_of_the_unix_epoch() - time_origin;
}

// https://w3c.github.io/hr-time/#dfn-coarsen-time
Expand Down Expand Up @@ -86,6 +87,12 @@ DOMHighResTimeStamp coarsened_shared_current_time(bool cross_origin_isolated_cap
return coarsen_time(unsafe_shared_current_time(), cross_origin_isolated_capability);
}

// https://w3c.github.io/hr-time/#wall-clock-unsafe-current-time
DOMHighResTimeStamp wall_clock_unsafe_current_time()
{
return UnixDateTime::now().nanoseconds_since_epoch() / 1.0e6;
}

// https://w3c.github.io/hr-time/#dfn-unsafe-shared-current-time
DOMHighResTimeStamp unsafe_shared_current_time()
{
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LibWeb/HighResolutionTime/TimeOrigin.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@

namespace Web::HighResolutionTime {

DOMHighResTimeStamp estimated_monotonic_time_of_the_unix_epoch();
DOMHighResTimeStamp get_time_origin_timestamp(JS::Object const&);
DOMHighResTimeStamp coarsen_time(DOMHighResTimeStamp timestamp, bool cross_origin_isolated_capability = false);
DOMHighResTimeStamp current_high_resolution_time(JS::Object const&);
DOMHighResTimeStamp relative_high_resolution_time(DOMHighResTimeStamp, JS::Object const&);
DOMHighResTimeStamp relative_high_resolution_coarsen_time(DOMHighResTimeStamp, JS::Object const&);
DOMHighResTimeStamp coarsened_shared_current_time(bool cross_origin_isolated_capability = false);
DOMHighResTimeStamp wall_clock_unsafe_current_time();
DOMHighResTimeStamp unsafe_shared_current_time();

}
4 changes: 2 additions & 2 deletions Libraries/LibWeb/UserTiming/PerformanceMark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <LibWeb/Bindings/PerformanceMarkPrototype.h>
#include <LibWeb/HTML/StructuredSerialize.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/HighResolutionTime/Performance.h>
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
#include <LibWeb/NavigationTiming/EntryNames.h>
#include <LibWeb/PerformanceTimeline/EntryTypes.h>
Expand Down Expand Up @@ -68,8 +69,7 @@ WebIDL::ExceptionOr<GC::Ref<PerformanceMark>> PerformanceMark::construct_impl(JS
}
// 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();
start_time = HighResolutionTime::current_high_resolution_time(current_principal_global_object);
}

// 6. Set entry's duration attribute to 0.
Expand Down
27 changes: 27 additions & 0 deletions Tests/LibWeb/Text/expected/wpt-import/user-timing/mark.any.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Harness status: OK

Found 22 tests

22 Pass
Pass Entry 0 is properly created
Pass Entry 1 is properly created
Pass Entry 0 has the proper name
Pass Entry 0 startTime is approximately correct (up to 20ms difference allowed)
Pass Entry 0 has the proper entryType
Pass Entry 0 duration == 0
Pass getEntriesByName("mark", "mark")[0] returns an object containing a "mark" mark
Pass The mark returned by getEntriesByName("mark", "mark")[0] matches the mark returned by getEntriesByName("mark")[0]
Pass getEntries()[0] returns an object containing a "mark" mark
Pass The mark returned by getEntries()[0] matches the mark returned by getEntriesByName("mark")[0]
Pass getEntriesByType("mark")[0] returns an object containing a "mark" mark
Pass The mark returned by getEntriesByType("mark")[0] matches the mark returned by getEntriesByName("mark")[0]
Pass Entry 1 has the proper name
Pass Entry 1 startTime is approximately correct (up to 20ms difference allowed)
Pass Entry 1 has the proper entryType
Pass Entry 1 duration == 0
Pass getEntriesByName("mark", "mark")[1] returns an object containing a "mark" mark
Pass The mark returned by getEntriesByName("mark", "mark")[1] matches the mark returned by getEntriesByName("mark")[1]
Pass getEntries()[1] returns an object containing a "mark" mark
Pass The mark returned by getEntries()[1] matches the mark returned by getEntriesByName("mark")[1]
Pass getEntriesByType("mark")[1] returns an object containing a "mark" mark
Pass The mark returned by getEntriesByType("mark")[1] matches the mark returned by getEntriesByName("mark")[1]
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ Harness status: OK

Found 8 tests

7 Pass
1 Fail
8 Pass
Pass Measure of navigationStart to now should be positive value.
Pass Measure of navigationStart to loadEventEnd should be positive value.
Pass Measure of current mark to navigationStart should be negative value.
Fail loadTime plus loadEventEnd to a mark "a" should equal to navigationStart to "a".
Pass loadTime plus loadEventEnd to a mark "a" should equal to navigationStart to "a".
Pass Second measure of current mark to navigationStart should be negative value.
Pass Measures of loadTime should have same duration.
Pass Measure from domComplete event to most recent mark "a" should have longer duration.
Expand Down
15 changes: 15 additions & 0 deletions Tests/LibWeb/Text/input/wpt-import/user-timing/mark.any.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<meta charset=utf-8>

<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>

<div id=log></div>
<script src="../user-timing/mark.any.js"></script>
Loading

0 comments on commit c6313b1

Please sign in to comment.