diff options
Diffstat (limited to 'WebCore/dom/MessagePort.cpp')
-rw-r--r-- | WebCore/dom/MessagePort.cpp | 142 |
1 files changed, 69 insertions, 73 deletions
diff --git a/WebCore/dom/MessagePort.cpp b/WebCore/dom/MessagePort.cpp index 9f3e4d2..9f6e649 100644 --- a/WebCore/dom/MessagePort.cpp +++ b/WebCore/dom/MessagePort.cpp @@ -55,28 +55,41 @@ MessagePort::~MessagePort() m_scriptExecutionContext->destroyedMessagePort(this); } -void MessagePort::postMessage(const String& message, ExceptionCode& ec) +// FIXME: remove this when we update the ObjC bindings (bug #28774). +void MessagePort::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, ExceptionCode& ec) { - postMessage(message, 0, ec); + MessagePortArray ports; + if (port) + ports.append(port); + postMessage(message, &ports, ec); } -void MessagePort::postMessage(const String& message, MessagePort* dataPort, ExceptionCode& ec) +void MessagePort::postMessage(PassRefPtr<SerializedScriptValue> message, ExceptionCode& ec) +{ + postMessage(message, static_cast<MessagePortArray*>(0), ec); +} + +void MessagePort::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, ExceptionCode& ec) { if (!m_entangledChannel) return; ASSERT(m_scriptExecutionContext); - OwnPtr<MessagePortChannel> channel; - if (dataPort) { - if (dataPort == this || m_entangledChannel->isConnectedTo(dataPort)) { - ec = INVALID_STATE_ERR; - return; + OwnPtr<MessagePortChannelArray> channels; + // Make sure we aren't connected to any of the passed-in ports. + if (ports) { + for (unsigned int i = 0; i < ports->size(); ++i) { + MessagePort* dataPort = (*ports)[i].get(); + if (dataPort == this || m_entangledChannel->isConnectedTo(dataPort)) { + ec = INVALID_STATE_ERR; + return; + } } - channel = dataPort->disentangle(ec); + channels = MessagePort::disentanglePorts(ports, ec); if (ec) return; } - m_entangledChannel->postMessageToRemote(MessagePortChannel::EventData::create(message, channel.release())); + m_entangledChannel->postMessageToRemote(MessagePortChannel::EventData::create(message, channels.release())); } PassOwnPtr<MessagePortChannel> MessagePort::disentangle(ExceptionCode& ec) @@ -155,20 +168,8 @@ void MessagePort::dispatchMessages() OwnPtr<MessagePortChannel::EventData> eventData; while (m_entangledChannel && m_entangledChannel->tryGetMessageFromRemote(eventData)) { - RefPtr<MessagePort> port; - OwnPtr<MessagePortChannel> channel = eventData->channel(); - if (channel) { - // The remote side sent over a MessagePortChannel, so create a MessagePort to wrap it. - port = MessagePort::create(*m_scriptExecutionContext); - port->entangle(channel.release()); - } - RefPtr<Event> evt = MessageEvent::create(eventData->message(), "", "", 0, port.release()); - - if (m_onMessageListener) { - evt->setTarget(this); - evt->setCurrentTarget(this); - m_onMessageListener->handleEvent(evt.get(), false); - } + OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*m_scriptExecutionContext, eventData->channels()); + RefPtr<Event> evt = MessageEvent::create(ports.release(), eventData->message()); ExceptionCode ec = 0; dispatchEvent(evt.release(), ec); @@ -176,73 +177,68 @@ void MessagePort::dispatchMessages() } } -void MessagePort::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool) +bool MessagePort::hasPendingActivity() { - EventListenersMap::iterator iter = m_eventListeners.find(eventType); - if (iter == m_eventListeners.end()) { - ListenerVector listeners; - listeners.append(eventListener); - m_eventListeners.add(eventType, listeners); - } else { - ListenerVector& listeners = iter->second; - for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { - if (*listenerIter == eventListener) - return; - } - - listeners.append(eventListener); - m_eventListeners.add(eventType, listeners); - } + // The spec says that entangled message ports should always be treated as if they have a strong reference. + // We'll also stipulate that the queue needs to be open (if the app drops its reference to the port before start()-ing it, then it's not really entangled as it's unreachable). + return m_started && m_entangledChannel && m_entangledChannel->hasPendingActivity(); } -void MessagePort::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool) +MessagePort* MessagePort::locallyEntangledPort() { - EventListenersMap::iterator iter = m_eventListeners.find(eventType); - if (iter == m_eventListeners.end()) - return; - - ListenerVector& listeners = iter->second; - for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { - if (*listenerIter == eventListener) { - listeners.remove(listenerIter - listeners.begin()); - return; - } - } + return m_entangledChannel ? m_entangledChannel->locallyEntangledPort(m_scriptExecutionContext) : 0; } -bool MessagePort::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) +PassOwnPtr<MessagePortChannelArray> MessagePort::disentanglePorts(const MessagePortArray* ports, ExceptionCode& ec) { - if (!event || event->type().isEmpty()) { - ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; - return true; + if (!ports || !ports->size()) + return 0; + + // HashSet used to efficiently check for duplicates in the passed-in array. + HashSet<MessagePort*> portSet; + + // Walk the incoming array - if there are any duplicate ports, or null ports or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec). + for (unsigned int i = 0; i < ports->size(); ++i) { + MessagePort* port = (*ports)[i].get(); + if (!port || !port->isEntangled() || portSet.contains(port)) { + ec = INVALID_STATE_ERR; + return 0; + } + portSet.add(port); } - - ListenerVector listenersCopy = m_eventListeners.get(event->type()); - for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) { - event->setTarget(this); - event->setCurrentTarget(this); - listenerIter->get()->handleEvent(event.get(), false); + + // Passed-in ports passed validity checks, so we can disentangle them. + MessagePortChannelArray* portArray = new MessagePortChannelArray(ports->size()); + for (unsigned int i = 0 ; i < ports->size() ; ++i) { + OwnPtr<MessagePortChannel> channel = (*ports)[i]->disentangle(ec); + ASSERT(!ec); // Can't generate exception here if passed above checks. + (*portArray)[i] = channel.release(); } - - return !event->defaultPrevented(); + return portArray; } -void MessagePort::setOnmessage(PassRefPtr<EventListener> eventListener) +PassOwnPtr<MessagePortArray> MessagePort::entanglePorts(ScriptExecutionContext& context, PassOwnPtr<MessagePortChannelArray> channels) { - m_onMessageListener = eventListener; - start(); + if (!channels || !channels->size()) + return 0; + + MessagePortArray* portArray = new MessagePortArray(channels->size()); + for (unsigned int i = 0; i < channels->size(); ++i) { + RefPtr<MessagePort> port = MessagePort::create(context); + port->entangle((*channels)[i].release()); + (*portArray)[i] = port.release(); + } + return portArray; } -bool MessagePort::hasPendingActivity() +EventTargetData* MessagePort::eventTargetData() { - // The spec says that entangled message ports should always be treated as if they have a strong reference. - // We'll also stipulate that the queue needs to be open (if the app drops its reference to the port before start()-ing it, then it's not really entangled as it's unreachable). - return m_started && m_entangledChannel && m_entangledChannel->hasPendingActivity(); + return &m_eventTargetData; } -MessagePort* MessagePort::locallyEntangledPort() +EventTargetData* MessagePort::ensureEventTargetData() { - return m_entangledChannel ? m_entangledChannel->locallyEntangledPort(m_scriptExecutionContext) : 0; + return &m_eventTargetData; } } // namespace WebCore |