diff options
Diffstat (limited to 'dom/performance/PerformanceObserver.cpp')
-rw-r--r-- | dom/performance/PerformanceObserver.cpp | 184 |
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; + } +} |