blob: ed0b6285e8391796d0351fdda73df83b1d6ec8cb [file] [log] [blame]
/*
* Copyright (C) 2007 Henry Mason (hmason@mac.com)
* Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "core/events/MessageEvent.h"
#include "bindings/core/v8/ExceptionMessages.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/V8ArrayBuffer.h"
#include "bindings/core/v8/V8PrivateProperty.h"
#include <memory>
namespace blink {
static inline bool isValidSource(EventTarget* source) {
return !source || source->toLocalDOMWindow() || source->toMessagePort() ||
source->toServiceWorker();
}
MessageEvent::MessageEvent() : m_dataType(DataTypeScriptValue) {}
MessageEvent::MessageEvent(const AtomicString& type,
const MessageEventInit& initializer)
: Event(type, initializer),
m_dataType(DataTypeScriptValue),
m_source(nullptr) {
if (initializer.hasData())
m_dataAsScriptValue = initializer.data();
if (initializer.hasOrigin())
m_origin = initializer.origin();
if (initializer.hasLastEventId())
m_lastEventId = initializer.lastEventId();
if (initializer.hasSource() && isValidSource(initializer.source()))
m_source = initializer.source();
if (initializer.hasPorts())
m_ports = new MessagePortArray(initializer.ports());
DCHECK(isValidSource(m_source.get()));
}
MessageEvent::MessageEvent(const String& origin,
const String& lastEventId,
EventTarget* source,
MessagePortArray* ports,
const String& suborigin)
: Event(EventTypeNames::message, false, false),
m_dataType(DataTypeScriptValue),
m_origin(origin),
m_lastEventId(lastEventId),
m_source(source),
m_ports(ports) {
DCHECK(isValidSource(m_source.get()));
}
MessageEvent::MessageEvent(PassRefPtr<SerializedScriptValue> data,
const String& origin,
const String& lastEventId,
EventTarget* source,
MessagePortArray* ports,
const String& suborigin)
: Event(EventTypeNames::message, false, false),
m_dataType(DataTypeSerializedScriptValue),
m_dataAsSerializedScriptValue(data),
m_origin(origin),
m_lastEventId(lastEventId),
m_source(source),
m_ports(ports) {
if (m_dataAsSerializedScriptValue)
m_dataAsSerializedScriptValue
->registerMemoryAllocatedWithCurrentScriptContext();
DCHECK(isValidSource(m_source.get()));
}
MessageEvent::MessageEvent(PassRefPtr<SerializedScriptValue> data,
const String& origin,
const String& lastEventId,
EventTarget* source,
std::unique_ptr<MessagePortChannelArray> channels,
const String& suborigin)
: Event(EventTypeNames::message, false, false),
m_dataType(DataTypeSerializedScriptValue),
m_dataAsSerializedScriptValue(data),
m_origin(origin),
m_lastEventId(lastEventId),
m_source(source),
m_channels(std::move(channels)),
m_suborigin(suborigin) {
if (m_dataAsSerializedScriptValue)
m_dataAsSerializedScriptValue
->registerMemoryAllocatedWithCurrentScriptContext();
DCHECK(isValidSource(m_source.get()));
}
MessageEvent::MessageEvent(const String& data,
const String& origin,
const String& suborigin)
: Event(EventTypeNames::message, false, false),
m_dataType(DataTypeString),
m_dataAsString(data),
m_origin(origin) {}
MessageEvent::MessageEvent(Blob* data,
const String& origin,
const String& suborigin)
: Event(EventTypeNames::message, false, false),
m_dataType(DataTypeBlob),
m_dataAsBlob(data),
m_origin(origin) {}
MessageEvent::MessageEvent(DOMArrayBuffer* data,
const String& origin,
const String& suborigin)
: Event(EventTypeNames::message, false, false),
m_dataType(DataTypeArrayBuffer),
m_dataAsArrayBuffer(data),
m_origin(origin) {}
MessageEvent::~MessageEvent() {}
MessageEvent* MessageEvent::create(const AtomicString& type,
const MessageEventInit& initializer,
ExceptionState& exceptionState) {
if (initializer.source() && !isValidSource(initializer.source())) {
exceptionState.throwTypeError(
"The optional 'source' property is neither a Window nor MessagePort.");
return nullptr;
}
return new MessageEvent(type, initializer);
}
void MessageEvent::initMessageEvent(const AtomicString& type,
bool canBubble,
bool cancelable,
ScriptValue data,
const String& origin,
const String& lastEventId,
EventTarget* source,
MessagePortArray* ports) {
if (isBeingDispatched())
return;
initEvent(type, canBubble, cancelable);
m_dataType = DataTypeScriptValue;
m_dataAsScriptValue = data;
m_origin = origin;
m_lastEventId = lastEventId;
m_source = source;
m_ports = ports;
m_suborigin = "";
}
void MessageEvent::initMessageEvent(const AtomicString& type,
bool canBubble,
bool cancelable,
PassRefPtr<SerializedScriptValue> data,
const String& origin,
const String& lastEventId,
EventTarget* source,
MessagePortArray* ports) {
if (isBeingDispatched())
return;
initEvent(type, canBubble, cancelable);
m_dataType = DataTypeSerializedScriptValue;
m_dataAsSerializedScriptValue = data;
m_origin = origin;
m_lastEventId = lastEventId;
m_source = source;
m_ports = ports;
m_suborigin = "";
if (m_dataAsSerializedScriptValue)
m_dataAsSerializedScriptValue
->registerMemoryAllocatedWithCurrentScriptContext();
}
const AtomicString& MessageEvent::interfaceName() const {
return EventNames::MessageEvent;
}
MessagePortArray MessageEvent::ports(bool& isNull) const {
// TODO(bashi): Currently we return a copied array because the binding
// layer could modify the content of the array while executing JS callbacks.
// Avoid copying once we can make sure that the binding layer won't
// modify the content.
if (m_ports) {
isNull = false;
return *m_ports;
}
isNull = true;
return MessagePortArray();
}
MessagePortArray MessageEvent::ports() const {
bool unused;
return ports(unused);
}
void MessageEvent::entangleMessagePorts(ExecutionContext* context) {
m_ports = MessagePort::entanglePorts(*context, std::move(m_channels));
}
DEFINE_TRACE(MessageEvent) {
visitor->trace(m_dataAsBlob);
visitor->trace(m_dataAsArrayBuffer);
visitor->trace(m_source);
visitor->trace(m_ports);
Event::trace(visitor);
}
v8::Local<v8::Object> MessageEvent::associateWithWrapper(
v8::Isolate* isolate,
const WrapperTypeInfo* wrapperType,
v8::Local<v8::Object> wrapper) {
wrapper = Event::associateWithWrapper(isolate, wrapperType, wrapper);
// Ensures a wrapper is created for the data to return now so that V8 knows
// how much memory is used via the wrapper. To keep the wrapper alive, it's
// set to the wrapper of the MessageEvent as a private value.
switch (getDataType()) {
case MessageEvent::DataTypeScriptValue:
case MessageEvent::DataTypeSerializedScriptValue:
break;
case MessageEvent::DataTypeString:
V8PrivateProperty::getMessageEventCachedData(isolate).set(
isolate->GetCurrentContext(), wrapper,
v8String(isolate, dataAsString()));
break;
case MessageEvent::DataTypeBlob:
break;
case MessageEvent::DataTypeArrayBuffer:
V8PrivateProperty::getMessageEventCachedData(isolate).set(
isolate->GetCurrentContext(), wrapper,
toV8(dataAsArrayBuffer(), wrapper, isolate));
break;
}
return wrapper;
}
} // namespace blink