michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SharedWorker.h" michael@0: michael@0: #include "nsPIDOMWindow.h" michael@0: michael@0: #include "mozilla/EventDispatcher.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/dom/SharedWorkerBinding.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsIClassInfoImpl.h" michael@0: #include "nsIDOMEvent.h" michael@0: michael@0: #include "MessagePort.h" michael@0: #include "RuntimeService.h" michael@0: #include "WorkerPrivate.h" michael@0: michael@0: using mozilla::dom::Optional; michael@0: using mozilla::dom::Sequence; michael@0: using namespace mozilla; michael@0: michael@0: USING_WORKERS_NAMESPACE michael@0: michael@0: SharedWorker::SharedWorker(nsPIDOMWindow* aWindow, michael@0: WorkerPrivate* aWorkerPrivate) michael@0: : DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate), michael@0: mSuspended(false) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: MOZ_ASSERT(aWorkerPrivate); michael@0: michael@0: mSerial = aWorkerPrivate->NextMessagePortSerial(); michael@0: michael@0: mMessagePort = new MessagePort(aWindow, this, mSerial); michael@0: } michael@0: michael@0: SharedWorker::~SharedWorker() michael@0: { michael@0: AssertIsOnMainThread(); michael@0: Close(); michael@0: MOZ_ASSERT(!mWorkerPrivate); michael@0: } michael@0: michael@0: // static michael@0: already_AddRefed michael@0: SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx, michael@0: const nsAString& aScriptURL, michael@0: const mozilla::dom::Optional& aName, michael@0: ErrorResult& aRv) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: michael@0: RuntimeService* rts = RuntimeService::GetOrCreateService(); michael@0: if (!rts) { michael@0: aRv = NS_ERROR_NOT_AVAILABLE; michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCString name; michael@0: if (aName.WasPassed()) { michael@0: name = NS_ConvertUTF16toUTF8(aName.Value()); michael@0: } michael@0: michael@0: nsRefPtr sharedWorker; michael@0: nsresult rv = rts->CreateSharedWorker(aGlobal, aScriptURL, name, michael@0: getter_AddRefs(sharedWorker)); michael@0: if (NS_FAILED(rv)) { michael@0: aRv = rv; michael@0: return nullptr; michael@0: } michael@0: michael@0: return sharedWorker.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: SharedWorker::Port() michael@0: { michael@0: AssertIsOnMainThread(); michael@0: michael@0: nsRefPtr messagePort = mMessagePort; michael@0: return messagePort.forget(); michael@0: } michael@0: michael@0: void michael@0: SharedWorker::Suspend() michael@0: { michael@0: AssertIsOnMainThread(); michael@0: MOZ_ASSERT(!IsSuspended()); michael@0: michael@0: mSuspended = true; michael@0: } michael@0: michael@0: void michael@0: SharedWorker::Resume() michael@0: { michael@0: AssertIsOnMainThread(); michael@0: MOZ_ASSERT(IsSuspended()); michael@0: michael@0: mSuspended = false; michael@0: michael@0: if (!mSuspendedEvents.IsEmpty()) { michael@0: nsTArray> events; michael@0: mSuspendedEvents.SwapElements(events); michael@0: michael@0: for (uint32_t index = 0; index < events.Length(); index++) { michael@0: nsCOMPtr& event = events[index]; michael@0: MOZ_ASSERT(event); michael@0: michael@0: nsCOMPtr target; michael@0: if (NS_SUCCEEDED(event->GetTarget(getter_AddRefs(target)))) { michael@0: bool ignored; michael@0: if (NS_FAILED(target->DispatchEvent(event, &ignored))) { michael@0: NS_WARNING("Failed to dispatch event!"); michael@0: } michael@0: } else { michael@0: NS_WARNING("Failed to get target!"); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: SharedWorker::QueueEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: MOZ_ASSERT(aEvent); michael@0: MOZ_ASSERT(IsSuspended()); michael@0: michael@0: mSuspendedEvents.AppendElement(aEvent); michael@0: } michael@0: michael@0: void michael@0: SharedWorker::Close() michael@0: { michael@0: AssertIsOnMainThread(); michael@0: michael@0: if (mMessagePort) { michael@0: mMessagePort->Close(); michael@0: } michael@0: michael@0: if (mWorkerPrivate) { michael@0: AutoSafeJSContext cx; michael@0: NoteDeadWorker(cx); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SharedWorker::PostMessage(JSContext* aCx, JS::Handle aMessage, michael@0: const Optional>& aTransferable, michael@0: ErrorResult& aRv) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: MOZ_ASSERT(mWorkerPrivate); michael@0: MOZ_ASSERT(mMessagePort); michael@0: michael@0: mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(), michael@0: aMessage, aTransferable, aRv); michael@0: } michael@0: michael@0: void michael@0: SharedWorker::NoteDeadWorker(JSContext* aCx) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: MOZ_ASSERT(mWorkerPrivate); michael@0: michael@0: mWorkerPrivate->UnregisterSharedWorker(aCx, this); michael@0: mWorkerPrivate = nullptr; michael@0: } michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(SharedWorker, DOMEventTargetHelper) michael@0: NS_IMPL_RELEASE_INHERITED(SharedWorker, DOMEventTargetHelper) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SharedWorker) michael@0: NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(SharedWorker) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SharedWorker, michael@0: DOMEventTargetHelper) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedEvents) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker, michael@0: DOMEventTargetHelper) michael@0: tmp->Close(); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedEvents) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: michael@0: JSObject* michael@0: SharedWorker::WrapObject(JSContext* aCx) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: michael@0: return SharedWorkerBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: nsresult michael@0: SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor) michael@0: { michael@0: AssertIsOnMainThread(); michael@0: michael@0: nsIDOMEvent*& event = aVisitor.mDOMEvent; michael@0: michael@0: if (IsSuspended() && event) { michael@0: QueueEvent(event); michael@0: michael@0: aVisitor.mCanHandle = false; michael@0: aVisitor.mParentTarget = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return DOMEventTargetHelper::PreHandleEvent(aVisitor); michael@0: }