diff options
Diffstat (limited to 'dom/workers/SharedWorker.cpp')
-rw-r--r-- | dom/workers/SharedWorker.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/dom/workers/SharedWorker.cpp b/dom/workers/SharedWorker.cpp new file mode 100644 index 000000000..b0eed2def --- /dev/null +++ b/dom/workers/SharedWorker.cpp @@ -0,0 +1,207 @@ +/* -*- 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 "SharedWorker.h" + +#include "nsPIDOMWindow.h" + +#include "mozilla/EventDispatcher.h" +#include "mozilla/Preferences.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/SharedWorkerBinding.h" +#include "mozilla/Telemetry.h" +#include "nsContentUtils.h" +#include "nsIClassInfoImpl.h" +#include "nsIDOMEvent.h" + +#include "RuntimeService.h" +#include "WorkerPrivate.h" + +using mozilla::dom::Optional; +using mozilla::dom::Sequence; +using mozilla::dom::MessagePort; +using namespace mozilla; + +USING_WORKERS_NAMESPACE + +SharedWorker::SharedWorker(nsPIDOMWindowInner* aWindow, + WorkerPrivate* aWorkerPrivate, + MessagePort* aMessagePort) + : DOMEventTargetHelper(aWindow) + , mWorkerPrivate(aWorkerPrivate) + , mMessagePort(aMessagePort) + , mFrozen(false) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aWorkerPrivate); + MOZ_ASSERT(aMessagePort); +} + +SharedWorker::~SharedWorker() +{ + AssertIsOnMainThread(); +} + +// static +already_AddRefed<SharedWorker> +SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx, + const nsAString& aScriptURL, + const mozilla::dom::Optional<nsAString>& aName, + ErrorResult& aRv) +{ + AssertIsOnMainThread(); + + RuntimeService* rts = RuntimeService::GetOrCreateService(); + if (!rts) { + aRv = NS_ERROR_NOT_AVAILABLE; + return nullptr; + } + + nsCString name; + if (aName.WasPassed()) { + name = NS_ConvertUTF16toUTF8(aName.Value()); + } + + RefPtr<SharedWorker> sharedWorker; + nsresult rv = rts->CreateSharedWorker(aGlobal, aScriptURL, name, + getter_AddRefs(sharedWorker)); + if (NS_FAILED(rv)) { + aRv = rv; + return nullptr; + } + + Telemetry::Accumulate(Telemetry::SHARED_WORKER_COUNT, 1); + + return sharedWorker.forget(); +} + +MessagePort* +SharedWorker::Port() +{ + AssertIsOnMainThread(); + return mMessagePort; +} + +void +SharedWorker::Freeze() +{ + AssertIsOnMainThread(); + MOZ_ASSERT(!IsFrozen()); + + mFrozen = true; +} + +void +SharedWorker::Thaw() +{ + AssertIsOnMainThread(); + MOZ_ASSERT(IsFrozen()); + + mFrozen = false; + + if (!mFrozenEvents.IsEmpty()) { + nsTArray<nsCOMPtr<nsIDOMEvent>> events; + mFrozenEvents.SwapElements(events); + + for (uint32_t index = 0; index < events.Length(); index++) { + nsCOMPtr<nsIDOMEvent>& event = events[index]; + MOZ_ASSERT(event); + + nsCOMPtr<nsIDOMEventTarget> target; + if (NS_SUCCEEDED(event->GetTarget(getter_AddRefs(target)))) { + bool ignored; + if (NS_FAILED(target->DispatchEvent(event, &ignored))) { + NS_WARNING("Failed to dispatch event!"); + } + } else { + NS_WARNING("Failed to get target!"); + } + } + } +} + +void +SharedWorker::QueueEvent(nsIDOMEvent* aEvent) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aEvent); + MOZ_ASSERT(IsFrozen()); + + mFrozenEvents.AppendElement(aEvent); +} + +void +SharedWorker::Close() +{ + AssertIsOnMainThread(); + + if (mMessagePort) { + mMessagePort->Close(); + } +} + +void +SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, + const Optional<Sequence<JS::Value>>& aTransferable, + ErrorResult& aRv) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(mWorkerPrivate); + MOZ_ASSERT(mMessagePort); + + mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv); +} + +NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SharedWorker) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_CYCLE_COLLECTION_CLASS(SharedWorker) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SharedWorker, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrozenEvents) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrozenEvents) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +JSObject* +SharedWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + AssertIsOnMainThread(); + + return SharedWorkerBinding::Wrap(aCx, this, aGivenProto); +} + +nsresult +SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor) +{ + AssertIsOnMainThread(); + + if (IsFrozen()) { + nsCOMPtr<nsIDOMEvent> event = aVisitor.mDOMEvent; + if (!event) { + event = EventDispatcher::CreateEvent(aVisitor.mEvent->mOriginalTarget, + aVisitor.mPresContext, + aVisitor.mEvent, EmptyString()); + } + + QueueEvent(event); + + aVisitor.mCanHandle = false; + aVisitor.mParentTarget = nullptr; + return NS_OK; + } + + return DOMEventTargetHelper::PreHandleEvent(aVisitor); +} |