mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 928312: Convert the worker global object and all remaining EventTargets to new DOM bindings. r=bent,peterv,smaug
This commit is contained in:
parent
f66e59b158
commit
2789485d96
@ -665,6 +665,7 @@ GK_ATOM(oncomplete, "oncomplete")
|
||||
GK_ATOM(oncompositionend, "oncompositionend")
|
||||
GK_ATOM(oncompositionstart, "oncompositionstart")
|
||||
GK_ATOM(oncompositionupdate, "oncompositionupdate")
|
||||
GK_ATOM(onconnect, "onconnect")
|
||||
GK_ATOM(onconnected, "onconnected")
|
||||
GK_ATOM(onconnecting, "onconnecting")
|
||||
GK_ATOM(oncontextmenu, "oncontextmenu")
|
||||
|
@ -4,6 +4,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDOMMessageEvent.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/MessagePortList.h"
|
||||
@ -55,6 +56,12 @@ nsDOMMessageEvent::~nsDOMMessageEvent()
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsDOMMessageEvent::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return mozilla::dom::MessageEventBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMessageEvent::GetData(JSContext* aCx, JS::Value* aData)
|
||||
{
|
||||
@ -148,7 +155,7 @@ nsDOMMessageEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
if (!event->mWindowSource) {
|
||||
MessagePort* port = nullptr;
|
||||
MessagePortBase* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, aCx, aParam.mSource, port);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_INVALID_ARG);
|
||||
@ -160,7 +167,7 @@ nsDOMMessageEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
|
||||
}
|
||||
|
||||
if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
|
||||
nsTArray<nsRefPtr<MessagePort> > ports;
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
|
||||
ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
|
||||
}
|
||||
@ -193,6 +200,13 @@ nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMessageEvent::SetPorts(mozilla::dom::MessagePortList* aPorts)
|
||||
{
|
||||
MOZ_ASSERT(!mPorts && aPorts);
|
||||
mPorts = aPorts;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewDOMMessageEvent(nsIDOMEvent** aInstancePtrResult,
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
|
@ -9,10 +9,12 @@
|
||||
#include "nsIDOMMessageEvent.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class MessageEventInit;
|
||||
class MessagePort;
|
||||
class MessagePortBase;
|
||||
class MessagePortList;
|
||||
class OwningWindowProxyOrMessagePort;
|
||||
}
|
||||
@ -44,10 +46,7 @@ public:
|
||||
NS_FORWARD_TO_NSDOMEVENT
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
|
||||
{
|
||||
return mozilla::dom::MessageEventBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv);
|
||||
|
||||
@ -58,6 +57,8 @@ public:
|
||||
return mPorts;
|
||||
}
|
||||
|
||||
void SetPorts(mozilla::dom::MessagePortList* aPorts);
|
||||
|
||||
static already_AddRefed<nsDOMMessageEvent>
|
||||
Constructor(const mozilla::dom::GlobalObject& aGlobal, JSContext* aCx,
|
||||
const nsAString& aType,
|
||||
@ -69,7 +70,7 @@ private:
|
||||
nsString mOrigin;
|
||||
nsString mLastEventId;
|
||||
nsCOMPtr<nsIDOMWindow> mWindowSource;
|
||||
nsCOMPtr<mozilla::dom::MessagePort> mPortSource;
|
||||
nsCOMPtr<mozilla::dom::MessagePortBase> mPortSource;
|
||||
nsRefPtr<mozilla::dom::MessagePortList> mPorts;
|
||||
};
|
||||
|
||||
|
@ -525,7 +525,8 @@ nsEventListenerManager::ListenerCanHandle(nsListenerStruct* aLs,
|
||||
}
|
||||
return aLs->mTypeString.Equals(aEvent->typeString);
|
||||
}
|
||||
MOZ_ASSERT(mIsMainThreadELM);
|
||||
MOZ_ASSERT_IF(aEvent->eventStructType != NS_SCRIPT_ERROR_EVENT,
|
||||
mIsMainThreadELM);
|
||||
return aLs->mEventType == aEvent->message;
|
||||
}
|
||||
|
||||
@ -596,6 +597,10 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
|
||||
aHandler, getter_AddRefs(scriptListener));
|
||||
|
||||
if (!aName && aTypeString.EqualsLiteral("error")) {
|
||||
eventType = NS_LOAD_ERROR;
|
||||
}
|
||||
|
||||
EventListenerHolder holder(scriptListener);
|
||||
AddEventListenerInternal(holder, eventType, aName, aTypeString, flags,
|
||||
true);
|
||||
@ -1245,17 +1250,28 @@ nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
|
||||
void
|
||||
nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
|
||||
{
|
||||
if (!aHandler) {
|
||||
RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
|
||||
return;
|
||||
}
|
||||
if (mIsMainThreadELM) {
|
||||
if (!aHandler) {
|
||||
RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Untrusted events are always permitted for non-chrome script
|
||||
// handlers.
|
||||
SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
|
||||
EmptyString(), nsEventHandler(aHandler),
|
||||
!mIsMainThreadELM ||
|
||||
!nsContentUtils::IsCallerChrome());
|
||||
// Untrusted events are always permitted for non-chrome script
|
||||
// handlers.
|
||||
SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
|
||||
EmptyString(), nsEventHandler(aHandler),
|
||||
!nsContentUtils::IsCallerChrome());
|
||||
} else {
|
||||
if (!aHandler) {
|
||||
RemoveEventHandler(nullptr, NS_LITERAL_STRING("error"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Untrusted events are always permitted.
|
||||
SetEventHandlerInternal(nullptr, JS::NullPtr(), nullptr,
|
||||
NS_LITERAL_STRING("error"),
|
||||
nsEventHandler(aHandler), true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -485,8 +485,12 @@ public:
|
||||
}
|
||||
mozilla::dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler()
|
||||
{
|
||||
const nsEventHandler* handler =
|
||||
GetEventHandlerInternal(nsGkAtoms::onerror, EmptyString());
|
||||
const nsEventHandler* handler;
|
||||
if (mIsMainThreadELM) {
|
||||
handler = GetEventHandlerInternal(nsGkAtoms::onerror, EmptyString());
|
||||
} else {
|
||||
handler = GetEventHandlerInternal(nullptr, NS_LITERAL_STRING("onerror"));
|
||||
}
|
||||
return handler ? handler->OnErrorEventHandler() : nullptr;
|
||||
}
|
||||
mozilla::dom::OnBeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler()
|
||||
|
@ -190,10 +190,14 @@ PostMessageWriteStructuredClone(JSContext* cx,
|
||||
}
|
||||
}
|
||||
|
||||
MessagePort* port = nullptr;
|
||||
MessagePortBase* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, cx, obj, port);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsRefPtr<MessagePort> newPort = port->Clone();
|
||||
nsRefPtr<MessagePortBase> newPort = port->Clone();
|
||||
|
||||
if (!newPort) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
|
||||
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
|
||||
@ -282,6 +286,17 @@ PostMessageRunnable::Run()
|
||||
return status ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow)
|
||||
: nsDOMEventTargetHelper(aWindow)
|
||||
{
|
||||
// SetIsDOMBinding() is called by nsDOMEventTargetHelper's ctor.
|
||||
}
|
||||
|
||||
MessagePortBase::MessagePortBase()
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
||||
@ -326,16 +341,14 @@ NS_IMPL_ADDREF_INHERITED(MessagePort, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MessagePort, nsDOMEventTargetHelper)
|
||||
|
||||
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
|
||||
: nsDOMEventTargetHelper(aWindow)
|
||||
: MessagePortBase(aWindow)
|
||||
, mMessageQueueEnabled(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MessagePort);
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
MessagePort::~MessagePort()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MessagePort);
|
||||
Close();
|
||||
}
|
||||
|
||||
@ -346,9 +359,9 @@ MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<JS::Handle<JS::Value> >& aTransfer,
|
||||
ErrorResult& aRv)
|
||||
MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<PostMessageRunnable> event = new PostMessageRunnable();
|
||||
|
||||
@ -359,9 +372,18 @@ MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
scInfo.mEvent = event;
|
||||
scInfo.mPort = this;
|
||||
|
||||
JS::Handle<JS::Value> transferable = aTransfer.WasPassed()
|
||||
? aTransfer.Value()
|
||||
: JS::UndefinedHandleValue;
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||
JSObject* array =
|
||||
JS_NewArrayObject(aCx, realTransferable.Length(),
|
||||
const_cast<JS::Value*>(realTransferable.Elements()));
|
||||
if (!array) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
transferable.setObject(*array);
|
||||
}
|
||||
|
||||
if (!buffer.write(aCx, aMessage, transferable, &kPostMessageCallbacks,
|
||||
&scInfo)) {
|
||||
@ -454,7 +476,7 @@ MessagePort::Entangle(MessagePort* aMessagePort)
|
||||
mEntangledPort = aMessagePort;
|
||||
}
|
||||
|
||||
already_AddRefed<MessagePort>
|
||||
already_AddRefed<MessagePortBase>
|
||||
MessagePort::Clone()
|
||||
{
|
||||
nsRefPtr<MessagePort> newPort = new MessagePort(nullptr);
|
||||
|
@ -7,7 +7,6 @@
|
||||
#define mozilla_dom_MessagePort_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
@ -18,14 +17,47 @@ namespace dom {
|
||||
class DispatchEventRunnable;
|
||||
class PostMessageRunnable;
|
||||
|
||||
class MessagePort MOZ_FINAL : public nsDOMEventTargetHelper
|
||||
class MessagePortBase : public nsDOMEventTargetHelper
|
||||
{
|
||||
protected:
|
||||
MessagePortBase(nsPIDOMWindow* aWindow);
|
||||
MessagePortBase();
|
||||
|
||||
public:
|
||||
|
||||
virtual void
|
||||
PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
virtual void
|
||||
Start() = 0;
|
||||
|
||||
virtual void
|
||||
Close() = 0;
|
||||
|
||||
// The 'message' event handler has to call |Start()| method, so we
|
||||
// cannot use IMPL_EVENT_HANDLER macro here.
|
||||
virtual EventHandlerNonNull*
|
||||
GetOnmessage() = 0;
|
||||
|
||||
virtual void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback) = 0;
|
||||
|
||||
// Duplicate this message port. This method is used by the Structured Clone
|
||||
// Algorithm and makes the new MessagePort active with the entangled
|
||||
// MessagePort of this object.
|
||||
virtual already_AddRefed<MessagePortBase>
|
||||
Clone() = 0;
|
||||
};
|
||||
|
||||
class MessagePort MOZ_FINAL : public MessagePortBase
|
||||
{
|
||||
friend class DispatchEventRunnable;
|
||||
friend class PostMessageRunnable;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
@ -35,24 +67,22 @@ public:
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<JS::Handle<JS::Value> >& aTransfer,
|
||||
ErrorResult& aRv);
|
||||
virtual void
|
||||
PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
Start();
|
||||
virtual void
|
||||
Start() MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
Close();
|
||||
virtual void
|
||||
Close() MOZ_OVERRIDE;
|
||||
|
||||
// The 'message' event handler has to call |Start()| method, so we
|
||||
// cannot use IMPL_EVENT_HANDLER macro here.
|
||||
EventHandlerNonNull*
|
||||
GetOnmessage();
|
||||
virtual EventHandlerNonNull*
|
||||
GetOnmessage() MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback);
|
||||
virtual void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
// Non WebIDL methods
|
||||
|
||||
@ -62,11 +92,8 @@ public:
|
||||
void
|
||||
Entangle(MessagePort* aMessagePort);
|
||||
|
||||
// Duplicate this message port. This method is used by the Structured Clone
|
||||
// Algorithm and makes the new MessagePort active with the entangled
|
||||
// MessagePort of this object.
|
||||
already_AddRefed<MessagePort>
|
||||
Clone();
|
||||
virtual already_AddRefed<MessagePortBase>
|
||||
Clone() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Dispatch events from the Message Queue using a nsRunnable.
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessagePortList)
|
||||
|
||||
public:
|
||||
MessagePortList(nsISupports* aOwner, nsTArray<nsRefPtr<MessagePort> >& aPorts)
|
||||
MessagePortList(nsISupports* aOwner, nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
|
||||
: mOwner(aOwner)
|
||||
, mPorts(aPorts)
|
||||
{
|
||||
@ -48,13 +48,13 @@ public:
|
||||
return mPorts.Length();
|
||||
}
|
||||
|
||||
MessagePort*
|
||||
MessagePortBase*
|
||||
Item(uint32_t aIndex)
|
||||
{
|
||||
return mPorts.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
MessagePort*
|
||||
MessagePortBase*
|
||||
IndexedGetter(uint32_t aIndex, bool &aFound)
|
||||
{
|
||||
aFound = aIndex < mPorts.Length();
|
||||
@ -66,7 +66,7 @@ public:
|
||||
|
||||
public:
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsTArray<nsRefPtr<MessagePort> > mPorts;
|
||||
nsTArray<nsRefPtr<MessagePortBase>> mPorts;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -172,7 +172,6 @@
|
||||
#include "GeneratedEvents.h"
|
||||
#include "GeneratedEventClasses.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
// so we can get logging even in release builds
|
||||
#define FORCE_PR_LOG 1
|
||||
@ -7477,7 +7476,7 @@ PostMessageReadStructuredClone(JSContext* cx,
|
||||
if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MESSAGEPORT) {
|
||||
NS_ASSERTION(!data, "Data should be empty");
|
||||
|
||||
MessagePort* port;
|
||||
MessagePortBase* port;
|
||||
if (JS_ReadBytes(reader, &port, sizeof(port))) {
|
||||
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
if (global) {
|
||||
@ -7531,10 +7530,14 @@ PostMessageWriteStructuredClone(JSContext* cx,
|
||||
}
|
||||
|
||||
if (MessageChannel::PrefEnabled()) {
|
||||
MessagePort* port = nullptr;
|
||||
MessagePortBase* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, cx, obj, port);
|
||||
if (NS_SUCCEEDED(rv) && scInfo->subsumes) {
|
||||
nsRefPtr<MessagePort> newPort = port->Clone();
|
||||
nsRefPtr<MessagePortBase> newPort = port->Clone();
|
||||
|
||||
if (!newPort) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
|
||||
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
|
||||
|
@ -15,16 +15,6 @@
|
||||
struct JSTracer;
|
||||
class XPCWrappedNativeScope;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
class DOMBindingBase;
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_WRAPPERCACHE_IID \
|
||||
{ 0x6f3179a1, 0x36f7, 0x4a5c, \
|
||||
{ 0x8c, 0xf1, 0xad, 0xc8, 0x7c, 0xde, 0x3e, 0x87 } }
|
||||
@ -60,8 +50,6 @@ class DOMBindingBase;
|
||||
*/
|
||||
class nsWrapperCache
|
||||
{
|
||||
friend class mozilla::dom::workers::DOMBindingBase;
|
||||
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID)
|
||||
|
||||
|
@ -24,12 +24,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638
|
||||
} catch(e) {
|
||||
ok(!what, "Should MessageChannel exist?");
|
||||
}
|
||||
try {
|
||||
status = MessagePort;
|
||||
ok(what, "Should MessagePort exist?");
|
||||
} catch(e) {
|
||||
ok(!what, "Should MessagePort exist?");
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -2153,11 +2153,39 @@ ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadsafeCheckIsChrome(JSContext* aCx, JSObject* aObj) {
|
||||
ThreadsafeCheckIsChrome(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
using mozilla::dom::workers::GetWorkerPrivateFromContext;
|
||||
return NS_IsMainThread() ? xpc::AccessCheck::isChrome(aObj):
|
||||
GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
|
||||
}
|
||||
|
||||
void
|
||||
TraceGlobal(JSTracer* aTrc, JSObject* aObj)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL);
|
||||
mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
|
||||
}
|
||||
|
||||
bool
|
||||
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
JS::MutableHandle<jsid> aId, unsigned aFlags,
|
||||
JS::MutableHandle<JSObject*> aObjp)
|
||||
{
|
||||
bool resolved;
|
||||
if (!JS_ResolveStandardClass(aCx, aObj, aId, &resolved)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aObjp.set(resolved ? aObj.get() : nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
|
||||
{
|
||||
return JS_EnumerateStandardClasses(aCx, aObj);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -2270,6 +2270,62 @@ public:
|
||||
bool
|
||||
ThreadsafeCheckIsChrome(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
void
|
||||
TraceGlobal(JSTracer* aTrc, JSObject* aObj);
|
||||
|
||||
bool
|
||||
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
|
||||
JS::MutableHandle<jsid> aId, unsigned aFlags,
|
||||
JS::MutableHandle<JSObject*> aObjp);
|
||||
|
||||
bool
|
||||
EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
|
||||
|
||||
template <class T, JS::Handle<JSObject*> (*ProtoGetter)(JSContext*,
|
||||
JS::Handle<JSObject*>)>
|
||||
JSObject*
|
||||
CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
|
||||
const JSClass* aClass, JS::CompartmentOptions& aOptions,
|
||||
JSPrincipals* aPrincipal)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx,
|
||||
JS_NewGlobalObject(aCx, aClass, aPrincipal, JS::DontFireOnNewGlobalHook,
|
||||
aOptions));
|
||||
if (!global) {
|
||||
NS_WARNING("Failed to create global");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
dom::AllocateProtoAndIfaceCache(global);
|
||||
|
||||
js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
|
||||
NS_ADDREF(aObject);
|
||||
|
||||
aCache->SetIsDOMBinding();
|
||||
aCache->SetWrapper(global);
|
||||
|
||||
/* Intl API is broken and makes this fail intermittently, see bug 934889.
|
||||
if (!JS_InitStandardClasses(aCx, global)) {
|
||||
NS_WARNING("Failed to init standard classes");
|
||||
return nullptr;
|
||||
}
|
||||
*/
|
||||
|
||||
JS::Handle<JSObject*> proto = ProtoGetter(aCx, global);
|
||||
NS_ENSURE_TRUE(proto, nullptr);
|
||||
|
||||
if (!JS_SetPrototype(aCx, global, proto)) {
|
||||
NS_WARNING("Failed to set proto");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -280,6 +280,11 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsDOMDataContainerEvent',
|
||||
},
|
||||
|
||||
'DedicatedWorkerGlobalScope': {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
'workers': True,
|
||||
},
|
||||
|
||||
'DelayNode': [
|
||||
{
|
||||
'resultNotAddRefed': [ 'delayTime' ],
|
||||
@ -365,38 +370,15 @@ DOMInterfaces = {
|
||||
]
|
||||
},
|
||||
|
||||
'Event': [
|
||||
{
|
||||
'Event': {
|
||||
'nativeType': 'nsDOMEvent',
|
||||
},
|
||||
{
|
||||
'nativeType': 'JSObject',
|
||||
'workers': True,
|
||||
'skipGen': True
|
||||
}],
|
||||
|
||||
'EventListener': [
|
||||
{
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'EventTarget': [
|
||||
{
|
||||
'EventTarget': {
|
||||
'hasXPConnectImpls': True,
|
||||
'concrete': False,
|
||||
'jsImplParent': 'nsDOMEventTargetHelper'
|
||||
},
|
||||
{
|
||||
'workers': True,
|
||||
'nativeOwnership': 'worker',
|
||||
'concrete': False,
|
||||
# XXXkhuey ownerGlobal returns WindowProxy? which boils down to a JSObject*
|
||||
# on a worker, and nsRefPtr<JSObject> fails in the expected way. This is
|
||||
# ugly but it's all going away soon anyways.
|
||||
'resultNotAddRefed': [
|
||||
'ownerGlobal'
|
||||
]
|
||||
}],
|
||||
|
||||
'Exception': {
|
||||
'headerFile': 'mozilla/dom/DOMException.h',
|
||||
@ -745,6 +727,14 @@ DOMInterfaces = {
|
||||
'nativeType': 'nsDOMMessageEvent',
|
||||
},
|
||||
|
||||
'MessagePort': {
|
||||
'nativeType': 'mozilla::dom::MessagePortBase',
|
||||
'headerFile': 'mozilla/dom/MessagePort.h',
|
||||
'binaryNames': {
|
||||
'postMessage': 'postMessageMoz',
|
||||
},
|
||||
},
|
||||
|
||||
'MimeType': {
|
||||
'headerFile' : 'nsMimeTypeArray.h',
|
||||
'nativeType': 'nsMimeType',
|
||||
@ -954,6 +944,11 @@ DOMInterfaces = {
|
||||
'implicitJSContext': [ 'constructor' ],
|
||||
},
|
||||
|
||||
'SharedWorkerGlobalScope': {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
'workers': True,
|
||||
},
|
||||
|
||||
'SimpleGestureEvent': {
|
||||
'nativeType': 'nsDOMSimpleGestureEvent',
|
||||
},
|
||||
@ -1463,29 +1458,20 @@ DOMInterfaces = {
|
||||
'customWrapperManagement': True,
|
||||
},
|
||||
|
||||
'WorkerGlobalScope': {
|
||||
'headerFile': 'mozilla/dom/WorkerScope.h',
|
||||
'workers': True,
|
||||
'concrete': False,
|
||||
'implicitJSContext': [
|
||||
'close', 'importScripts',
|
||||
],
|
||||
},
|
||||
|
||||
'WorkerLocation': {
|
||||
'headerFile': 'mozilla/dom/workers/bindings/Location.h',
|
||||
'workers': True,
|
||||
},
|
||||
|
||||
'WorkerMessagePort': [{
|
||||
'nativeType': 'mozilla::dom::workers::MessagePort',
|
||||
'headerFile': 'mozilla/dom/workers/bindings/MessagePort.h',
|
||||
'implicitJSContext': [ 'postMessage' ],
|
||||
'binaryNames': {
|
||||
'postMessage': 'postMessageMoz',
|
||||
},
|
||||
},
|
||||
{
|
||||
'nativeType': 'mozilla::dom::workers::WorkerMessagePort',
|
||||
'headerFile': 'mozilla/dom/workers/bindings/WorkerMessagePort.h',
|
||||
'workers': True,
|
||||
'nativeOwnership': 'worker',
|
||||
'binaryNames': {
|
||||
'postMessage': 'postMessageMoz',
|
||||
},
|
||||
}],
|
||||
|
||||
'WorkerNavigator': {
|
||||
'headerFile': 'mozilla/dom/workers/bindings/Navigator.h',
|
||||
'workers': True,
|
||||
@ -1499,7 +1485,6 @@ DOMInterfaces = {
|
||||
},
|
||||
{
|
||||
'workers': True,
|
||||
'nativeOwnership': 'worker',
|
||||
# XXXkhuey responseXML returns Document? which boils down to a JSObject*
|
||||
# on a worker, and nsRefPtr<JSObject> fails in the expected way. channel is
|
||||
# similar. This is ugly but it's all going away soon anyways.
|
||||
@ -1508,17 +1493,11 @@ DOMInterfaces = {
|
||||
]
|
||||
}],
|
||||
|
||||
'XMLHttpRequestEventTarget': [
|
||||
{
|
||||
'XMLHttpRequestEventTarget': {
|
||||
'nativeType': 'nsXHREventTarget',
|
||||
'headerFile': 'nsXMLHttpRequest.h',
|
||||
'concrete': False
|
||||
},
|
||||
{
|
||||
'workers': True,
|
||||
'nativeOwnership': 'worker',
|
||||
'concrete': False,
|
||||
}],
|
||||
|
||||
'XMLHttpRequestUpload': [
|
||||
{
|
||||
@ -1527,7 +1506,6 @@ DOMInterfaces = {
|
||||
},
|
||||
{
|
||||
'workers': True,
|
||||
'nativeOwnership': 'worker',
|
||||
}],
|
||||
|
||||
'XMLSerializer': {
|
||||
|
@ -63,7 +63,8 @@ def isTypeCopyConstructible(type):
|
||||
|
||||
def wantsAddProperty(desc):
|
||||
return desc.concrete and not desc.nativeOwnership == 'worker' and \
|
||||
desc.wrapperCache and not desc.customWrapperManagement
|
||||
desc.wrapperCache and not desc.customWrapperManagement and \
|
||||
not desc.interface.getExtendedAttribute("Global")
|
||||
|
||||
class CGThing():
|
||||
"""
|
||||
@ -152,19 +153,22 @@ def NativePropertyHooks(descriptor):
|
||||
return "&sWorkerNativePropertyHooks" if descriptor.workers else "sNativePropertyHooks"
|
||||
|
||||
def DOMClass(descriptor):
|
||||
protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
|
||||
# Pad out the list to the right length with _ID_Count so we
|
||||
# guarantee that all the lists are the same length. _ID_Count
|
||||
# is never the ID of any prototype, so it's safe to use as
|
||||
# padding.
|
||||
protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
|
||||
prototypeChainString = ', '.join(protoList)
|
||||
if descriptor.nativeOwnership == 'worker':
|
||||
participant = "nullptr"
|
||||
else:
|
||||
participant = "GetCCParticipant<%s>::Get()" % descriptor.nativeType
|
||||
getParentObject = "GetParentObject<%s>::Get" % descriptor.nativeType
|
||||
return """{
|
||||
def make_name(d):
|
||||
return "%s%s" % (d.interface.identifier.name, '_workers' if d.workers else '')
|
||||
|
||||
protoList = ['prototypes::id::' + make_name(descriptor.getDescriptor(proto)) for proto in descriptor.prototypeChain]
|
||||
# Pad out the list to the right length with _ID_Count so we
|
||||
# guarantee that all the lists are the same length. _ID_Count
|
||||
# is never the ID of any prototype, so it's safe to use as
|
||||
# padding.
|
||||
protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
|
||||
prototypeChainString = ', '.join(protoList)
|
||||
if descriptor.nativeOwnership == 'worker':
|
||||
participant = "nullptr"
|
||||
else:
|
||||
participant = "GetCCParticipant<%s>::Get()" % descriptor.nativeType
|
||||
getParentObject = "GetParentObject<%s>::Get" % descriptor.nativeType
|
||||
return """{
|
||||
{ %s },
|
||||
IsBaseOf<nsISupports, %s >::value,
|
||||
%s,
|
||||
@ -188,11 +192,20 @@ class CGDOMJSClass(CGThing):
|
||||
def define(self):
|
||||
traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'nullptr'
|
||||
callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
|
||||
classFlags = "JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(3)"
|
||||
classFlags = "JSCLASS_IS_DOMJSCLASS | "
|
||||
if self.descriptor.interface.getExtendedAttribute("Global"):
|
||||
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
|
||||
traceHook = "mozilla::dom::TraceGlobal"
|
||||
else:
|
||||
classFlags += "JSCLASS_HAS_RESERVED_SLOTS(3)"
|
||||
if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
|
||||
newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
|
||||
classFlags += " | JSCLASS_NEW_RESOLVE"
|
||||
enumerateHook = ENUMERATE_HOOK_NAME
|
||||
elif self.descriptor.interface.getExtendedAttribute("Global"):
|
||||
newResolveHook = "(JSResolveOp) mozilla::dom::ResolveGlobal"
|
||||
classFlags += " | JSCLASS_NEW_RESOLVE"
|
||||
enumerateHook = "mozilla::dom::EnumerateGlobal"
|
||||
else:
|
||||
newResolveHook = "JS_ResolveStub"
|
||||
enumerateHook = "JS_EnumerateStub"
|
||||
@ -1790,8 +1803,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
|
||||
self.properties = properties
|
||||
def definition_body(self):
|
||||
protoChain = self.descriptor.prototypeChain
|
||||
if len(protoChain) == 1:
|
||||
if len(self.descriptor.prototypeChain) == 1:
|
||||
parentProtoType = "Rooted"
|
||||
if self.descriptor.interface.getExtendedAttribute("ArrayClass"):
|
||||
getParentProto = "aCx, JS_GetArrayPrototype(aCx, aGlobal)"
|
||||
@ -1799,6 +1811,9 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
getParentProto = "aCx, JS_GetObjectPrototype(aCx, aGlobal)"
|
||||
else:
|
||||
parentProtoName = self.descriptor.prototypeChain[-2]
|
||||
parentDesc = self.descriptor.getDescriptor(parentProtoName)
|
||||
if parentDesc.workers:
|
||||
parentProtoName += '_workers'
|
||||
getParentProto = ("%s::GetProtoObject(aCx, aGlobal)" %
|
||||
toBindingNamespace(parentProtoName))
|
||||
parentProtoType = "Handle"
|
||||
@ -1809,7 +1824,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
parentWithInterfaceObject = parentWithInterfaceObject.parent
|
||||
if parentWithInterfaceObject:
|
||||
parentIfaceName = parentWithInterfaceObject.identifier.name
|
||||
if self.descriptor.workers:
|
||||
parentDesc = self.descriptor.getDescriptor(parentIfaceName)
|
||||
if parentDesc.workers:
|
||||
parentIfaceName += "_workers"
|
||||
getConstructorProto = ("%s::GetConstructorObject(aCx, aGlobal)" %
|
||||
toBindingNamespace(parentIfaceName))
|
||||
@ -2365,6 +2381,47 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
|
||||
"global"),
|
||||
InitUnforgeableProperties(self.descriptor, self.properties))
|
||||
|
||||
class CGWrapGlobalMethod(CGAbstractMethod):
|
||||
"""
|
||||
Create a wrapper JSObject for a global. The global must implement
|
||||
nsWrapperCache.
|
||||
|
||||
properties should be a PropertyArrays instance.
|
||||
"""
|
||||
def __init__(self, descriptor, properties):
|
||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||
args = [Argument('JSContext*', 'aCx'),
|
||||
Argument('JS::Handle<JSObject*>', 'aScope'),
|
||||
Argument(descriptor.nativeType + '*', 'aObject'),
|
||||
Argument('nsWrapperCache*', 'aCache'),
|
||||
Argument('JS::CompartmentOptions&', 'aOptions'),
|
||||
Argument('JSPrincipals*', 'aPrincipal')]
|
||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
|
||||
self.descriptor = descriptor
|
||||
self.properties = properties
|
||||
|
||||
def definition_body(self):
|
||||
return """%s
|
||||
MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache),
|
||||
"nsISupports must be on our primary inheritance chain");
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx);
|
||||
obj = CreateGlobal<%s, GetProtoObject>(aCx,
|
||||
aObject,
|
||||
aCache,
|
||||
&Class.mBase,
|
||||
aOptions,
|
||||
aPrincipal);
|
||||
|
||||
%s
|
||||
|
||||
// XXXkhuey can't do this yet until workers can lazy resolve.
|
||||
// JS_FireOnNewGlobalObject(aCx, obj);
|
||||
|
||||
return obj;""" % (AssertInheritanceChain(self.descriptor),
|
||||
self.descriptor.nativeType,
|
||||
InitUnforgeableProperties(self.descriptor, self.properties))
|
||||
|
||||
builtinNames = {
|
||||
IDLType.Tags.bool: 'bool',
|
||||
IDLType.Tags.int8: 'int8_t',
|
||||
@ -5628,10 +5685,11 @@ class CGLegacyCallHook(CGAbstractBindingMethod):
|
||||
|
||||
class CGNewResolveHook(CGAbstractBindingMethod):
|
||||
"""
|
||||
NewResolve hook for our object
|
||||
NewResolve hook for objects with custom hooks.
|
||||
"""
|
||||
def __init__(self, descriptor):
|
||||
assert descriptor.interface.getExtendedAttribute("NeedNewResolve")
|
||||
|
||||
args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'obj'),
|
||||
Argument('JS::Handle<jsid>', 'id'), Argument('unsigned', 'flags'),
|
||||
Argument('JS::MutableHandle<JSObject*>', 'objp')]
|
||||
@ -5657,10 +5715,11 @@ class CGNewResolveHook(CGAbstractBindingMethod):
|
||||
|
||||
class CGEnumerateHook(CGAbstractBindingMethod):
|
||||
"""
|
||||
Enumerate hook for our object
|
||||
Enumerate hook for objects with custom hooks.
|
||||
"""
|
||||
def __init__(self, descriptor):
|
||||
assert descriptor.interface.getExtendedAttribute("NeedNewResolve")
|
||||
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'obj')]
|
||||
# Our "self" is actually the "obj" argument in this case, not the thisval.
|
||||
@ -8246,7 +8305,10 @@ class CGDescriptor(CGThing):
|
||||
cgThings.append(CGDOMJSClass(descriptor))
|
||||
cgThings.append(CGGetJSClassMethod(descriptor))
|
||||
|
||||
if descriptor.wrapperCache:
|
||||
if descriptor.interface.getExtendedAttribute("Global"):
|
||||
assert descriptor.wrapperCache
|
||||
cgThings.append(CGWrapGlobalMethod(descriptor, properties))
|
||||
elif descriptor.wrapperCache:
|
||||
cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
|
||||
cgThings.append(CGWrapMethod(descriptor))
|
||||
else:
|
||||
|
@ -165,6 +165,10 @@ class Configuration:
|
||||
if d.workers == workers:
|
||||
return d
|
||||
|
||||
if workers:
|
||||
for d in self.descriptorsByName[interfaceName]:
|
||||
return d
|
||||
|
||||
raise NoSuchDescriptorError("For " + interfaceName + " found no matches");
|
||||
def getDescriptorProvider(self, workers):
|
||||
"""
|
||||
@ -414,7 +418,7 @@ class Descriptor(DescriptorProvider):
|
||||
self.prototypeChain = []
|
||||
parent = interface
|
||||
while parent:
|
||||
self.prototypeChain.insert(0, make_name(parent.identifier.name))
|
||||
self.prototypeChain.insert(0, parent.identifier.name)
|
||||
parent = parent.parent
|
||||
config.maxProtoChainLength = max(config.maxProtoChainLength,
|
||||
len(self.prototypeChain))
|
||||
|
@ -167,7 +167,7 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mHandler.Type() == nsEventHandler::eOnError) {
|
||||
MOZ_ASSERT(mEventName == nsGkAtoms::onerror);
|
||||
MOZ_ASSERT_IF(mEventName, mEventName == nsGkAtoms::onerror);
|
||||
|
||||
nsString errorMsg, file;
|
||||
EventOrString msgOrEvent;
|
||||
|
@ -329,6 +329,7 @@ var interfaceNamesInGlobalScope =
|
||||
"MediaStreamEvent",
|
||||
"MediaStreamTrack",
|
||||
"MessageEvent",
|
||||
"MessagePort",
|
||||
"MimeType",
|
||||
"MimeTypeArray",
|
||||
"ModalContentWindow",
|
||||
|
21
dom/webidl/DedicatedWorkerGlobalScope.webidl
Normal file
21
dom/webidl/DedicatedWorkerGlobalScope.webidl
Normal file
@ -0,0 +1,21 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#the-workerglobalscope-common-interface
|
||||
*
|
||||
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera
|
||||
* Software ASA.
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
|
||||
[Global, Func="mozilla::dom::workers::DedicatedWorkerGlobalScope::Visible"]
|
||||
interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<any> transfer);
|
||||
|
||||
attribute EventHandler onmessage;
|
||||
};
|
@ -41,7 +41,6 @@ interface MessageEvent : Event {
|
||||
* the similarly-named method on the nsIDOMEvent interface, also setting the
|
||||
* data, origin, source, and lastEventId attributes of this appropriately.
|
||||
*/
|
||||
[Pref="dom.messageChannel.enabled"]
|
||||
readonly attribute MessagePortList? ports;
|
||||
};
|
||||
|
||||
|
@ -7,11 +7,9 @@
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
|
||||
*/
|
||||
|
||||
[Pref="dom.messageChannel.enabled"]
|
||||
interface MessagePort : EventTarget {
|
||||
// TODO void postMessage(any message, optional sequence<Transferable> transfer);
|
||||
[Throws]
|
||||
void postMessage(any message, optional any transfer);
|
||||
void postMessage(any message, optional sequence<Transferable> transferable);
|
||||
|
||||
void start();
|
||||
void close();
|
||||
|
@ -7,7 +7,7 @@
|
||||
[PrefControlled,
|
||||
Constructor(DOMString scriptURL, optional DOMString name)]
|
||||
interface SharedWorker : EventTarget {
|
||||
readonly attribute WorkerMessagePort port;
|
||||
readonly attribute MessagePort port;
|
||||
};
|
||||
|
||||
SharedWorker implements AbstractWorker;
|
||||
|
19
dom/webidl/SharedWorkerGlobalScope.webidl
Normal file
19
dom/webidl/SharedWorkerGlobalScope.webidl
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#the-workerglobalscope-common-interface
|
||||
*
|
||||
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera
|
||||
* Software ASA.
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
|
||||
[Global, Func="mozilla::dom::workers::SharedWorkerGlobalScope::Visible"]
|
||||
interface SharedWorkerGlobalScope : WorkerGlobalScope {
|
||||
readonly attribute DOMString name;
|
||||
attribute EventHandler onconnect;
|
||||
};
|
40
dom/webidl/WorkerGlobalScope.webidl
Normal file
40
dom/webidl/WorkerGlobalScope.webidl
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#the-workerglobalscope-common-interface
|
||||
*
|
||||
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera
|
||||
* Software ASA.
|
||||
* You are granted a license to use, reproduce and create derivative works of
|
||||
* this document.
|
||||
*/
|
||||
|
||||
interface WorkerGlobalScope : EventTarget {
|
||||
readonly attribute WorkerGlobalScope self;
|
||||
readonly attribute WorkerLocation location;
|
||||
|
||||
void close();
|
||||
attribute OnErrorEventHandler onerror;
|
||||
|
||||
// also has additional members in a partial interface
|
||||
};
|
||||
|
||||
partial interface WorkerGlobalScope {
|
||||
[Throws]
|
||||
void importScripts(DOMString... urls);
|
||||
|
||||
readonly attribute WorkerNavigator navigator;
|
||||
};
|
||||
|
||||
WorkerGlobalScope implements WindowTimers;
|
||||
WorkerGlobalScope implements WindowBase64;
|
||||
|
||||
// Mozilla extensions
|
||||
partial interface WorkerGlobalScope {
|
||||
attribute EventHandler onclose;
|
||||
|
||||
void dump(optional DOMString str);
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
// XXX Remove me soon!
|
||||
[PrefControlled]
|
||||
interface WorkerMessagePort : EventTarget {
|
||||
[Throws]
|
||||
void postMessage(any message, optional sequence<any> transferable);
|
||||
|
||||
void start();
|
||||
|
||||
void close();
|
||||
|
||||
[SetterThrows=Workers, GetterThrows=Workers]
|
||||
attribute EventHandler onmessage;
|
||||
};
|
@ -57,7 +57,6 @@ dictionary MozXMLHttpRequestParameters
|
||||
Constructor(DOMString ignored)]
|
||||
interface XMLHttpRequest : XMLHttpRequestEventTarget {
|
||||
// event handler
|
||||
[SetterThrows=Workers, GetterThrows=Workers]
|
||||
attribute EventHandler onreadystatechange;
|
||||
|
||||
// states
|
||||
|
@ -67,6 +67,7 @@ WEBIDL_FILES = [
|
||||
'CSSValueList.webidl',
|
||||
'DataContainerEvent.webidl',
|
||||
'DataStore.webidl',
|
||||
'DedicatedWorkerGlobalScope.webidl',
|
||||
'DelayNode.webidl',
|
||||
'DesktopNotification.webidl',
|
||||
'DeviceMotionEvent.webidl',
|
||||
@ -272,6 +273,7 @@ WEBIDL_FILES = [
|
||||
'ScrollAreaEvent.webidl',
|
||||
'SettingsManager.webidl',
|
||||
'SharedWorker.webidl',
|
||||
'SharedWorkerGlobalScope.webidl',
|
||||
'SimpleGestureEvent.webidl',
|
||||
'SourceBuffer.webidl',
|
||||
'SourceBufferList.webidl',
|
||||
@ -415,10 +417,9 @@ WEBIDL_FILES = [
|
||||
'WebSocket.webidl',
|
||||
'WheelEvent.webidl',
|
||||
'WifiOptions.webidl',
|
||||
'Window.webidl',
|
||||
'Worker.webidl',
|
||||
'WorkerGlobalScope.webidl',
|
||||
'WorkerLocation.webidl',
|
||||
'WorkerMessagePort.webidl',
|
||||
'WorkerNavigator.webidl',
|
||||
'XMLDocument.webidl',
|
||||
'XMLHttpRequest.webidl',
|
||||
|
@ -1,79 +0,0 @@
|
||||
/* -*- 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 "DOMBindingBase.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
DOMBindingBase::DOMBindingBase(JSContext* aCx)
|
||||
: mJSContext(aCx)
|
||||
{
|
||||
if (!aCx) {
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
}
|
||||
|
||||
DOMBindingBase::~DOMBindingBase()
|
||||
{
|
||||
if (!mJSContext) {
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(DOMBindingBase)
|
||||
NS_IMPL_RELEASE(DOMBindingBase)
|
||||
NS_INTERFACE_MAP_BEGIN(DOMBindingBase)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
void
|
||||
DOMBindingBase::_trace(JSTracer* aTrc)
|
||||
{
|
||||
TraceJSObject(aTrc, "cached wrapper");
|
||||
}
|
||||
|
||||
void
|
||||
DOMBindingBase::_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
ClearWrapper();
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
JSContext*
|
||||
DOMBindingBase::GetJSContext() const {
|
||||
return mJSContext ? mJSContext : nsContentUtils::GetCurrentJSContext();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JSObject*
|
||||
DOMBindingBase::GetJSObject() const
|
||||
{
|
||||
// Make sure that the public method results in the same bits as our private
|
||||
// method.
|
||||
MOZ_ASSERT(GetWrapperJSObject() == GetWrapperPreserveColor());
|
||||
return GetWrapperJSObject();
|
||||
}
|
||||
|
||||
void
|
||||
DOMBindingBase::SetJSObject(JSObject* aObject)
|
||||
{
|
||||
// Make sure that the public method results in the same bits as our private
|
||||
// method.
|
||||
SetWrapper(aObject);
|
||||
|
||||
uint8_t oldFlags = mFlags;
|
||||
|
||||
SetWrapperJSObject(aObject);
|
||||
|
||||
MOZ_ASSERT(oldFlags == mFlags && aObject == mWrapper);
|
||||
}
|
||||
#endif
|
@ -1,137 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_dombindingbase_h__
|
||||
#define mozilla_dom_workers_dombindingbase_h__
|
||||
|
||||
#include "mozilla/dom/workers/Workers.h"
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
#define BINDING_ENSURE_TRUE(_cond, _result, _retval) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!(_cond)) { \
|
||||
NS_WARNING("BINDING_ENSURE failed!"); \
|
||||
aRv = _result; \
|
||||
return _retval; \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
#define BINDING_ENSURE_SUCCESS(_cond, _result, _retval) \
|
||||
BINDING_ENSURE_TRUE(NS_SUCCEEDED(_cond), _result, _retval)
|
||||
|
||||
class DOMBindingBase : public nsWrapperCache,
|
||||
public nsISupports
|
||||
{
|
||||
JSContext* mJSContext;
|
||||
|
||||
protected:
|
||||
DOMBindingBase(JSContext* aCx);
|
||||
virtual ~DOMBindingBase();
|
||||
|
||||
virtual void
|
||||
_trace(JSTracer* aTrc);
|
||||
|
||||
virtual void
|
||||
_finalize(JSFreeOp* aFop);
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
JSContext*
|
||||
GetJSContext() const;
|
||||
|
||||
void
|
||||
TraceJSObject(JSTracer* aTrc, const char* aName)
|
||||
{
|
||||
if (GetJSObject()) {
|
||||
TraceWrapperJSObject(aTrc, aName);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
JSObject*
|
||||
GetJSObject() const;
|
||||
|
||||
void
|
||||
SetJSObject(JSObject* aObject);
|
||||
#else
|
||||
JSObject*
|
||||
GetJSObject() const
|
||||
{
|
||||
return GetWrapperJSObject();
|
||||
}
|
||||
|
||||
void
|
||||
SetJSObject(JSObject* aObject)
|
||||
{
|
||||
SetWrapperJSObject(aObject);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DOMBindingAnchor
|
||||
{
|
||||
T* mBinding;
|
||||
JS::Anchor<JSObject*> mAnchor;
|
||||
|
||||
public:
|
||||
DOMBindingAnchor()
|
||||
: mBinding(nullptr)
|
||||
{ }
|
||||
|
||||
DOMBindingAnchor(T* aBinding)
|
||||
{
|
||||
*this = aBinding;
|
||||
}
|
||||
|
||||
DOMBindingAnchor&
|
||||
operator=(T* aBinding)
|
||||
{
|
||||
mBinding = aBinding;
|
||||
|
||||
if (aBinding) {
|
||||
JSObject* obj = aBinding->GetJSObject();
|
||||
MOZ_ASSERT(obj);
|
||||
|
||||
mAnchor.set(obj);
|
||||
}
|
||||
else {
|
||||
mAnchor.clear();
|
||||
}
|
||||
}
|
||||
|
||||
T*
|
||||
get() const
|
||||
{
|
||||
return const_cast<T*>(mBinding);
|
||||
}
|
||||
|
||||
T*
|
||||
operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
operator T*() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
private:
|
||||
DOMBindingAnchor(const DOMBindingAnchor& aOther) MOZ_DELETE;
|
||||
|
||||
DOMBindingAnchor&
|
||||
operator=(const DOMBindingAnchor& aOther) MOZ_DELETE;
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_dombindingbase_h__
|
@ -1,96 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_dombindinginlines_h__
|
||||
#define mozilla_dom_workers_dombindinginlines_h__
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/dom/JSSlots.h"
|
||||
#include "mozilla/dom/URLBinding.h"
|
||||
#include "mozilla/dom/WorkerMessagePortBinding.h"
|
||||
#include "mozilla/dom/XMLHttpRequestBinding.h"
|
||||
#include "mozilla/dom/XMLHttpRequestUploadBinding.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class URL;
|
||||
class WorkerMessagePort;
|
||||
class XMLHttpRequest;
|
||||
class XMLHttpRequestUpload;
|
||||
|
||||
namespace {
|
||||
|
||||
template <class T>
|
||||
struct WrapPrototypeTraits
|
||||
{ };
|
||||
|
||||
// XXX I kinda hate this, but we decided it wasn't worth generating this in the
|
||||
// binding headers.
|
||||
#define SPECIALIZE_PROTO_TRAITS(_class) \
|
||||
template <> \
|
||||
struct WrapPrototypeTraits<_class> \
|
||||
{ \
|
||||
static inline const JSClass* \
|
||||
GetJSClass() \
|
||||
{ \
|
||||
using namespace mozilla::dom; \
|
||||
return _class##Binding_workers::GetJSClass(); \
|
||||
} \
|
||||
\
|
||||
static inline JSObject* \
|
||||
GetProtoObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal) \
|
||||
{ \
|
||||
using namespace mozilla::dom; \
|
||||
return _class##Binding_workers::GetProtoObject(aCx, aGlobal); \
|
||||
} \
|
||||
};
|
||||
|
||||
SPECIALIZE_PROTO_TRAITS(URL)
|
||||
SPECIALIZE_PROTO_TRAITS(WorkerMessagePort)
|
||||
SPECIALIZE_PROTO_TRAITS(XMLHttpRequest)
|
||||
SPECIALIZE_PROTO_TRAITS(XMLHttpRequestUpload)
|
||||
|
||||
#undef SPECIALIZE_PROTO_TRAITS
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
template <class T>
|
||||
inline JSObject*
|
||||
Wrap(JSContext* aCx, JSObject* aGlobal, nsRefPtr<T>& aConcreteObject)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
if (!aGlobal) {
|
||||
aGlobal = JS::CurrentGlobalOrNull(aCx);
|
||||
if (!aGlobal) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, aGlobal);
|
||||
JSObject* proto = WrapPrototypeTraits<T>::GetProtoObject(aCx, global);
|
||||
if (!proto) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* wrapper =
|
||||
JS_NewObject(aCx, WrapPrototypeTraits<T>::GetJSClass(), proto, global);
|
||||
if (!wrapper) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
js::SetReservedSlot(wrapper, DOM_OBJECT_SLOT,
|
||||
PRIVATE_TO_JSVAL(aConcreteObject));
|
||||
|
||||
aConcreteObject->SetIsDOMBinding();
|
||||
aConcreteObject->SetWrapper(wrapper);
|
||||
|
||||
NS_ADDREF(aConcreteObject.get());
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_dombindinginlines_h__
|
@ -1,429 +0,0 @@
|
||||
/* -*- 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 "EventListenerManager.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/Tracer.h"
|
||||
#include "js/Vector.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsAutoJSValHolder.h"
|
||||
|
||||
#include "Events.h"
|
||||
#include "EventTarget.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla;
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
struct ListenerData;
|
||||
|
||||
struct EventListenerManager::ListenerCollection :
|
||||
public LinkedListElement<EventListenerManager::ListenerCollection>
|
||||
{
|
||||
jsid mTypeId;
|
||||
LinkedList<ListenerData> mListeners;
|
||||
|
||||
static ListenerCollection*
|
||||
Add(JSContext* aCx, LinkedList<ListenerCollection>& aCollections, jsid aTypeId)
|
||||
{
|
||||
ListenerCollection* collection =
|
||||
static_cast<ListenerCollection*>(JS_malloc(aCx,
|
||||
sizeof(ListenerCollection)));
|
||||
if (!collection) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new (collection) ListenerCollection(aTypeId);
|
||||
aCollections.insertBack(collection);
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
static void
|
||||
Remove(JSContext* aCx, ListenerCollection* aCollection)
|
||||
{
|
||||
aCollection->remove();
|
||||
MOZ_ASSERT(aCollection->mListeners.isEmpty());
|
||||
JS_free(aCx, aCollection);
|
||||
}
|
||||
|
||||
private:
|
||||
ListenerCollection(jsid aTypeId)
|
||||
: mTypeId(aTypeId)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ListenerData : LinkedListElement<ListenerData>
|
||||
{
|
||||
JS::Heap<JSObject*> mListener;
|
||||
EventListenerManager::Phase mPhase;
|
||||
bool mWantsUntrusted;
|
||||
|
||||
static ListenerData*
|
||||
Add(JSContext* aCx, LinkedList<ListenerData>& aListeners, JSObject* aListener,
|
||||
EventListenerManager::Phase aPhase, bool aWantsUntrusted)
|
||||
{
|
||||
ListenerData* listenerData =
|
||||
static_cast<ListenerData*>(JS_malloc(aCx, sizeof(ListenerData)));
|
||||
if (!listenerData) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new (listenerData) ListenerData(aListener, aPhase, aWantsUntrusted);
|
||||
aListeners.insertBack(listenerData);
|
||||
return listenerData;
|
||||
}
|
||||
|
||||
static void
|
||||
Remove(JSContext* aCx, ListenerData* aListenerData)
|
||||
{
|
||||
if (JS::IsIncrementalBarrierNeeded(aCx)) {
|
||||
JS::IncrementalObjectBarrier(aListenerData->mListener);
|
||||
}
|
||||
|
||||
aListenerData->remove();
|
||||
JS_free(aCx, aListenerData);
|
||||
}
|
||||
|
||||
private:
|
||||
ListenerData(JSObject* aListener, EventListenerManager::Phase aPhase,
|
||||
bool aWantsUntrusted)
|
||||
: mListener(aListener),
|
||||
mPhase(aPhase),
|
||||
mWantsUntrusted(aWantsUntrusted)
|
||||
{}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
inline void
|
||||
DestroyList(JSFreeOp* aFop, LinkedList<T>& aList)
|
||||
{
|
||||
while (!aList.isEmpty()) {
|
||||
T* elem = aList.popFirst();
|
||||
JS_freeop(aFop, elem);
|
||||
}
|
||||
}
|
||||
|
||||
inline EventListenerManager::ListenerCollection*
|
||||
GetCollectionForType(const LinkedList<EventListenerManager::ListenerCollection>& aList,
|
||||
const jsid& aTypeId)
|
||||
{
|
||||
for (const EventListenerManager::ListenerCollection* collection = aList.getFirst();
|
||||
collection;
|
||||
collection = collection->getNext()) {
|
||||
if (collection->mTypeId == aTypeId) {
|
||||
// We need to either cast away const here or write a second copy of this
|
||||
// method that takes a non-const LinkedList
|
||||
return const_cast<EventListenerManager::ListenerCollection*>(collection);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
class ContextAllocPolicy
|
||||
{
|
||||
JSContext* const mCx;
|
||||
|
||||
public:
|
||||
ContextAllocPolicy(JSContext* aCx)
|
||||
: mCx(aCx)
|
||||
{ }
|
||||
|
||||
void*
|
||||
malloc_(size_t aBytes) const
|
||||
{
|
||||
JSAutoRequest ar(mCx);
|
||||
return JS_malloc(mCx, aBytes);
|
||||
}
|
||||
|
||||
void*
|
||||
realloc_(void* aPtr, size_t aOldBytes, size_t aBytes) const
|
||||
{
|
||||
JSAutoRequest ar(mCx);
|
||||
return JS_realloc(mCx, aPtr, aBytes);
|
||||
}
|
||||
|
||||
void
|
||||
free_(void* aPtr) const
|
||||
{
|
||||
JS_free(mCx, aPtr);
|
||||
}
|
||||
|
||||
void
|
||||
reportAllocOverflow() const
|
||||
{
|
||||
JS_ReportAllocationOverflow(mCx);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
#ifdef DEBUG
|
||||
EventListenerManager::~EventListenerManager()
|
||||
{
|
||||
MOZ_ASSERT(mCollections.isEmpty());
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
EventListenerManager::TraceInternal(JSTracer* aTrc) const
|
||||
{
|
||||
MOZ_ASSERT(!mCollections.isEmpty());
|
||||
|
||||
for (const ListenerCollection* collection = mCollections.getFirst();
|
||||
collection;
|
||||
collection = collection->getNext()) {
|
||||
|
||||
for (const ListenerData* listenerElem = collection->mListeners.getFirst();
|
||||
listenerElem;
|
||||
listenerElem = listenerElem->getNext()) {
|
||||
JS_CallHeapObjectTracer(aTrc,
|
||||
&const_cast<ListenerData*>(listenerElem)->mListener,
|
||||
"EventListenerManager listener object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::FinalizeInternal(JSFreeOp* aFop)
|
||||
{
|
||||
MOZ_ASSERT(!mCollections.isEmpty());
|
||||
|
||||
for (ListenerCollection* collection = mCollections.getFirst();
|
||||
collection;
|
||||
collection = collection->getNext()) {
|
||||
DestroyList(aFop, collection->mListeners);
|
||||
}
|
||||
|
||||
DestroyList(aFop, mCollections);
|
||||
|
||||
MOZ_ASSERT(mCollections.isEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::Add(JSContext* aCx, const jsid& aType,
|
||||
JS::Handle<JSObject*> aListener, Phase aPhase,
|
||||
bool aWantsUntrusted, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aListener);
|
||||
|
||||
ListenerCollection* collection =
|
||||
GetCollectionForType(mCollections, aType);
|
||||
if (!collection) {
|
||||
collection = ListenerCollection::Add(aCx, mCollections, aType);
|
||||
if (!collection) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (ListenerData* listenerData = collection->mListeners.getFirst();
|
||||
listenerData;
|
||||
listenerData = listenerData->getNext()) {
|
||||
if (listenerData->mListener == aListener &&
|
||||
listenerData->mPhase == aPhase) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ListenerData* listenerData =
|
||||
ListenerData::Add(aCx, collection->mListeners,
|
||||
aListener, aPhase, aWantsUntrusted);
|
||||
if (!listenerData) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerManager::Remove(JSContext* aCx, const jsid& aType,
|
||||
JS::Handle<JSObject*> aListener, Phase aPhase,
|
||||
bool aClearEmpty)
|
||||
{
|
||||
MOZ_ASSERT(aListener);
|
||||
|
||||
ListenerCollection* collection =
|
||||
GetCollectionForType(mCollections, aType);
|
||||
if (collection) {
|
||||
for (ListenerData* listenerData = collection->mListeners.getFirst();
|
||||
listenerData;
|
||||
listenerData = listenerData->getNext()) {
|
||||
if (listenerData->mListener == aListener &&
|
||||
listenerData->mPhase == aPhase) {
|
||||
ListenerData::Remove(aCx, listenerData);
|
||||
if (aClearEmpty && collection->mListeners.isEmpty()) {
|
||||
ListenerCollection::Remove(aCx, collection);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
EventListenerManager::GetEventListener(const jsid& aType) const
|
||||
{
|
||||
const ListenerCollection* collection =
|
||||
GetCollectionForType(mCollections, aType);
|
||||
if (collection) {
|
||||
for (const ListenerData* listenerData = collection->mListeners.getFirst();
|
||||
listenerData;
|
||||
listenerData = listenerData->getNext()) {
|
||||
if (listenerData->mPhase == Onfoo) {
|
||||
return listenerData->mListener;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
EventListenerManager::DispatchEvent(JSContext* aCx, const EventTarget& aTarget,
|
||||
JSObject* event, ErrorResult& aRv) const
|
||||
{
|
||||
JS::Rooted<JSObject*> aEvent(aCx, event);
|
||||
using namespace mozilla::dom::workers::events;
|
||||
|
||||
if (!IsSupportedEventClass(aEvent)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
if (!JS_GetProperty(aCx, aEvent, "target", &val)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JSVAL_IS_NULL(val)) {
|
||||
// Already has a target, must be recursively dispatched. Throw.
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mCollections.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSString*> eventType(aCx);
|
||||
bool eventIsTrusted;
|
||||
|
||||
if (!JS_GetProperty(aCx, aEvent, "type", &val) ||
|
||||
!(eventType = JS_ValueToString(aCx, val)) ||
|
||||
!(eventType = JS_InternJSString(aCx, eventType))) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have already ensure that the event is one of our types of events so
|
||||
// there is no need to worry about this property being faked.
|
||||
if (!JS_GetProperty(aCx, aEvent, "isTrusted", &val) ||
|
||||
!JS_ValueToBoolean(aCx, val, &eventIsTrusted)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
ListenerCollection* collection =
|
||||
GetCollectionForType(mCollections, INTERNED_STRING_TO_JSID(aCx, eventType));
|
||||
if (!collection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::AutoValueVector listeners(aCx);
|
||||
for (ListenerData* listenerData = collection->mListeners.getFirst();
|
||||
listenerData;
|
||||
listenerData = listenerData->getNext()) {
|
||||
// Listeners that don't want untrusted events will be skipped if this is an
|
||||
// untrusted event.
|
||||
if (eventIsTrusted || listenerData->mWantsUntrusted) {
|
||||
if (!listeners.append(OBJECT_TO_JSVAL(listenerData->mListener))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (listeners.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetEventTarget(aEvent, aTarget.GetJSObject());
|
||||
|
||||
for (size_t index = 0; index < listeners.length(); index++) {
|
||||
if (EventImmediatePropagationStopped(aEvent)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// If anything fails in here we want to report the exception and continue on
|
||||
// to the next listener rather than bailing out. If something fails and
|
||||
// does not set an exception then we bail out entirely as we've either run
|
||||
// out of memory or the operation callback has indicated that we should
|
||||
// stop running.
|
||||
|
||||
JS::Rooted<JS::Value> listenerVal(aCx, listeners[index]);
|
||||
|
||||
JS::Rooted<JSObject*> listenerObj(aCx);
|
||||
if (!JS_ValueToObject(aCx, listenerVal, &listenerObj)) {
|
||||
if (!JS_ReportPendingException(aCx)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
static const char sHandleEventChars[] = "handleEvent";
|
||||
|
||||
JS::Rooted<JSObject*> thisObj(aCx, aTarget.GetJSObject());
|
||||
|
||||
bool hasHandleEvent;
|
||||
if (!JS_HasProperty(aCx, listenerObj, sHandleEventChars, &hasHandleEvent)) {
|
||||
if (!JS_ReportPendingException(aCx)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasHandleEvent) {
|
||||
if (!JS_GetProperty(aCx, listenerObj, sHandleEventChars, &listenerVal)) {
|
||||
if (!JS_ReportPendingException(aCx)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
thisObj = listenerObj;
|
||||
}
|
||||
|
||||
jsval argv[] = { OBJECT_TO_JSVAL(aEvent) };
|
||||
JS::Rooted<JS::Value> rval(aCx);
|
||||
if (!JS_CallFunctionValue(aCx, thisObj, listenerVal, ArrayLength(argv),
|
||||
argv, rval.address())) {
|
||||
if (!JS_ReportPendingException(aCx)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return EventWasCanceled(aEvent);
|
||||
}
|
||||
|
||||
bool
|
||||
EventListenerManager::HasListenersForTypeInternal(JSContext* aCx,
|
||||
const jsid& aType) const
|
||||
{
|
||||
MOZ_ASSERT(!mCollections.isEmpty());
|
||||
return !!GetCollectionForType(mCollections, aType);
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_listenermanager_h__
|
||||
#define mozilla_dom_workers_listenermanager_h__
|
||||
|
||||
#include "mozilla/dom/workers/Workers.h"
|
||||
|
||||
#include "mozilla/LinkedList.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class EventTarget;
|
||||
|
||||
// XXX Current impl doesn't divide into phases.
|
||||
// XXX Current impl doesn't handle event target chains.
|
||||
class EventListenerManager
|
||||
{
|
||||
public:
|
||||
struct ListenerCollection;
|
||||
|
||||
private:
|
||||
LinkedList<ListenerCollection> mCollections;
|
||||
|
||||
public:
|
||||
EventListenerManager()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
~EventListenerManager();
|
||||
#endif
|
||||
|
||||
void
|
||||
_trace(JSTracer* aTrc) const
|
||||
{
|
||||
if (!mCollections.isEmpty()) {
|
||||
TraceInternal(aTrc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
if (!mCollections.isEmpty()) {
|
||||
FinalizeInternal(aFop);
|
||||
}
|
||||
}
|
||||
|
||||
enum Phase
|
||||
{
|
||||
All = 0,
|
||||
Capturing,
|
||||
Onfoo,
|
||||
Bubbling
|
||||
};
|
||||
|
||||
void
|
||||
AddEventListener(JSContext* aCx, const jsid& aType,
|
||||
JS::Handle<JSObject*> aListener,
|
||||
bool aCapturing, bool aWantsUntrusted, ErrorResult& aRv)
|
||||
{
|
||||
Add(aCx, aType, aListener, aCapturing ? Capturing : Bubbling,
|
||||
aWantsUntrusted, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
RemoveEventListener(JSContext* aCx, const jsid& aType,
|
||||
JS::Handle<JSObject*> aListener, bool aCapturing)
|
||||
{
|
||||
if (mCollections.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Remove(aCx, aType, aListener, aCapturing ? Capturing : Bubbling, true);
|
||||
}
|
||||
|
||||
bool
|
||||
DispatchEvent(JSContext* aCx, const EventTarget& aTarget, JSObject* aEvent,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
JSObject*
|
||||
GetEventListener(const jsid& aType) const;
|
||||
|
||||
void
|
||||
SetEventListener(JSContext* aCx, const jsid& aType,
|
||||
JS::Handle<JSObject*> aListener,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
JS::Rooted<JSObject*> existing(aCx, GetEventListener(aType));
|
||||
if (existing) {
|
||||
Remove(aCx, aType, existing, Onfoo, false);
|
||||
}
|
||||
|
||||
if (aListener) {
|
||||
Add(aCx, aType, aListener, Onfoo, false, aRv);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HasListeners() const
|
||||
{
|
||||
return !mCollections.isEmpty();
|
||||
}
|
||||
|
||||
bool
|
||||
HasListenersForType(JSContext* aCx, const jsid& aType) const
|
||||
{
|
||||
return HasListeners() && HasListenersForTypeInternal(aCx, aType);
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
TraceInternal(JSTracer* aTrc) const;
|
||||
|
||||
void
|
||||
FinalizeInternal(JSFreeOp* aFop);
|
||||
|
||||
void
|
||||
Add(JSContext* aCx, const jsid& aType, JS::Handle<JSObject*> aListener,
|
||||
Phase aPhase, bool aWantsUntrusted, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Remove(JSContext* aCx, const jsid& aType, JS::Handle<JSObject*> aListener,
|
||||
Phase aPhase, bool aClearEmpty);
|
||||
|
||||
bool
|
||||
HasListenersForTypeInternal(JSContext* aCx, const jsid& aType) const;
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif /* mozilla_dom_workers_listenermanager_h__ */
|
@ -1,119 +0,0 @@
|
||||
/* -*- 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 "EventTarget.h"
|
||||
#include "mozilla/dom/EventListenerBinding.h"
|
||||
#include "mozilla/dom/EventHandlerBinding.h"
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
using mozilla::ErrorResult;
|
||||
using mozilla::dom::EventListener;
|
||||
using mozilla::dom::Nullable;
|
||||
using mozilla::dom::EventHandlerNonNull;
|
||||
|
||||
void
|
||||
EventTarget::_trace(JSTracer* aTrc)
|
||||
{
|
||||
mListenerManager._trace(aTrc);
|
||||
DOMBindingBase::_trace(aTrc);
|
||||
}
|
||||
|
||||
void
|
||||
EventTarget::_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
mListenerManager._finalize(aFop);
|
||||
DOMBindingBase::_finalize(aFop);
|
||||
}
|
||||
|
||||
already_AddRefed<EventHandlerNonNull>
|
||||
EventTarget::GetEventListener(const nsAString& aType, ErrorResult& aRv) const
|
||||
{
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
JS::RootedString type(cx,
|
||||
JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
|
||||
if (!type || !(type = JS_InternJSString(cx, type))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS::RootedObject listener(
|
||||
cx, mListenerManager.GetEventListener(INTERNED_STRING_TO_JSID(cx, type)));
|
||||
if (!listener) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<EventHandlerNonNull> handler = new EventHandlerNonNull(listener);
|
||||
return handler.forget();
|
||||
}
|
||||
|
||||
void
|
||||
EventTarget::SetEventListener(const nsAString& aType,
|
||||
EventHandlerNonNull* aListener,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
JS::RootedString type(cx,
|
||||
JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
|
||||
if (!type || !(type = JS_InternJSString(cx, type))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::RootedObject listener(cx);
|
||||
if (aListener) {
|
||||
listener = aListener->Callable();
|
||||
}
|
||||
mListenerManager.SetEventListener(cx, INTERNED_STRING_TO_JSID(cx, type),
|
||||
listener, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
EventTarget::AddEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aCapturing, Nullable<bool> aWantsUntrusted,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!aListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
JS::RootedString type(cx,
|
||||
JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
|
||||
if (!type || !(type = JS_InternJSString(cx, type))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
bool wantsUntrusted = !aWantsUntrusted.IsNull() && aWantsUntrusted.Value();
|
||||
mListenerManager.AddEventListener(cx, INTERNED_STRING_TO_JSID(cx, type),
|
||||
aListener->Callback(), aCapturing,
|
||||
wantsUntrusted, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
EventTarget::RemoveEventListener(const nsAString& aType,
|
||||
EventListener* aListener,
|
||||
bool aCapturing, ErrorResult& aRv)
|
||||
{
|
||||
if (!aListener) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
JS::RootedString type(cx,
|
||||
JS_NewUCStringCopyN(cx, aType.BeginReading(), aType.Length()));
|
||||
if (!type || !(type = JS_InternJSString(cx, type))) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
mListenerManager.RemoveEventListener(cx, INTERNED_STRING_TO_JSID(cx, type),
|
||||
aListener->Callback(), aCapturing);
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_eventtarget_h__
|
||||
#define mozilla_dom_workers_eventtarget_h__
|
||||
|
||||
#include "mozilla/dom/workers/bindings/DOMBindingBase.h"
|
||||
|
||||
// I hate having to export this...
|
||||
#include "mozilla/dom/workers/bindings/EventListenerManager.h"
|
||||
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class EventListener;
|
||||
class EventHandlerNonNull;
|
||||
} // namespace mozilla
|
||||
} // namespace dom
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class EventTarget : public DOMBindingBase
|
||||
{
|
||||
EventListenerManager mListenerManager;
|
||||
|
||||
protected:
|
||||
EventTarget(JSContext* aCx)
|
||||
: DOMBindingBase(aCx)
|
||||
{ }
|
||||
|
||||
virtual ~EventTarget()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual void
|
||||
_trace(JSTracer* aTrc) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
_finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
AddEventListener(const nsAString& aType, EventListener* aListener,
|
||||
bool aCapture, Nullable<bool> aWantsUntrusted,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
RemoveEventListener(const nsAString& aType, EventListener* aListener,
|
||||
bool aCapture, ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
DispatchEvent(JS::Handle<JSObject*> aEvent, ErrorResult& aRv) const
|
||||
{
|
||||
return mListenerManager.DispatchEvent(GetJSContext(), *this, aEvent, aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<EventHandlerNonNull>
|
||||
GetEventListener(const nsAString& aType, ErrorResult& aRv) const;
|
||||
|
||||
void
|
||||
SetEventListener(const nsAString& aType, EventHandlerNonNull* aListener,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
HasListeners() const
|
||||
{
|
||||
return mListenerManager.HasListeners();
|
||||
}
|
||||
|
||||
void SetEventHandler(const nsAString& aType, EventHandlerNonNull* aHandler,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
GetEventHandler(const nsAString& aType)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* GetOwnerGlobal() const
|
||||
{
|
||||
// We have no windows
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_eventtarget_h__
|
File diff suppressed because it is too large
Load Diff
@ -1,61 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_events_h__
|
||||
#define mozilla_dom_workers_events_h__
|
||||
|
||||
#include "Workers.h"
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
namespace events {
|
||||
|
||||
bool
|
||||
InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal, bool aMainRuntime);
|
||||
|
||||
JSObject*
|
||||
CreateGenericEvent(JSContext* aCx, JS::Handle<JSString*> aType, bool aBubbles,
|
||||
bool aCancelable, bool aMainRuntime);
|
||||
|
||||
JSObject*
|
||||
CreateMessageEvent(JSContext* aCx, JSAutoStructuredCloneBuffer& aData,
|
||||
nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
|
||||
bool aMainRuntime);
|
||||
|
||||
JSObject*
|
||||
CreateErrorEvent(JSContext* aCx, JS::Handle<JSString*> aMessage,
|
||||
JS::Handle<JSString*> aFilename,
|
||||
uint32_t aLineNumber, bool aMainRuntime);
|
||||
|
||||
JSObject*
|
||||
CreateProgressEvent(JSContext* aCx, JS::Handle<JSString*> aType,
|
||||
bool aLengthComputable, double aLoaded, double aTotal);
|
||||
|
||||
JSObject*
|
||||
CreateConnectEvent(JSContext* aCx, JS::Handle<JSObject*> aMessagePort);
|
||||
|
||||
bool
|
||||
IsSupportedEventClass(JSObject* aEvent);
|
||||
|
||||
void
|
||||
SetEventTarget(JSObject* aEvent, JSObject* aTarget);
|
||||
|
||||
bool
|
||||
EventWasCanceled(JSObject* aEvent);
|
||||
|
||||
bool
|
||||
EventImmediatePropagationStopped(JSObject* aEvent);
|
||||
|
||||
bool
|
||||
DispatchEventToTarget(JSContext* aCx, JS::Handle<JSObject*> aTarget,
|
||||
JS::Handle<JSObject*> aEvent, bool* aPreventDefaultCalled);
|
||||
|
||||
} // namespace events
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_events_h__
|
@ -15,8 +15,7 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerLocation, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerLocation, Release)
|
||||
|
||||
/* static */ already_AddRefed<WorkerLocation>
|
||||
WorkerLocation::Create(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
|
||||
WorkerPrivate::LocationInfo& aInfo)
|
||||
WorkerLocation::Create(WorkerPrivate::LocationInfo& aInfo)
|
||||
{
|
||||
nsRefPtr<WorkerLocation> location =
|
||||
new WorkerLocation(NS_ConvertUTF8toUTF16(aInfo.mHref),
|
||||
|
@ -50,8 +50,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WorkerLocation)
|
||||
|
||||
static already_AddRefed<WorkerLocation>
|
||||
Create(JSContext* aCx, JS::Handle<JSObject*> aGlobal,
|
||||
WorkerPrivate::LocationInfo& aInfo);
|
||||
Create(WorkerPrivate::LocationInfo& aInfo);
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
@ -5,12 +5,15 @@
|
||||
|
||||
#include "MessagePort.h"
|
||||
|
||||
#include "mozilla/dom/WorkerMessagePortBinding.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
using mozilla::dom::EventHandlerNonNull;
|
||||
using mozilla::dom::MessagePortBase;
|
||||
using mozilla::dom::Optional;
|
||||
using mozilla::dom::Sequence;
|
||||
|
||||
@ -18,72 +21,81 @@ USING_WORKERS_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
class DelayedEventRunnable MOZ_FINAL : public nsIRunnable
|
||||
class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable
|
||||
{
|
||||
nsRefPtr<MessagePort> mMessagePort;
|
||||
nsCOMPtr<nsIDOMEvent> mEvent;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
|
||||
|
||||
public:
|
||||
DelayedEventRunnable(MessagePort* aMessagePort,
|
||||
already_AddRefed<nsIDOMEvent> aEvent)
|
||||
: mMessagePort(aMessagePort), mEvent(aEvent)
|
||||
DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
Target aTarget,
|
||||
MessagePort* aMessagePort,
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
|
||||
: WorkerRunnable(aWorkerPrivate, aTarget,
|
||||
aTarget == WorkerThread ? ModifyBusyCount : UnchangedBusyCount,
|
||||
SkipWhenClearing),
|
||||
mMessagePort(aMessagePort)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aMessagePort);
|
||||
MOZ_ASSERT(aEvent.get());
|
||||
MOZ_ASSERT(aEvents.Length());
|
||||
|
||||
mEvents.SwapElements(aEvents);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
|
||||
uint64_t aSerial)
|
||||
: nsDOMEventTargetHelper(aWindow), mSharedWorker(aSharedWorker),
|
||||
mSerial(aSerial), mStarted(false)
|
||||
: MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
|
||||
mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial)
|
||||
: mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
MessagePort::~MessagePort()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
MessagePort::PrefEnabled()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// Currently tied to the SharedWorker preference.
|
||||
return SharedWorker::PrefEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::PostMessageMoz(JSContext* aCx, JS::HandleValue aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertCorrectThread();
|
||||
|
||||
if (IsClosed()) {
|
||||
aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
|
||||
if (mSharedWorker) {
|
||||
mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
|
||||
}
|
||||
else {
|
||||
mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage,
|
||||
aTransferable, aRv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::Start()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertCorrectThread();
|
||||
|
||||
if (IsClosed()) {
|
||||
NS_WARNING("Called start() after calling close()!");
|
||||
@ -97,21 +109,34 @@ MessagePort::Start()
|
||||
mStarted = true;
|
||||
|
||||
if (!mQueuedEvents.IsEmpty()) {
|
||||
for (uint32_t index = 0; index < mQueuedEvents.Length(); index++) {
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new DelayedEventRunnable(this, mQueuedEvents[index].forget());
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
|
||||
NS_WARNING("Failed to dispatch queued event!");
|
||||
}
|
||||
WorkerRunnable::Target target = WorkerRunnable::WorkerThread;
|
||||
WorkerPrivate* workerPrivate = mWorkerPrivate;
|
||||
|
||||
if (!workerPrivate) {
|
||||
target = WorkerRunnable::ParentThread;
|
||||
workerPrivate = mSharedWorker->GetWorkerPrivate();
|
||||
}
|
||||
mQueuedEvents.Clear();
|
||||
|
||||
nsRefPtr<DelayedEventRunnable> runnable =
|
||||
new DelayedEventRunnable(workerPrivate, target, this, mQueuedEvents);
|
||||
runnable->Dispatch(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::Close()
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
if (!IsClosed()) {
|
||||
CloseInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::QueueEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertCorrectThread();
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT(!IsClosed());
|
||||
MOZ_ASSERT(!mStarted);
|
||||
@ -119,10 +144,41 @@ MessagePort::QueueEvent(nsIDOMEvent* aEvent)
|
||||
mQueuedEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
MessagePort::GetOnmessage()
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString())
|
||||
: GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
|
||||
}
|
||||
else {
|
||||
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
|
||||
}
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
already_AddRefed<MessagePortBase>
|
||||
MessagePort::Clone()
|
||||
{
|
||||
NS_WARNING("Haven't implemented structured clone for these ports yet!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::CloseInternal()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertCorrectThread();
|
||||
MOZ_ASSERT(!IsClosed());
|
||||
MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty());
|
||||
|
||||
@ -133,8 +189,29 @@ MessagePort::CloseInternal()
|
||||
}
|
||||
|
||||
mSharedWorker = nullptr;
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
MessagePort::AssertCorrectThread() const
|
||||
{
|
||||
if (IsClosed()) {
|
||||
return; // Can't assert anything if we nulled out our pointers.
|
||||
}
|
||||
|
||||
MOZ_ASSERT((mSharedWorker || mWorkerPrivate) &&
|
||||
!(mSharedWorker && mWorkerPrivate));
|
||||
|
||||
if (mSharedWorker) {
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
else {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MessagePort, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MessagePort, nsDOMEventTargetHelper)
|
||||
|
||||
@ -157,15 +234,15 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
JSObject*
|
||||
MessagePort::WrapObject(JSContext* aCx, JS::HandleObject aScope)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertCorrectThread();
|
||||
|
||||
return WorkerMessagePortBinding::Wrap(aCx, aScope, this);
|
||||
return MessagePortBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MessagePort::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertCorrectThread();
|
||||
|
||||
nsIDOMEvent*& event = aVisitor.mDOMEvent;
|
||||
|
||||
@ -174,7 +251,7 @@ MessagePort::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
|
||||
if (IsClosed()) {
|
||||
preventDispatch = true;
|
||||
} else if (mSharedWorker->IsSuspended()) {
|
||||
} else if (NS_IsMainThread() && mSharedWorker->IsSuspended()) {
|
||||
mSharedWorker->QueueEvent(event);
|
||||
preventDispatch = true;
|
||||
} else if (!mStarted) {
|
||||
@ -192,18 +269,17 @@ MessagePort::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
||||
return nsDOMEventTargetHelper::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DelayedEventRunnable, nsIRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DelayedEventRunnable::Run()
|
||||
bool
|
||||
DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mMessagePort);
|
||||
MOZ_ASSERT(mEvent);
|
||||
mMessagePort->AssertCorrectThread();
|
||||
MOZ_ASSERT(mEvents.Length());
|
||||
|
||||
bool ignored;
|
||||
nsresult rv = mMessagePort->DispatchEvent(mEvent, &ignored);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (uint32_t i = 0; i < mEvents.Length(); i++) {
|
||||
mMessagePort->DispatchEvent(mEvents[i], &ignored);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return true;
|
||||
}
|
||||
|
@ -8,8 +8,9 @@
|
||||
|
||||
#include "Workers.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
|
||||
class nsIDOMEvent;
|
||||
class nsPIDOMWindow;
|
||||
@ -17,14 +18,17 @@ class nsPIDOMWindow;
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class SharedWorker;
|
||||
class WorkerPrivate;
|
||||
|
||||
class MessagePort MOZ_FINAL : public nsDOMEventTargetHelper
|
||||
class MessagePort MOZ_FINAL : public mozilla::dom::MessagePortBase
|
||||
{
|
||||
friend class SharedWorker;
|
||||
friend class WorkerPrivate;
|
||||
|
||||
typedef mozilla::ErrorResult ErrorResult;
|
||||
|
||||
nsRefPtr<SharedWorker> mSharedWorker;
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mQueuedEvents;
|
||||
uint64_t mSerial;
|
||||
bool mStarted;
|
||||
@ -33,23 +37,16 @@ public:
|
||||
static bool
|
||||
PrefEnabled();
|
||||
|
||||
void
|
||||
virtual void
|
||||
PostMessageMoz(JSContext* aCx, JS::HandleValue aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
ErrorResult& aRv) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
Start();
|
||||
virtual void
|
||||
Start() MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
Close()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!IsClosed()) {
|
||||
CloseInternal();
|
||||
}
|
||||
}
|
||||
virtual void
|
||||
Close() MOZ_OVERRIDE;
|
||||
|
||||
uint64_t
|
||||
Serial() const
|
||||
@ -63,30 +60,19 @@ public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, nsDOMEventTargetHelper)
|
||||
|
||||
EventHandlerNonNull*
|
||||
GetOnmessage()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
virtual EventHandlerNonNull*
|
||||
GetOnmessage() MOZ_OVERRIDE;
|
||||
|
||||
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
|
||||
}
|
||||
virtual void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
|
||||
|
||||
Start();
|
||||
}
|
||||
virtual already_AddRefed<MessagePortBase>
|
||||
Clone() MOZ_OVERRIDE;
|
||||
|
||||
bool
|
||||
IsClosed() const
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
return !mSharedWorker;
|
||||
return !mSharedWorker && !mWorkerPrivate;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
@ -95,10 +81,19 @@ public:
|
||||
virtual nsresult
|
||||
PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertCorrectThread() const;
|
||||
#else
|
||||
void
|
||||
AssertCorrectThread() const { }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// This class can only be created by SharedWorker.
|
||||
// This class can only be created by SharedWorker or WorkerPrivate.
|
||||
MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
|
||||
uint64_t aSerial);
|
||||
MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial);
|
||||
|
||||
// This class is reference-counted and will be destroyed from Release().
|
||||
~MessagePort();
|
||||
|
@ -17,7 +17,7 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
|
||||
|
||||
/* static */ already_AddRefed<WorkerNavigator>
|
||||
WorkerNavigator::Create(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
|
||||
WorkerNavigator::Create()
|
||||
{
|
||||
RuntimeService* rts = RuntimeService::GetService();
|
||||
MOZ_ASSERT(rts);
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WorkerNavigator)
|
||||
|
||||
static already_AddRefed<WorkerNavigator>
|
||||
Create(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
||||
Create();
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
80
dom/workers/RegisterBindings.cpp
Normal file
80
dom/workers/RegisterBindings.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
/* -*- 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 "WorkerPrivate.h"
|
||||
#include "ChromeWorkerScope.h"
|
||||
#include "File.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMExceptionBinding.h"
|
||||
#include "mozilla/dom/EventBinding.h"
|
||||
#include "mozilla/dom/EventHandlerBinding.h"
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "mozilla/dom/FileReaderSyncBinding.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ImageDataBinding.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/TextDecoderBinding.h"
|
||||
#include "mozilla/dom/TextEncoderBinding.h"
|
||||
#include "mozilla/dom/XMLHttpRequestBinding.h"
|
||||
#include "mozilla/dom/XMLHttpRequestUploadBinding.h"
|
||||
#include "mozilla/dom/URLBinding.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/WorkerLocationBinding.h"
|
||||
#include "mozilla/dom/WorkerNavigatorBinding.h"
|
||||
#include "mozilla/OSFileConstants.h"
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
using namespace mozilla::dom;
|
||||
|
||||
bool
|
||||
WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
|
||||
{
|
||||
JS::Rooted<JSObject*> eventTargetProto(aCx,
|
||||
EventTargetBinding::GetProtoObject(aCx, aGlobal));
|
||||
if (!eventTargetProto) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsChromeWorker()) {
|
||||
if (!ChromeWorkerBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!DefineChromeWorkerFunctions(aCx, aGlobal) ||
|
||||
!DefineOSFileConstants(aCx, aGlobal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Init other classes we care about.
|
||||
if (!file::InitClasses(aCx, aGlobal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init other paris-bindings.
|
||||
if (!DOMExceptionBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!EventBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!FileReaderSyncBinding_workers::GetConstructorObject(aCx, aGlobal) ||
|
||||
!ImageDataBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!MessageEventBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!MessagePortBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!TextDecoderBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!TextEncoderBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!XMLHttpRequestBinding_workers::GetConstructorObject(aCx, aGlobal) ||
|
||||
!XMLHttpRequestUploadBinding_workers::GetConstructorObject(aCx, aGlobal) ||
|
||||
!URLBinding_workers::GetConstructorObject(aCx, aGlobal) ||
|
||||
!WorkerBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!WorkerLocationBinding_workers::GetConstructorObject(aCx, aGlobal) ||
|
||||
!WorkerNavigatorBinding_workers::GetConstructorObject(aCx, aGlobal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!JS_DefineProfilingFunctions(aCx, aGlobal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -49,7 +49,6 @@
|
||||
#include "OSFileConstants.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "Events.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
|
@ -891,41 +891,32 @@ LoadWorkerScript(JSContext* aCx)
|
||||
return LoadAllScripts(aCx, worker, loadInfos, true);
|
||||
}
|
||||
|
||||
bool
|
||||
Load(JSContext* aCx, unsigned aURLCount, jsval* aURLs)
|
||||
void
|
||||
Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
const Sequence<nsString>& aScriptURLs, ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
|
||||
NS_ASSERTION(worker, "This should never be null!");
|
||||
const uint32_t urlCount = aScriptURLs.Length();
|
||||
|
||||
if (!aURLCount) {
|
||||
return true;
|
||||
if (!urlCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aURLCount > MAX_CONCURRENT_SCRIPTS) {
|
||||
JS_ReportError(aCx, "Cannot load more than %d scripts at one time!",
|
||||
MAX_CONCURRENT_SCRIPTS);
|
||||
return false;
|
||||
if (urlCount > MAX_CONCURRENT_SCRIPTS) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<ScriptLoadInfo> loadInfos;
|
||||
loadInfos.SetLength(uint32_t(aURLCount));
|
||||
loadInfos.SetLength(urlCount);
|
||||
|
||||
for (unsigned index = 0; index < aURLCount; index++) {
|
||||
JSString* str = JS_ValueToString(aCx, aURLs[index]);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length;
|
||||
const jschar* buffer = JS_GetStringCharsAndLength(aCx, str, &length);
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
loadInfos[index].mURL.Assign(buffer, length);
|
||||
for (uint32_t index = 0; index < urlCount; index++) {
|
||||
loadInfos[index].mURL = aScriptURLs[index];
|
||||
}
|
||||
|
||||
return LoadAllScripts(aCx, worker, loadInfos, false);
|
||||
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false)) {
|
||||
// LoadAllScripts can fail if we're shutting down.
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace scriptloader
|
||||
|
@ -14,6 +14,18 @@ class nsIDocument;
|
||||
class nsString;
|
||||
class nsIChannel;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
template <typename T>
|
||||
class Sequence;
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
namespace scriptloader {
|
||||
@ -36,7 +48,10 @@ void ReportLoadError(JSContext* aCx, const nsAString& aURL,
|
||||
|
||||
bool LoadWorkerScript(JSContext* aCx);
|
||||
|
||||
bool Load(JSContext* aCx, unsigned aURLCount, jsval* aURLs);
|
||||
void Load(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
const mozilla::dom::Sequence<nsString>& aScriptURLs,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
} // namespace scriptloader
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "Workers.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/workers/bindings/MessagePort.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
|
||||
class nsIDOMEvent;
|
||||
@ -81,6 +82,12 @@ public:
|
||||
virtual nsresult
|
||||
PreHandleEvent(nsEventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
|
||||
WorkerPrivate*
|
||||
GetWorkerPrivate() const
|
||||
{
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
||||
private:
|
||||
// This class can only be created from the RuntimeService.
|
||||
SharedWorker(nsPIDOMWindow* aWindow,
|
||||
|
@ -1,225 +0,0 @@
|
||||
/* -*- 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 "WorkerMessagePort.h"
|
||||
|
||||
#include "DOMBindingInlines.h"
|
||||
#include "Events.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
using mozilla::dom::Optional;
|
||||
using mozilla::dom::Sequence;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
using namespace mozilla::dom::workers::events;
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
DispatchMessageEvent(JSContext* aCx, JS::HandleObject aMessagePort,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
||||
{
|
||||
MOZ_ASSERT(aMessagePort);
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
aBuffer.swap(buffer);
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
||||
aClonedObjects.SwapElements(clonedObjects);
|
||||
|
||||
JS::Rooted<JSObject*> event(aCx,
|
||||
CreateMessageEvent(aCx, buffer, clonedObjects, false));
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dummy;
|
||||
return DispatchEventToTarget(aCx, aMessagePort, event, &dummy);
|
||||
}
|
||||
|
||||
|
||||
class QueuedMessageEventRunnable : public WorkerRunnable
|
||||
{
|
||||
JSAutoStructuredCloneBuffer mBuffer;
|
||||
nsTArray<nsCOMPtr<nsISupports>> mClonedObjects;
|
||||
nsRefPtr<WorkerMessagePort> mMessagePort;
|
||||
JSObject* mMessagePortObject;
|
||||
|
||||
public:
|
||||
QueuedMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount,
|
||||
RunWhenClearing),
|
||||
mMessagePortObject(nullptr)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
mBuffer.swap(aBuffer);
|
||||
mClonedObjects.SwapElements(aClonedObjects);
|
||||
}
|
||||
|
||||
bool
|
||||
Hold(JSContext* aCx, WorkerMessagePort* aMessagePort)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aMessagePort);
|
||||
MOZ_ASSERT(aMessagePort->GetJSObject());
|
||||
MOZ_ASSERT(!mMessagePortObject);
|
||||
|
||||
if (!JS_AddNamedObjectRoot(aCx, &mMessagePortObject,
|
||||
"WorkerMessagePort::MessageEventRunnable::"
|
||||
"mMessagePortObject")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mMessagePortObject = aMessagePort->GetJSObject();
|
||||
mMessagePort = aMessagePort;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
JS::Rooted<JSObject*> messagePortObject(aCx, mMessagePortObject);
|
||||
mMessagePortObject = nullptr;
|
||||
|
||||
JS_RemoveObjectRoot(aCx, &mMessagePortObject);
|
||||
|
||||
nsRefPtr<WorkerMessagePort> messagePort;
|
||||
mMessagePort.swap(messagePort);
|
||||
|
||||
return DispatchMessageEvent(aCx, messagePortObject, mBuffer,
|
||||
mClonedObjects);
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
WorkerMessagePort::_trace(JSTracer* aTrc)
|
||||
{
|
||||
EventTarget::_trace(aTrc);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerMessagePort::_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
EventTarget::_finalize(aFop);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerMessagePort::PostMessageMoz(
|
||||
JSContext* /* aCx */, JS::HandleValue aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mClosed) {
|
||||
aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
workerPrivate->PostMessageToParentMessagePort(cx, Serial(), aMessage,
|
||||
aTransferable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerMessagePort::Start()
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(GetJSContext());
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
if (mClosed) {
|
||||
NS_WARNING("Called start() after calling close()!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
mStarted = true;
|
||||
|
||||
if (!mQueuedMessages.IsEmpty()) {
|
||||
for (uint32_t index = 0; index < mQueuedMessages.Length(); index++) {
|
||||
MessageInfo& info = mQueuedMessages[index];
|
||||
|
||||
nsRefPtr<QueuedMessageEventRunnable> runnable =
|
||||
new QueuedMessageEventRunnable(workerPrivate, info.mBuffer,
|
||||
info.mClonedObjects);
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
if (!runnable->Hold(cx, this) ||
|
||||
!runnable->Dispatch(cx)) {
|
||||
NS_WARNING("Failed to dispatch queued event!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
mQueuedMessages.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerMessagePort::MaybeDispatchEvent(
|
||||
JSContext* aCx,
|
||||
JSAutoStructuredCloneBuffer& aBuffer,
|
||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
|
||||
{
|
||||
if (mClosed) {
|
||||
NS_WARNING("Not going to ever run this event!");
|
||||
aBuffer.clear();
|
||||
aClonedObjects.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mStarted) {
|
||||
// Queue the message for later.
|
||||
MessageInfo* info = mQueuedMessages.AppendElement();
|
||||
info->mBuffer.swap(aBuffer);
|
||||
info->mClonedObjects.SwapElements(aClonedObjects);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Go ahead and dispatch the event.
|
||||
JS::Rooted<JSObject*> target(aCx, GetJSObject());
|
||||
return DispatchMessageEvent(aCx, target, aBuffer, aClonedObjects);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerMessagePort::CloseInternal()
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(GetJSContext());
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
MOZ_ASSERT(!IsClosed());
|
||||
MOZ_ASSERT_IF(mStarted, mQueuedMessages.IsEmpty());
|
||||
|
||||
mClosed = true;
|
||||
|
||||
workerPrivate->DisconnectMessagePort(Serial());
|
||||
|
||||
if (!mStarted) {
|
||||
mQueuedMessages.Clear();
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_workermessageport_h__
|
||||
#define mozilla_dom_workers_workermessageport_h__
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/workers/bindings/EventTarget.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class WorkerPrivate;
|
||||
|
||||
class WorkerMessagePort : public EventTarget
|
||||
{
|
||||
friend class WorkerPrivate;
|
||||
|
||||
typedef mozilla::ErrorResult ErrorResult;
|
||||
|
||||
struct MessageInfo
|
||||
{
|
||||
JSAutoStructuredCloneBuffer mBuffer;
|
||||
nsTArray<nsCOMPtr<nsISupports>> mClonedObjects;
|
||||
};
|
||||
|
||||
nsTArray<MessageInfo> mQueuedMessages;
|
||||
uint64_t mSerial;
|
||||
bool mStarted;
|
||||
bool mClosed;
|
||||
|
||||
public:
|
||||
virtual void
|
||||
_trace(JSTracer* aTrc) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
_finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
PostMessageMoz(JSContext* aCx, JS::HandleValue aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Start();
|
||||
|
||||
void
|
||||
Close()
|
||||
{
|
||||
if (!IsClosed()) {
|
||||
CloseInternal();
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<EventHandlerNonNull>
|
||||
GetOnmessage(ErrorResult& aRv)
|
||||
{
|
||||
return GetEventListener(NS_LITERAL_STRING("message"), aRv);
|
||||
}
|
||||
|
||||
void
|
||||
SetOnmessage(EventHandlerNonNull* aListener, ErrorResult& aRv)
|
||||
{
|
||||
SetEventListener(NS_LITERAL_STRING("message"), aListener, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Serial() const
|
||||
{
|
||||
return mSerial;
|
||||
}
|
||||
|
||||
bool
|
||||
MaybeDispatchEvent(JSContext* aCx, JSAutoStructuredCloneBuffer& aBuffer,
|
||||
nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects);
|
||||
|
||||
bool
|
||||
IsClosed() const
|
||||
{
|
||||
return mClosed;
|
||||
}
|
||||
|
||||
private:
|
||||
// Only created by WorkerPrivate.
|
||||
WorkerMessagePort(JSContext* aCx, uint64_t aSerial)
|
||||
: EventTarget(aCx), mSerial(aSerial), mStarted(false), mClosed(false)
|
||||
{ }
|
||||
|
||||
virtual ~WorkerMessagePort()
|
||||
{ }
|
||||
|
||||
void
|
||||
CloseInternal();
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_workermessageport_h__
|
@ -37,8 +37,11 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "mozilla/dom/ErrorEventBinding.h"
|
||||
#include "mozilla/dom/FunctionBinding.h"
|
||||
#include "mozilla/dom/ImageData.h"
|
||||
#include "mozilla/dom/ImageDataBinding.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/MessagePortList.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Util.h"
|
||||
@ -62,8 +65,6 @@
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#include "DOMBindingInlines.h"
|
||||
#include "Events.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "File.h"
|
||||
#include "MessagePort.h"
|
||||
@ -72,7 +73,6 @@
|
||||
#include "ScriptLoader.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerFeature.h"
|
||||
#include "WorkerMessagePort.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
// GC will run once every thirty seconds during normal execution.
|
||||
@ -93,7 +93,6 @@ using mozilla::AutoPushJSContext;
|
||||
using mozilla::AutoSafeJSContext;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
using namespace mozilla::dom::workers::events;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsWorkerMallocSizeOf)
|
||||
@ -811,7 +810,8 @@ public:
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
JS::Rooted<JSObject*> global(aCx, CreateGlobalScope(aCx));
|
||||
JS::Rooted<JSObject*> global(aCx,
|
||||
aWorkerPrivate->CreateGlobalScope(aCx));
|
||||
if (!global) {
|
||||
NS_WARNING("Failed to make global!");
|
||||
return false;
|
||||
@ -838,18 +838,21 @@ public:
|
||||
|
||||
aWorkerPrivate->CloseHandlerStarted();
|
||||
|
||||
JS::Rooted<JSString*> type(aCx, JS_InternString(aCx, "close"));
|
||||
if (!type) {
|
||||
return false;
|
||||
}
|
||||
WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope();
|
||||
|
||||
JS::Rooted<JSObject*> event(aCx, CreateGenericEvent(aCx, type, false, false, false));
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv =
|
||||
NS_NewDOMEvent(getter_AddRefs(event), globalScope, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
bool ignored;
|
||||
return DispatchEventToTarget(aCx, target, event, &ignored);
|
||||
rv = event->InitEvent(NS_LITERAL_STRING("close"), false, false);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -889,6 +892,46 @@ public:
|
||||
mClonedObjects.SwapElements(aClonedObjects);
|
||||
}
|
||||
|
||||
bool
|
||||
DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
nsDOMEventTargetHelper* aTarget, bool aIsMainThread)
|
||||
{
|
||||
// Release reference to objects that were AddRef'd for
|
||||
// cloning into worker when array goes out of scope.
|
||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
||||
clonedObjects.SwapElements(mClonedObjects);
|
||||
|
||||
JS::Rooted<JS::Value> messageData(aCx);
|
||||
if (!mBuffer.read(aCx, &messageData,
|
||||
workers::WorkerStructuredCloneCallbacks(aIsMainThread))) {
|
||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMMessageEvent> event =
|
||||
new nsDOMMessageEvent(aTarget, nullptr, nullptr);
|
||||
nsresult rv =
|
||||
event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false /* non-bubbling */,
|
||||
true /* cancelable */,
|
||||
messageData,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(aCx, rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
||||
|
||||
nsEventStatus dummy = nsEventStatus_eIgnore;
|
||||
aTarget->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
@ -916,64 +959,23 @@ public:
|
||||
|
||||
aWorkerPrivate->AssertInnerWindowIsCorrect();
|
||||
|
||||
// Release reference to objects that were AddRef'd for
|
||||
// cloning into worker when array goes out of scope.
|
||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
||||
clonedObjects.SwapElements(mClonedObjects);
|
||||
|
||||
JS::Rooted<JS::Value> messageData(aCx);
|
||||
if (!mBuffer.read(aCx, messageData.address(),
|
||||
workers::WorkerStructuredCloneCallbacks(!aWorkerPrivate->GetParent()))) {
|
||||
xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMMessageEvent> event =
|
||||
new nsDOMMessageEvent(aWorkerPrivate, nullptr, nullptr);
|
||||
nsresult rv =
|
||||
event->InitMessageEvent(NS_LITERAL_STRING("message"),
|
||||
false /* non-bubbling */,
|
||||
true /* cancelable */,
|
||||
messageData,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
xpc::Throw(aCx, rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
||||
|
||||
nsEventStatus dummy = nsEventStatus_eIgnore;
|
||||
aWorkerPrivate->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
|
||||
return true;
|
||||
return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate,
|
||||
!aWorkerPrivate->GetParent());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
|
||||
if (mToMessagePort) {
|
||||
nsRefPtr<WorkerMessagePort> port =
|
||||
nsRefPtr<workers::MessagePort> port =
|
||||
aWorkerPrivate->GetMessagePort(mMessagePortSerial);
|
||||
if (!port) {
|
||||
// Must have been closed already.
|
||||
return true;
|
||||
}
|
||||
return port->MaybeDispatchEvent(aCx, mBuffer, mClonedObjects);
|
||||
return DispatchDOMEvent(aCx, aWorkerPrivate, port, false);
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> target(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
NS_ASSERTION(target, "This should never be null!");
|
||||
|
||||
JS::Rooted<JSObject*> event(aCx,
|
||||
CreateMessageEvent(aCx, mBuffer, mClonedObjects, false));
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dummy;
|
||||
return DispatchEventToTarget(aCx, target, event, &dummy);
|
||||
return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
|
||||
false);
|
||||
}
|
||||
|
||||
void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate, bool aRunResult)
|
||||
@ -1191,6 +1193,8 @@ public:
|
||||
nsRefPtr<ErrorEvent> event =
|
||||
ErrorEvent::Constructor(aTarget, NS_LITERAL_STRING("error"), init);
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
aTarget->DispatchDOMEvent(nullptr, event, nullptr, &status);
|
||||
|
||||
@ -1210,17 +1214,25 @@ public:
|
||||
|
||||
if (aWorkerPrivate ||
|
||||
!(sgo = nsJSUtils::GetStaticScriptGlobal(target))) {
|
||||
// Fire a normal ErrorEvent if we're running on a worker thread.
|
||||
JS::Rooted<JSObject*> event(aCx,
|
||||
CreateErrorEvent(aCx, message, filename, aLineNumber, false));
|
||||
if (!event) {
|
||||
return false;
|
||||
WorkerGlobalScope* globalTarget = aWorkerPrivate->GlobalScope();
|
||||
MOZ_ASSERT(target == globalTarget->GetWrapperPreserveColor());
|
||||
|
||||
// Icky, we have to fire an InternalScriptErrorEvent...
|
||||
InternalScriptErrorEvent event(true, NS_LOAD_ERROR);
|
||||
event.lineNr = aLineNumber;
|
||||
event.errorMsg = aMessage.get();
|
||||
event.fileName = aFilename.get();
|
||||
event.typeString = NS_LITERAL_STRING("error");
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsIDOMEventTarget* target = static_cast<nsIDOMEventTarget*>(globalTarget);
|
||||
if (NS_FAILED(nsEventDispatcher::Dispatch(target, nullptr, &event,
|
||||
nullptr, &status))) {
|
||||
NS_WARNING("Failed to dispatch worker thread error event!");
|
||||
status = nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
if (!DispatchEventToTarget(aCx, target, event,
|
||||
&preventDefaultCalled)) {
|
||||
return false;
|
||||
}
|
||||
preventDefaultCalled = status == nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
else {
|
||||
// Icky, we have to fire an InternalScriptErrorEvent...
|
||||
@ -1905,8 +1917,8 @@ class WorkerPrivateParent<Derived>::SynchronizeAndResumeRunnable
|
||||
struct WorkerPrivate::TimeoutInfo
|
||||
{
|
||||
TimeoutInfo()
|
||||
: mTimeoutVal(JS::UndefinedValue()), mLineNumber(0), mId(0), mIsInterval(false),
|
||||
mCanceled(false)
|
||||
: mTimeoutCallable(JS::UndefinedValue()), mLineNumber(0), mId(0),
|
||||
mIsInterval(false), mCanceled(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate::TimeoutInfo);
|
||||
}
|
||||
@ -1926,13 +1938,14 @@ struct WorkerPrivate::TimeoutInfo
|
||||
return mTargetTime < aOther.mTargetTime;
|
||||
}
|
||||
|
||||
JS::Heap<JS::Value> mTimeoutVal;
|
||||
JS::Heap<JS::Value> mTimeoutCallable;
|
||||
nsString mTimeoutString;
|
||||
nsTArray<JS::Heap<JS::Value> > mExtraArgVals;
|
||||
mozilla::TimeStamp mTargetTime;
|
||||
mozilla::TimeDuration mInterval;
|
||||
nsCString mFilename;
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mId;
|
||||
int32_t mId;
|
||||
bool mIsInterval;
|
||||
bool mCanceled;
|
||||
};
|
||||
@ -2151,7 +2164,7 @@ JSObject*
|
||||
WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
MOZ_ASSERT(!mIsSharedWorker,
|
||||
MOZ_ASSERT(!IsSharedWorker(),
|
||||
"We should never wrap a WorkerPrivate for a SharedWorker");
|
||||
|
||||
AssertIsOnParentThread();
|
||||
@ -2721,6 +2734,12 @@ WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
ports.AppendElement(port);
|
||||
|
||||
nsRefPtr<MessagePortList> portList = new MessagePortList(port, ports);
|
||||
event->SetPorts(portList);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent;
|
||||
CallQueryInterface(event.get(), getter_AddRefs(domEvent));
|
||||
NS_ASSERTION(domEvent, "This should never fail!");
|
||||
@ -3787,6 +3806,13 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
|
||||
DisableMemoryReporter();
|
||||
|
||||
StopAcceptingEvents();
|
||||
|
||||
// Clear away our MessagePorts.
|
||||
mWorkerPorts.Clear();
|
||||
|
||||
// Unroot the global
|
||||
mScope = nullptr;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -4191,33 +4217,18 @@ WorkerPrivate::ResumeInternal(JSContext* aCx)
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::TraceInternal(JSTracer* aTrc)
|
||||
WorkerPrivate::TraceTimeouts(const TraceCallbacks& aCallbacks,
|
||||
void* aClosure) const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
for (uint32_t index = 0; index < mTimeouts.Length(); index++) {
|
||||
TimeoutInfo* info = mTimeouts[index];
|
||||
JS_CallHeapValueTracer(aTrc, &info->mTimeoutVal,
|
||||
"WorkerPrivate timeout value");
|
||||
aCallbacks.Trace(&info->mTimeoutCallable, "mTimeoutCallable", aClosure);
|
||||
for (uint32_t index2 = 0; index2 < info->mExtraArgVals.Length(); index2++) {
|
||||
JS_CallHeapValueTracer(aTrc, &info->mExtraArgVals[index2],
|
||||
"WorkerPrivate timeout extra argument value");
|
||||
aCallbacks.Trace(&info->mExtraArgVals[index2], "mExtraArgVals[i]", aClosure);
|
||||
}
|
||||
}
|
||||
|
||||
// MessagePort objects are basically held alive as long as the global.
|
||||
mWorkerPorts.EnumerateRead(TraceMessagePorts, aTrc);
|
||||
}
|
||||
|
||||
// static
|
||||
PLDHashOperator
|
||||
WorkerPrivate::TraceMessagePorts(const uint64_t& aKey,
|
||||
WorkerMessagePort* aData,
|
||||
void* aUserArg)
|
||||
{
|
||||
JSTracer* trc = static_cast<JSTracer*>(aUserArg);
|
||||
aData->TraceJSObject(trc, "mWorkerPorts");
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4463,49 +4474,17 @@ WorkerPrivate::DestroySyncLoop(uint32_t aSyncLoopKey)
|
||||
mSyncQueues.RemoveElementAt(aSyncLoopKey);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::PostMessageToParentInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
JS::Handle<JS::Value> aTransferable,
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
JSStructuredCloneCallbacks* callbacks =
|
||||
IsChromeWorker() ?
|
||||
&gChromeWorkerStructuredCloneCallbacks :
|
||||
&gWorkerStructuredCloneCallbacks;
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (!buffer.write(aCx, aMessage, aTransferable, callbacks, &clonedObjects)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<MessageEventRunnable> runnable =
|
||||
new MessageEventRunnable(this, WorkerRunnable::ParentThread, buffer,
|
||||
clonedObjects, aToMessagePort, aMessagePortSerial);
|
||||
return runnable->Dispatch(aCx);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::PostMessageToParentMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JS::HandleValue aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
WorkerPrivate::PostMessageToParentInternal(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
if (!mWorkerPorts.Get(aMessagePortSerial)) {
|
||||
// This port has been closed from the main thread. There's no point in
|
||||
// sending this message so just bail.
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
|
||||
if (aTransferable.WasPassed()) {
|
||||
const Sequence<JS::Value>& realTransferable = aTransferable.Value();
|
||||
@ -4519,12 +4498,47 @@ WorkerPrivate::PostMessageToParentMessagePort(
|
||||
transferable.setObject(*array);
|
||||
}
|
||||
|
||||
if (!PostMessageToParentInternal(aCx, aMessage, transferable, true,
|
||||
aMessagePortSerial)) {
|
||||
JSStructuredCloneCallbacks* callbacks =
|
||||
IsChromeWorker() ?
|
||||
&gChromeWorkerStructuredCloneCallbacks :
|
||||
&gWorkerStructuredCloneCallbacks;
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports>> clonedObjects;
|
||||
|
||||
JSAutoStructuredCloneBuffer buffer;
|
||||
if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) {
|
||||
aRv = NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<MessageEventRunnable> runnable =
|
||||
new MessageEventRunnable(this, WorkerRunnable::ParentThread, buffer,
|
||||
clonedObjects, aToMessagePort, aMessagePortSerial);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::PostMessageToParentMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JS::HandleValue aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
if (!mWorkerPorts.GetWeak(aMessagePortSerial)) {
|
||||
// This port has been closed from the main thread. There's no point in
|
||||
// sending this message so just bail.
|
||||
return;
|
||||
}
|
||||
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, true,
|
||||
aMessagePortSerial, aRv);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
@ -4733,14 +4747,18 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aMessage,
|
||||
mErrorHandlerRecursionCount--;
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::SetTimeout(JSContext* aCx, unsigned aArgc, jsval* aVp,
|
||||
bool aIsInterval)
|
||||
int32_t
|
||||
WorkerPrivate::SetTimeout(JSContext* aCx,
|
||||
Function* aHandler,
|
||||
const nsAString& aStringHandler,
|
||||
int32_t aTimeout,
|
||||
const Sequence<JS::Value>& aArguments,
|
||||
bool aIsInterval,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
NS_ASSERTION(aArgc, "Huh?!");
|
||||
|
||||
const uint32_t timerId = mNextTimeoutId++;
|
||||
const int32_t timerId = mNextTimeoutId++;
|
||||
|
||||
Status currentStatus;
|
||||
{
|
||||
@ -4757,63 +4775,48 @@ WorkerPrivate::SetTimeout(JSContext* aCx, unsigned aArgc, jsval* aVp,
|
||||
// If the worker is trying to call setTimeout/setInterval and the parent
|
||||
// thread has initiated the close process then just silently fail.
|
||||
if (currentStatus >= Closing) {
|
||||
return false;
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsAutoPtr<TimeoutInfo> newInfo(new TimeoutInfo());
|
||||
newInfo->mIsInterval = aIsInterval;
|
||||
newInfo->mId = timerId;
|
||||
|
||||
if (MOZ_UNLIKELY(timerId == UINT32_MAX)) {
|
||||
if (MOZ_UNLIKELY(timerId == INT32_MAX)) {
|
||||
NS_WARNING("Timeout ids overflowed!");
|
||||
mNextTimeoutId = 1;
|
||||
}
|
||||
|
||||
JS::Value* argv = JS_ARGV(aCx, aVp);
|
||||
|
||||
// Take care of the main argument.
|
||||
if (argv[0].isObject()) {
|
||||
if (JS_ObjectIsCallable(aCx, &argv[0].toObject())) {
|
||||
newInfo->mTimeoutVal = argv[0];
|
||||
}
|
||||
else {
|
||||
JSString* timeoutStr = JS_ValueToString(aCx, argv[0]);
|
||||
if (!timeoutStr) {
|
||||
return false;
|
||||
}
|
||||
newInfo->mTimeoutVal.setString(timeoutStr);
|
||||
}
|
||||
if (aHandler) {
|
||||
newInfo->mTimeoutCallable = JS::ObjectValue(*aHandler->Callable());
|
||||
}
|
||||
else if (argv[0].isString()) {
|
||||
newInfo->mTimeoutVal = argv[0];
|
||||
else if (!aStringHandler.IsEmpty()) {
|
||||
newInfo->mTimeoutString = aStringHandler;
|
||||
}
|
||||
else {
|
||||
JS_ReportError(aCx, "Useless %s call (missing quotes around argument?)",
|
||||
aIsInterval ? "setInterval" : "setTimeout");
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// See if any of the optional arguments were passed.
|
||||
if (aArgc > 1) {
|
||||
double intervalMS = 0;
|
||||
JS::RootedValue interval(aCx, argv[1]);
|
||||
if (!JS::ToNumber(aCx, interval, &intervalMS)) {
|
||||
return false;
|
||||
}
|
||||
newInfo->mInterval = TimeDuration::FromMilliseconds(intervalMS);
|
||||
aTimeout = std::max(0, aTimeout);
|
||||
newInfo->mInterval = TimeDuration::FromMilliseconds(aTimeout);
|
||||
|
||||
if (aArgc > 2 && newInfo->mTimeoutVal.isObject()) {
|
||||
nsTArray<JS::Heap<JS::Value> > extraArgVals(aArgc - 2);
|
||||
for (unsigned index = 2; index < aArgc; index++) {
|
||||
extraArgVals.AppendElement(argv[index]);
|
||||
}
|
||||
newInfo->mExtraArgVals.SwapElements(extraArgVals);
|
||||
uint32_t argc = aArguments.Length();
|
||||
if (argc && !newInfo->mTimeoutCallable.isUndefined()) {
|
||||
nsTArray<JS::Heap<JS::Value>> extraArgVals(argc);
|
||||
for (uint32_t index = 0; index < argc; index++) {
|
||||
extraArgVals.AppendElement(aArguments[index]);
|
||||
}
|
||||
newInfo->mExtraArgVals.SwapElements(extraArgVals);
|
||||
}
|
||||
|
||||
newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
|
||||
|
||||
if (newInfo->mTimeoutVal.isString()) {
|
||||
if (!newInfo->mTimeoutString.IsEmpty()) {
|
||||
const char* filenameChars;
|
||||
uint32_t lineNumber;
|
||||
if (nsJSUtils::GetCallingLocation(aCx, &filenameChars, &lineNumber)) {
|
||||
@ -4825,18 +4828,19 @@ WorkerPrivate::SetTimeout(JSContext* aCx, unsigned aArgc, jsval* aVp,
|
||||
}
|
||||
}
|
||||
|
||||
mTimeouts.InsertElementSorted(newInfo.get(), GetAutoPtrComparator(mTimeouts));
|
||||
nsAutoPtr<TimeoutInfo>* insertedInfo =
|
||||
mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
|
||||
|
||||
// If the timeout we just made is set to fire next then we need to update the
|
||||
// timer.
|
||||
if (mTimeouts[0] == newInfo) {
|
||||
if (insertedInfo == mTimeouts.Elements()) {
|
||||
nsresult rv;
|
||||
|
||||
if (!mTimer) {
|
||||
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to create timer!");
|
||||
return false;
|
||||
aRv.Throw(rv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsRefPtr<TimerRunnable> timerRunnable = new TimerRunnable(this);
|
||||
@ -4845,31 +4849,30 @@ WorkerPrivate::SetTimeout(JSContext* aCx, unsigned aArgc, jsval* aVp,
|
||||
new WorkerRunnableEventTarget(timerRunnable);
|
||||
rv = mTimer->SetTarget(target);
|
||||
if (NS_FAILED(rv)) {
|
||||
JS_ReportError(aCx, "Failed to set timer's target!");
|
||||
return false;
|
||||
aRv.Throw(rv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mTimerRunning) {
|
||||
if (!ModifyBusyCountFromWorker(aCx, true)) {
|
||||
return false;
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
mTimerRunning = true;
|
||||
}
|
||||
|
||||
if (!RescheduleTimeoutTimer(aCx)) {
|
||||
return false;
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
JS_SET_RVAL(aCx, aVp, INT_TO_JSVAL(timerId));
|
||||
|
||||
newInfo.forget();
|
||||
return true;
|
||||
return timerId;
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::ClearTimeout(JSContext* aCx, uint32_t aId)
|
||||
void
|
||||
WorkerPrivate::ClearTimeout(int32_t aId)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
@ -4884,8 +4887,6 @@ WorkerPrivate::ClearTimeout(JSContext* aCx, uint32_t aId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -4937,32 +4938,31 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
|
||||
// JS_ReportPendingException returns false (i.e. uncatchable exception) then
|
||||
// break out of the loop.
|
||||
|
||||
if (info->mTimeoutVal.isString()) {
|
||||
JSString* expression = info->mTimeoutVal.toString();
|
||||
|
||||
JS::CompileOptions options(aCx);
|
||||
options.setPrincipals(principal)
|
||||
.setFileAndLine(info->mFilename.get(), info->mLineNumber);
|
||||
|
||||
size_t stringLength;
|
||||
const jschar* string = JS_GetStringCharsAndLength(aCx, expression,
|
||||
&stringLength);
|
||||
if ((!string || !JS::Evaluate(aCx, global, options, string, stringLength, nullptr)) &&
|
||||
if (!info->mTimeoutCallable.isUndefined()) {
|
||||
JS::Rooted<JS::Value> rval(aCx);
|
||||
/*
|
||||
* unsafeGet() is needed below because the argument is a not a const
|
||||
* pointer, even though values are not modified.
|
||||
*/
|
||||
if (!JS_CallFunctionValue(aCx, global, info->mTimeoutCallable,
|
||||
info->mExtraArgVals.Length(),
|
||||
info->mExtraArgVals.Elements()->unsafeGet(),
|
||||
rval.address()) &&
|
||||
!JS_ReportPendingException(aCx)) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
JS::Rooted<JS::Value> rval(aCx);
|
||||
/*
|
||||
* unsafeGet() is needed below because the argument is a not a const
|
||||
* pointer, even though values are not modified.
|
||||
*/
|
||||
if (!JS_CallFunctionValue(aCx, global, info->mTimeoutVal,
|
||||
info->mExtraArgVals.Length(),
|
||||
info->mExtraArgVals.Elements()->unsafeGet(),
|
||||
rval.address()) &&
|
||||
nsString expression = info->mTimeoutString;
|
||||
|
||||
JS::CompileOptions options(aCx);
|
||||
options.setPrincipals(principal)
|
||||
.setFileAndLine(info->mFilename.get(), info->mLineNumber);
|
||||
|
||||
if ((expression.IsEmpty() ||
|
||||
!JS::Evaluate(aCx, global, options, expression.get(),
|
||||
expression.Length(), nullptr)) &&
|
||||
!JS_ReportPendingException(aCx)) {
|
||||
retval = false;
|
||||
break;
|
||||
@ -5217,32 +5217,53 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
NS_ASSERTION(!mWorkerPorts.Get(aMessagePortSerial),
|
||||
NS_ASSERTION(!mWorkerPorts.GetWeak(aMessagePortSerial),
|
||||
"Already have this port registered!");
|
||||
|
||||
nsRefPtr<WorkerMessagePort> port =
|
||||
new WorkerMessagePort(aCx, aMessagePortSerial);
|
||||
WorkerGlobalScope* globalScope = GlobalScope();
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||
JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
|
||||
MOZ_ASSERT(jsGlobal);
|
||||
|
||||
JS::Rooted<JSObject*> portObj(aCx, Wrap(aCx, global, port));
|
||||
if (!portObj) {
|
||||
nsRefPtr<MessagePort> port = new MessagePort(this, aMessagePortSerial);
|
||||
|
||||
JS::Rooted<JS::Value> jsPort(aCx);
|
||||
if (!WrapNewBindingObject(aCx, jsGlobal, port, &jsPort)) {
|
||||
MOZ_ASSERT(JS_IsExceptionPending(aCx));
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> event(aCx, CreateConnectEvent(aCx, portObj));
|
||||
if (!event) {
|
||||
GlobalObject globalObject(aCx, jsGlobal);
|
||||
if (globalObject.Failed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MessageEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
init.mSource = &jsPort.toObject();
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
nsRefPtr<nsDOMMessageEvent> event =
|
||||
nsDOMMessageEvent::Constructor(globalObject, aCx,
|
||||
NS_LITERAL_STRING("connect"), init, rv);
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
ports.AppendElement(port);
|
||||
|
||||
nsRefPtr<MessagePortList> portList =
|
||||
new MessagePortList(static_cast<nsIDOMEventTarget*>(globalScope), ports);
|
||||
event->SetPorts(portList);
|
||||
|
||||
mWorkerPorts.Put(aMessagePortSerial, port);
|
||||
|
||||
bool dummy;
|
||||
if (!DispatchEventToTarget(aCx, global, event, &dummy)) {
|
||||
mWorkerPorts.Remove(aMessagePortSerial);
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
||||
|
||||
nsEventStatus dummy = nsEventStatus_eIgnore;
|
||||
globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -5251,24 +5272,58 @@ WorkerPrivate::DisconnectMessagePort(uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
// The port may have already been removed from this list since either the main
|
||||
// thread or the worker thread can remove it.
|
||||
mWorkerPorts.Remove(aMessagePortSerial);
|
||||
}
|
||||
|
||||
WorkerMessagePort*
|
||||
workers::MessagePort*
|
||||
WorkerPrivate::GetMessagePort(uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
WorkerMessagePort* port;
|
||||
if (mWorkerPorts.Get(aMessagePortSerial, &port)) {
|
||||
nsRefPtr<MessagePort> port;
|
||||
if (mWorkerPorts.Get(aMessagePortSerial, getter_AddRefs(port))) {
|
||||
return port;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
WorkerPrivate::CreateGlobalScope(JSContext* aCx)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<WorkerGlobalScope> globalScope;
|
||||
if (IsSharedWorker()) {
|
||||
globalScope = new SharedWorkerGlobalScope(this, SharedWorkerName());
|
||||
}
|
||||
else {
|
||||
globalScope = new DedicatedWorkerGlobalScope(this);
|
||||
}
|
||||
|
||||
JS::CompartmentOptions options;
|
||||
if (IsChromeWorker()) {
|
||||
options.setVersion(JSVERSION_LATEST);
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx,
|
||||
globalScope->WrapGlobalObject(aCx, options,
|
||||
GetWorkerPrincipal()));
|
||||
NS_ENSURE_TRUE(global, nullptr);
|
||||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
if (!RegisterBindings(aCx, global)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mScope = globalScope.forget();
|
||||
|
||||
JS_FireOnNewGlobalObject(aCx, global);
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
template <class Derived>
|
||||
void
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsEventQueue.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -44,11 +45,17 @@ namespace JS {
|
||||
class RuntimeStats;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Function;
|
||||
}
|
||||
}
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class MessagePort;
|
||||
class SharedWorker;
|
||||
class WorkerMessagePort;
|
||||
class WorkerGlobalScope;
|
||||
class WorkerPrivate;
|
||||
|
||||
class WorkerRunnable : public nsIRunnable
|
||||
@ -782,6 +789,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher;
|
||||
|
||||
// Things touched on worker thread only.
|
||||
nsRefPtr<WorkerGlobalScope> mScope;
|
||||
nsTArray<ParentType*> mChildWorkers;
|
||||
nsTArray<WorkerFeature*> mFeatures;
|
||||
nsTArray<nsAutoPtr<TimeoutInfo> > mTimeouts;
|
||||
@ -789,7 +797,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsRefPtr<MemoryReporter> mMemoryReporter;
|
||||
|
||||
nsDataHashtable<nsUint64HashKey, WorkerMessagePort*> mWorkerPorts;
|
||||
nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
|
||||
|
||||
mozilla::TimeStamp mKillTime;
|
||||
uint32_t mErrorHandlerRecursionCount;
|
||||
@ -872,7 +880,7 @@ public:
|
||||
ResumeInternal(JSContext* aCx);
|
||||
|
||||
void
|
||||
TraceInternal(JSTracer* aTrc);
|
||||
TraceTimeouts(const TraceCallbacks& aCallbacks, void* aClosure) const;
|
||||
|
||||
bool
|
||||
ModifyBusyCountFromWorker(JSContext* aCx, bool aIncrease);
|
||||
@ -911,12 +919,13 @@ public:
|
||||
void
|
||||
DestroySyncLoop(uint32_t aSyncLoopKey);
|
||||
|
||||
bool
|
||||
void
|
||||
PostMessageToParent(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
JS::Handle<JS::Value> aTransferable)
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
return PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0);
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
@ -933,11 +942,17 @@ public:
|
||||
void
|
||||
ReportError(JSContext* aCx, const char* aMessage, JSErrorReport* aReport);
|
||||
|
||||
bool
|
||||
SetTimeout(JSContext* aCx, unsigned aArgc, jsval* aVp, bool aIsInterval);
|
||||
int32_t
|
||||
SetTimeout(JSContext* aCx,
|
||||
Function* aHandler,
|
||||
const nsAString& aStringHandler,
|
||||
int32_t aTimeout,
|
||||
const Sequence<JS::Value>& aArguments,
|
||||
bool aIsInterval,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
ClearTimeout(JSContext* aCx, uint32_t aId);
|
||||
void
|
||||
ClearTimeout(int32_t aId);
|
||||
|
||||
bool
|
||||
RunExpiredTimeouts(JSContext* aCx);
|
||||
@ -991,6 +1006,13 @@ public:
|
||||
return mJSContext;
|
||||
}
|
||||
|
||||
WorkerGlobalScope*
|
||||
GlobalScope() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mScope;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertIsOnWorkerThread() const;
|
||||
@ -1039,9 +1061,15 @@ public:
|
||||
void
|
||||
DisconnectMessagePort(uint64_t aMessagePortSerial);
|
||||
|
||||
WorkerMessagePort*
|
||||
MessagePort*
|
||||
GetMessagePort(uint64_t aMessagePortSerial);
|
||||
|
||||
JSObject*
|
||||
CreateGlobalScope(JSContext* aCx);
|
||||
|
||||
bool
|
||||
RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
@ -1112,17 +1140,13 @@ private:
|
||||
void
|
||||
WaitForWorkerEvents(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
static PLDHashOperator
|
||||
TraceMessagePorts(const uint64_t& aKey,
|
||||
WorkerMessagePort* aData,
|
||||
void* aUserArg);
|
||||
|
||||
bool
|
||||
void
|
||||
PostMessageToParentInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
JS::Handle<JS::Value> aTransferable,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial);
|
||||
uint64_t aMessagePortSerial,
|
||||
ErrorResult& aRv);
|
||||
};
|
||||
|
||||
// This class is only used to trick the DOM bindings. We never create
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,16 +3,155 @@
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_workerscope_h__
|
||||
#define mozilla_dom_workers_workerscope_h__
|
||||
#ifndef mozilla_dom_workerscope_h__
|
||||
#define mozilla_dom_workerscope_h__
|
||||
|
||||
#include "Workers.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Function;
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class WorkerPrivate;
|
||||
class WorkerLocation;
|
||||
class WorkerNavigator;
|
||||
|
||||
class WorkerGlobalScope : public nsDOMEventTargetHelper,
|
||||
public nsIGlobalObject
|
||||
{
|
||||
nsRefPtr<WorkerLocation> mLocation;
|
||||
nsRefPtr<WorkerNavigator> mNavigator;
|
||||
|
||||
protected:
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
WorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
|
||||
virtual ~WorkerGlobalScope();
|
||||
|
||||
public:
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::HandleObject aScope) MOZ_OVERRIDE;
|
||||
|
||||
virtual JSObject*
|
||||
WrapGlobalObject(JSContext* aCx, JS::CompartmentOptions& aOptions,
|
||||
JSPrincipals* aPrincipal) = 0;
|
||||
|
||||
virtual JSObject*
|
||||
GetGlobalJSObject(void) MOZ_OVERRIDE
|
||||
{
|
||||
return GetWrapper();
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerGlobalScope,
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
already_AddRefed<WorkerGlobalScope>
|
||||
Self()
|
||||
{
|
||||
return nsRefPtr<WorkerGlobalScope>(this).forget();
|
||||
}
|
||||
|
||||
already_AddRefed<WorkerLocation>
|
||||
Location();
|
||||
already_AddRefed<WorkerNavigator>
|
||||
Navigator();
|
||||
void
|
||||
Close(JSContext* aCx);
|
||||
|
||||
OnErrorEventHandlerNonNull*
|
||||
GetOnerror();
|
||||
void
|
||||
SetOnerror(OnErrorEventHandlerNonNull* aHandler);
|
||||
|
||||
void
|
||||
ImportScripts(JSContext* aCx, const Sequence<nsString>& aScriptURLs,
|
||||
ErrorResult& aRv);
|
||||
|
||||
int32_t
|
||||
SetTimeout(JSContext* aCx, Function& aHandler, const int32_t aTimeout,
|
||||
const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
|
||||
int32_t
|
||||
SetTimeout(const nsAString& aHandler, const int32_t aTimeout,
|
||||
ErrorResult& aRv);
|
||||
void
|
||||
ClearTimeout(int32_t aHandle, ErrorResult& aRv);
|
||||
int32_t
|
||||
SetInterval(JSContext* aCx, Function& aHandler,
|
||||
const Optional<int32_t>& aTimeout,
|
||||
const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
|
||||
int32_t
|
||||
SetInterval(const nsAString& aHandler, const Optional<int32_t>& aTimeout,
|
||||
ErrorResult& aRv);
|
||||
void
|
||||
ClearInterval(int32_t aHandle, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const;
|
||||
void
|
||||
Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const;
|
||||
|
||||
IMPL_EVENT_HANDLER(close)
|
||||
|
||||
void
|
||||
Dump(const Optional<nsAString>& aString) const;
|
||||
};
|
||||
|
||||
class DedicatedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
|
||||
{
|
||||
~DedicatedWorkerGlobalScope() { }
|
||||
|
||||
public:
|
||||
DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
static bool
|
||||
Visible(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
virtual JSObject*
|
||||
WrapGlobalObject(JSContext* aCx, JS::CompartmentOptions& aOptions,
|
||||
JSPrincipals* aPrincipal) MOZ_OVERRIDE;
|
||||
|
||||
void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
};
|
||||
|
||||
class SharedWorkerGlobalScope MOZ_FINAL : public WorkerGlobalScope
|
||||
{
|
||||
const nsString mName;
|
||||
|
||||
~SharedWorkerGlobalScope() { }
|
||||
|
||||
public:
|
||||
SharedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsString& aName);
|
||||
|
||||
static bool
|
||||
Visible(JSContext* aCx, JSObject* aObj);
|
||||
|
||||
virtual JSObject*
|
||||
WrapGlobalObject(JSContext* aCx, JS::CompartmentOptions& aOptions,
|
||||
JSPrincipals* aPrincipal) MOZ_OVERRIDE;
|
||||
|
||||
void GetName(DOMString& aName) const {
|
||||
aName.AsAString() = mName;
|
||||
}
|
||||
|
||||
IMPL_EVENT_HANDLER(connect)
|
||||
};
|
||||
|
||||
JSObject*
|
||||
CreateGlobalScope(JSContext* aCx);
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif /* mozilla_dom_workers_workerscope_h__ */
|
||||
#endif /* mozilla_dom_workerscope_h__ */
|
||||
|
@ -16,19 +16,16 @@
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXMLHttpRequest.h"
|
||||
|
||||
#include "Events.h"
|
||||
#include "EventTarget.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
#include "File.h"
|
||||
#include "RuntimeService.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "XMLHttpRequestUpload.h"
|
||||
|
||||
#include "DOMBindingInlines.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
@ -746,24 +743,41 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> event(aCx, mProgressEvent ?
|
||||
events::CreateProgressEvent(aCx, type, mLengthComputable,
|
||||
mLoaded, mTotal) :
|
||||
events::CreateGenericEvent(aCx, type, false, false,
|
||||
false));
|
||||
nsXHREventTarget* target;
|
||||
if (mUploadEvent) {
|
||||
target = xhr->GetUploadObjectNoCreate();
|
||||
}
|
||||
else {
|
||||
target = xhr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
if (mProgressEvent) {
|
||||
NS_NewDOMProgressEvent(getter_AddRefs(event), target, nullptr, nullptr);
|
||||
nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
|
||||
|
||||
if (progress) {
|
||||
progress->InitProgressEvent(mType, false, false, mLengthComputable,
|
||||
mLoaded, mTotal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_NewDOMEvent(getter_AddRefs(event), target, nullptr, nullptr);
|
||||
|
||||
if (event) {
|
||||
event->InitEvent(mType, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> target(aCx, mUploadEvent ?
|
||||
xhr->GetUploadObjectNoCreate()->GetJSObject() :
|
||||
xhr->GetJSObject());
|
||||
MOZ_ASSERT(target);
|
||||
event->SetTrusted(true);
|
||||
|
||||
bool dummy;
|
||||
if (!events::DispatchEventToTarget(aCx, target, event, &dummy)) {
|
||||
JS_ReportPendingException(aCx);
|
||||
}
|
||||
target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
|
||||
// After firing the event set mResponse to JSVAL_NULL for chunked response
|
||||
// types.
|
||||
@ -1423,41 +1437,60 @@ Proxy::HandleEvent(nsIDOMEvent* aEvent)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
XMLHttpRequest::XMLHttpRequest(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
: XMLHttpRequestEventTarget(aCx), mJSObject(nullptr), mUpload(nullptr),
|
||||
mWorkerPrivate(aWorkerPrivate),
|
||||
XMLHttpRequest::XMLHttpRequest(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mResponseType(XMLHttpRequestResponseType::Text), mTimeout(0),
|
||||
mJSObjectRooted(false), mBackgroundRequest(false),
|
||||
mWithCredentials(false), mCanceled(false), mMozAnon(false), mMozSystem(false)
|
||||
mRooted(false), mBackgroundRequest(false), mWithCredentials(false),
|
||||
mCanceled(false), mMozAnon(false), mMozSystem(false)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
XMLHttpRequest::~XMLHttpRequest()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mJSObjectRooted);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequest::_trace(JSTracer* aTrc)
|
||||
{
|
||||
if (mUpload) {
|
||||
mUpload->TraceJSObject(aTrc, "XMLHttpRequest::mUpload");
|
||||
}
|
||||
JS_CallHeapValueTracer(aTrc, &mStateData.mResponse, "XMLHttpRequest::mResponse");
|
||||
XMLHttpRequestEventTarget::_trace(aTrc);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequest::_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
ReleaseProxy(XHRIsGoingAway);
|
||||
XMLHttpRequestEventTarget::_finalize(aFop);
|
||||
|
||||
MOZ_ASSERT(!mRooted);
|
||||
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(XMLHttpRequest, nsXHREventTarget)
|
||||
NS_IMPL_RELEASE_INHERITED(XMLHttpRequest, nsXHREventTarget)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XMLHttpRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequest,
|
||||
nsXHREventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequest,
|
||||
nsXHREventTarget)
|
||||
tmp->ReleaseProxy(XHRIsGoingAway);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequest,
|
||||
nsXHREventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mStateData.mResponse)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
JSObject*
|
||||
XMLHttpRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return XMLHttpRequestBinding_workers::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
// static
|
||||
XMLHttpRequest*
|
||||
already_AddRefed<XMLHttpRequest>
|
||||
XMLHttpRequest::Constructor(const GlobalObject& aGlobal,
|
||||
const MozXMLHttpRequestParameters& aParams,
|
||||
ErrorResult& aRv)
|
||||
@ -1466,20 +1499,14 @@ XMLHttpRequest::Constructor(const GlobalObject& aGlobal,
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsRefPtr<XMLHttpRequest> xhr = new XMLHttpRequest(cx, workerPrivate);
|
||||
|
||||
if (!Wrap(cx, aGlobal.Get(), xhr)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<XMLHttpRequest> xhr = new XMLHttpRequest(workerPrivate);
|
||||
|
||||
if (workerPrivate->XHRParamsAllowed()) {
|
||||
xhr->mMozAnon = aParams.mMozAnon;
|
||||
xhr->mMozSystem = aParams.mMozSystem;
|
||||
}
|
||||
|
||||
xhr->mJSObject = xhr->GetJSObject();
|
||||
return xhr;
|
||||
return xhr.forget();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1524,30 +1551,19 @@ XMLHttpRequest::MaybePin(ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mJSObjectRooted) {
|
||||
if (mRooted) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
/*
|
||||
* It's safe to use unsafeGet() here: the unsafeness comes from the
|
||||
* possibility of updating the value of mJSObject without triggering the post
|
||||
* barriers. However if the value will always be marked, post barriers are
|
||||
* unnecessary.
|
||||
*/
|
||||
if (!JS_AddNamedObjectRoot(cx, mJSObject.unsafeGet(), "XMLHttpRequest::mJSObjectRooted")) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
JSContext* cx = GetCurrentThreadJSContext();
|
||||
|
||||
if (!mWorkerPrivate->AddFeature(cx, this)) {
|
||||
JS_RemoveObjectRoot(cx, mJSObject.unsafeGet());
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
mJSObjectRooted = true;
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
mRooted = true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1561,15 +1577,14 @@ XMLHttpRequest::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
|
||||
if (mProxy->mSeenUploadLoadStart) {
|
||||
MOZ_ASSERT(mUpload);
|
||||
|
||||
JS::Rooted<JSObject*> target(GetJSContext(), mUpload->GetJSObject());
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
DispatchPrematureAbortEvent(target, STRING_abort, true, aRv);
|
||||
DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("abort"), true,
|
||||
aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchPrematureAbortEvent(target, STRING_loadend, true, aRv);
|
||||
DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("loadend"), true,
|
||||
aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@ -1578,20 +1593,19 @@ XMLHttpRequest::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
if (mProxy->mSeenLoadStart) {
|
||||
JS::Rooted<JSObject*> target(GetJSContext(), GetJSObject());
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
DispatchPrematureAbortEvent(target, STRING_readystatechange, false, aRv);
|
||||
DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("readystatechange"),
|
||||
false, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchPrematureAbortEvent(target, STRING_abort, false, aRv);
|
||||
DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("abort"), false, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchPrematureAbortEvent(target, STRING_loadend, false, aRv);
|
||||
DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("loadend"), false,
|
||||
aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
@ -1601,43 +1615,45 @@ XMLHttpRequest::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequest::DispatchPrematureAbortEvent(JS::Handle<JSObject*> aTarget,
|
||||
uint8_t aEventType,
|
||||
XMLHttpRequest::DispatchPrematureAbortEvent(EventTarget* aTarget,
|
||||
const nsAString& aEventType,
|
||||
bool aUploadTarget,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aTarget);
|
||||
MOZ_ASSERT(aEventType <= STRING_COUNT);
|
||||
|
||||
if (!mProxy) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
if (aEventType.EqualsLiteral("readystatechange")) {
|
||||
NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
|
||||
|
||||
JS::Rooted<JSString*> type(cx, JS_NewStringCopyZ(cx, sEventStrings[aEventType]));
|
||||
if (!type) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> event(cx);
|
||||
if (aEventType == STRING_readystatechange) {
|
||||
event = events::CreateGenericEvent(cx, type, false, false, false);
|
||||
}
|
||||
else if (aUploadTarget) {
|
||||
event = events::CreateProgressEvent(cx, type,
|
||||
mProxy->mLastUploadLengthComputable,
|
||||
mProxy->mLastUploadLoaded,
|
||||
mProxy->mLastUploadTotal);
|
||||
if (event) {
|
||||
event->InitEvent(aEventType, false, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
event = events::CreateProgressEvent(cx, type,
|
||||
mProxy->mLastLengthComputable,
|
||||
mProxy->mLastLoaded,
|
||||
mProxy->mLastTotal);
|
||||
NS_NewDOMProgressEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
|
||||
|
||||
nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
|
||||
if (progress) {
|
||||
if (aUploadTarget) {
|
||||
progress->InitProgressEvent(aEventType, false, false,
|
||||
mProxy->mLastUploadLengthComputable,
|
||||
mProxy->mLastUploadLoaded,
|
||||
mProxy->mLastUploadTotal);
|
||||
}
|
||||
else {
|
||||
progress->InitProgressEvent(aEventType, false, false,
|
||||
mProxy->mLastLengthComputable,
|
||||
mProxy->mLastLoaded,
|
||||
mProxy->mLastTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!event) {
|
||||
@ -1645,11 +1661,9 @@ XMLHttpRequest::DispatchPrematureAbortEvent(JS::Handle<JSObject*> aTarget,
|
||||
return;
|
||||
}
|
||||
|
||||
bool dummy;
|
||||
if (!events::DispatchEventToTarget(cx, aTarget, event, &dummy)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
event->SetTrusted(true);
|
||||
|
||||
aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1657,16 +1671,15 @@ XMLHttpRequest::Unpin()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
NS_ASSERTION(mJSObjectRooted, "Mismatched calls to Unpin!");
|
||||
MOZ_ASSERT(mRooted, "Mismatched calls to Unpin!");
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
|
||||
/* See the comment in MaybePin() for why this is safe. */
|
||||
JS_RemoveObjectRoot(cx, mJSObject.unsafeGet());
|
||||
JSContext* cx = GetCurrentThreadJSContext();
|
||||
|
||||
mWorkerPrivate->RemoveFeature(cx, this);
|
||||
|
||||
mJSObjectRooted = false;
|
||||
mRooted = false;
|
||||
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1696,7 +1709,7 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody,
|
||||
|
||||
mProxy->mOuterChannelId++;
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
JSContext* cx = mWorkerPrivate->GetJSContext();
|
||||
|
||||
nsRefPtr<SendRunnable> runnable =
|
||||
new SendRunnable(mWorkerPrivate, mProxy, aStringBody, aBody,
|
||||
@ -1731,7 +1744,7 @@ bool
|
||||
XMLHttpRequest::Notify(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(GetJSContext() == aCx);
|
||||
MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
|
||||
|
||||
if (aStatus >= Canceling && !mCanceled) {
|
||||
mCanceled = true;
|
||||
@ -1770,7 +1783,7 @@ XMLHttpRequest::Open(const nsACString& aMethod, const nsAString& aUrl,
|
||||
mBackgroundRequest, mWithCredentials,
|
||||
mTimeout);
|
||||
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
ReleaseProxy();
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
@ -1797,7 +1810,7 @@ XMLHttpRequest::SetRequestHeader(const nsACString& aHeader,
|
||||
|
||||
nsRefPtr<SetRequestHeaderRunnable> runnable =
|
||||
new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -1823,7 +1836,7 @@ XMLHttpRequest::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
|
||||
|
||||
nsRefPtr<SetTimeoutRunnable> runnable =
|
||||
new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -1849,7 +1862,7 @@ XMLHttpRequest::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
|
||||
|
||||
nsRefPtr<SetWithCredentialsRunnable> runnable =
|
||||
new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -1877,7 +1890,7 @@ XMLHttpRequest::SetMozBackgroundRequest(bool aBackgroundRequest,
|
||||
nsRefPtr<SetBackgroundRequestRunnable> runnable =
|
||||
new SetBackgroundRequestRunnable(mWorkerPrivate, mProxy,
|
||||
aBackgroundRequest);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -1894,15 +1907,12 @@ XMLHttpRequest::GetUpload(ErrorResult& aRv)
|
||||
}
|
||||
|
||||
if (!mUpload) {
|
||||
XMLHttpRequestUpload* upload =
|
||||
XMLHttpRequestUpload::Create(GetJSContext(), this);
|
||||
mUpload = XMLHttpRequestUpload::Create(this);
|
||||
|
||||
if (!upload) {
|
||||
if (!mUpload) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mUpload = upload;
|
||||
}
|
||||
|
||||
return mUpload;
|
||||
@ -1968,7 +1978,7 @@ XMLHttpRequest::Send(JSObject* aBody, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
JSContext* cx = GetJSContext();
|
||||
JSContext* cx = mWorkerPrivate->GetJSContext();
|
||||
|
||||
JS::Rooted<JS::Value> valToClone(cx);
|
||||
if (JS_IsArrayBufferObject(aBody) || JS_IsArrayBufferViewObject(aBody) ||
|
||||
@ -2029,7 +2039,7 @@ XMLHttpRequest::Abort(ErrorResult& aRv)
|
||||
mProxy->mOuterEventStreamId++;
|
||||
|
||||
nsRefPtr<AbortRunnable> runnable = new AbortRunnable(mWorkerPrivate, mProxy);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -2055,7 +2065,7 @@ XMLHttpRequest::GetResponseHeader(const nsACString& aHeader,
|
||||
nsRefPtr<GetResponseHeaderRunnable> runnable =
|
||||
new GetResponseHeaderRunnable(mWorkerPrivate, mProxy, aHeader,
|
||||
responseHeader);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -2081,7 +2091,7 @@ XMLHttpRequest::GetAllResponseHeaders(nsACString& aResponseHeaders,
|
||||
nsCString responseHeaders;
|
||||
nsRefPtr<GetAllResponseHeadersRunnable> runnable =
|
||||
new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -2111,7 +2121,7 @@ XMLHttpRequest::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
|
||||
|
||||
nsRefPtr<OverrideMimeTypeRunnable> runnable =
|
||||
new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -2144,7 +2154,7 @@ XMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aResponseType,
|
||||
|
||||
nsRefPtr<SetResponseTypeRunnable> runnable =
|
||||
new SetResponseTypeRunnable(mWorkerPrivate, mProxy, responseType);
|
||||
if (!runnable->Dispatch(GetJSContext())) {
|
||||
if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
@ -2164,7 +2174,8 @@ XMLHttpRequest::GetResponse(JSContext* /* unused */, ErrorResult& aRv)
|
||||
MOZ_ASSERT(NS_SUCCEEDED(mStateData.mResponseResult));
|
||||
|
||||
JSString* str =
|
||||
JS_NewUCStringCopyN(GetJSContext(), mStateData.mResponseText.get(),
|
||||
JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(),
|
||||
mStateData.mResponseText.get(),
|
||||
mStateData.mResponseText.Length());
|
||||
if (!str) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
@ -2184,3 +2195,12 @@ XMLHttpRequest::GetResponseText(nsAString& aResponseText, ErrorResult& aRv)
|
||||
aRv = mStateData.mResponseTextResult;
|
||||
aResponseText = mStateData.mResponseText;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequest::UpdateState(const StateData& aStateData)
|
||||
{
|
||||
mStateData = aStateData;
|
||||
if (JSVAL_IS_GCTHING(mStateData.mResponse)) {
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#ifndef mozilla_dom_workers_xmlhttprequest_h__
|
||||
#define mozilla_dom_workers_xmlhttprequest_h__
|
||||
|
||||
#include "mozilla/dom/workers/bindings/XMLHttpRequestEventTarget.h"
|
||||
#include "mozilla/dom/workers/bindings/WorkerFeature.h"
|
||||
|
||||
// Need this for XMLHttpRequestResponseType.
|
||||
@ -15,6 +14,7 @@
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsXMLHttpRequest.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
@ -22,7 +22,7 @@ class Proxy;
|
||||
class XMLHttpRequestUpload;
|
||||
class WorkerPrivate;
|
||||
|
||||
class XMLHttpRequest : public XMLHttpRequestEventTarget,
|
||||
class XMLHttpRequest : public nsXHREventTarget,
|
||||
public WorkerFeature
|
||||
{
|
||||
public:
|
||||
@ -45,8 +45,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
JS::Heap<JSObject*> mJSObject;
|
||||
XMLHttpRequestUpload* mUpload;
|
||||
nsRefPtr<XMLHttpRequestUpload> mUpload;
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<Proxy> mProxy;
|
||||
XMLHttpRequestResponseType mResponseType;
|
||||
@ -54,7 +53,7 @@ private:
|
||||
|
||||
uint32_t mTimeout;
|
||||
|
||||
bool mJSObjectRooted;
|
||||
bool mRooted;
|
||||
bool mBackgroundRequest;
|
||||
bool mWithCredentials;
|
||||
bool mCanceled;
|
||||
@ -63,22 +62,30 @@ private:
|
||||
bool mMozSystem;
|
||||
|
||||
protected:
|
||||
XMLHttpRequest(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
|
||||
XMLHttpRequest(WorkerPrivate* aWorkerPrivate);
|
||||
virtual ~XMLHttpRequest();
|
||||
|
||||
public:
|
||||
virtual void
|
||||
_trace(JSTracer* aTrc) MOZ_OVERRIDE;
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
_finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(XMLHttpRequest,
|
||||
nsXHREventTarget)
|
||||
|
||||
static XMLHttpRequest*
|
||||
nsISupports*
|
||||
GetParentObject() const
|
||||
{
|
||||
// There's only one global on a worker, so we don't need to specify.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static already_AddRefed<XMLHttpRequest>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const MozXMLHttpRequestParameters& aParams,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static XMLHttpRequest*
|
||||
static already_AddRefed<XMLHttpRequest>
|
||||
Constructor(const GlobalObject& aGlobal, const nsAString& ignored,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -98,22 +105,7 @@ public:
|
||||
bool
|
||||
Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE;
|
||||
|
||||
#define IMPL_GETTER_AND_SETTER(_type) \
|
||||
already_AddRefed<EventHandlerNonNull> \
|
||||
GetOn##_type(ErrorResult& aRv) \
|
||||
{ \
|
||||
return GetEventListener(NS_LITERAL_STRING(#_type), aRv); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
SetOn##_type(EventHandlerNonNull* aListener, ErrorResult& aRv) \
|
||||
{ \
|
||||
SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv); \
|
||||
}
|
||||
|
||||
IMPL_GETTER_AND_SETTER(readystatechange)
|
||||
|
||||
#undef IMPL_GETTER_AND_SETTER
|
||||
IMPL_EVENT_HANDLER(readystatechange)
|
||||
|
||||
uint16_t
|
||||
ReadyState() const
|
||||
@ -260,10 +252,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
UpdateState(const StateData& aStateData)
|
||||
{
|
||||
mStateData = aStateData;
|
||||
}
|
||||
UpdateState(const StateData& aStateData);
|
||||
|
||||
void
|
||||
NullResponseText()
|
||||
@ -295,13 +284,14 @@ private:
|
||||
MaybeDispatchPrematureAbortEvents(ErrorResult& aRv);
|
||||
|
||||
void
|
||||
DispatchPrematureAbortEvent(JS::Handle<JSObject*> aTarget, uint8_t aEventType,
|
||||
bool aUploadTarget, ErrorResult& aRv);
|
||||
DispatchPrematureAbortEvent(EventTarget* aTarget,
|
||||
const nsAString& aEventType, bool aUploadTarget,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
SendInProgress() const
|
||||
{
|
||||
return mJSObjectRooted;
|
||||
return mRooted;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1,20 +0,0 @@
|
||||
/* -*- 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 "XMLHttpRequestEventTarget.h"
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
void
|
||||
XMLHttpRequestEventTarget::_trace(JSTracer* aTrc)
|
||||
{
|
||||
EventTarget::_trace(aTrc);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestEventTarget::_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
EventTarget::_finalize(aFop);
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_xmlhttprequesteventtarget_h__
|
||||
#define mozilla_dom_workers_xmlhttprequesteventtarget_h__
|
||||
|
||||
#include "mozilla/dom/workers/bindings/EventTarget.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class XMLHttpRequestEventTarget : public EventTarget
|
||||
{
|
||||
protected:
|
||||
XMLHttpRequestEventTarget(JSContext* aCx)
|
||||
: EventTarget(aCx)
|
||||
{ }
|
||||
|
||||
virtual ~XMLHttpRequestEventTarget()
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual void
|
||||
_trace(JSTracer* aTrc) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
_finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
|
||||
|
||||
#define IMPL_GETTER_AND_SETTER(_type) \
|
||||
already_AddRefed<EventHandlerNonNull> \
|
||||
GetOn##_type(ErrorResult& aRv) \
|
||||
{ \
|
||||
return GetEventListener(NS_LITERAL_STRING(#_type), aRv); \
|
||||
} \
|
||||
\
|
||||
void \
|
||||
SetOn##_type(EventHandlerNonNull* aListener, ErrorResult& aRv) \
|
||||
{ \
|
||||
SetEventListener(NS_LITERAL_STRING(#_type), aListener, aRv); \
|
||||
}
|
||||
|
||||
IMPL_GETTER_AND_SETTER(loadstart)
|
||||
IMPL_GETTER_AND_SETTER(progress)
|
||||
IMPL_GETTER_AND_SETTER(abort)
|
||||
IMPL_GETTER_AND_SETTER(error)
|
||||
IMPL_GETTER_AND_SETTER(load)
|
||||
IMPL_GETTER_AND_SETTER(timeout)
|
||||
IMPL_GETTER_AND_SETTER(loadend)
|
||||
|
||||
#undef IMPL_GETTER_AND_SETTER
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_xmlhttprequesteventtarget_h__
|
@ -7,29 +7,39 @@
|
||||
|
||||
#include "XMLHttpRequest.h"
|
||||
|
||||
#include "DOMBindingInlines.h"
|
||||
#include "mozilla/dom/XMLHttpRequestUploadBinding.h"
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
XMLHttpRequestUpload::XMLHttpRequestUpload(XMLHttpRequest* aXHR)
|
||||
: mXHR(aXHR)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
XMLHttpRequestUpload::~XMLHttpRequestUpload()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(XMLHttpRequestUpload, nsXHREventTarget)
|
||||
NS_IMPL_RELEASE_INHERITED(XMLHttpRequestUpload, nsXHREventTarget)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XMLHttpRequestUpload)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(XMLHttpRequestUpload, nsXHREventTarget,
|
||||
mXHR)
|
||||
|
||||
JSObject*
|
||||
XMLHttpRequestUpload::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return XMLHttpRequestUploadBinding_workers::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
// static
|
||||
XMLHttpRequestUpload*
|
||||
XMLHttpRequestUpload::Create(JSContext* aCx, XMLHttpRequest* aXHR)
|
||||
already_AddRefed<XMLHttpRequestUpload>
|
||||
XMLHttpRequestUpload::Create(XMLHttpRequest* aXHR)
|
||||
{
|
||||
nsRefPtr<XMLHttpRequestUpload> upload = new XMLHttpRequestUpload(aCx, aXHR);
|
||||
return Wrap(aCx, nullptr, upload) ? upload : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestUpload::_trace(JSTracer* aTrc)
|
||||
{
|
||||
if (mXHR) {
|
||||
mXHR->TraceJSObject(aTrc, "mXHR");
|
||||
}
|
||||
XMLHttpRequestEventTarget::_trace(aTrc);
|
||||
}
|
||||
|
||||
void
|
||||
XMLHttpRequestUpload::_finalize(JSFreeOp* aFop)
|
||||
{
|
||||
XMLHttpRequestEventTarget::_finalize(aFop);
|
||||
nsRefPtr<XMLHttpRequestUpload> upload = new XMLHttpRequestUpload(aXHR);
|
||||
return upload.forget();
|
||||
}
|
||||
|
@ -6,33 +6,43 @@
|
||||
#ifndef mozilla_dom_workers_xmlhttprequestupload_h__
|
||||
#define mozilla_dom_workers_xmlhttprequestupload_h__
|
||||
|
||||
#include "mozilla/dom/workers/bindings/XMLHttpRequestEventTarget.h"
|
||||
#include "nsXMLHttpRequest.h"
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class XMLHttpRequest;
|
||||
|
||||
class XMLHttpRequestUpload : public XMLHttpRequestEventTarget
|
||||
class XMLHttpRequestUpload MOZ_FINAL : public nsXHREventTarget
|
||||
{
|
||||
XMLHttpRequest* mXHR;
|
||||
nsRefPtr<XMLHttpRequest> mXHR;
|
||||
|
||||
protected:
|
||||
XMLHttpRequestUpload(JSContext* aCx, XMLHttpRequest* aXHR)
|
||||
: XMLHttpRequestEventTarget(aCx), mXHR(aXHR)
|
||||
{ }
|
||||
XMLHttpRequestUpload(XMLHttpRequest* aXHR);
|
||||
|
||||
virtual ~XMLHttpRequestUpload()
|
||||
{ }
|
||||
~XMLHttpRequestUpload();
|
||||
|
||||
public:
|
||||
static XMLHttpRequestUpload*
|
||||
Create(JSContext* aCx, XMLHttpRequest* aXHR);
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
virtual void
|
||||
_trace(JSTracer* aTrc) MOZ_OVERRIDE;
|
||||
static already_AddRefed<XMLHttpRequestUpload>
|
||||
Create(XMLHttpRequest* aXHR);
|
||||
|
||||
virtual void
|
||||
_finalize(JSFreeOp* aFop) MOZ_OVERRIDE;
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XMLHttpRequestUpload, nsXHREventTarget)
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
nsISupports*
|
||||
GetParentObject() const
|
||||
{
|
||||
// There's only one global on a worker, so we don't need to specify.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
HasListeners()
|
||||
{
|
||||
return mListenerManager && mListenerManager->HasListeners();
|
||||
}
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -11,6 +11,7 @@ MODULE = 'dom'
|
||||
# Public stuff.
|
||||
EXPORTS.mozilla.dom += [
|
||||
'WorkerPrivate.h',
|
||||
'WorkerScope.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom.workers += [
|
||||
@ -19,9 +20,6 @@ EXPORTS.mozilla.dom.workers += [
|
||||
|
||||
# Stuff needed for the bindings, not really public though.
|
||||
EXPORTS.mozilla.dom.workers.bindings += [
|
||||
'DOMBindingBase.h',
|
||||
'EventListenerManager.h',
|
||||
'EventTarget.h',
|
||||
'FileReaderSync.h',
|
||||
'Location.h',
|
||||
'MessagePort.h',
|
||||
@ -29,33 +27,26 @@ EXPORTS.mozilla.dom.workers.bindings += [
|
||||
'SharedWorker.h',
|
||||
'URL.h',
|
||||
'WorkerFeature.h',
|
||||
'WorkerMessagePort.h',
|
||||
'XMLHttpRequest.h',
|
||||
'XMLHttpRequestEventTarget.h',
|
||||
'XMLHttpRequestUpload.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'ChromeWorkerScope.cpp',
|
||||
'DOMBindingBase.cpp',
|
||||
'EventListenerManager.cpp',
|
||||
'Events.cpp',
|
||||
'EventTarget.cpp',
|
||||
'File.cpp',
|
||||
'FileReaderSync.cpp',
|
||||
'Location.cpp',
|
||||
'MessagePort.cpp',
|
||||
'Navigator.cpp',
|
||||
'Principal.cpp',
|
||||
'RegisterBindings.cpp',
|
||||
'RuntimeService.cpp',
|
||||
'ScriptLoader.cpp',
|
||||
'SharedWorker.cpp',
|
||||
'URL.cpp',
|
||||
'WorkerMessagePort.cpp',
|
||||
'WorkerPrivate.cpp',
|
||||
'WorkerScope.cpp',
|
||||
'XMLHttpRequest.cpp',
|
||||
'XMLHttpRequestEventTarget.cpp',
|
||||
'XMLHttpRequestUpload.cpp',
|
||||
]
|
||||
|
||||
@ -73,4 +64,4 @@ LOCAL_INCLUDES += [
|
||||
'/content/base/src',
|
||||
'/content/events/src',
|
||||
'/xpcom/build',
|
||||
]
|
||||
]
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
var data = [ -1, 0, 1, 1.5, null, undefined, true, false, "foo",
|
||||
var data = [ -1, 0, 1, 1.5, /* null ,*/ undefined, true, false, "foo",
|
||||
"123456789012345", "1234567890123456", "12345678901234567"];
|
||||
|
||||
var str = "";
|
||||
|
@ -5,15 +5,18 @@
|
||||
const fakeEventType = "foo";
|
||||
|
||||
function testEventTarget(event) {
|
||||
if (event.target !== self || event.currentTarget !== self) {
|
||||
if (event.target !== self) {
|
||||
throw new Error("Event has a bad target!");
|
||||
}
|
||||
if (event.currentTarget) {
|
||||
throw new Error("Event has a bad currentTarget!");
|
||||
}
|
||||
postMessage(event.data);
|
||||
}
|
||||
|
||||
addEventListener(fakeEventType, function(event) {
|
||||
throw new Error("Trusted event listener received untrusted event!");
|
||||
}, false);
|
||||
}, false, false);
|
||||
|
||||
addEventListener(fakeEventType, function(event) {
|
||||
if (event.target !== self || event.currentTarget !== self) {
|
||||
@ -49,9 +52,14 @@ onmessage = function(event) {
|
||||
throw new Error("Recursive dispatch didn't fail!");
|
||||
}
|
||||
|
||||
event.initMessageEvent(fakeEventType, event.bubbles, event.cancelable,
|
||||
event.data, "*", null);
|
||||
event = new MessageEvent(fakeEventType, { bubbles: event.bubbles,
|
||||
cancelable: event.cancelable,
|
||||
data: event.data,
|
||||
origin: "*",
|
||||
source: null
|
||||
});
|
||||
self.dispatchEvent(event);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -36,16 +36,24 @@ for (var index = 0; index < propsToCheck.length; index++) {
|
||||
}
|
||||
|
||||
onconnect = function(event) {
|
||||
if (!(event instanceof WorkerMessageEvent)) {
|
||||
throw new Error("'connect' event is not a WorkerMessageEvent!");
|
||||
if (!("SharedWorkerGlobalScope" in self)) {
|
||||
throw new Error("SharedWorkerGlobalScope should be visible!");
|
||||
}
|
||||
if (!(self instanceof SharedWorkerGlobalScope)) {
|
||||
throw new Error("The global should be a SharedWorkerGlobalScope!");
|
||||
}
|
||||
if (!(self instanceof WorkerGlobalScope)) {
|
||||
throw new Error("The global should be a WorkerGlobalScope!");
|
||||
}
|
||||
if ("DedicatedWorkerGlobalScope" in self) {
|
||||
throw new Error("DedicatedWorkerGlobalScope should not be visible!");
|
||||
}
|
||||
if (!(event instanceof MessageEvent)) {
|
||||
throw new Error("'connect' event is not a MessageEvent!");
|
||||
}
|
||||
if (!("ports" in event)) {
|
||||
throw new Error("'connect' event doesn't have a 'ports' property!");
|
||||
}
|
||||
if (!Array.isArray(event.ports)) {
|
||||
throw new Error("'connect' event has 'ports' property that isn't an " +
|
||||
"Array!");
|
||||
}
|
||||
if (event.ports.length != 1) {
|
||||
throw new Error("'connect' event has a 'ports' property with length '" +
|
||||
event.ports.length + "'!");
|
||||
@ -53,28 +61,26 @@ onconnect = function(event) {
|
||||
if (!event.ports[0]) {
|
||||
throw new Error("'connect' event has a null 'ports[0]' property!");
|
||||
}
|
||||
if (!(event.ports[0] instanceof WorkerMessagePort)) {
|
||||
if (!(event.ports[0] instanceof MessagePort)) {
|
||||
throw new Error("'connect' event has a 'ports[0]' property that isn't a " +
|
||||
"MessagePort!");
|
||||
}
|
||||
if (!(event.ports[0] == event.source)) {
|
||||
throw new Error("'connect' event source property is incorrect!");
|
||||
}
|
||||
if (event.data) {
|
||||
throw new Error("'connect' event has data: " + event.data);
|
||||
}
|
||||
|
||||
event.ports[0].onmessage = function(event) {
|
||||
if (!(event instanceof WorkerMessageEvent)) {
|
||||
throw new Error("'message' event is not a WorkerMessageEvent!");
|
||||
if (!(event instanceof MessageEvent)) {
|
||||
throw new Error("'message' event is not a MessageEvent!");
|
||||
}
|
||||
if (!("ports" in event)) {
|
||||
throw new Error("'message' event doesn't have a 'ports' property!");
|
||||
}
|
||||
if (!Array.isArray(event.ports)) {
|
||||
throw new Error("'message' event has 'ports' property that isn't an " +
|
||||
"Array!");
|
||||
}
|
||||
if (event.ports.length) {
|
||||
throw new Error("'message' event has a 'ports' property with length '" +
|
||||
event.ports.length + "'!");
|
||||
if (!(event.ports === null)) {
|
||||
throw new Error("'message' event has a non-null 'ports' property!");
|
||||
}
|
||||
event.target.postMessage(event.data);
|
||||
throw new Error(event.data);
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
function messageListener(event) {
|
||||
var exception;
|
||||
try {
|
||||
@ -11,8 +13,7 @@ function messageListener(event) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (!(exception instanceof TypeError) ||
|
||||
exception.message != "setting a property that has only a getter") {
|
||||
if (!(exception instanceof TypeError)) {
|
||||
throw exception;
|
||||
}
|
||||
|
||||
@ -36,4 +37,17 @@ function messageListener(event) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!("DedicatedWorkerGlobalScope" in self)) {
|
||||
throw new Error("DedicatedWorkerGlobalScope should be visible!");
|
||||
}
|
||||
if (!(self instanceof DedicatedWorkerGlobalScope)) {
|
||||
throw new Error("The global should be a SharedWorkerGlobalScope!");
|
||||
}
|
||||
if (!(self instanceof WorkerGlobalScope)) {
|
||||
throw new Error("The global should be a WorkerGlobalScope!");
|
||||
}
|
||||
if ("SharedWorkerGlobalScope" in self) {
|
||||
throw new Error("SharedWorkerGlobalScope should not be visible!");
|
||||
}
|
||||
|
||||
addEventListener("message", { handleEvent: messageListener });
|
||||
|
@ -24,19 +24,17 @@
|
||||
const sentMessage = "ping";
|
||||
const errorFilename = href.substring(0, href.lastIndexOf("/") + 1) +
|
||||
filename;
|
||||
const errorLine = 80;
|
||||
const errorLine = 86;
|
||||
const errorColumn = 0;
|
||||
|
||||
ok(!("SharedWorker" in window), "No SharedWorker without pref set");
|
||||
ok(!("WorkerMessagePort" in window),
|
||||
"No WorkerMessagePort without pref set");
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [[swPref, true]] }, function() {
|
||||
var worker = new SharedWorker(filename);
|
||||
|
||||
ok(worker instanceof SharedWorker, "Got SharedWorker instance");
|
||||
ok(!("postMessage" in worker), "SharedWorker has no 'postMessage'");
|
||||
ok(worker.port instanceof WorkerMessagePort,
|
||||
ok(worker.port instanceof MessagePort,
|
||||
"Shared worker has MessagePort");
|
||||
|
||||
var receivedMessage;
|
||||
|
Loading…
Reference in New Issue
Block a user