diff -r 000000000000 -r 6474c204b198 dom/workers/SharedWorker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/workers/SharedWorker.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,218 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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/SharedWorkerBinding.h" +#include "nsContentUtils.h" +#include "nsIClassInfoImpl.h" +#include "nsIDOMEvent.h" + +#include "MessagePort.h" +#include "RuntimeService.h" +#include "WorkerPrivate.h" + +using mozilla::dom::Optional; +using mozilla::dom::Sequence; +using namespace mozilla; + +USING_WORKERS_NAMESPACE + +SharedWorker::SharedWorker(nsPIDOMWindow* aWindow, + WorkerPrivate* aWorkerPrivate) +: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate), + mSuspended(false) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(aWorkerPrivate); + + mSerial = aWorkerPrivate->NextMessagePortSerial(); + + mMessagePort = new MessagePort(aWindow, this, mSerial); +} + +SharedWorker::~SharedWorker() +{ + AssertIsOnMainThread(); + Close(); + MOZ_ASSERT(!mWorkerPrivate); +} + +// static +already_AddRefed +SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx, + const nsAString& aScriptURL, + const mozilla::dom::Optional& 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()); + } + + nsRefPtr sharedWorker; + nsresult rv = rts->CreateSharedWorker(aGlobal, aScriptURL, name, + getter_AddRefs(sharedWorker)); + if (NS_FAILED(rv)) { + aRv = rv; + return nullptr; + } + + return sharedWorker.forget(); +} + +already_AddRefed +SharedWorker::Port() +{ + AssertIsOnMainThread(); + + nsRefPtr messagePort = mMessagePort; + return messagePort.forget(); +} + +void +SharedWorker::Suspend() +{ + AssertIsOnMainThread(); + MOZ_ASSERT(!IsSuspended()); + + mSuspended = true; +} + +void +SharedWorker::Resume() +{ + AssertIsOnMainThread(); + MOZ_ASSERT(IsSuspended()); + + mSuspended = false; + + if (!mSuspendedEvents.IsEmpty()) { + nsTArray> events; + mSuspendedEvents.SwapElements(events); + + for (uint32_t index = 0; index < events.Length(); index++) { + nsCOMPtr& event = events[index]; + MOZ_ASSERT(event); + + nsCOMPtr 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(IsSuspended()); + + mSuspendedEvents.AppendElement(aEvent); +} + +void +SharedWorker::Close() +{ + AssertIsOnMainThread(); + + if (mMessagePort) { + mMessagePort->Close(); + } + + if (mWorkerPrivate) { + AutoSafeJSContext cx; + NoteDeadWorker(cx); + } +} + +void +SharedWorker::PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(mWorkerPrivate); + MOZ_ASSERT(mMessagePort); + + mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(), + aMessage, aTransferable, aRv); +} + +void +SharedWorker::NoteDeadWorker(JSContext* aCx) +{ + AssertIsOnMainThread(); + MOZ_ASSERT(mWorkerPrivate); + + mWorkerPrivate->UnregisterSharedWorker(aCx, this); + mWorkerPrivate = nullptr; +} + +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(mSuspendedEvents) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SharedWorker, + DOMEventTargetHelper) + tmp->Close(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedEvents) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +JSObject* +SharedWorker::WrapObject(JSContext* aCx) +{ + AssertIsOnMainThread(); + + return SharedWorkerBinding::Wrap(aCx, this); +} + +nsresult +SharedWorker::PreHandleEvent(EventChainPreVisitor& aVisitor) +{ + AssertIsOnMainThread(); + + nsIDOMEvent*& event = aVisitor.mDOMEvent; + + if (IsSuspended() && event) { + QueueEvent(event); + + aVisitor.mCanHandle = false; + aVisitor.mParentTarget = nullptr; + return NS_OK; + } + + return DOMEventTargetHelper::PreHandleEvent(aVisitor); +}