michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ 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 michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WorkerScope.h" michael@0: michael@0: #include "jsapi.h" michael@0: #include "mozilla/EventListenerManager.h" michael@0: #include "mozilla/dom/FunctionBinding.h" michael@0: #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h" michael@0: #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h" michael@0: #include "mozilla/dom/Console.h" michael@0: michael@0: #ifdef ANDROID michael@0: #include michael@0: #endif michael@0: michael@0: #include "Location.h" michael@0: #include "Navigator.h" michael@0: #include "Principal.h" michael@0: #include "RuntimeService.h" michael@0: #include "ScriptLoader.h" michael@0: #include "WorkerPrivate.h" michael@0: michael@0: #define UNWRAP_WORKER_OBJECT(Interface, obj, value) \ michael@0: UnwrapObject(obj, value) michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: USING_WORKERS_NAMESPACE michael@0: michael@0: BEGIN_WORKERS_NAMESPACE michael@0: michael@0: WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate) michael@0: : mWorkerPrivate(aWorkerPrivate) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: SetIsDOMBinding(); michael@0: } michael@0: michael@0: WorkerGlobalScope::~WorkerGlobalScope() michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope, michael@0: DOMEventTargetHelper) michael@0: tmp->mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope, michael@0: DOMEventTargetHelper) michael@0: tmp->mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope, michael@0: DOMEventTargetHelper) michael@0: tmp->mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: tmp->mWorkerPrivate->TraceTimeouts(aCallbacks, aClosure); michael@0: NS_IMPL_CYCLE_COLLECTION_TRACE_END michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(WorkerGlobalScope, DOMEventTargetHelper) michael@0: NS_IMPL_RELEASE_INHERITED(WorkerGlobalScope, DOMEventTargetHelper) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScope) michael@0: NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) michael@0: NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) michael@0: michael@0: JSObject* michael@0: WorkerGlobalScope::WrapObject(JSContext* aCx) michael@0: { michael@0: MOZ_CRASH("We should never get here!"); michael@0: } michael@0: michael@0: already_AddRefed michael@0: WorkerGlobalScope::GetConsole() michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: if (!mConsole) { michael@0: mConsole = new Console(nullptr); michael@0: MOZ_ASSERT(mConsole); michael@0: } michael@0: michael@0: return mConsole.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: WorkerGlobalScope::Location() michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: if (!mLocation) { michael@0: WorkerPrivate::LocationInfo& info = mWorkerPrivate->GetLocationInfo(); michael@0: michael@0: mLocation = WorkerLocation::Create(info); michael@0: MOZ_ASSERT(mLocation); michael@0: } michael@0: michael@0: nsRefPtr location = mLocation; michael@0: return location.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: WorkerGlobalScope::Navigator() michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: if (!mNavigator) { michael@0: mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine()); michael@0: MOZ_ASSERT(mNavigator); michael@0: } michael@0: michael@0: nsRefPtr navigator = mNavigator; michael@0: return navigator.forget(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: WorkerGlobalScope::GetExistingNavigator() const michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: nsRefPtr navigator = mNavigator; michael@0: return navigator.forget(); michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::Close(JSContext* aCx) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: mWorkerPrivate->CloseInternal(aCx); michael@0: } michael@0: michael@0: OnErrorEventHandlerNonNull* michael@0: WorkerGlobalScope::GetOnerror() michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: EventListenerManager* elm = GetExistingListenerManager(); michael@0: return elm ? elm->GetOnErrorEventHandler() : nullptr; michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull* aHandler) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: EventListenerManager* elm = GetOrCreateListenerManager(); michael@0: if (elm) { michael@0: elm->SetEventHandler(aHandler); michael@0: } michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::ImportScripts(JSContext* aCx, michael@0: const Sequence& aScriptURLs, michael@0: ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: scriptloader::Load(aCx, mWorkerPrivate, aScriptURLs, aRv); michael@0: } michael@0: michael@0: int32_t michael@0: WorkerGlobalScope::SetTimeout(JSContext* aCx, michael@0: Function& aHandler, michael@0: const int32_t aTimeout, michael@0: const Sequence& aArguments, michael@0: ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), aTimeout, michael@0: aArguments, false, aRv); michael@0: } michael@0: michael@0: int32_t michael@0: WorkerGlobalScope::SetTimeout(JSContext* /* unused */, michael@0: const nsAString& aHandler, michael@0: const int32_t aTimeout, michael@0: const Sequence& /* unused */, michael@0: ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: Sequence dummy; michael@0: return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr, michael@0: aHandler, aTimeout, dummy, false, aRv); michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::ClearTimeout(int32_t aHandle, ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: mWorkerPrivate->ClearTimeout(aHandle); michael@0: } michael@0: michael@0: int32_t michael@0: WorkerGlobalScope::SetInterval(JSContext* aCx, michael@0: Function& aHandler, michael@0: const Optional& aTimeout, michael@0: const Sequence& aArguments, michael@0: ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0; michael@0: michael@0: return mWorkerPrivate->SetTimeout(aCx, &aHandler, EmptyString(), timeout, michael@0: aArguments, !!timeout, aRv); michael@0: } michael@0: michael@0: int32_t michael@0: WorkerGlobalScope::SetInterval(JSContext* /* unused */, michael@0: const nsAString& aHandler, michael@0: const Optional& aTimeout, michael@0: const Sequence& /* unused */, michael@0: ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: Sequence dummy; michael@0: michael@0: int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0; michael@0: michael@0: return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr, michael@0: aHandler, timeout, dummy, !!timeout, aRv); michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::ClearInterval(int32_t aHandle, ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: mWorkerPrivate->ClearTimeout(aHandle); michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: aRv = nsContentUtils::Atob(aAtob, aOutput); michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: aRv = nsContentUtils::Btoa(aBtoa, aOutput); michael@0: } michael@0: michael@0: void michael@0: WorkerGlobalScope::Dump(const Optional& aString) const michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: michael@0: if (!aString.WasPassed()) { michael@0: return; michael@0: } michael@0: michael@0: if (!mWorkerPrivate->DumpEnabled()) { michael@0: return; michael@0: } michael@0: michael@0: NS_ConvertUTF16toUTF8 str(aString.Value()); michael@0: michael@0: #ifdef ANDROID michael@0: __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get()); michael@0: #endif michael@0: fputs(str.get(), stdout); michael@0: fflush(stdout); michael@0: } michael@0: michael@0: DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate) michael@0: : WorkerGlobalScope(aWorkerPrivate) michael@0: { michael@0: } michael@0: michael@0: /* static */ bool michael@0: DedicatedWorkerGlobalScope::Visible(JSContext* aCx, JSObject* aObj) michael@0: { michael@0: DedicatedWorkerGlobalScope* self = nullptr; michael@0: nsresult rv = UNWRAP_WORKER_OBJECT(DedicatedWorkerGlobalScope, aObj, self); michael@0: return NS_SUCCEEDED(rv) && self; michael@0: } michael@0: michael@0: JSObject* michael@0: DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: MOZ_ASSERT(!mWorkerPrivate->IsSharedWorker()); michael@0: michael@0: JS::CompartmentOptions options; michael@0: mWorkerPrivate->CopyJSCompartmentOptions(options); michael@0: michael@0: // We're wrapping the global, so the scope is undefined. michael@0: JS::Rooted scope(aCx); michael@0: michael@0: return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, michael@0: options, michael@0: GetWorkerPrincipal()); michael@0: } michael@0: michael@0: void michael@0: DedicatedWorkerGlobalScope::PostMessage(JSContext* aCx, michael@0: JS::Handle aMessage, michael@0: const Optional>& aTransferable, michael@0: ErrorResult& aRv) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: mWorkerPrivate->PostMessageToParent(aCx, aMessage, aTransferable, aRv); michael@0: } michael@0: michael@0: SharedWorkerGlobalScope::SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, michael@0: const nsCString& aName) michael@0: : WorkerGlobalScope(aWorkerPrivate), mName(aName) michael@0: { michael@0: } michael@0: michael@0: /* static */ bool michael@0: SharedWorkerGlobalScope::Visible(JSContext* aCx, JSObject* aObj) michael@0: { michael@0: SharedWorkerGlobalScope* self = nullptr; michael@0: nsresult rv = UNWRAP_WORKER_OBJECT(SharedWorkerGlobalScope, aObj, self); michael@0: return NS_SUCCEEDED(rv) && self; michael@0: } michael@0: michael@0: JSObject* michael@0: SharedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx) michael@0: { michael@0: mWorkerPrivate->AssertIsOnWorkerThread(); michael@0: MOZ_ASSERT(mWorkerPrivate->IsSharedWorker()); michael@0: michael@0: JS::CompartmentOptions options; michael@0: mWorkerPrivate->CopyJSCompartmentOptions(options); michael@0: michael@0: // We're wrapping the global, so the scope is undefined. michael@0: JS::Rooted scope(aCx); michael@0: michael@0: return SharedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options, michael@0: GetWorkerPrincipal()); michael@0: } michael@0: michael@0: bool michael@0: GetterOnlyJSNative(JSContext* aCx, unsigned aArgc, JS::Value* aVp) michael@0: { michael@0: JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr, JSMSG_GETTER_ONLY); michael@0: return false; michael@0: } michael@0: michael@0: END_WORKERS_NAMESPACE