OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (C) 2015 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
esprehn
2015/07/18 22:24:16
short copyright
MikeB
2015/07/20 23:06:50
Done.
| |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 #include "core/timing/PerformanceObserver.h" | |
33 | |
34 #include "bindings/core/v8/ExceptionState.h" | |
35 #include "core/dom/ExceptionCode.h" | |
36 #include "core/dom/Microtask.h" | |
37 #include "core/inspector/InspectorInstrumentation.h" | |
38 #include "core/timing/PerformanceBase.h" | |
39 #include "core/timing/PerformanceEntry.h" | |
40 #include "core/timing/PerformanceObserverCallback.h" | |
41 #include "core/timing/PerformanceObserverEntryList.h" | |
42 #include "core/timing/PerformanceObserverInit.h" | |
43 #include "core/timing/PerformanceObserverRegistration.h" | |
44 #include "wtf/MainThread.h" | |
45 #include <algorithm> | |
46 | |
47 namespace blink { | |
48 | |
49 static unsigned s_observerPriority = 0; | |
50 | |
51 struct PerformanceObserver::ObserverLessThan { | |
52 bool operator()(const Member<PerformanceObserver>& lhs, const Member<Perform anceObserver>& rhs) | |
53 { | |
esprehn
2015/07/18 22:24:16
If you just use a ListHashSet you don't need this
MikeB
2015/07/20 23:06:50
Done.
| |
54 return lhs->m_priority < rhs->m_priority; | |
55 } | |
56 }; | |
57 | |
58 PerformanceObserver* PerformanceObserver::create(PerformanceBase* performance, P erformanceObserverCallback* callback) | |
59 { | |
60 ASSERT(isMainThread()); | |
61 return new PerformanceObserver(performance, callback); | |
62 } | |
63 | |
64 PerformanceObserver::PerformanceObserver(PerformanceBase* performance, Performan ceObserverCallback* callback) | |
65 : m_callback(callback) | |
66 , m_performance(performance) | |
67 , m_priority(s_observerPriority++) | |
esprehn
2015/07/18 22:24:16
or this
MikeB
2015/07/20 23:06:50
Done.
| |
68 { | |
69 } | |
70 | |
71 PerformanceObserver::~PerformanceObserver() | |
72 { | |
73 if (!m_performanceEntries.isEmpty()) | |
74 InspectorInstrumentation::didClearAllPerformanceObservations(m_callback- >executionContext(), this); | |
75 } | |
76 | |
77 void PerformanceObserver::observe(const PerformanceObserverInit& observerInit, E xceptionState& exceptionState) | |
78 { | |
79 PerformanceBase* performance = m_performance.get(); | |
80 if (!performance) { | |
81 exceptionState.throwTypeError("Window may be destroyed? Performance targ et is invalid."); | |
82 return; | |
83 } | |
84 | |
85 HashSet<AtomicString> entryType; | |
86 if (observerInit.hasEntryType() && observerInit.entryType().size()) { | |
87 const Vector<String>& sequence = observerInit.entryType(); | |
88 for (unsigned i = 0; i < sequence.size(); ++i) | |
89 entryType.add(AtomicString(sequence[i])); | |
90 } else { | |
91 exceptionState.throwTypeError("A Performance Observer MUST have a non-em pty typeFilter attribute."); | |
92 return; | |
93 } | |
94 for (auto registration : m_registrations) { | |
95 if (registration->performance() == performance) { | |
96 registration->resetObservation(entryType); | |
97 return; | |
98 } | |
99 } | |
100 PerformanceObserverRegistration::create(*this, performance, entryType); | |
101 } | |
102 | |
103 void PerformanceObserver::disconnect() | |
104 { | |
105 m_performanceEntries.clear(); | |
106 InspectorInstrumentation::didClearAllPerformanceObservations(m_callback->exe cutionContext(), this); | |
107 // registration->unregister() will call m_registrations.remove() and would | |
108 // invalidate the iterator being used here if we don't make a copy. | |
109 PerformanceObserverRegistrationSet copyOfRegistrations(m_registrations); | |
110 for (auto registration : copyOfRegistrations) { | |
111 registration->unregister(); | |
112 } | |
113 } | |
114 | |
115 void PerformanceObserver::observationStarted(PerformanceObserverRegistration* re gistration) | |
116 { | |
117 ASSERT(!m_registrations.contains(registration)); | |
118 m_registrations.add(registration); | |
119 } | |
120 | |
121 void PerformanceObserver::observationEnded(PerformanceObserverRegistration* regi stration) | |
122 { | |
123 ASSERT(m_registrations.contains(registration)); | |
124 m_registrations.remove(m_registrations.find(registration)); | |
125 } | |
126 | |
127 static PerformanceObserverSet& activePerformanceObservers() | |
128 { | |
129 DEFINE_STATIC_LOCAL(Persistent<PerformanceObserverSet>, activeObservers, (ne w PerformanceObserverSet())); | |
130 return *activeObservers; | |
131 } | |
132 | |
133 static PerformanceObserverSet& suspendedPerformanceObservers() | |
134 { | |
135 DEFINE_STATIC_LOCAL(Persistent<PerformanceObserverSet>, suspendedObservers, (new PerformanceObserverSet())); | |
136 return *suspendedObservers; | |
137 } | |
138 | |
139 static void activateObserver(PerformanceObserver* observer) | |
140 { | |
141 if (activePerformanceObservers().isEmpty()) | |
142 Microtask::enqueueMicrotask(WTF::bind(&PerformanceObserver::deliverObser vations)); | |
143 | |
144 activePerformanceObservers().add(observer); | |
145 } | |
146 | |
147 void PerformanceObserver::enqueuePerformanceEntry(PerformanceEntry* entry) | |
148 { | |
149 ASSERT(isMainThread()); | |
150 m_performanceEntries.append(entry); | |
151 activateObserver(this); | |
152 InspectorInstrumentation::didEnqueuePerformanceObserverEntries(m_callback->e xecutionContext(), this); | |
153 } | |
154 | |
155 bool PerformanceObserver::shouldBeSuspended() const | |
156 { | |
157 return m_callback->executionContext() && m_callback->executionContext()->act iveDOMObjectsAreSuspended(); | |
158 } | |
159 | |
160 void PerformanceObserver::deliver() | |
161 { | |
162 ASSERT(!shouldBeSuspended()); | |
163 | |
164 if (m_performanceEntries.isEmpty()) | |
165 return; | |
166 | |
167 // TODO(mpb) | |
168 PerformanceEntryVector performanceEntries; | |
169 performanceEntries.swap(m_performanceEntries); | |
170 Member<PerformanceObserverEntryList> entryList(new PerformanceObserverEntryL ist(performanceEntries)); | |
171 | |
172 InspectorInstrumentation::willDeliverPerformanceObservations(m_callback->exe cutionContext(), this); | |
173 m_callback->handleEvent(entryList, this); | |
174 InspectorInstrumentation::didDeliverPerformanceObservations(m_callback->exec utionContext()); | |
175 } | |
176 | |
177 void PerformanceObserver::resumeSuspendedObservers() | |
178 { | |
179 ASSERT(isMainThread()); | |
180 if (suspendedPerformanceObservers().isEmpty()) | |
181 return; | |
182 | |
183 PerformanceObserverVector suspended; | |
184 copyToVector(suspendedPerformanceObservers(), suspended); | |
185 for (size_t i = 0; i < suspended.size(); ++i) { | |
186 if (!suspended[i]->shouldBeSuspended()) { | |
187 suspendedPerformanceObservers().remove(suspended[i]); | |
188 activateObserver(suspended[i]); | |
189 } | |
190 } | |
191 } | |
192 | |
193 void PerformanceObserver::deliverObservations() | |
194 { | |
195 ASSERT(isMainThread()); | |
196 PerformanceObserverVector observers; | |
197 copyToVector(activePerformanceObservers(), observers); | |
198 activePerformanceObservers().clear(); | |
199 std::sort(observers.begin(), observers.end(), ObserverLessThan()); | |
200 for (size_t i = 0; i < observers.size(); ++i) { | |
201 if (observers[i]->shouldBeSuspended()) | |
202 suspendedPerformanceObservers().add(observers[i]); | |
203 else | |
204 observers[i]->deliver(); | |
205 } | |
206 } | |
207 | |
208 DEFINE_TRACE(PerformanceObserver) | |
209 { | |
210 visitor->trace(m_callback); | |
211 visitor->trace(m_performance); | |
212 visitor->trace(m_performanceEntries); | |
213 visitor->trace(m_registrations); | |
214 } | |
215 | |
216 } // namespace blink | |
OLD | NEW |