/src/mozilla-central/dom/performance/PerformanceObserver.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "PerformanceObserver.h" |
8 | | |
9 | | #include "mozilla/dom/Performance.h" |
10 | | #include "mozilla/dom/PerformanceBinding.h" |
11 | | #include "mozilla/dom/PerformanceEntryBinding.h" |
12 | | #include "mozilla/dom/PerformanceObserverBinding.h" |
13 | | #include "mozilla/dom/WorkerPrivate.h" |
14 | | #include "mozilla/dom/WorkerScope.h" |
15 | | #include "nsIScriptError.h" |
16 | | #include "nsPIDOMWindow.h" |
17 | | #include "nsQueryObject.h" |
18 | | #include "nsString.h" |
19 | | #include "PerformanceEntry.h" |
20 | | #include "PerformanceObserverEntryList.h" |
21 | | |
22 | | using namespace mozilla; |
23 | | using namespace mozilla::dom; |
24 | | |
25 | | NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceObserver) |
26 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PerformanceObserver) |
27 | 0 | tmp->Disconnect(); |
28 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback) |
29 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance) |
30 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) |
31 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
32 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
33 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PerformanceObserver) |
34 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback) |
35 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance) |
36 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) |
37 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
38 | | NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(PerformanceObserver) |
39 | | |
40 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserver) |
41 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserver) |
42 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserver) |
43 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
44 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
45 | 0 | NS_INTERFACE_MAP_END |
46 | | |
47 | | PerformanceObserver::PerformanceObserver(nsPIDOMWindowInner* aOwner, |
48 | | PerformanceObserverCallback& aCb) |
49 | | : mOwner(aOwner) |
50 | | , mCallback(&aCb) |
51 | | , mConnected(false) |
52 | 0 | { |
53 | 0 | MOZ_ASSERT(mOwner); |
54 | 0 | mPerformance = aOwner->GetPerformance(); |
55 | 0 | } |
56 | | |
57 | | PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate, |
58 | | PerformanceObserverCallback& aCb) |
59 | | : mCallback(&aCb) |
60 | | , mConnected(false) |
61 | 0 | { |
62 | 0 | MOZ_ASSERT(aWorkerPrivate); |
63 | 0 | mPerformance = aWorkerPrivate->GlobalScope()->GetPerformance(); |
64 | 0 | } |
65 | | |
66 | | PerformanceObserver::~PerformanceObserver() |
67 | 0 | { |
68 | 0 | Disconnect(); |
69 | 0 | MOZ_ASSERT(!mConnected); |
70 | 0 | } |
71 | | |
72 | | // static |
73 | | already_AddRefed<PerformanceObserver> |
74 | | PerformanceObserver::Constructor(const GlobalObject& aGlobal, |
75 | | PerformanceObserverCallback& aCb, |
76 | | ErrorResult& aRv) |
77 | 0 | { |
78 | 0 | if (NS_IsMainThread()) { |
79 | 0 | nsCOMPtr<nsPIDOMWindowInner> ownerWindow = |
80 | 0 | do_QueryInterface(aGlobal.GetAsSupports()); |
81 | 0 | if (!ownerWindow) { |
82 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
83 | 0 | return nullptr; |
84 | 0 | } |
85 | 0 | |
86 | 0 | RefPtr<PerformanceObserver> observer = |
87 | 0 | new PerformanceObserver(ownerWindow, aCb); |
88 | 0 | return observer.forget(); |
89 | 0 | } |
90 | 0 | |
91 | 0 | JSContext* cx = aGlobal.Context(); |
92 | 0 | WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); |
93 | 0 | MOZ_ASSERT(workerPrivate); |
94 | 0 |
|
95 | 0 | RefPtr<PerformanceObserver> observer = |
96 | 0 | new PerformanceObserver(workerPrivate, aCb); |
97 | 0 | return observer.forget(); |
98 | 0 | } |
99 | | |
100 | | JSObject* |
101 | | PerformanceObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
102 | 0 | { |
103 | 0 | return PerformanceObserver_Binding::Wrap(aCx, this, aGivenProto); |
104 | 0 | } |
105 | | |
106 | | void |
107 | | PerformanceObserver::Notify() |
108 | 0 | { |
109 | 0 | if (mQueuedEntries.IsEmpty()) { |
110 | 0 | return; |
111 | 0 | } |
112 | 0 | RefPtr<PerformanceObserverEntryList> list = |
113 | 0 | new PerformanceObserverEntryList(this, mQueuedEntries); |
114 | 0 |
|
115 | 0 | mQueuedEntries.Clear(); |
116 | 0 |
|
117 | 0 | ErrorResult rv; |
118 | 0 | mCallback->Call(this, *list, *this, rv); |
119 | 0 | if (NS_WARN_IF(rv.Failed())) { |
120 | 0 | rv.SuppressException(); |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | void |
125 | | PerformanceObserver::QueueEntry(PerformanceEntry* aEntry) |
126 | 0 | { |
127 | 0 | MOZ_ASSERT(aEntry); |
128 | 0 |
|
129 | 0 | nsAutoString entryType; |
130 | 0 | aEntry->GetEntryType(entryType); |
131 | 0 | if (!mEntryTypes.Contains<nsString>(entryType)) { |
132 | 0 | return; |
133 | 0 | } |
134 | 0 | |
135 | 0 | mQueuedEntries.AppendElement(aEntry); |
136 | 0 | } |
137 | | |
138 | | static const char16_t *const sValidTypeNames[4] = { |
139 | | u"navigation", |
140 | | u"mark", |
141 | | u"measure", |
142 | | u"resource", |
143 | | }; |
144 | | |
145 | | void |
146 | | PerformanceObserver::Observe(const PerformanceObserverInit& aOptions) |
147 | 0 | { |
148 | 0 | if (aOptions.mEntryTypes.IsEmpty()) { |
149 | 0 | return; |
150 | 0 | } |
151 | 0 | |
152 | 0 | nsTArray<nsString> validEntryTypes; |
153 | 0 |
|
154 | 0 | for (const char16_t* name : sValidTypeNames) { |
155 | 0 | nsDependentString validTypeName(name); |
156 | 0 | if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) && |
157 | 0 | !validEntryTypes.Contains<nsString>(validTypeName)) { |
158 | 0 | validEntryTypes.AppendElement(validTypeName); |
159 | 0 | } |
160 | 0 | } |
161 | 0 |
|
162 | 0 | nsAutoString invalidTypesJoined; |
163 | 0 | bool addComma = false; |
164 | 0 | for (const auto& type : aOptions.mEntryTypes) { |
165 | 0 | if (!validEntryTypes.Contains<nsString>(type)) { |
166 | 0 | if (addComma) { |
167 | 0 | invalidTypesJoined.AppendLiteral(", "); |
168 | 0 | } |
169 | 0 | addComma = true; |
170 | 0 | invalidTypesJoined.Append(type); |
171 | 0 | } |
172 | 0 | } |
173 | 0 |
|
174 | 0 | if (!invalidTypesJoined.IsEmpty()) { |
175 | 0 | if (!NS_IsMainThread()) { |
176 | 0 | nsTArray<nsString> params; |
177 | 0 | params.AppendElement(invalidTypesJoined); |
178 | 0 | WorkerPrivate::ReportErrorToConsole("UnsupportedEntryTypesIgnored", |
179 | 0 | params); |
180 | 0 | } else { |
181 | 0 | nsCOMPtr<nsPIDOMWindowInner> ownerWindow = |
182 | 0 | do_QueryInterface(mOwner); |
183 | 0 | nsIDocument* document = ownerWindow->GetExtantDoc(); |
184 | 0 | const char16_t* params[] = { invalidTypesJoined.get() }; |
185 | 0 | nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, |
186 | 0 | NS_LITERAL_CSTRING("DOM"), document, |
187 | 0 | nsContentUtils::eDOM_PROPERTIES, |
188 | 0 | "UnsupportedEntryTypesIgnored", params, 1); |
189 | 0 | } |
190 | 0 | } |
191 | 0 |
|
192 | 0 | if (validEntryTypes.IsEmpty()) { |
193 | 0 | return; |
194 | 0 | } |
195 | 0 | |
196 | 0 | mEntryTypes.SwapElements(validEntryTypes); |
197 | 0 |
|
198 | 0 | mPerformance->AddObserver(this); |
199 | 0 |
|
200 | 0 | if (aOptions.mBuffered) { |
201 | 0 | for (auto entryType : mEntryTypes) { |
202 | 0 | nsTArray<RefPtr<PerformanceEntry>> existingEntries; |
203 | 0 | mPerformance->GetEntriesByType(entryType, existingEntries); |
204 | 0 | if (!existingEntries.IsEmpty()) { |
205 | 0 | mQueuedEntries.AppendElements(existingEntries); |
206 | 0 | } |
207 | 0 | } |
208 | 0 | } |
209 | 0 |
|
210 | 0 | mConnected = true; |
211 | 0 | } |
212 | | |
213 | | void |
214 | | PerformanceObserver::Disconnect() |
215 | 0 | { |
216 | 0 | if (mConnected) { |
217 | 0 | MOZ_ASSERT(mPerformance); |
218 | 0 | mPerformance->RemoveObserver(this); |
219 | 0 | mConnected = false; |
220 | 0 | } |
221 | 0 | } |
222 | | |
223 | | void |
224 | | PerformanceObserver::TakeRecords(nsTArray<RefPtr<PerformanceEntry>>& aRetval) |
225 | 0 | { |
226 | 0 | MOZ_ASSERT(aRetval.IsEmpty()); |
227 | 0 | aRetval.SwapElements(mQueuedEntries); |
228 | 0 | } |