diff -r 000000000000 -r 6474c204b198 dom/workers/WorkerScope.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/workers/WorkerScope.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,359 @@ +/* -*- 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/EventListenerManager.h" +#include "mozilla/dom/FunctionBinding.h" +#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h" +#include "mozilla/dom/SharedWorkerGlobalScopeBinding.h" +#include "mozilla/dom/Console.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; +using namespace mozilla::dom; +USING_WORKERS_NAMESPACE + +BEGIN_WORKERS_NAMESPACE + +WorkerGlobalScope::WorkerGlobalScope(WorkerPrivate* aWorkerPrivate) +: mWorkerPrivate(aWorkerPrivate) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + SetIsDOMBinding(); +} + +WorkerGlobalScope::~WorkerGlobalScope() +{ + mWorkerPrivate->AssertIsOnWorkerThread(); +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerGlobalScope) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WorkerGlobalScope, + DOMEventTargetHelper) + tmp->mWorkerPrivate->AssertIsOnWorkerThread(); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WorkerGlobalScope, + DOMEventTargetHelper) + tmp->mWorkerPrivate->AssertIsOnWorkerThread(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(WorkerGlobalScope, + DOMEventTargetHelper) + tmp->mWorkerPrivate->AssertIsOnWorkerThread(); + + tmp->mWorkerPrivate->TraceTimeouts(aCallbacks, aClosure); +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_ADDREF_INHERITED(WorkerGlobalScope, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(WorkerGlobalScope, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerGlobalScope) + NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +JSObject* +WorkerGlobalScope::WrapObject(JSContext* aCx) +{ + MOZ_CRASH("We should never get here!"); +} + +already_AddRefed +WorkerGlobalScope::GetConsole() +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + if (!mConsole) { + mConsole = new Console(nullptr); + MOZ_ASSERT(mConsole); + } + + return mConsole.forget(); +} + +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(mWorkerPrivate->OnLine()); + MOZ_ASSERT(mNavigator); + } + + nsRefPtr navigator = mNavigator; + return navigator.forget(); +} + +already_AddRefed +WorkerGlobalScope::GetExistingNavigator() const +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr navigator = mNavigator; + return navigator.forget(); +} + +void +WorkerGlobalScope::Close(JSContext* aCx) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + mWorkerPrivate->CloseInternal(aCx); +} + +OnErrorEventHandlerNonNull* +WorkerGlobalScope::GetOnerror() +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + EventListenerManager* elm = GetExistingListenerManager(); + return elm ? elm->GetOnErrorEventHandler() : nullptr; +} + +void +WorkerGlobalScope::SetOnerror(OnErrorEventHandlerNonNull* aHandler) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + EventListenerManager* 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(JSContext* /* unused */, + const nsAString& aHandler, + const int32_t aTimeout, + const Sequence& /* unused */, + 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(JSContext* /* unused */, + const nsAString& aHandler, + const Optional& aTimeout, + const Sequence& /* unused */, + 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, 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 nsCString& 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, 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