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