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 e683e99
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 33 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 };
};

}
6 changes: 2 additions & 4 deletions Libraries/LibWeb/HighResolutionTime/Performance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ GC_DEFINE_ALLOCATOR(Performance);

Performance::Performance(JS::Realm& realm)
: DOM::EventTarget(realm)
, m_timer(Core::TimerType::Precise)
{
m_timer.start();
}

Performance::~Performance() = default;
Expand Down Expand Up @@ -68,8 +66,8 @@ GC::Ptr<NavigationTiming::PerformanceNavigation> Performance::navigation()
// https://w3c.github.io/hr-time/#timeorigin-attribute
double Performance::time_origin() const
{
// FIXME: The timeOrigin attribute MUST return the number of milliseconds in the duration returned by get time origin timestamp for the relevant global object of this.
return static_cast<double>(m_timer.origin_time().nanoseconds()) / 1e6;
// The timeOrigin attribute MUST return the number of milliseconds in the duration returned by get time origin timestamp for the relevant global object of this.
return get_time_origin_timestamp(HTML::relevant_principal_global_object(*this));
}

// https://w3c.github.io/hr-time/#now-method
Expand Down
2 changes: 0 additions & 2 deletions Libraries/LibWeb/HighResolutionTime/Performance.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ class Performance final : public DOM::EventTarget {

GC::Ptr<NavigationTiming::PerformanceNavigation> m_navigation;
GC::Ptr<NavigationTiming::PerformanceTiming> m_timing;

Core::ElapsedTimer m_timer;
};

}
38 changes: 23 additions & 15 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 time_origin - estimated_monotonic_time_of_the_unix_epoch();
}

// https://w3c.github.io/hr-time/#dfn-coarsen-time
Expand Down Expand Up @@ -75,8 +76,9 @@ DOMHighResTimeStamp relative_high_resolution_time(DOMHighResTimeStamp time, JS::
// https://w3c.github.io/hr-time/#dfn-relative-high-resolution-coarse-time
DOMHighResTimeStamp relative_high_resolution_coarsen_time(DOMHighResTimeStamp coarsen_time, JS::Object const& global)
{
// The relative high resolution coarse time given a DOMHighResTimeStamp coarseTime and a global object global, is the difference between coarseTime and the result of calling get time origin timestamp with global.
return coarsen_time - get_time_origin_timestamp(global);
// The relative high resolution coarse time given a moment from the monotonic clock coarseTime and a global object global, is the duration from global's relevant settings object's time origin to coarseTime.
auto time_origin = HTML::relevant_principal_settings_object(global).time_origin();
return coarsen_time - time_origin;
}

// https://w3c.github.io/hr-time/#dfn-coarsened-shared-current-time
Expand All @@ -86,6 +88,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
5 changes: 3 additions & 2 deletions Tests/LibWeb/Text/input/performance-now.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
return;
}

let timestamp = performance.now();
let monotonicTime = performance.now();
let date = Date.now();
let relativeDate = date - performance.timeOrigin;
let allowedDifference = 300;

if (timestamp <= date - allowedDifference || timestamp >= date + allowedDifference) {
if (Math.abs( monotonicTime - relativeDate) >= allowedDifference) {
println('performance.now() should be close to Date.now(), but was ' + (timestamp - date));
return;
}
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 e683e99

Please sign in to comment.