mirror of
https://github.com/roytam1/palemoon26.git
synced 2026-05-26 05:44:31 +00:00
ported mozilla patches:
- bug677638 - (initial) MessageChannel API - bug887241, Use strings, not atoms, for worker events, r=khuey
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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); \
|
||||
} \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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); \
|
||||
} \
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
@@ -176,7 +176,9 @@ webidl_files = \
|
||||
MediaStreamAudioDestinationNode.webidl \
|
||||
MediaStreamEvent.webidl \
|
||||
MediaStreamTrack.webidl \
|
||||
MessageChannel.webidl \
|
||||
MessageEvent.webidl \
|
||||
MessagePort.webidl \
|
||||
MobileMessageManager.webidl \
|
||||
MouseEvent.webidl \
|
||||
MouseScrollEvent.webidl \
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user