aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/performanceobserver.rs
blob: dc66e88b5a36740d0b54ebeaedcc02bcff78fce4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceEntryList as DOMPerformanceEntryList;
use crate::dom::bindings::codegen::Bindings::PerformanceObserverBinding;
use crate::dom::bindings::codegen::Bindings::PerformanceObserverBinding::PerformanceObserverCallback;
use crate::dom::bindings::codegen::Bindings::PerformanceObserverBinding::PerformanceObserverInit;
use crate::dom::bindings::codegen::Bindings::PerformanceObserverBinding::PerformanceObserverMethods;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::performance::PerformanceEntryList;
use crate::dom::performanceentry::PerformanceEntry;
use crate::dom::performanceobserverentrylist::PerformanceObserverEntryList;
use dom_struct::dom_struct;
use std::rc::Rc;

/// List of allowed performance entry types.
const VALID_ENTRY_TYPES: &'static [&'static str] = &[
    "mark",       // User Timing API
    "measure",    // User Timing API
    "resource",   // Resource Timing API
    "navigation", // Navigation Timing API
    // "frame", //TODO Frame Timing API
    // "server", XXX Server Timing API
    "paint", // Paint Timing API
];

#[dom_struct]
pub struct PerformanceObserver {
    reflector_: Reflector,
    #[ignore_malloc_size_of = "can't measure Rc values"]
    callback: Rc<PerformanceObserverCallback>,
    entries: DomRefCell<DOMPerformanceEntryList>,
}

impl PerformanceObserver {
    fn new_inherited(
        callback: Rc<PerformanceObserverCallback>,
        entries: DomRefCell<DOMPerformanceEntryList>,
    ) -> PerformanceObserver {
        PerformanceObserver {
            reflector_: Reflector::new(),
            callback,
            entries,
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        global: &GlobalScope,
        callback: Rc<PerformanceObserverCallback>,
        entries: DOMPerformanceEntryList,
    ) -> DomRoot<PerformanceObserver> {
        let observer = PerformanceObserver::new_inherited(callback, DomRefCell::new(entries));
        reflect_dom_object(Box::new(observer), global, PerformanceObserverBinding::Wrap)
    }

    pub fn Constructor(
        global: &GlobalScope,
        callback: Rc<PerformanceObserverCallback>,
    ) -> Fallible<DomRoot<PerformanceObserver>> {
        Ok(PerformanceObserver::new(global, callback, Vec::new()))
    }

    /// Buffer a new performance entry.
    pub fn queue_entry(&self, entry: &PerformanceEntry) {
        self.entries.borrow_mut().push(DomRoot::from_ref(entry));
    }

    /// Trigger performance observer callback with the list of performance entries
    /// buffered since the last callback call.
    pub fn notify(&self) {
        let entries = self.entries.borrow();
        if entries.is_empty() {
            return;
        }
        let mut entries = entries.clone();
        let global = self.global();
        let entry_list = PerformanceEntryList::new(entries.drain(..).collect());
        let observer_entry_list = PerformanceObserverEntryList::new(&global, entry_list);
        let _ = self
            .callback
            .Call__(&observer_entry_list, self, ExceptionHandling::Report);
    }

    pub fn callback(&self) -> Rc<PerformanceObserverCallback> {
        self.callback.clone()
    }

    pub fn entries(&self) -> DOMPerformanceEntryList {
        self.entries.borrow().clone()
    }

    pub fn set_entries(&self, entries: DOMPerformanceEntryList) {
        *self.entries.borrow_mut() = entries;
    }
}

impl PerformanceObserverMethods for PerformanceObserver {
    // https://w3c.github.io/performance-timeline/#dom-performanceobserver-observe()
    fn Observe(&self, options: &PerformanceObserverInit) -> Fallible<()> {
        // step 1
        // Make sure the client is asking to observe events from allowed entry types.
        let entry_types = options
            .entryTypes
            .iter()
            .filter(|e| VALID_ENTRY_TYPES.contains(&e.as_ref()))
            .map(|e| e.clone())
            .collect::<Vec<DOMString>>();
        // step 2
        // There must be at least one valid entry type.
        if entry_types.is_empty() {
            return Err(Error::Type("entryTypes cannot be empty".to_string()));
        }

        // step 3-4-5
        self.global()
            .performance()
            .add_observer(self, entry_types, options.buffered);

        Ok(())
    }

    // https://w3c.github.io/performance-timeline/#dom-performanceobserver-disconnect()
    fn Disconnect(&self) {
        self.global().performance().remove_observer(self);
        self.entries.borrow_mut().clear();
    }
}