ported mozilla patches:

- bug677638 - (initial) MessageChannel API
- bug887241, Use strings, not atoms, for worker events, r=khuey
This commit is contained in:
2018-08-25 22:56:03 +08:00
parent 8b5ae12ba7
commit b20724f725
36 changed files with 1787 additions and 85 deletions
+6 -3
View File
@@ -3181,9 +3181,12 @@ nsContentUtils::IsEventAttributeName(nsIAtom* aName, int32_t aType)
uint32_t
nsContentUtils::GetEventId(nsIAtom* aName)
{
EventNameMapping mapping;
if (sAtomEventTable->Get(aName, &mapping))
return mapping.mId;
if (aName) {
EventNameMapping mapping;
if (sAtomEventTable->Get(aName, &mapping)) {
return mapping.mId;
}
}
return NS_USER_DEFINED_EVENT;
}
+4 -2
View File
@@ -2115,13 +2115,15 @@ nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
#define EVENT(name_, id_, type_, struct_) \
EventHandlerNonNull* nsINode::GetOn##name_() { \
nsEventListenerManager *elm = GetListenerManager(false); \
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_) : nullptr; \
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
: nullptr; \
} \
void nsINode::SetOn##name_(EventHandlerNonNull* handler, \
ErrorResult& error) { \
nsEventListenerManager *elm = GetListenerManager(true); \
if (elm) { \
error = elm->SetEventHandler(nsGkAtoms::on##name_, handler); \
error = elm->SetEventHandler(nsGkAtoms::on##name_, \
EmptyString(), handler); \
} else { \
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
} \
+8 -9
View File
@@ -48,18 +48,16 @@ public:
ErrorResult& aRv);
bool DispatchEvent(nsDOMEvent& aEvent, ErrorResult& aRv);
// Note, this takes the type in onfoo form!
EventHandlerNonNull* GetEventHandler(const nsAString& aType)
{
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
return GetEventHandler(type);
return GetEventHandler(type, EmptyString());
}
// Note, this takes the type in onfoo form!
void SetEventHandler(const nsAString& aType, EventHandlerNonNull* aHandler,
ErrorResult& rv)
{
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
return SetEventHandler(type, aHandler, rv);
}
ErrorResult& rv);
// Note, for an event 'foo' aType will be 'onfoo'.
virtual void EventListenerAdded(nsIAtom* aType) {}
@@ -71,9 +69,10 @@ public:
virtual nsIDOMWindow* GetOwnerGlobal() = 0;
protected:
EventHandlerNonNull* GetEventHandler(nsIAtom* aType);
void SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,
ErrorResult& rv);
EventHandlerNonNull* GetEventHandler(nsIAtom* aType,
const nsAString& aTypeString);
void SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
EventHandlerNonNull* aHandler, ErrorResult& rv);
};
NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)
+21 -4
View File
@@ -23,17 +23,34 @@ EventTarget::RemoveEventListener(const nsAString& aType,
}
EventHandlerNonNull*
EventTarget::GetEventHandler(nsIAtom* aType)
EventTarget::GetEventHandler(nsIAtom* aType, const nsAString& aTypeString)
{
nsEventListenerManager* elm = GetListenerManager(false);
return elm ? elm->GetEventHandler(aType) : nullptr;
return elm ? elm->GetEventHandler(aType, aTypeString) : nullptr;
}
void
EventTarget::SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,
EventTarget::SetEventHandler(const nsAString& aType,
EventHandlerNonNull* aHandler,
ErrorResult& rv)
{
rv = GetListenerManager(true)->SetEventHandler(aType, aHandler);
if (NS_IsMainThread()) {
nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
return SetEventHandler(type, EmptyString(), aHandler, rv);
}
return SetEventHandler(nullptr,
Substring(aType, 2), // Remove "on"
aHandler, rv);
}
void
EventTarget::SetEventHandler(nsIAtom* aType, const nsAString& aTypeString,
EventHandlerNonNull* aHandler,
ErrorResult& rv)
{
rv = GetListenerManager(true)->SetEventHandler(aType,
aTypeString,
aHandler);
}
} // namespace dom
+13 -8
View File
@@ -59,6 +59,7 @@ nsDOMEvent::ConstructorInit(mozilla::dom::EventTarget* aOwner,
{
SetIsDOMBinding();
SetOwner(aOwner);
mIsMainThreadEvent = mOwner || NS_IsMainThread();
mPrivateDataDuplicated = false;
@@ -221,19 +222,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// nsIDOMEventInterface
NS_METHOD nsDOMEvent::GetType(nsAString& aType)
{
if (!mCachedType.IsEmpty()) {
aType = mCachedType;
if (!mIsMainThreadEvent || !mEvent->typeString.IsEmpty()) {
aType = mEvent->typeString;
return NS_OK;
}
const char* name = GetEventName(mEvent->message);
if (name) {
CopyASCIItoUTF16(name, aType);
mCachedType = aType;
return NS_OK;
} else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) {
aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on"
mCachedType = aType;
mEvent->typeString = aType;
return NS_OK;
}
@@ -459,9 +459,15 @@ nsDOMEvent::PreventDefault()
void
nsDOMEvent::SetEventType(const nsAString& aEventTypeArg)
{
mEvent->userType =
nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
&(mEvent->message));
if (mIsMainThreadEvent) {
mEvent->userType =
nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
&(mEvent->message));
} else {
mEvent->userType = nullptr;
mEvent->message = NS_USER_DEFINED_EVENT;
mEvent->typeString = aEventTypeArg;
}
}
NS_IMETHODIMP
@@ -488,7 +494,6 @@ nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, bool aCanBubbleArg, bool a
// re-dispatching it.
mEvent->target = nullptr;
mEvent->originalTarget = nullptr;
mCachedType = aEventTypeArg;
return NS_OK;
}
+1 -1
View File
@@ -185,9 +185,9 @@ protected:
nsRefPtr<nsPresContext> mPresContext;
nsCOMPtr<mozilla::dom::EventTarget> mExplicitOriginalTarget;
nsCOMPtr<nsPIDOMWindow> mOwner; // nsPIDOMWindow for now.
nsString mCachedType;
bool mEventIsInternal;
bool mPrivateDataDuplicated;
bool mIsMainThreadEvent;
};
#define NS_FORWARD_TO_NSDOMEVENT \
@@ -289,7 +289,7 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
handler = new EventHandlerNonNull(callable);
}
ErrorResult rv;
SetEventHandler(aType, handler, rv);
SetEventHandler(aType, EmptyString(), handler, rv);
return rv.ErrorCode();
}
@@ -298,7 +298,7 @@ nsDOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
JSContext* aCx,
JS::Value* aValue)
{
EventHandlerNonNull* handler = GetEventHandler(aType);
EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
if (handler) {
*aValue = JS::ObjectValue(*handler->Callable());
} else {
+11 -2
View File
@@ -166,12 +166,21 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMEventTargetHelper,
#define IMPL_EVENT_HANDLER(_event) \
inline mozilla::dom::EventHandlerNonNull* GetOn##_event() \
{ \
return GetEventHandler(nsGkAtoms::on##_event); \
if (NS_IsMainThread()) { \
return GetEventHandler(nsGkAtoms::on##_event, EmptyString()); \
} \
return GetEventHandler(nullptr, NS_LITERAL_STRING(#_event)); \
} \
inline void SetOn##_event(mozilla::dom::EventHandlerNonNull* aCallback, \
mozilla::ErrorResult& aRv) \
{ \
SetEventHandler(nsGkAtoms::on##_event, aCallback, aRv); \
if (NS_IsMainThread()) { \
SetEventHandler(nsGkAtoms::on##_event, EmptyString(), \
aCallback, aRv); \
} else { \
SetEventHandler(nullptr, NS_LITERAL_STRING(#_event), \
aCallback, aRv); \
} \
}
/* Use this macro to declare functions that forward the behavior of this
+72 -40
View File
@@ -64,9 +64,11 @@ using namespace mozilla::hal;
static PRLogModuleInfo* gXssPRLog;
#endif
#define EVENT_TYPE_EQUALS(ls, type, userType, allEvents) \
((ls->mEventType == type && \
(ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType)) || \
#define EVENT_TYPE_EQUALS(ls, type, userType, typeString, allEvents) \
((ls->mEventType == type && \
(ls->mEventType != NS_USER_DEFINED_EVENT || \
(mIsMainThreadELM && ls->mTypeAtom == userType) || \
(!mIsMainThreadELM && ls->mTypeString.Equals(typeString)))) || \
(allEvents && ls->mAllEvents))
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
@@ -116,12 +118,14 @@ nsEventListenerManager::nsEventListenerManager(EventTarget* aTarget) :
mMayHaveTouchEventListener(false),
mMayHaveMouseEnterLeaveEventListener(false),
mClearingListeners(false),
mIsMainThreadELM(NS_IsMainThread()),
mNoListenerForEvent(0),
mTarget(aTarget)
{
NS_ASSERTION(aTarget, "unexpected null pointer");
++sCreatedCount;
if (mIsMainThreadELM)
++sCreatedCount;
// enable logging for XSS
#ifdef PR_LOGGING
@@ -217,11 +221,14 @@ nsEventListenerManager::AddEventListenerInternal(
const EventListenerHolder& aListener,
uint32_t aType,
nsIAtom* aTypeAtom,
const nsAString& aTypeString,
const EventListenerFlags& aFlags,
bool aHandler,
bool aAllEvents)
{
NS_ABORT_IF_FALSE((aType && aTypeAtom) || aAllEvents, "Missing type");
MOZ_ASSERT((NS_IsMainThread() && aType && aTypeAtom) || // Main thread
(!NS_IsMainThread() && aType && !aTypeString.IsEmpty()) || // non-main-thread
aAllEvents, "Missing type"); // all-events listener
if (!aListener || mClearingListeners) {
return;
@@ -238,7 +245,7 @@ nsEventListenerManager::AddEventListenerInternal(
if (ls->mListener == aListener &&
ls->mListenerIsHandler == aHandler &&
ls->mFlags == aFlags &&
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aAllEvents)) {
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents)) {
return;
}
}
@@ -248,7 +255,9 @@ nsEventListenerManager::AddEventListenerInternal(
ls = aAllEvents ? mListeners.InsertElementAt(0) : mListeners.AppendElement();
ls->mListener = aListener;
MOZ_ASSERT(aType < PR_UINT16_MAX);
ls->mEventType = aType;
ls->mTypeString = aTypeString;
ls->mTypeAtom = aTypeAtom;
ls->mFlags = aFlags;
ls->mListenerIsHandler = aHandler;
@@ -451,6 +460,7 @@ nsEventListenerManager::RemoveEventListenerInternal(
const EventListenerHolder& aListener,
uint32_t aType,
nsIAtom* aUserType,
const nsAString& aTypeString,
const EventListenerFlags& aFlags,
bool aAllEvents)
{
@@ -471,7 +481,7 @@ nsEventListenerManager::RemoveEventListenerInternal(
for (uint32_t i = 0; i < count; ++i) {
ls = &mListeners.ElementAt(i);
if (EVENT_TYPE_EQUALS(ls, aType, aUserType, aAllEvents)) {
if (EVENT_TYPE_EQUALS(ls, aType, aUserType, aTypeString, aAllEvents)) {
++typeCount;
if (ls->mListener == aListener &&
ls->mFlags.EqualsIgnoringTrustness(aFlags)) {
@@ -513,15 +523,23 @@ nsEventListenerManager::RemoveEventListenerInternal(
}
}
static inline bool
ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
bool
nsEventListenerManager::ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent)
{
// This is slightly different from EVENT_TYPE_EQUALS in that it returns
// true even when aEvent->message == NS_USER_DEFINED_EVENT and
// aLs=>mEventType != NS_USER_DEFINED_EVENT as long as the atoms are the same
return (aEvent->message == NS_USER_DEFINED_EVENT ?
(aLs->mTypeAtom == aEvent->userType) :
(aLs->mEventType == aEvent->message)) || aLs->mAllEvents;
if (aLs->mAllEvents) {
return true;
}
if (aEvent->message == NS_USER_DEFINED_EVENT) {
if (mIsMainThreadELM) {
return aLs->mTypeAtom == aEvent->userType;
}
return aLs->mTypeString.Equals(aEvent->typeString);
}
MOZ_ASSERT(mIsMainThreadELM);
return aLs->mEventType == aEvent->message;
}
void
@@ -529,9 +547,10 @@ nsEventListenerManager::AddEventListenerByType(const EventListenerHolder& aListe
const nsAString& aType,
const EventListenerFlags& aFlags)
{
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
nsCOMPtr<nsIAtom> atom =
mIsMainThreadELM ? do_GetAtom(NS_LITERAL_STRING("on") + aType) : nullptr;
uint32_t type = nsContentUtils::GetEventId(atom);
AddEventListenerInternal(aListener, type, atom, aFlags);
AddEventListenerInternal(aListener, type, atom, aType, aFlags);
}
void
@@ -540,14 +559,16 @@ nsEventListenerManager::RemoveEventListenerByType(
const nsAString& aType,
const EventListenerFlags& aFlags)
{
nsCOMPtr<nsIAtom> atom = do_GetAtom(NS_LITERAL_STRING("on") + aType);
nsCOMPtr<nsIAtom> atom =
mIsMainThreadELM ? do_GetAtom(NS_LITERAL_STRING("on") + aType) : nullptr;
uint32_t type = nsContentUtils::GetEventId(atom);
RemoveEventListenerInternal(aListener, type, atom, aFlags);
RemoveEventListenerInternal(aListener, type, atom, aType, aFlags);
}
nsListenerStruct*
nsEventListenerManager::FindEventHandler(uint32_t aEventType,
nsIAtom* aTypeAtom)
nsIAtom* aTypeAtom,
const nsAString& aTypeString)
{
// Run through the listeners for this type and see if a script
// listener is registered
@@ -556,7 +577,7 @@ nsEventListenerManager::FindEventHandler(uint32_t aEventType,
for (uint32_t i = 0; i < count; ++i) {
ls = &mListeners.ElementAt(i);
if (ls->mListenerIsHandler &&
EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom, false)) {
EVENT_TYPE_EQUALS(ls, aEventType, aTypeAtom, aTypeString, false)) {
return ls;
}
}
@@ -567,6 +588,7 @@ nsresult
nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
JS::Handle<JSObject*> aScopeObject,
nsIAtom* aName,
const nsAString& aTypeString,
const nsEventHandler& aHandler,
bool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct)
@@ -576,7 +598,7 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
nsresult rv = NS_OK;
uint32_t eventType = nsContentUtils::GetEventId(aName);
nsListenerStruct* ls = FindEventHandler(eventType, aName);
nsListenerStruct* ls = FindEventHandler(eventType, aName, aTypeString);
if (!ls) {
// If we didn't find a script listener or no listeners existed
@@ -590,9 +612,10 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
if (NS_SUCCEEDED(rv)) {
EventListenerHolder holder(scriptListener);
AddEventListenerInternal(holder, eventType, aName, flags, true);
AddEventListenerInternal(holder, eventType, aName, aTypeString, flags,
true);
ls = FindEventHandler(eventType, aName);
ls = FindEventHandler(eventType, aName, aTypeString);
}
} else {
nsIJSEventListener* scriptListener = ls->GetJSListener();
@@ -761,8 +784,8 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
global->GetGlobalJSObject());
nsListenerStruct *ls;
rv = SetEventHandlerInternal(context, scope, aName, nsEventHandler(),
aPermitUntrustedEvents, &ls);
rv = SetEventHandlerInternal(context, scope, aName, EmptyString(),
nsEventHandler(), aPermitUntrustedEvents, &ls);
NS_ENSURE_SUCCESS(rv, rv);
if (!aDeferCompilation) {
@@ -773,14 +796,15 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
}
void
nsEventListenerManager::RemoveEventHandler(nsIAtom* aName)
nsEventListenerManager::RemoveEventHandler(nsIAtom* aName,
const nsAString& aTypeString)
{
if (mClearingListeners) {
return;
}
uint32_t eventType = nsContentUtils::GetEventId(aName);
nsListenerStruct* ls = FindEventHandler(eventType, aName);
nsListenerStruct* ls = FindEventHandler(eventType, aName, aTypeString);
if (ls) {
mListeners.RemoveElementAt(uint32_t(ls - &mListeners.ElementAt(0)));
@@ -1095,8 +1119,8 @@ nsEventListenerManager::AddListenerForAllEvents(nsIDOMEventListener* aListener,
flags.mAllowUntrustedEvents = aWantsUntrusted;
flags.mInSystemGroup = aSystemEventGroup;
EventListenerHolder holder(aListener);
AddEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, flags,
false, true);
AddEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, EmptyString(),
flags, false, true);
}
void
@@ -1108,8 +1132,8 @@ nsEventListenerManager::RemoveListenerForAllEvents(nsIDOMEventListener* aListene
flags.mCapture = aUseCapture;
flags.mInSystemGroup = aSystemEventGroup;
EventListenerHolder holder(aListener);
RemoveEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, flags,
true);
RemoveEventListenerInternal(holder, NS_EVENT_TYPE_ALL, nullptr, EmptyString(),
flags, true);
}
bool
@@ -1231,10 +1255,11 @@ nsEventListenerManager::HasUnloadListeners()
nsresult
nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
const nsAString& aTypeString,
EventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(aEventName);
RemoveEventHandler(aEventName, aTypeString);
return NS_OK;
}
@@ -1242,15 +1267,17 @@ nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, JS::NullPtr(), aEventName,
nsEventHandler(aHandler),
!nsContentUtils::IsCallerChrome(), &ignored);
aTypeString, nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome(),
&ignored);
}
nsresult
nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(nsGkAtoms::onerror);
RemoveEventHandler(nsGkAtoms::onerror, EmptyString());
return NS_OK;
}
@@ -1258,15 +1285,17 @@ nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onerror,
nsEventHandler(aHandler),
!nsContentUtils::IsCallerChrome(), &ignored);
EmptyString(), nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome(),
&ignored);
}
nsresult
nsEventListenerManager::SetEventHandler(BeforeUnloadEventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(nsGkAtoms::onbeforeunload);
RemoveEventHandler(nsGkAtoms::onbeforeunload, EmptyString());
return NS_OK;
}
@@ -1274,15 +1303,18 @@ nsEventListenerManager::SetEventHandler(BeforeUnloadEventHandlerNonNull* aHandle
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, JS::NullPtr(), nsGkAtoms::onbeforeunload,
nsEventHandler(aHandler),
!nsContentUtils::IsCallerChrome(), &ignored);
EmptyString(), nsEventHandler(aHandler),
!mIsMainThreadELM ||
!nsContentUtils::IsCallerChrome(),
&ignored);
}
const nsEventHandler*
nsEventListenerManager::GetEventHandlerInternal(nsIAtom *aEventName)
nsEventListenerManager::GetEventHandlerInternal(nsIAtom *aEventName,
const nsAString& aTypeString)
{
uint32_t eventType = nsContentUtils::GetEventId(aEventName);
nsListenerStruct* ls = FindEventHandler(eventType, aEventName);
nsListenerStruct* ls = FindEventHandler(eventType, aEventName, aTypeString);
if (!ls) {
return nullptr;
+23 -10
View File
@@ -163,8 +163,9 @@ typedef enum
struct nsListenerStruct
{
mozilla::dom::EventListenerHolder mListener;
nsCOMPtr<nsIAtom> mTypeAtom;
uint32_t mEventType;
nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
nsString mTypeString; // for non-main-threads
uint16_t mEventType;
uint8_t mListenerType;
bool mListenerIsHandler : 1;
bool mHandlerIsString : 1;
@@ -298,7 +299,7 @@ public:
/**
* Remove the current "inline" event listener for aName.
*/
void RemoveEventHandler(nsIAtom *aName);
void RemoveEventHandler(nsIAtom *aName, const nsAString& aTypeString);
void HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent,
@@ -431,7 +432,8 @@ protected:
/**
* Find the nsListenerStruct for the "inline" event listener for aTypeAtom.
*/
nsListenerStruct* FindEventHandler(uint32_t aEventType, nsIAtom* aTypeAtom);
nsListenerStruct* FindEventHandler(uint32_t aEventType, nsIAtom* aTypeAtom,
const nsAString& aTypeString);
/**
* Set the "inline" event listener for aName to aHandler. aHandler may be
@@ -444,6 +446,7 @@ protected:
nsresult SetEventHandlerInternal(nsIScriptContext *aContext,
JS::Handle<JSObject*> aScopeGlobal,
nsIAtom* aName,
const nsAString& aTypeString,
const nsEventHandler& aHandler,
bool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct);
@@ -458,6 +461,7 @@ public:
* aHandler is null, this will actually remove the event listener
*/
nsresult SetEventHandler(nsIAtom* aEventName,
const nsAString& aTypeString,
mozilla::dom::EventHandlerNonNull* aHandler);
nsresult SetEventHandler(mozilla::dom::OnErrorEventHandlerNonNull* aHandler);
nsresult SetEventHandler(mozilla::dom::BeforeUnloadEventHandlerNonNull* aHandler);
@@ -471,20 +475,23 @@ public:
* OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
* for others.
*/
mozilla::dom::EventHandlerNonNull* GetEventHandler(nsIAtom *aEventName)
mozilla::dom::EventHandlerNonNull* GetEventHandler(nsIAtom *aEventName,
const nsAString& aTypeString)
{
const nsEventHandler* handler = GetEventHandlerInternal(aEventName);
const nsEventHandler* handler =
GetEventHandlerInternal(aEventName, aTypeString);
return handler ? handler->EventHandler() : nullptr;
}
mozilla::dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler()
{
const nsEventHandler* handler = GetEventHandlerInternal(nsGkAtoms::onerror);
const nsEventHandler* handler =
GetEventHandlerInternal(nsGkAtoms::onerror, EmptyString());
return handler ? handler->OnErrorEventHandler() : nullptr;
}
mozilla::dom::BeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler()
{
const nsEventHandler* handler =
GetEventHandlerInternal(nsGkAtoms::onbeforeunload);
GetEventHandlerInternal(nsGkAtoms::onbeforeunload, EmptyString());
return handler ? handler->BeforeUnloadEventHandler() : nullptr;
}
@@ -493,7 +500,8 @@ protected:
* Helper method for implementing the various Get*EventHandler above. Will
* return null if we don't have an event handler for this event name.
*/
const nsEventHandler* GetEventHandlerInternal(nsIAtom* aEventName);
const nsEventHandler* GetEventHandlerInternal(nsIAtom* aEventName,
const nsAString& aTypeString);
void AddEventListener(const nsAString& aType,
const mozilla::dom::EventListenerHolder& aListener,
@@ -507,6 +515,7 @@ protected:
const mozilla::dom::EventListenerHolder& aListener,
uint32_t aType,
nsIAtom* aTypeAtom,
const nsAString& aTypeString,
const mozilla::dom::EventListenerFlags& aFlags,
bool aHandler = false,
bool aAllEvents = false);
@@ -514,6 +523,7 @@ protected:
const mozilla::dom::EventListenerHolder& aListener,
uint32_t aType,
nsIAtom* aUserType,
const nsAString& aTypeString,
const mozilla::dom::EventListenerFlags& aFlags,
bool aAllEvents = false);
void RemoveAllListeners();
@@ -522,6 +532,8 @@ protected:
nsPIDOMWindow* GetInnerWindowForTarget();
already_AddRefed<nsPIDOMWindow> GetTargetAsInnerWindow() const;
bool ListenerCanHandle(nsListenerStruct* aLs, nsEvent* aEvent);
uint32_t mMayHavePaintEventListener : 1;
uint32_t mMayHaveMutationListeners : 1;
uint32_t mMayHaveCapturingListeners : 1;
@@ -530,7 +542,8 @@ protected:
uint32_t mMayHaveTouchEventListener : 1;
uint32_t mMayHaveMouseEnterLeaveEventListener : 1;
uint32_t mClearingListeners : 1;
uint32_t mNoListenerForEvent : 24;
uint32_t mIsMainThreadELM : 1;
uint32_t mNoListenerForEvent : 23;
nsAutoTObserverArray<nsListenerStruct, 2> mListeners;
mozilla::dom::EventTarget* mTarget; //WEAK
@@ -1020,7 +1020,7 @@ nsGenericHTMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
else if (IsEventAttributeName(aAttribute)) {
nsEventListenerManager* manager = GetListenerManager(false);
if (manager) {
manager->RemoveEventHandler(aAttribute);
manager->RemoveEventHandler(aAttribute, EmptyString());
}
}
}
+1 -1
View File
@@ -666,7 +666,7 @@ nsSVGElement::UnsetAttrInternal(int32_t aNamespaceID, nsIAtom* aName,
nsEventListenerManager* manager = GetListenerManager(false);
if (manager) {
nsIAtom* eventName = GetEventNameForAttr(aName);
manager->RemoveEventHandler(eventName);
manager->RemoveEventHandler(eventName, EmptyString());
}
return;
}
+81
View File
@@ -0,0 +1,81 @@
/* -*- Mode: C++; 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/. */
#include "MessageChannel.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/MessageChannelBinding.h"
#include "mozilla/dom/MessagePort.h"
#include "nsContentUtils.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(MessageChannel, mWindow, mPort1, mPort2)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
namespace {
bool gPrefInitialized = false;
bool gPrefEnabled = false;
}
/* static */ bool
MessageChannel::PrefEnabled()
{
if (!gPrefInitialized) {
Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled");
gPrefInitialized = true;
}
return gPrefEnabled;
}
MessageChannel::MessageChannel(nsPIDOMWindow* aWindow)
: mWindow(aWindow)
{
MOZ_COUNT_CTOR(MessageChannel);
SetIsDOMBinding();
mPort1 = new MessagePort(mWindow);
mPort2 = new MessagePort(mWindow);
mPort1->Entangle(mPort2);
mPort2->Entangle(mPort1);
}
MessageChannel::~MessageChannel()
{
MOZ_COUNT_DTOR(MessageChannel);
}
JSObject*
MessageChannel::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MessageChannelBinding::Wrap(aCx, aScope, this);
}
/* static */ already_AddRefed<MessageChannel>
MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.Get());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<MessageChannel> channel = new MessageChannel(window);
return channel.forget();
}
} // namespace dom
} // namespace mozilla
+72
View File
@@ -0,0 +1,72 @@
/* -*- Mode: C++; 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/. */
#ifndef mozilla_dom_MessageChannel_h
#define mozilla_dom_MessageChannel_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "nsCOMPtr.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class MessagePort;
class MessageChannel MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessageChannel)
static bool PrefEnabled();
public:
MessageChannel(nsPIDOMWindow* aWindow);
~MessageChannel();
nsPIDOMWindow*
GetParentObject() const
{
return mWindow;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
static already_AddRefed<MessageChannel>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
MessagePort*
Port1() const
{
return mPort1;
}
MessagePort*
Port2() const
{
return mPort2;
}
private:
nsCOMPtr<nsPIDOMWindow> mWindow;
nsRefPtr<MessagePort> mPort1;
nsRefPtr<MessagePort> mPort2;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessageChannel_h
+477
View File
@@ -0,0 +1,477 @@
/* -*- Mode: C++; 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/. */
#include "MessagePort.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/StructuredCloneTags.h"
#include "nsGlobalWindow.h"
#include "nsContentUtils.h"
#include "nsEventDispatcher.h"
#include "nsPresContext.h"
#include "nsDOMEvent.h"
#include "nsIDocument.h"
#include "nsIDOMFile.h"
#include "nsIDOMFileList.h"
#include "nsIDOMMessageEvent.h"
#include "nsIPresShell.h"
namespace mozilla {
namespace dom {
class DispatchEventRunnable : public nsRunnable
{
friend class MessagePort;
public:
DispatchEventRunnable(MessagePort* aPort)
: mPort(aPort)
{
}
NS_IMETHOD
Run()
{
nsRefPtr<DispatchEventRunnable> mKungFuDeathGrip(this);
mPort->mDispatchRunnable = nullptr;
mPort->Dispatch();
return NS_OK;
}
private:
nsRefPtr<MessagePort> mPort;
};
class PostMessageRunnable : public nsRunnable
{
friend class MessagePort;
public:
NS_DECL_NSIRUNNABLE
PostMessageRunnable()
: mMessage(nullptr)
, mMessageLen(0)
{
}
~PostMessageRunnable()
{
// Ensure that the buffer is freed
if (mMessage) {
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(mMessage, mMessageLen);
}
}
void SetJSData(JSAutoStructuredCloneBuffer& aBuffer)
{
NS_ASSERTION(!mMessage && mMessageLen == 0, "Don't call twice!");
aBuffer.steal(&mMessage, &mMessageLen);
}
bool StoreISupports(nsISupports* aSupports)
{
mSupportsArray.AppendElement(aSupports);
return true;
}
void Dispatch(MessagePort* aPort)
{
mPort = aPort;
NS_DispatchToCurrentThread(this);
}
private:
nsRefPtr<MessagePort> mPort;
uint64_t* mMessage;
size_t mMessageLen;
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
};
namespace {
struct StructuredCloneInfo
{
PostMessageRunnable* mEvent;
MessagePort* mPort;
};
static JSObject*
PostMessageReadStructuredClone(JSContext* cx,
JSStructuredCloneReader* reader,
uint32_t tag,
uint32_t data,
void* closure)
{
NS_ASSERTION(closure, "Must have closure!");
if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
NS_ASSERTION(!data, "Data should be empty");
nsISupports* supports;
if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
JS::Rooted<JSObject*> global(cx, JS_GetGlobalForScopeChain(cx));
if (global) {
JS::Rooted<JS::Value> val(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
val.address(),
getter_AddRefs(wrapper)))) {
return JSVAL_TO_OBJECT(val);
}
}
}
}
if (tag == SCTAG_DOM_MESSAGEPORT) {
NS_ASSERTION(!data, "Data should be empty");
MessagePort* port;
if (JS_ReadBytes(reader, &port, sizeof(port))) {
JS::Rooted<JSObject*> global(cx, JS_GetGlobalForScopeChain(cx));
if (global) {
JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
if (JS_WrapObject(cx, obj.address())) {
return obj;
}
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
if (runtimeCallbacks) {
return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
}
return nullptr;
}
static JSBool
PostMessageWriteStructuredClone(JSContext* cx,
JSStructuredCloneWriter* writer,
JS::Handle<JSObject*> obj,
void *closure)
{
StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(closure);
NS_ASSERTION(scInfo, "Must have scInfo!");
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
if (wrappedNative) {
uint32_t scTag = 0;
nsISupports* supports = wrappedNative->Native();
nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
if (blob) {
scTag = SCTAG_DOM_BLOB;
}
nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
if (list) {
scTag = SCTAG_DOM_FILELIST;
}
if (scTag) {
return JS_WriteUint32Pair(writer, scTag, 0) &&
JS_WriteBytes(writer, &supports, sizeof(supports)) &&
scInfo->mEvent->StoreISupports(supports);
}
}
MessagePort* port = nullptr;
nsresult rv = mozilla::dom::UnwrapObject<MessagePort>(cx, obj, port);
if (NS_SUCCEEDED(rv)) {
nsRefPtr<MessagePort> newPort = port->Clone(scInfo->mPort->GetOwner());
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
scInfo->mEvent->StoreISupports(newPort);
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
if (runtimeCallbacks) {
return runtimeCallbacks->write(cx, writer, obj, nullptr);
}
return false;
}
JSStructuredCloneCallbacks kPostMessageCallbacks = {
PostMessageReadStructuredClone,
PostMessageWriteStructuredClone,
nullptr
};
} // anonymous namespace
NS_IMETHODIMP
PostMessageRunnable::Run()
{
nsresult rv;
MOZ_ASSERT(mPort);
// Ensure that the buffer is freed even if we fail to post the message
JSAutoStructuredCloneBuffer buffer;
buffer.adopt(mMessage, mMessageLen);
mMessage = nullptr;
mMessageLen = 0;
// Get the JSContext for the target window
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mPort->GetOwner());
NS_ENSURE_STATE(sgo);
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
: nsContentUtils::GetSafeJSContext());
MOZ_ASSERT(cx);
// Deserialize the structured clone data
JS::Rooted<JS::Value> messageData(cx);
{
StructuredCloneInfo scInfo;
scInfo.mEvent = this;
scInfo.mPort = mPort;
if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks,
&scInfo)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
}
// Create the event
nsIDocument* doc = mPort->GetOwner()->GetExtantDoc();
if (!doc) {
return NS_OK;
}
ErrorResult error;
nsRefPtr<nsDOMEvent> event =
doc->CreateEvent(NS_LITERAL_STRING("MessageEvent"), error);
if (error.Failed()) {
return NS_OK;
}
nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event);
rv = message->InitMessageEvent(NS_LITERAL_STRING("message"),
false /* non-bubbling */,
true /* cancelable */,
messageData,
EmptyString(),
EmptyString(),
mPort->GetOwner());
if (NS_FAILED(rv)) {
return NS_OK;
}
message->SetTrusted(true);
bool status;
mPort->DispatchEvent(event, &status);
return status ? NS_OK : NS_ERROR_FAILURE;
}
//NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntangledPort)
// Custom unlink loop because this array contains nsRunnable objects
// which are not cycle colleactable.
while (!tmp->mMessageQueue.IsEmpty()) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mPort);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mSupportsArray);
tmp->mMessageQueue.RemoveElementAt(0);
}
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntangledPort)
// Custom unlink loop because this array contains nsRunnable objects
// which are not cycle colleactable.
for (uint32_t i = 0, len = tmp->mMessageQueue.Length(); i < len; ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mPort);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mSupportsArray);
}
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(MessagePort, nsDOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MessagePort, nsDOMEventTargetHelper)
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
: nsDOMEventTargetHelper(aWindow)
, mMessageQueueEnabled(false)
{
MOZ_COUNT_CTOR(MessagePort);
SetIsDOMBinding();
}
MessagePort::~MessagePort()
{
MOZ_COUNT_DTOR(MessagePort);
Close();
}
JSObject*
MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MessagePortBinding::Wrap(aCx, aScope, this);
}
void
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<JS::Handle<JS::Value> >& aTransfer,
ErrorResult& aRv)
{
nsRefPtr<PostMessageRunnable> event = new PostMessageRunnable();
// We *must* clone the data here, or the JS::Value could be modified
// by script
JSAutoStructuredCloneBuffer buffer;
StructuredCloneInfo scInfo;
scInfo.mEvent = event;
scInfo.mPort = this;
JS::Handle<JS::Value> transferable = aTransfer.WasPassed()
? aTransfer.Value()
: JS::UndefinedHandleValue;
if (!buffer.write(aCx, aMessage, transferable, &kPostMessageCallbacks,
&scInfo)) {
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
return;
}
event->SetJSData(buffer);
if (!mEntangledPort) {
return;
}
mEntangledPort->mMessageQueue.AppendElement(event);
mEntangledPort->Dispatch();
}
void
MessagePort::Start()
{
if (mMessageQueueEnabled) {
return;
}
mMessageQueueEnabled = true;
Dispatch();
}
void
MessagePort::Dispatch()
{
if (!mMessageQueueEnabled || mMessageQueue.IsEmpty() || mDispatchRunnable) {
return;
}
nsRefPtr<PostMessageRunnable> event = mMessageQueue.ElementAt(0);
mMessageQueue.RemoveElementAt(0);
event->Dispatch(this);
mDispatchRunnable = new DispatchEventRunnable(this);
NS_DispatchToCurrentThread(mDispatchRunnable);
}
void
MessagePort::Close()
{
if (!mEntangledPort) {
return;
}
// This avoids loops.
nsRefPtr<MessagePort> port = mEntangledPort;
mEntangledPort = nullptr;
// Let's disentangle the 2 ports symmetrically.
port->Close();
}
EventHandlerNonNull*
MessagePort::GetOnmessage()
{
if (NS_IsMainThread()) {
return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
}
return GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
}
void
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv)
{
if (NS_IsMainThread()) {
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback, aRv);
} else {
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback, aRv);
}
// When using onmessage, the call to start() is implied.
Start();
}
void
MessagePort::Entangle(MessagePort* aMessagePort)
{
MOZ_ASSERT(aMessagePort);
MOZ_ASSERT(aMessagePort != this);
Close();
mEntangledPort = aMessagePort;
}
already_AddRefed<MessagePort>
MessagePort::Clone(nsPIDOMWindow* aWindow)
{
nsRefPtr<MessagePort> newPort = new MessagePort(aWindow->GetCurrentInnerWindow());
// Move all the events in the port message queue of original port.
newPort->mMessageQueue.SwapElements(mMessageQueue);
if (mEntangledPort) {
nsRefPtr<MessagePort> port = mEntangledPort;
mEntangledPort = nullptr;
newPort->Entangle(port);
port->Entangle(newPort);
}
return newPort.forget();
}
} // namespace dom
} // namespace mozilla
+86
View File
@@ -0,0 +1,86 @@
/* -*- Mode: C++; 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/. */
#ifndef mozilla_dom_MessagePort_h
#define mozilla_dom_MessagePort_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsDOMEventTargetHelper.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class DispatchEventRunnable;
class PostMessageRunnable;
class MessagePort MOZ_FINAL : public nsDOMEventTargetHelper
{
friend class DispatchEventRunnable;
friend class PostMessageRunnable;
public:
NS_DECL_ISUPPORTS_INHERITED
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
nsDOMEventTargetHelper)
MessagePort(nsPIDOMWindow* aWindow);
~MessagePort();
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);
void
Start();
void
Close();
// The 'message' event handler has to call |Start()| method, so we
// cannot use IMPL_EVENT_HANDLER macro here.
EventHandlerNonNull*
GetOnmessage();
void
SetOnmessage(EventHandlerNonNull* aCallback, ErrorResult& aRv);
// Non WebIDL methods
// This method entangles this MessagePort with another one.
// If it is already entangled, it's disentangled first and enatangle to the
// new one.
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(nsPIDOMWindow* aWindow);
private:
// Dispatch events from the Message Queue using a nsRunnable.
void Dispatch();
nsRefPtr<DispatchEventRunnable> mDispatchRunnable;
nsRefPtr<MessagePort> mEntangledPort;
nsTArray<nsRefPtr<PostMessageRunnable> > mMessageQueue;
bool mMessageQueueEnabled;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessagePort_h
+1
View File
@@ -28,6 +28,7 @@ enum StructuredCloneTags {
// These tags are used for both main thread and workers.
SCTAG_DOM_IMAGEDATA,
SCTAG_DOM_MESSAGEPORT,
SCTAG_DOM_MAX
};
+4
View File
@@ -60,6 +60,8 @@ EXPORTS.mozilla.dom += [
'DOMCursor.h',
'DOMError.h',
'DOMRequest.h',
'MessageChannel.h',
'MessagePort.h',
'ScreenOrientation.h',
'StructuredCloneTags.h',
'URL.h',
@@ -72,6 +74,8 @@ CPP_SOURCES += [
'DOMError.cpp',
'DOMRequest.cpp',
'Navigator.cpp',
'MessageChannel.cpp',
'MessagePort.cpp',
'URL.cpp',
'nsContentPermissionHelper.cpp',
'nsDOMClassInfo.cpp',
+33
View File
@@ -210,6 +210,9 @@
#include "prlog.h"
#include "prenv.h"
#include "mozilla/dom/MessageChannel.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/indexedDB/IDBFactory.h"
#include "mozilla/dom/quota/QuotaManager.h"
@@ -6667,6 +6670,7 @@ namespace {
struct StructuredCloneInfo {
PostMessageEvent* event;
bool subsumes;
nsPIDOMWindow* window;
};
static JSObject*
@@ -6696,6 +6700,21 @@ PostMessageReadStructuredClone(JSContext* cx,
}
}
if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MESSAGEPORT) {
NS_ASSERTION(!data, "Data should be empty");
MessagePort* port;
if (JS_ReadBytes(reader, &port, sizeof(port))) {
JS::Rooted<JSObject*> global(cx, JS_GetGlobalForScopeChain(cx));
if (global) {
JS::Rooted<JSObject*> obj(cx, port->WrapObject(cx, global));
if (JS_WrapObject(cx, obj.address())) {
return obj;
}
}
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
@@ -6736,6 +6755,18 @@ PostMessageWriteStructuredClone(JSContext* cx,
scInfo->event->StoreISupports(supports);
}
if (MessageChannel::PrefEnabled()) {
MessagePort* port = nullptr;
nsresult rv = mozilla::dom::UnwrapObject<MessagePort>(cx, obj, port);
if (NS_SUCCEEDED(rv) && scInfo->subsumes) {
nsRefPtr<MessagePort> newPort = port->Clone(scInfo->window);
return JS_WriteUint32Pair(writer, SCTAG_DOM_MESSAGEPORT, 0) &&
JS_WriteBytes(writer, &newPort, sizeof(newPort)) &&
scInfo->event->StoreISupports(newPort);
}
}
const JSStructuredCloneCallbacks* runtimeCallbacks =
js::GetContextStructuredCloneCallbacks(cx);
@@ -6827,6 +6858,7 @@ PostMessageEvent::Run()
{
StructuredCloneInfo scInfo;
scInfo.event = this;
scInfo.window = targetWindow;
if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks,
&scInfo)) {
@@ -6973,6 +7005,7 @@ nsGlobalWindow::PostMessageMoz(const JS::Value& aMessage,
JSAutoStructuredCloneBuffer buffer;
StructuredCloneInfo scInfo;
scInfo.event = event;
scInfo.window = this;
nsIPrincipal* principal = GetPrincipal();
if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)))
+4 -2
View File
@@ -715,14 +715,16 @@ public:
mozilla::dom::EventHandlerNonNull* GetOn##name_() \
{ \
nsEventListenerManager *elm = GetListenerManager(false); \
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_) : nullptr; \
return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
: nullptr; \
} \
void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler, \
mozilla::ErrorResult& error) \
{ \
nsEventListenerManager *elm = GetListenerManager(true); \
if (elm) { \
error = elm->SetEventHandler(nsGkAtoms::on##name_, handler); \
error = elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), \
handler); \
} else { \
error.Throw(NS_ERROR_OUT_OF_MEMORY); \
} \
+11
View File
@@ -31,6 +31,17 @@ MOCHITEST_FILES = \
test_Image_constructor.html \
test_setting_opener.html \
test_error.html \
test_messageChannel.html \
test_messageChannel_cloning.html \
iframe_messageChannel_cloning.html \
test_messageChannel_post.html \
iframe_messageChannel_post.html \
test_messageChannel_transferable.html \
test_messageChannel_start.html \
test_messageChannel_pingpong.html \
iframe_messageChannel_pingpong.html \
test_messageChannel_unshipped.html \
test_messageChannel_pref.html \
test_url.html \
$(NULL)
@@ -0,0 +1,22 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
function ok(a, msg) {
window.parent.postMessage({ status: a ? "OK" : "KO", message: msg }, "*");
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
ok (evt.data, "Data received");
ok (evt.data.port instanceof MessagePort, "Data contains a MessagePort");
var a = new MessageChannel();
window.parent.postMessage({ status: "FINISH", port: a.port2 }, '*');
}
</script>
</body>
</html>
@@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
function ok(what, msg) {
window.parent.postMessage({type: what ? 'OK' : 'KO', msg: msg }, '*');
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.type == 'PORT') {
var port = evt.data.port;
var counter = 0;
port.onmessage = function(evt) {
if (counter++ == 0) {
ok(!(evt.data % 2), "The number " + evt.data + " has been received correctly by the iframe");
window.parent.postMessage({ type: 'PORT', port: port }, '*');
}
else {
ok(false, "Wrong message!");
}
}
} else {
ok(false, "Unknown message");
}
}
</script>
</body>
</html>
@@ -0,0 +1,24 @@
<!DOCTYPE HTML>
<html>
<body>
<script type="application/javascript">
var port;
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
port = evt.data.port;
port.addEventListener('message', receivePostMessage, false);
function receivePostMessage(evt) {
port.postMessage(evt.data);
}
port.start();
window.parent.postMessage({ status: "READY" }, '*');
}
</script>
</body>
</html>
+49
View File
@@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - basic support</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe name="x" id="x"></iframe>
<iframe name="y" id="y"></iframe>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTest() {
/** Test for Bug 677638 **/
var a = new MessageChannel();
ok(a, "MessageChannel created");
var port1 = a.port1;
ok(port1, "MessageChannel.port1 exists");
is(port1, a.port1, "MessageChannel.port1 is port1");
var port2 = a.port2;
ok(port2, "MessageChannel.port1 exists");
is(port2, a.port2, "MessageChannel.port2 is port2");
[ 'postMessage', 'start', 'close' ].forEach(function(e) {
ok(e in port1, "MessagePort1." + e + " exists");
ok(e in port2, "MessagePort2." + e + " exists");
});
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>
@@ -0,0 +1,70 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
// This test checks if MessagePorts can be shared with iframes
function test_iframe() {
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'OK') {
ok(true, evt.data.message);
} else if (evt.data.status == 'KO') {
ok(false, evt.data.message);
} else if (evt.data.status == 'FINISH') {
ok (evt.data.port instanceof MessagePort, "Data contains a MessagePort");
window.removeEventListener('message', receiveMessage);
runTest();
} else {
ok(false, "Unknown message");
}
}
var a = new MessageChannel();
ok(a, "MessageChannel created");
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_cloning.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
}
var tests = [
test_iframe
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>
@@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTest() {
var MAX = 100;
var a = new MessageChannel();
ok(a, "MessageChannel created");
// Populate the message queue of this port.
for (var i = 0; i < MAX; ++i) {
a.port1.postMessage(i);
}
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
// This test sends the port from this window to the iframe and viceversa.
if (evt.data.type == 'PORT') {
var port = evt.data.port;
var counter = 0;
port.onmessage = function(evt) {
// only 1 message should be received by this port.
if (counter++ == 0) {
ok(evt.data % 2, "The number " + evt.data + " has been received correctly by the main window");
if (evt.data < MAX - 1) {
ifr.contentWindow.postMessage({ type: 'PORT', port: port }, '*');
} else {
SimpleTest.finish();
}
} else {
ok(false, "Wrong message!");
}
}
} else if (evt.data.type == 'OK') {
ok(true, evt.data.msg);
} else if (evt.data.type == 'KO') {
ok(false, evt.data.msg);
} else {
ok(false, "Unknown message");
}
}
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_pingpong.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ type: 'PORT', port: a.port2 }, '*');
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>
@@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function start() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'READY') {
runTest();
} else {
ok(false, "Unknown message");
}
}
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_post.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
var tests = [ 42,
null,
undefined,
"hello world",
new Blob([]),
true ];
a.port1.onmessage = function(evt) {
ok(tests.length, "We are waiting for a message");
is(tests[0], evt.data, "Value ok: " + tests[0]);
tests.shift();
runTest();
}
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
a.port1.postMessage(tests[0]);
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, start);
</script>
</body>
</html>
@@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - pref</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTest(what) {
var status;
try {
status = MessageChannel;
ok(what, "Should MessageChannel exist?");
} catch(e) {
ok(!what, "Should MessageChannel exist?");
}
try {
status = MessagePort;
ok(what, "Should MessagePort exist?");
} catch(e) {
ok(!what, "Should MessagePort exist?");
}
}
SimpleTest.waitForExplicitFinish();
runTest(false);
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]},
function() { runTest(true); SimpleTest.finish(); });
</script>
</body>
</html>
@@ -0,0 +1,234 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - start/close</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
function testOnMessage() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
a.port1.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
a.port2.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
}
function testAddEventListener() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
a.port1.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
a.port2.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
setTimeout(runTests, 0);
}
function testAddEventListenerAndStart() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
a.port1.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port1.start();
a.port2.start();
}
function testAddEventListener1AndStart() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 1;
a.port1.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
a.port1.start();
}
function testAddEventListener2AndStart() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 1;
a.port1.addEventListener('message', function(evt) {
ok(false, "This method should not be called");
}, false);
a.port2.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.start();
}
function testTimer() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
setTimeout(function() {
var events = 2;
a.port1.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
a.port2.onmessage = function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}
}, 200);
}
function testAddEventListenerAndStartWrongOrder() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
a.port1.start();
a.port1.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
a.port2.start();
a.port2.addEventListener('message', function(evt) {
ok(true, "This method should be called");
if (!--events) runTests();
}, false);
}
function testOnMessageClone() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
a.port1.postMessage(42);
a.port2.postMessage(43);
ok(true, "MessagePort{1,2}.postmessage() invoked");
var events = 2;
addEventListener('message', testOnMessageCloneCb, false);
function testOnMessageCloneCb(evt) {
a.port1.onmessage = function(evt) {
ok(true, "This method should be called");
testOnMessageCloneFinish();
}
evt.data.onmessage = function(evt) {
ok(true, "This method should be called");
testOnMessageCloneFinish();
}
a.port2.onmessage = function(evt) {
ok(false, "This method should not be called");
}
}
function testOnMessageCloneFinish() {
if (!--events) {
removeEventListener('message', testOnMessageCloneCb);
runTests();
}
}
postMessage(a.port2, '*');
}
var tests = [
testOnMessage,
testAddEventListener,
testAddEventListenerAndStart,
testAddEventListener1AndStart,
testAddEventListener2AndStart,
testTimer,
testAddEventListenerAndStartWrongOrder,
testOnMessageClone,
];
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
</script>
</body>
</html>
@@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - port cloning</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function start() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
if (evt.data.status == 'READY') {
runTest();
} else {
ok(false, "Unknown message");
}
}
var div = document.getElementById("content");
ok(div, "Parent exists");
var ifr = document.createElement("iframe");
ifr.addEventListener("load", iframeLoaded, false);
ifr.setAttribute('src', "iframe_messageChannel_post.html");
div.appendChild(ifr);
function iframeLoaded() {
ifr.contentWindow.postMessage({ port: a.port2 }, '*');
}
a.port1.addEventListener('message', receivePortMessage, false);
function receivePortMessage(evt) {
is(evt.data.ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
SimpleTest.finish();
}
// Start() is not implicity invoked when addEventListener is used.
a.port1.start();
var size = 1024 * 1024 * 32;
var ab = new ArrayBuffer(size);
is(ab.byteLength, size, "The size is: " + size + " == " + ab.byteLength);
function runTest() {
a.port1.postMessage({ab: ab, cb: ab}, [ab]);
ok(ab.byteLength == 0, "PostMessage - The size is: 0 == " + ab.byteLength)
}
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, start);
</script>
</body>
</html>
@@ -0,0 +1,123 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677638
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 677638 - unshipped message port queue</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677638">Mozilla Bug 677638</a>
<div id="content"></div>
<pre id="test">
</pre>
<script type="application/javascript">
function test_orderedMessages() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
var b = new MessageChannel();
ok(b, "MessageChannel created");
var expectedNumber = 1;
function testEvent(number, id) {
is(expectedNumber, number, "This is the right number!");
ok(!((expectedNumber - id) % 4), "From the right port: " + expectedNumber + " " + id);
expectedNumber++;
if (expectedNumber >100) {
runTests();
}
}
a.port1.onmessage = function(evt) {
testEvent(evt.data, 2);
};
a.port2.onmessage = function(evt) {
testEvent(evt.data, 1);
};
b.port1.onmessage = function(evt) {
testEvent(evt.data, 4);
};
b.port2.onmessage = function(evt) {
testEvent(evt.data, 3);
};
for (var i = 0; i < 100;) {
a.port1.postMessage(++i);
a.port2.postMessage(++i);
b.port1.postMessage(++i);
b.port2.postMessage(++i);
}
}
function test_unstarted() {
var a = new MessageChannel();
ok(a, "MessageChannel created");
var b = new MessageChannel();
ok(b, "MessageChannel created");
var expectedNumber = 1;
function testEvent(number, id) {
is(expectedNumber, number, "This is the right number!");
ok(!((expectedNumber - id) % 3), "From the right port: " + expectedNumber + " " + id);
expectedNumber++;
// 102 because it's the first multiple of 3.
if (expectedNumber > 102) {
runTests();
}
}
a.port1.onmessage = function(evt) {
testEvent(evt.data, 2);
};
a.port2.onmessage = function(evt) {
testEvent(evt.data, 1);
};
b.port1.addEventListener("message", function() {
ok(false, "shouldn't be called");
});
b.port2.onmessage = function(evt) {
testEvent(evt.data, 3);
};
for (var i = 0; i < 100;) {
a.port1.postMessage(++i);
a.port2.postMessage(++i);
b.port1.postMessage(++i);
b.port2.postMessage(1000);
}
}
var tests = [
test_orderedMessages,
test_unstarted
];
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTests);
</script>
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
/* -*- 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/.
*
* For more information on this interface, please see
* http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
*/
[Constructor, Pref="dom.messageChannel.enabled"]
interface MessageChannel {
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
};
+23
View File
@@ -0,0 +1,23 @@
/* -*- 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/.
*
* For more information on this interface, please see
* 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 start();
void close();
// event handlers
[SetterThrows]
attribute EventHandler onmessage;
};
// MessagePort implements Transferable;
+2
View File
@@ -176,7 +176,9 @@ webidl_files = \
MediaStreamAudioDestinationNode.webidl \
MediaStreamEvent.webidl \
MediaStreamTrack.webidl \
MessageChannel.webidl \
MessageEvent.webidl \
MessagePort.webidl \
MobileMessageManager.webidl \
MouseEvent.webidl \
MouseScrollEvent.webidl \
+3
View File
@@ -681,6 +681,9 @@ public:
// Additional type info for user defined events
nsCOMPtr<nsIAtom> userType;
nsString typeString; // always set on non-main-thread events
// Event targets, needed by DOM Events
nsCOMPtr<mozilla::dom::EventTarget> target;
nsCOMPtr<mozilla::dom::EventTarget> currentTarget;