Index: Source/core/timing/PerformanceObserver.cpp |
diff --git a/Source/core/timing/PerformanceObserver.cpp b/Source/core/timing/PerformanceObserver.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9f03a254e75c39e8bb2bd809de531d59518972ce |
--- /dev/null |
+++ b/Source/core/timing/PerformanceObserver.cpp |
@@ -0,0 +1,216 @@ |
+/* |
+ * Copyright (C) 2015 Google Inc. All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions are |
+ * met: |
+ * |
+ * * Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above |
+ * copyright notice, this list of conditions and the following disclaimer |
+ * in the documentation and/or other materials provided with the |
+ * distribution. |
+ * * Neither the name of Google Inc. nor the names of its |
+ * contributors may be used to endorse or promote products derived from |
+ * this software without specific prior written permission. |
esprehn
2015/07/18 22:24:16
short copyright
MikeB
2015/07/20 23:06:50
Done.
|
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+ |
+#include "config.h" |
+#include "core/timing/PerformanceObserver.h" |
+ |
+#include "bindings/core/v8/ExceptionState.h" |
+#include "core/dom/ExceptionCode.h" |
+#include "core/dom/Microtask.h" |
+#include "core/inspector/InspectorInstrumentation.h" |
+#include "core/timing/PerformanceBase.h" |
+#include "core/timing/PerformanceEntry.h" |
+#include "core/timing/PerformanceObserverCallback.h" |
+#include "core/timing/PerformanceObserverEntryList.h" |
+#include "core/timing/PerformanceObserverInit.h" |
+#include "core/timing/PerformanceObserverRegistration.h" |
+#include "wtf/MainThread.h" |
+#include <algorithm> |
+ |
+namespace blink { |
+ |
+static unsigned s_observerPriority = 0; |
+ |
+struct PerformanceObserver::ObserverLessThan { |
+ bool operator()(const Member<PerformanceObserver>& lhs, const Member<PerformanceObserver>& rhs) |
+ { |
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.
|
+ return lhs->m_priority < rhs->m_priority; |
+ } |
+}; |
+ |
+PerformanceObserver* PerformanceObserver::create(PerformanceBase* performance, PerformanceObserverCallback* callback) |
+{ |
+ ASSERT(isMainThread()); |
+ return new PerformanceObserver(performance, callback); |
+} |
+ |
+PerformanceObserver::PerformanceObserver(PerformanceBase* performance, PerformanceObserverCallback* callback) |
+ : m_callback(callback) |
+ , m_performance(performance) |
+ , m_priority(s_observerPriority++) |
esprehn
2015/07/18 22:24:16
or this
MikeB
2015/07/20 23:06:50
Done.
|
+{ |
+} |
+ |
+PerformanceObserver::~PerformanceObserver() |
+{ |
+ if (!m_performanceEntries.isEmpty()) |
+ InspectorInstrumentation::didClearAllPerformanceObservations(m_callback->executionContext(), this); |
+} |
+ |
+void PerformanceObserver::observe(const PerformanceObserverInit& observerInit, ExceptionState& exceptionState) |
+{ |
+ PerformanceBase* performance = m_performance.get(); |
+ if (!performance) { |
+ exceptionState.throwTypeError("Window may be destroyed? Performance target is invalid."); |
+ return; |
+ } |
+ |
+ HashSet<AtomicString> entryType; |
+ if (observerInit.hasEntryType() && observerInit.entryType().size()) { |
+ const Vector<String>& sequence = observerInit.entryType(); |
+ for (unsigned i = 0; i < sequence.size(); ++i) |
+ entryType.add(AtomicString(sequence[i])); |
+ } else { |
+ exceptionState.throwTypeError("A Performance Observer MUST have a non-empty typeFilter attribute."); |
+ return; |
+ } |
+ for (auto registration : m_registrations) { |
+ if (registration->performance() == performance) { |
+ registration->resetObservation(entryType); |
+ return; |
+ } |
+ } |
+ PerformanceObserverRegistration::create(*this, performance, entryType); |
+} |
+ |
+void PerformanceObserver::disconnect() |
+{ |
+ m_performanceEntries.clear(); |
+ InspectorInstrumentation::didClearAllPerformanceObservations(m_callback->executionContext(), this); |
+ // registration->unregister() will call m_registrations.remove() and would |
+ // invalidate the iterator being used here if we don't make a copy. |
+ PerformanceObserverRegistrationSet copyOfRegistrations(m_registrations); |
+ for (auto registration : copyOfRegistrations) { |
+ registration->unregister(); |
+ } |
+} |
+ |
+void PerformanceObserver::observationStarted(PerformanceObserverRegistration* registration) |
+{ |
+ ASSERT(!m_registrations.contains(registration)); |
+ m_registrations.add(registration); |
+} |
+ |
+void PerformanceObserver::observationEnded(PerformanceObserverRegistration* registration) |
+{ |
+ ASSERT(m_registrations.contains(registration)); |
+ m_registrations.remove(m_registrations.find(registration)); |
+} |
+ |
+static PerformanceObserverSet& activePerformanceObservers() |
+{ |
+ DEFINE_STATIC_LOCAL(Persistent<PerformanceObserverSet>, activeObservers, (new PerformanceObserverSet())); |
+ return *activeObservers; |
+} |
+ |
+static PerformanceObserverSet& suspendedPerformanceObservers() |
+{ |
+ DEFINE_STATIC_LOCAL(Persistent<PerformanceObserverSet>, suspendedObservers, (new PerformanceObserverSet())); |
+ return *suspendedObservers; |
+} |
+ |
+static void activateObserver(PerformanceObserver* observer) |
+{ |
+ if (activePerformanceObservers().isEmpty()) |
+ Microtask::enqueueMicrotask(WTF::bind(&PerformanceObserver::deliverObservations)); |
+ |
+ activePerformanceObservers().add(observer); |
+} |
+ |
+void PerformanceObserver::enqueuePerformanceEntry(PerformanceEntry* entry) |
+{ |
+ ASSERT(isMainThread()); |
+ m_performanceEntries.append(entry); |
+ activateObserver(this); |
+ InspectorInstrumentation::didEnqueuePerformanceObserverEntries(m_callback->executionContext(), this); |
+} |
+ |
+bool PerformanceObserver::shouldBeSuspended() const |
+{ |
+ return m_callback->executionContext() && m_callback->executionContext()->activeDOMObjectsAreSuspended(); |
+} |
+ |
+void PerformanceObserver::deliver() |
+{ |
+ ASSERT(!shouldBeSuspended()); |
+ |
+ if (m_performanceEntries.isEmpty()) |
+ return; |
+ |
+ // TODO(mpb) |
+ PerformanceEntryVector performanceEntries; |
+ performanceEntries.swap(m_performanceEntries); |
+ Member<PerformanceObserverEntryList> entryList(new PerformanceObserverEntryList(performanceEntries)); |
+ |
+ InspectorInstrumentation::willDeliverPerformanceObservations(m_callback->executionContext(), this); |
+ m_callback->handleEvent(entryList, this); |
+ InspectorInstrumentation::didDeliverPerformanceObservations(m_callback->executionContext()); |
+} |
+ |
+void PerformanceObserver::resumeSuspendedObservers() |
+{ |
+ ASSERT(isMainThread()); |
+ if (suspendedPerformanceObservers().isEmpty()) |
+ return; |
+ |
+ PerformanceObserverVector suspended; |
+ copyToVector(suspendedPerformanceObservers(), suspended); |
+ for (size_t i = 0; i < suspended.size(); ++i) { |
+ if (!suspended[i]->shouldBeSuspended()) { |
+ suspendedPerformanceObservers().remove(suspended[i]); |
+ activateObserver(suspended[i]); |
+ } |
+ } |
+} |
+ |
+void PerformanceObserver::deliverObservations() |
+{ |
+ ASSERT(isMainThread()); |
+ PerformanceObserverVector observers; |
+ copyToVector(activePerformanceObservers(), observers); |
+ activePerformanceObservers().clear(); |
+ std::sort(observers.begin(), observers.end(), ObserverLessThan()); |
+ for (size_t i = 0; i < observers.size(); ++i) { |
+ if (observers[i]->shouldBeSuspended()) |
+ suspendedPerformanceObservers().add(observers[i]); |
+ else |
+ observers[i]->deliver(); |
+ } |
+} |
+ |
+DEFINE_TRACE(PerformanceObserver) |
+{ |
+ visitor->trace(m_callback); |
+ visitor->trace(m_performance); |
+ visitor->trace(m_performanceEntries); |
+ visitor->trace(m_registrations); |
+} |
+ |
+} // namespace blink |