Bug 848294 - Update MessageEvent to be compatible with the spec, r=bz

This commit is contained in:
Andrea Marchesini 2013-09-11 16:10:01 +02:00
Родитель 50a1f2048b
Коммит 443f276420
17 изменённых файлов: 331 добавлений и 65 удалений

Просмотреть файл

@ -35,8 +35,9 @@
xhr.send(null);
}
function done() {
var event = document.createEvent("MessageEvent");
event.initMessageEvent("461743", true, false, "done", location.href, "", window);
var event = new MessageEvent('461743', { bubbles: true, cancelable: false,
data: "done", origin: location.href,
source: window });
document.dispatchEvent(event);
frames[0].document.removeEventListener("DOMNodeInserted", loadChrome, true);
frames[0].document.removeEventListener("DOMNodeInserted", delay, true);

Просмотреть файл

@ -44,8 +44,9 @@
}
document.getElementById("state").textContent = "done";
var event = document.createEvent("MessageEvent");
event.initMessageEvent("464620_a", true, false, "done", location.href, "", window);
var event = new MessageEvent('464620_a', { bubbles: true, cancelable: false,
data: "done", origin: location.href,
source: window });
document.dispatchEvent(event);
}
</script>

Просмотреть файл

@ -48,8 +48,9 @@
}
document.getElementById("state").textContent = "done";
var event = document.createEvent("MessageEvent");
event.initMessageEvent("464620_b", true, false, "done", location.href, "", window);
var event = new MessageEvent('464620_b', { bubbles: true, cancelable: false,
data: "done", origin: location.href,
source: window });
document.dispatchEvent(event);
}
</script>

Просмотреть файл

@ -4,6 +4,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDOMMessageEvent.h"
#include "mozilla/dom/MessagePort.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/dom/MessagePortList.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/HoldDropJSObjects.h"
#include "jsapi.h"
@ -15,11 +19,15 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMessageEvent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
tmp->mData = JSVAL_VOID;
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
@ -82,10 +90,88 @@ nsDOMMessageEvent::GetLastEventId(nsAString& aLastEventId)
NS_IMETHODIMP
nsDOMMessageEvent::GetSource(nsIDOMWindow** aSource)
{
NS_IF_ADDREF(*aSource = mSource);
NS_IF_ADDREF(*aSource = mWindowSource);
return NS_OK;
}
void
nsDOMMessageEvent::GetSource(Nullable<mozilla::dom::WindowProxyOrMessagePortReturnValue>& aValue) const
{
if (mWindowSource) {
aValue.SetValue().SetAsWindowProxy() = mWindowSource;
} else if (mPortSource) {
aValue.SetValue().SetAsMessagePort() = mPortSource;
}
}
/* static */ already_AddRefed<nsDOMMessageEvent>
nsDOMMessageEvent::Constructor(const mozilla::dom::GlobalObject& aGlobal,
JSContext* aCx, const nsAString& aType,
const mozilla::dom::MessageEventInit& aParam,
mozilla::ErrorResult& aRv)
{
nsCOMPtr<mozilla::dom::EventTarget> t =
do_QueryInterface(aGlobal.GetAsSupports());
nsRefPtr<nsDOMMessageEvent> event =
new nsDOMMessageEvent(t, nullptr, nullptr);
aRv = event->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
if (aRv.Failed()) {
return nullptr;
}
bool trusted = event->Init(t);
event->SetTrusted(trusted);
if (aParam.mData.WasPassed()) {
event->mData = aParam.mData.Value();
}
mozilla::HoldJSObjects(event.get());
if (aParam.mOrigin.WasPassed()) {
event->mOrigin = aParam.mOrigin.Value();
}
if (aParam.mLastEventId.WasPassed()) {
event->mLastEventId = aParam.mLastEventId.Value();
}
if (aParam.mSource) {
nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
nsContentUtils::XPConnect()->
GetWrappedNativeOfJSObject(aCx, aParam.mSource,
getter_AddRefs(wrappedNative));
if (wrappedNative) {
event->mWindowSource = do_QueryWrappedNative(wrappedNative);
}
if (!event->mWindowSource) {
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, aCx, aParam.mSource, port);
if (NS_FAILED(rv)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return nullptr;
}
event->mPortSource = port;
}
}
if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
nsTArray<nsRefPtr<MessagePort> > ports;
for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
}
event->mPorts = new MessagePortList(static_cast<nsDOMEventBase*>(event),
ports);
}
return event.forget();
}
NS_IMETHODIMP
nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
bool aCanBubble,
@ -102,7 +188,7 @@ nsDOMMessageEvent::InitMessageEvent(const nsAString& aType,
mozilla::HoldJSObjects(this);
mOrigin = aOrigin;
mLastEventId = aLastEventId;
mSource = aSource;
mWindowSource = aSource;
return NS_OK;
}

Просмотреть файл

@ -11,6 +11,13 @@
#include "nsCycleCollectionParticipant.h"
#include "mozilla/dom/MessageEventBinding.h"
namespace mozilla {
namespace dom {
class MessagePortList;
class WindowProxyOrMessagePortReturnValue;
}
}
/**
* Implements the MessageEvent event, used for cross-document messaging and
* server-sent events.
@ -43,31 +50,26 @@ public:
JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv);
already_AddRefed<nsIDOMWindow> GetSource()
void GetSource(Nullable<mozilla::dom::WindowProxyOrMessagePortReturnValue>& aValue) const;
mozilla::dom::MessagePortList* GetPorts()
{
nsCOMPtr<nsIDOMWindow> ret = mSource;
return ret.forget();
return mPorts;
}
void InitMessageEvent(JSContext* aCx,
const nsAString& aType,
bool aCanBubble,
bool aCancelable,
JS::Handle<JS::Value> aData,
const nsAString& aOrigin,
const nsAString& aLastEventId,
nsIDOMWindow* aSource,
mozilla::ErrorResult& aRv)
{
aRv = InitMessageEvent(aType, aCanBubble, aCancelable, aData,
aOrigin, aLastEventId, aSource);
}
static already_AddRefed<nsDOMMessageEvent>
Constructor(const mozilla::dom::GlobalObject& aGlobal, JSContext* aCx,
const nsAString& aType,
const mozilla::dom::MessageEventInit& aEventInit,
mozilla::ErrorResult& aRv);
private:
JS::Heap<JS::Value> mData;
nsString mOrigin;
nsString mLastEventId;
nsCOMPtr<nsIDOMWindow> mSource;
nsCOMPtr<nsIDOMWindow> mWindowSource;
nsCOMPtr<mozilla::dom::MessagePort> mPortSource;
nsRefPtr<mozilla::dom::MessagePortList> mPorts;
};
#endif // nsDOMMessageEvent_h__

Просмотреть файл

@ -96,6 +96,7 @@ MOCHITEST_FILES = \
test_bug855741.html \
test_dblclick_explicit_original_target.html \
test_all_synthetic_events.html \
test_messageEvent.html \
$(NULL)
ifeq (,$(filter gonk,$(MOZ_WIDGET_TOOLKIT)))

Просмотреть файл

@ -189,10 +189,9 @@ const kEventConstructors = {
},
},
MessageEvent: { create: function (aName, aProps) {
var e = document.createEvent("messageevent");
e.initMessageEvent(aName, aProps.bubbles, aProps.cancelable,
aProps.data, aProps.origin,
aProps.lastEventId, aProps.source);
var e = new MessageEvent("messageevent", { bubbles: aProps.bubbles,
cancelable: aProps.cancelable, data: aProps.data, origin: aProps.origin,
lastEventId: aProps.lastEventId, source: aProps.source });
return e;
},
},

Просмотреть файл

@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=848294
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 848294</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript">
function runTest() {
var channel = new MessageChannel();
var tests = [
{},
{ data: 42 },
{ data: {} },
{ data: true, origin: 'wow' },
{ data: [], lastEventId: 'wow2' },
{ data: null, source: null },
{ data: window, source: window },
{ data: window, source: channel.port1 },
{ data: window, source: channel.port1, ports: [ channel.port1, channel.port2 ] },
{ data: null, ports: null },
];
while (tests.length) {
var test = tests.shift();
var e = new MessageEvent('message', test);
ok(e, "MessageEvent created");
is(e.type, 'message', 'MessageEvent.type is right');
is(e.data, 'data' in test ? test.data : undefined, 'MessageEvent.data is ok');
is(e.origin, 'origin' in test ? test.origin : '', 'MessageEvent.origin is ok');
is(e.lastEventId, 'lastEventId' in test ? test.lastEventId : '', 'MessageEvent.lastEventId is ok');
is(e.source, 'source' in test ? test.source : undefined, 'MessageEvent.source is ok');
if (test.ports != undefined) {
is(e.ports.length, test.ports.length, 'MessageEvent.ports is ok');
is(e.ports, e.ports, 'MessageEvent.ports is ok');
} else {
ok(!('ports' in test) || test.ports == null, 'MessageEvent.ports is ok');
}
}
try {
var e = new MessageEvent('foobar', { source: 42 });
ok(false, "Source has to be a window or a port");
} catch(e) {
ok(true, "Source has to be a window or a port");
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, runTest);
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "MessagePortList.h"
#include "mozilla/dom/MessagePortListBinding.h"
#include "mozilla/dom/MessagePort.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(MessagePortList, mOwner, mPorts)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MessagePortList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MessagePortList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePortList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
MessagePortList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return MessagePortListBinding::Wrap(aCx, aScope, this);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_MessagePortList_h
#define mozilla_dom_MessagePortList_h
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/dom/MessagePort.h"
#include "nsWrapperCache.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
class MessagePortList MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessagePortList)
public:
MessagePortList(nsISupports* aOwner, nsTArray<nsRefPtr<MessagePort> >& aPorts)
: mOwner(aOwner)
, mPorts(aPorts)
{
SetIsDOMBinding();
}
nsISupports*
GetParentObject() const
{
return mOwner;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
uint32_t
Length() const
{
return mPorts.Length();
}
MessagePort*
Item(uint32_t aIndex)
{
return mPorts.SafeElementAt(aIndex);
}
MessagePort*
IndexedGetter(uint32_t aIndex, bool &aFound)
{
aFound = aIndex < mPorts.Length();
if (!aFound) {
return nullptr;
}
return mPorts[aIndex];
}
public:
nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<MessagePort> > mPorts;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_MessagePortList_h

Просмотреть файл

@ -57,6 +57,7 @@ EXPORTS.mozilla.dom += [
'DOMRequest.h',
'MessageChannel.h',
'MessagePort.h',
'MessagePortList.h',
'ScreenOrientation.h',
'StructuredCloneTags.h',
'URL.h',
@ -72,6 +73,7 @@ CPP_SOURCES += [
'Navigator.cpp',
'MessageChannel.cpp',
'MessagePort.cpp',
'MessagePortList.cpp',
'nsContentPermissionHelper.cpp',
'nsDOMClassInfo.cpp',
'nsDOMNavigationTiming.cpp',

Просмотреть файл

@ -37,24 +37,11 @@ function sendMsg()
{
try
{
var evt = document.createEvent("MessageEvent");
var evt = new MessageEvent('message', {
bubbles: bubbles, cancelable: cancelable, data: data,
origin: origin, lastEventId: lastEventId, source: window});
ok(evt instanceof MessageEvent, "I ordered a MessageEvent!");
if (isMozilla)
{
is(evt.source, null,
"not initialized yet, so null in our implementation");
is(evt.lastEventId, "",
"not initialized yet, so empty string in our implementation");
}
evt.initMessageEvent("message", bubbles, cancelable, data, origin,
lastEventId, null);
ok(evt.source === null, "null source is fine for a MessageEvent");
evt.initMessageEvent("message", bubbles, cancelable, data, origin,
lastEventId, window);
is(evt.data, data, "unexpected data");
is(evt.origin, origin, "unexpected origin");
is(evt.lastEventId, lastEventId, "unexpected lastEventId");

Просмотреть файл

@ -25,10 +25,9 @@ function run()
{
try
{
var msg = document.createEvent("MessageEvent");
msg.initMessageEvent("message", true, true,
"foo", "http://evil.com", "",
window);
var msg = new MessageEvent('message', { bubbles: true, cancelable: true,
data: "foo", origin: "http://evil.com",
source: window });
try
{

Просмотреть файл

@ -9,8 +9,8 @@
interface WindowProxy;
interface MessageEvent : Event
{
[Constructor(DOMString type, optional MessageEventInit eventInitDict)]
interface MessageEvent : Event {
/**
* Custom data associated with this event.
*/
@ -32,21 +32,25 @@ interface MessageEvent : Event
readonly attribute DOMString lastEventId;
/**
* The window which originated this event.
* The window or the port which originated this event.
*/
readonly attribute WindowProxy? source;
readonly attribute (WindowProxy or MessagePort)? source;
/**
* Initializes this event with the given data, in a manner analogous to
* the similarly-named method on the nsIDOMEvent interface, also setting the
* data, origin, source, and lastEventId attributes of this appropriately.
*/
[Throws]
void initMessageEvent(DOMString aType,
boolean aCanBubble,
boolean aCancelable,
any aData,
DOMString aOrigin,
DOMString aLastEventId,
WindowProxy? aSource);
readonly attribute MessagePortList? ports;
};
dictionary MessageEventInit : EventInit {
any data;
DOMString origin;
DOMString lastEventId;
// TODO bug 767926 - This should be: (WindowProxy or MessagePort)? source;
object? source = null;
sequence<MessagePort>? ports;
};

Просмотреть файл

@ -0,0 +1,11 @@
/* -*- 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/.
*/
[NoInterfaceObject, ArrayClass]
interface MessagePortList {
readonly attribute unsigned long length;
getter MessagePort? item(unsigned long index);
};

Просмотреть файл

@ -204,6 +204,7 @@ WEBIDL_FILES = [
'MessageChannel.webidl',
'MessageEvent.webidl',
'MessagePort.webidl',
'MessagePortList.webidl',
'MimeType.webidl',
'MimeTypeArray.webidl',
'MobileMessageManager.webidl',

Просмотреть файл

@ -30,8 +30,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=673468
};
let wrappers_as_keys_test = function () {
let e = document.createEvent("MessageEvent");
e.initMessageEvent("foo", false, false, { dummy: document.createElement("foo") }, null, null, null);
let e = new MessageEvent("foo", { bubbles: false, cancellable: false,
data: { dummy: document.createElement("foo") }});
window.eeeevent = e;
let live_dom = e.data.dummy;