summaryrefslogtreecommitdiffstats
path: root/dom/performance/PerformanceObserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/performance/PerformanceObserver.cpp')
-rw-r--r--dom/performance/PerformanceObserver.cpp184
1 files changed, 184 insertions, 0 deletions
diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp
new file mode 100644
index 000000000..11dd30ac2
--- /dev/null
+++ b/dom/performance/PerformanceObserver.cpp
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "PerformanceObserver.h"
+
+#include "mozilla/dom/Performance.h"
+#include "mozilla/dom/PerformanceBinding.h"
+#include "mozilla/dom/PerformanceEntryBinding.h"
+#include "mozilla/dom/PerformanceObserverBinding.h"
+#include "nsPIDOMWindow.h"
+#include "nsQueryObject.h"
+#include "nsString.h"
+#include "PerformanceEntry.h"
+#include "PerformanceObserverEntryList.h"
+#include "WorkerPrivate.h"
+#include "WorkerScope.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::dom::workers;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceObserver)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PerformanceObserver)
+ tmp->Disconnect();
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PerformanceObserver)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(PerformanceObserver)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserver)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserver)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserver)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+PerformanceObserver::PerformanceObserver(nsPIDOMWindowInner* aOwner,
+ PerformanceObserverCallback& aCb)
+ : mOwner(aOwner)
+ , mCallback(&aCb)
+ , mConnected(false)
+{
+ MOZ_ASSERT(mOwner);
+ mPerformance = aOwner->GetPerformance();
+}
+
+PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate,
+ PerformanceObserverCallback& aCb)
+ : mCallback(&aCb)
+ , mConnected(false)
+{
+ MOZ_ASSERT(aWorkerPrivate);
+ mPerformance = aWorkerPrivate->GlobalScope()->GetPerformance();
+}
+
+PerformanceObserver::~PerformanceObserver()
+{
+ Disconnect();
+ MOZ_ASSERT(!mConnected);
+}
+
+// static
+already_AddRefed<PerformanceObserver>
+PerformanceObserver::Constructor(const GlobalObject& aGlobal,
+ PerformanceObserverCallback& aCb,
+ ErrorResult& aRv)
+{
+ if (NS_IsMainThread()) {
+ nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
+ do_QueryInterface(aGlobal.GetAsSupports());
+ if (!ownerWindow) {
+ aRv.Throw(NS_ERROR_FAILURE);
+ return nullptr;
+ }
+ MOZ_ASSERT(ownerWindow->IsInnerWindow());
+
+ RefPtr<PerformanceObserver> observer =
+ new PerformanceObserver(ownerWindow, aCb);
+ return observer.forget();
+ }
+
+ JSContext* cx = aGlobal.Context();
+ WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
+ MOZ_ASSERT(workerPrivate);
+
+ RefPtr<PerformanceObserver> observer =
+ new PerformanceObserver(workerPrivate, aCb);
+ return observer.forget();
+}
+
+JSObject*
+PerformanceObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return PerformanceObserverBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+PerformanceObserver::Notify()
+{
+ if (mQueuedEntries.IsEmpty()) {
+ return;
+ }
+ RefPtr<PerformanceObserverEntryList> list =
+ new PerformanceObserverEntryList(this, mQueuedEntries);
+
+ ErrorResult rv;
+ mCallback->Call(this, *list, *this, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
+ }
+ mQueuedEntries.Clear();
+}
+
+void
+PerformanceObserver::QueueEntry(PerformanceEntry* aEntry)
+{
+ MOZ_ASSERT(aEntry);
+
+ nsAutoString entryType;
+ aEntry->GetEntryType(entryType);
+ if (!mEntryTypes.Contains<nsString>(entryType)) {
+ return;
+ }
+
+ mQueuedEntries.AppendElement(aEntry);
+}
+
+static const char16_t *const sValidTypeNames[4] = {
+ u"mark",
+ u"measure",
+ u"resource",
+ u"server"
+};
+
+void
+PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
+ ErrorResult& aRv)
+{
+ if (aOptions.mEntryTypes.IsEmpty()) {
+ aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
+ return;
+ }
+
+ nsTArray<nsString> validEntryTypes;
+
+ for (const char16_t* name : sValidTypeNames) {
+ nsDependentString validTypeName(name);
+ if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
+ !validEntryTypes.Contains<nsString>(validTypeName)) {
+ validEntryTypes.AppendElement(validTypeName);
+ }
+ }
+
+ if (validEntryTypes.IsEmpty()) {
+ aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
+ return;
+ }
+
+ mEntryTypes.SwapElements(validEntryTypes);
+
+ mPerformance->AddObserver(this);
+ mConnected = true;
+}
+
+void
+PerformanceObserver::Disconnect()
+{
+ if (mConnected) {
+ MOZ_ASSERT(mPerformance);
+ mPerformance->RemoveObserver(this);
+ mConnected = false;
+ }
+}