2023-03-23 17:07:52 +00:00
/*
* 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>
2025-01-07 10:08:14 +00:00
# include <LibWeb/HighResolutionTime/Performance.h>
2023-03-23 17:07:52 +00:00
# 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 {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( PerformanceMark ) ;
2023-11-19 19:47:52 +01:00
2023-03-23 17:07:52 +00:00
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
2024-11-15 04:01:23 +13:00
WebIDL : : ExceptionOr < GC : : Ref < PerformanceMark > > PerformanceMark : : construct_impl ( JS : : Realm & realm , String const & mark_name , Web : : UserTiming : : PerformanceMarkOptions const & mark_options )
2023-03-23 17:07:52 +00:00
{
2024-10-21 13:48:44 +13:00
auto & current_principal_global_object = HTML : : current_principal_global_object ( ) ;
2023-03-23 17:07:52 +00:00
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.
2024-10-21 13:48:44 +13:00
if ( is < HTML : : Window > ( current_principal_global_object ) ) {
2023-03-23 17:07:52 +00:00
bool matched = false ;
2023-05-13 13:27:30 +01:00
# define __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME(name, _) \
if ( mark_name = = NavigationTiming : : EntryNames : : name ) \
2023-03-23 17:07:52 +00:00
matched = true ;
ENUMERATE_NAVIGATION_TIMING_ENTRY_NAMES
# undef __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME
if ( matched )
2023-09-06 16:03:01 +12:00
return WebIDL : : SyntaxError : : create ( realm , MUST ( String : : formatted ( " '{}' markName cannot be used in a Window context because it is part of the PerformanceTiming interface " , mark_name ) ) ) ;
2023-03-23 17:07:52 +00:00
}
// 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 {
2025-01-07 10:08:14 +00:00
start_time = HighResolutionTime : : current_high_resolution_time ( current_principal_global_object ) ;
2023-03-23 17:07:52 +00:00
}
// 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.
2024-11-23 19:24:57 +13:00
detail = TRY ( HTML : : structured_deserialize ( vm , record , realm ) ) ;
2023-03-23 17:07:52 +00:00
}
// 2. Create a new PerformanceMark object (entry) with the current global object's realm.
2024-11-14 05:50:17 +13:00
return realm . create < PerformanceMark > ( realm , name , start_time , duration , detail ) ;
2023-03-23 17:07:52 +00:00
}
FlyString const & PerformanceMark : : entry_type ( ) const
{
return PerformanceTimeline : : EntryTypes : : mark ;
}
2023-08-07 08:41:28 +02:00
void PerformanceMark : : initialize ( JS : : Realm & realm )
2023-03-23 17:07:52 +00:00
{
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( PerformanceMark ) ;
2025-04-20 16:22:57 +02:00
Base : : initialize ( realm ) ;
2023-03-23 17:07:52 +00:00
}
void PerformanceMark : : visit_edges ( JS : : Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
visitor . visit ( m_detail ) ;
}
}