Bug 928312: Convert the worker global object and all remaining EventTargets to new DOM bindings. r=bent,peterv,smaug

This commit is contained in:
Kyle Huey 2013-11-05 22:16:26 +08:00
parent f66e59b158
commit 2789485d96
65 changed files with 1738 additions and 4975 deletions

View File

@ -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")

View File

@ -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,

View File

@ -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;
};

View File

@ -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

View File

@ -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()

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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)) &&

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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': {

View File

@ -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:

View File

@ -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))

View File

@ -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;

View File

@ -329,6 +329,7 @@ var interfaceNamesInGlobalScope =
"MediaStreamEvent",
"MediaStreamTrack",
"MessageEvent",
"MessagePort",
"MimeType",
"MimeTypeArray",
"ModalContentWindow",

View 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;
};

View File

@ -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;
};

View File

@ -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();

View File

@ -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;

View 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;
};

View 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);
};

View File

@ -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;
};

View File

@ -57,7 +57,6 @@ dictionary MozXMLHttpRequestParameters
Constructor(DOMString ignored)]
interface XMLHttpRequest : XMLHttpRequestEventTarget {
// event handler
[SetterThrows=Workers, GetterThrows=Workers]
attribute EventHandler onreadystatechange;
// states

View File

@ -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',

View File

@ -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

View File

@ -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__

View File

@ -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__

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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

View File

@ -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__

View File

@ -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),

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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;

View 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;
}

View File

@ -49,7 +49,6 @@
#include "OSFileConstants.h"
#include "xpcpublic.h"
#include "Events.h"
#include "SharedWorker.h"
#include "WorkerPrivate.h"

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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();
}
}

View File

@ -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__

View File

@ -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

View File

@ -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

View File

@ -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__ */

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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__

View File

@ -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();
}

View File

@ -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

View File

@ -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',
]
]

View File

@ -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 = "";

View File

@ -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;
}

View File

@ -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);

View File

@ -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 });

View File

@ -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;