PerformanceMark.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * Copyright (c) 2023, Luke Wilde <lukew@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/Bindings/Intrinsics.h>
  7. #include <LibWeb/Bindings/PerformanceMarkPrototype.h>
  8. #include <LibWeb/HTML/StructuredSerialize.h>
  9. #include <LibWeb/HTML/Window.h>
  10. #include <LibWeb/HighResolutionTime/TimeOrigin.h>
  11. #include <LibWeb/NavigationTiming/EntryNames.h>
  12. #include <LibWeb/PerformanceTimeline/EntryTypes.h>
  13. #include <LibWeb/UserTiming/PerformanceMark.h>
  14. #include <LibWeb/WebIDL/ExceptionOr.h>
  15. namespace Web::UserTiming {
  16. PerformanceMark::PerformanceMark(JS::Realm& realm, String const& name, HighResolutionTime::DOMHighResTimeStamp start_time, HighResolutionTime::DOMHighResTimeStamp duration, JS::Value detail)
  17. : PerformanceTimeline::PerformanceEntry(realm, name, start_time, duration)
  18. , m_detail(detail)
  19. {
  20. }
  21. PerformanceMark::~PerformanceMark() = default;
  22. // https://w3c.github.io/user-timing/#dfn-performancemark-constructor
  23. WebIDL::ExceptionOr<JS::NonnullGCPtr<PerformanceMark>> PerformanceMark::construct_impl(JS::Realm& realm, String const& mark_name, Web::UserTiming::PerformanceMarkOptions const& mark_options)
  24. {
  25. auto& current_global_object = realm.global_object();
  26. auto& vm = realm.vm();
  27. // 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.
  28. if (is<HTML::Window>(current_global_object)) {
  29. bool matched = false;
  30. #define __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME(name) \
  31. if (mark_name == NavigationTiming::EntryNames::name) \
  32. matched = true;
  33. ENUMERATE_NAVIGATION_TIMING_ENTRY_NAMES
  34. #undef __ENUMERATE_NAVIGATION_TIMING_ENTRY_NAME
  35. if (matched)
  36. return WebIDL::SyntaxError::create(realm, DeprecatedString::formatted("'{}' markName cannot be used in a Window context because it is part of the PerformanceTiming interface", mark_name));
  37. }
  38. // NOTE: Step 2 (creating the entry) is done after determining values, as we set the values once during creation and never change them after.
  39. // 3. Set entry's name attribute to markName.
  40. auto const& name = mark_name;
  41. // 4. Set entry's entryType attribute to DOMString "mark".
  42. // NOTE: Already done via the `entry_type` virtual function.
  43. // 5. Set entry's startTime attribute as follows:
  44. HighResolutionTime::DOMHighResTimeStamp start_time { 0.0 };
  45. // 1. If markOptions's startTime member is present, then:
  46. if (mark_options.start_time.has_value()) {
  47. // 1. If markOptions's startTime is negative, throw a TypeError.
  48. if (mark_options.start_time.value() < 0.0)
  49. return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "startTime cannot be negative"sv };
  50. // 2. Otherwise, set entry's startTime to the value of markOptions's startTime.
  51. start_time = mark_options.start_time.value();
  52. }
  53. // 2. Otherwise, set it to the value that would be returned by the Performance object's now() method.
  54. else {
  55. // FIXME: Performance#now doesn't currently use TimeOrigin's functions, update this and Performance#now to match Performance#now's specification.
  56. start_time = HighResolutionTime::unsafe_shared_current_time();
  57. }
  58. // 6. Set entry's duration attribute to 0.
  59. constexpr HighResolutionTime::DOMHighResTimeStamp duration = 0.0;
  60. // 7. If markOptions's detail is null, set entry's detail to null.
  61. JS::Value detail;
  62. if (mark_options.detail.is_null()) {
  63. detail = JS::js_null();
  64. }
  65. // 8. Otherwise:
  66. else {
  67. // 1. Let record be the result of calling the StructuredSerialize algorithm on markOptions's detail.
  68. auto record = TRY(HTML::structured_serialize(vm, mark_options.detail));
  69. // 2. Set entry's detail to the result of calling the StructuredDeserialize algorithm on record and the current realm.
  70. detail = TRY(HTML::structured_deserialize(vm, record, realm, Optional<HTML::SerializationMemory> {}));
  71. }
  72. // 2. Create a new PerformanceMark object (entry) with the current global object's realm.
  73. return MUST_OR_THROW_OOM(realm.heap().allocate<PerformanceMark>(realm, realm, name, start_time, duration, detail));
  74. }
  75. FlyString const& PerformanceMark::entry_type() const
  76. {
  77. return PerformanceTimeline::EntryTypes::mark;
  78. }
  79. JS::ThrowCompletionOr<void> PerformanceMark::initialize(JS::Realm& realm)
  80. {
  81. MUST_OR_THROW_OOM(Base::initialize(realm));
  82. set_prototype(&Bindings::ensure_web_prototype<Bindings::PerformanceMarkPrototype>(realm, "PerformanceMark"));
  83. return {};
  84. }
  85. void PerformanceMark::visit_edges(JS::Cell::Visitor& visitor)
  86. {
  87. Base::visit_edges(visitor);
  88. visitor.visit(m_detail);
  89. }
  90. }