Skip to main content

script/dom/performance/
performancemark.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use js::gc::HandleValue;
6use js::jsapi::Heap;
7use js::jsval::{JSVal, NullValue};
8use js::rust::{HandleObject, MutableHandleValue};
9use script_bindings::codegen::GenericBindings::PerformanceBinding::PerformanceMarkOptions;
10
11use crate::dom::PERFORMANCE_TIMING_ATTRIBUTES;
12use crate::dom::bindings::codegen::Bindings::PerformanceMarkBinding::PerformanceMarkMethods;
13use crate::dom::bindings::error::{Error, Fallible};
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::structuredclone;
16use crate::dom::bindings::trace::RootedTraceableBox;
17use crate::dom::window::Window;
18use crate::script_runtime::JSContext;
19
20impl_performance_entry_struct!(
21    PerformanceMarkBinding,
22    PerformanceMark, EntryType::Mark,
23    {
24        #[ignore_malloc_size_of = "Defined in rust-mozjs"]
25        detail: Heap<JSVal>,
26    }
27);
28
29impl PerformanceMark {
30    fn set_detail(&self, handle: HandleValue<'_>) {
31        self.detail.set(handle.get());
32    }
33
34    pub(crate) fn new_with_proto(
35        cx: &mut js::context::JSContext,
36        global: &GlobalScope,
37        _proto: Option<HandleObject>,
38        mark_name: DOMString,
39        mark_options: RootedTraceableBox<PerformanceMarkOptions>,
40    ) -> Fallible<DomRoot<PerformanceMark>> {
41        // The PerformanceMark constructor must run the following steps:
42        // Step 1. If the current global object is a Window object and markName uses the same name
43        // as a read only attribute in the PerformanceTiming interface, throw a SyntaxError.
44        if global.is::<Window>() && PERFORMANCE_TIMING_ATTRIBUTES.contains(&&*mark_name.str()) {
45            return Err(Error::Syntax(Some(
46                "Read-only attribute cannot be used as a mark name".to_owned(),
47            )));
48        }
49
50        // Step 2 - 4. Note: These are handled by the PerformanceMark default constructor below.
51
52        // Step 5. Set entry’s startTime attribute as follows:
53        let start_time = match mark_options.startTime {
54            // Step 5.1. If markOptions’s startTime member exists, then:
55            Some(start_time) => {
56                // Step 5.1.1. If markOptions’s startTime is negative, throw a TypeError.
57                if start_time.is_sign_negative() {
58                    return Err(Error::Type(c"startTime must not be negative".to_owned()));
59                }
60                // Step 5.1.2. Otherwise, set entry’s startTime to the value of markOptions’s startTime.
61                global.performance().time_origin() +
62                    Duration::microseconds(start_time.mul_add(1000.0, 0.0) as i64)
63            },
64            // Step 5.2. Otherwise, set it to the value that would be returned by the Performance object’s now() method.
65            None => CrossProcessInstant::now(),
66        };
67
68        // Step 6. Set entry’s duration attribute to 0.
69        let entry = PerformanceMark::new(
70            global,
71            mark_name,
72            start_time,
73            Duration::ZERO,
74            Default::default(),
75        );
76
77        // Step 7. If markOptions’s detail is null, set entry’s detail to null.
78        rooted!(&in(cx) let mut detail = NullValue());
79
80        // Step 8 Otherwise:
81        if !mark_options.detail.get().is_null_or_undefined() {
82            // Step 8.1. Let record be the result of calling the StructuredSerialize algorithm on markOptions’s detail.
83            let record = structuredclone::write(cx, mark_options.detail.handle(), None)?;
84
85            // Step 8.2. Set entry’s detail to the result of calling the StructuredDeserialize algorithm on record and the current realm.
86            structuredclone::read(cx, global, record, detail.handle_mut())?;
87        }
88        entry.set_detail(detail.handle());
89
90        Ok(entry)
91    }
92}
93
94impl PerformanceMarkMethods<crate::DomTypeHolder> for PerformanceMark {
95    fn Detail(&self, _cx: JSContext, mut retval: MutableHandleValue) {
96        retval.set(self.detail.get())
97    }
98
99    /// <https://w3c.github.io/user-timing/#the-performancemark-constructor>
100    fn Constructor(
101        cx: &mut js::context::JSContext,
102        global: &GlobalScope,
103        proto: Option<HandleObject>,
104        mark_name: DOMString,
105        mark_options: RootedTraceableBox<PerformanceMarkOptions>,
106    ) -> Fallible<DomRoot<PerformanceMark>> {
107        PerformanceMark::new_with_proto(cx, global, proto, mark_name, mark_options)
108    }
109}