ladybird/Libraries/LibWeb/NavigationTiming/PerformanceTiming.cpp
Martin Chrástek 9f3cf862e8 LibWeb: Fix PerformanceTiming getters producing wrong wall clock values
PerformanceTiming::monotonic_timestamp_to_wall_time_milliseconds
assumes all DocumentLoadTimingInfo values are monotonic timestamps
and converts them via wall_time = timestamp - epoch. This is correct
for navigation_start_time (a true monotonic timestamp), but wrong
for all other timing fields like load_event_end_time, dom_complete_time
etc., which are stored as relative timestamps via
current_high_resolution_time() (relative to time origin).

The computed wall clock value ends up off by navigation_start_time,
causing convert_name_to_timestamp() to return wrapped-around u64
values. This broke performance.measure() when using navigation timing
attribute names as start/end marks.

Add relative_timestamp_to_wall_time_milliseconds which adds back
navigation_start_time before the epoch subtraction, producing correct
UTC epoch ms for these fields.
2026-05-19 19:22:11 +02:00

63 lines
2.2 KiB
C++

/*
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2025, Tim Ledbetter <tim.ledbetter@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/PerformanceTiming.h>
#include <LibWeb/HighResolutionTime/TimeOrigin.h>
#include <LibWeb/NavigationTiming/PerformanceTiming.h>
namespace Web::NavigationTiming {
GC_DEFINE_ALLOCATOR(PerformanceTiming);
PerformanceTiming::PerformanceTiming(JS::Realm& realm)
: PlatformObject(realm)
{
}
PerformanceTiming::~PerformanceTiming() = default;
void PerformanceTiming::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(PerformanceTiming);
Base::initialize(realm);
}
DOM::DocumentLoadTimingInfo const& PerformanceTiming::document_load_timing_info(JS::Object const& global_object) const
{
VERIFY(is<HTML::Window>(global_object));
auto& window = static_cast<HTML::Window const&>(global_object);
auto document = window.document();
return document->load_timing_info();
}
u64 PerformanceTiming::monotonic_timestamp_to_wall_time_milliseconds(Function<HighResolutionTime::DOMHighResTimeStamp(DOM::DocumentLoadTimingInfo const&)> selector) const
{
auto& global_object = HTML::relevant_global_object(*this);
auto timestamp = selector(document_load_timing_info(global_object));
if (timestamp == 0)
return 0;
auto wall_time = timestamp - HighResolutionTime::estimated_monotonic_time_of_the_unix_epoch();
auto coarsened_time = HighResolutionTime::coarsen_time(wall_time);
return static_cast<u64>(coarsened_time);
}
u64 PerformanceTiming::relative_timestamp_to_wall_time_milliseconds(Function<HighResolutionTime::DOMHighResTimeStamp(DOM::DocumentLoadTimingInfo const&)> selector) const
{
auto& global_object = HTML::relevant_global_object(*this);
auto const& load_info = document_load_timing_info(global_object);
auto relative_timestamp = selector(load_info);
if (relative_timestamp == 0)
return 0;
auto absolute_timestamp = relative_timestamp + load_info.navigation_start_time;
auto wall_time = absolute_timestamp - HighResolutionTime::estimated_monotonic_time_of_the_unix_epoch();
auto coarsened_time = HighResolutionTime::coarsen_time(wall_time);
return static_cast<u64>(coarsened_time);
}
}