From d227fc870c7a697500a3c900c31baf05fb9a8524 Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Tue, 18 Aug 2009 15:36:45 +0100 Subject: Merge WebKit r47420 --- WebCore/page/Chrome.cpp | 7 + WebCore/page/Chrome.h | 7 + WebCore/page/ChromeClient.h | 8 + WebCore/page/DOMWindow.cpp | 40 ++++ WebCore/page/DOMWindow.h | 10 + WebCore/page/DOMWindow.idl | 10 +- WebCore/page/EventHandler.cpp | 8 +- WebCore/page/EventSource.cpp | 372 +++++++++++++++++++++++++++++ WebCore/page/EventSource.h | 146 +++++++++++ WebCore/page/EventSource.idl | 65 +++++ WebCore/page/Geolocation.cpp | 1 + WebCore/page/Navigator.cpp | 20 +- WebCore/page/Navigator.h | 5 + WebCore/page/Navigator.idl | 4 + WebCore/page/Page.h | 7 + WebCore/page/PositionOptions.h | 2 +- WebCore/page/SecurityOrigin.cpp | 27 ++- WebCore/page/SecurityOrigin.h | 6 + WebCore/page/animation/AnimationBase.cpp | 169 +++++++++++-- WebCore/page/haiku/DragControllerHaiku.cpp | 5 +- WebCore/page/haiku/EventHandlerHaiku.cpp | 11 +- 21 files changed, 895 insertions(+), 35 deletions(-) create mode 100644 WebCore/page/EventSource.cpp create mode 100644 WebCore/page/EventSource.h create mode 100644 WebCore/page/EventSource.idl (limited to 'WebCore/page') diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index 5a5670e..bcfef79 100644 --- a/WebCore/page/Chrome.cpp +++ b/WebCore/page/Chrome.cpp @@ -403,6 +403,13 @@ bool Chrome::setCursor(PlatformCursorHandle cursor) return m_client->setCursor(cursor); } +#if ENABLE(NOTIFICATIONS) +NotificationPresenter* Chrome::notificationPresenter() const +{ + return m_client->notificationPresenter(); +} +#endif + // -------- #if ENABLE(DASHBOARD_SUPPORT) diff --git a/WebCore/page/Chrome.h b/WebCore/page/Chrome.h index c26e450..e28661c 100644 --- a/WebCore/page/Chrome.h +++ b/WebCore/page/Chrome.h @@ -44,6 +44,9 @@ namespace WebCore { class IntRect; class Page; class String; +#if ENABLE(NOTIFICATIONS) + class NotificationPresenter; +#endif struct FrameLoadRequest; struct WindowFeatures; @@ -128,6 +131,10 @@ namespace WebCore { void focusNSView(NSView*); #endif +#if ENABLE(NOTIFICATIONS) + NotificationPresenter* notificationPresenter() const; +#endif + private: Page* m_page; ChromeClient* m_client; diff --git a/WebCore/page/ChromeClient.h b/WebCore/page/ChromeClient.h index 409a492..1010273 100644 --- a/WebCore/page/ChromeClient.h +++ b/WebCore/page/ChromeClient.h @@ -62,6 +62,10 @@ namespace WebCore { class GraphicsLayer; #endif +#if ENABLE(NOTIFICATIONS) + class NotificationPresenter; +#endif + class ChromeClient { public: virtual void chromeDestroyed() = 0; @@ -152,6 +156,10 @@ namespace WebCore { virtual void dashboardRegionsChanged(); #endif +#if ENABLE(NOTIFICATIONS) + virtual NotificationPresenter* notificationPresenter() const = 0; +#endif + virtual void populateVisitedLinks(); virtual FloatRect customHighlightRect(Node*, const AtomicString& type, const FloatRect& lineRect); diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index e50b488..0cc3e5f 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -80,6 +80,10 @@ #include "DOMApplicationCache.h" #endif +#if ENABLE(NOTIFICATIONS) +#include "NotificationCenter.h" +#endif + using std::min; using std::max; @@ -454,6 +458,10 @@ void DOMWindow::clear() m_applicationCache->disconnectFrame(); m_applicationCache = 0; #endif + +#if ENABLE(NOTIFICATIONS) + m_notifications = 0; +#endif } Screen* DOMWindow::screen() const @@ -593,6 +601,28 @@ Storage* DOMWindow::localStorage() const } #endif +#if ENABLE(NOTIFICATIONS) +NotificationCenter* DOMWindow::webkitNotifications() const +{ + if (m_notifications) + return m_notifications.get(); + + Document* document = this->document(); + if (!document) + return 0; + + Page* page = document->page(); + if (!page) + return 0; + + NotificationPresenter* provider = page->chrome()->notificationPresenter(); + if (provider) + m_notifications = NotificationCenter::create(document, provider); + + return m_notifications.get(); +} +#endif + void DOMWindow::postMessage(const String& message, MessagePort* messagePort, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) { if (!m_frame) @@ -1532,6 +1562,16 @@ void DOMWindow::setOnfocus(PassRefPtr eventListener) setAttributeEventListener(eventNames().focusEvent, eventListener); } +EventListener* DOMWindow::onhashchange() const +{ + return getAttributeEventListener(eventNames().hashchangeEvent); +} + +void DOMWindow::setOnhashchange(PassRefPtr eventListener) +{ + setAttributeEventListener(eventNames().hashchangeEvent, eventListener); +} + EventListener* DOMWindow::onkeydown() const { return getAttributeEventListener(eventNames().keydownEvent); diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index 12caf7e..ffe4ef5 100644 --- a/WebCore/page/DOMWindow.h +++ b/WebCore/page/DOMWindow.h @@ -56,6 +56,7 @@ namespace WebCore { class MessagePort; class Navigator; class Node; + class NotificationCenter; class PostMessageTimer; class ScheduledAction; class Screen; @@ -205,6 +206,10 @@ namespace WebCore { DOMApplicationCache* applicationCache() const; #endif +#if ENABLE(NOTIFICATIONS) + NotificationCenter* webkitNotifications() const; +#endif + void postMessage(const String& message, MessagePort*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); void postMessageTimerFired(PostMessageTimer*); @@ -274,6 +279,8 @@ namespace WebCore { void setOnerror(PassRefPtr); EventListener* onfocus() const; void setOnfocus(PassRefPtr); + EventListener* onhashchange() const; + void setOnhashchange(PassRefPtr); EventListener* onkeydown() const; void setOnkeydown(PassRefPtr); EventListener* onkeypress() const; @@ -441,6 +448,9 @@ namespace WebCore { #if ENABLE(OFFLINE_WEB_APPLICATIONS) mutable RefPtr m_applicationCache; #endif +#if ENABLE(NOTIFICATIONS) + mutable RefPtr m_notifications; +#endif RegisteredEventListenerVector m_eventListeners; }; diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index aba92f0..4e7835e 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -55,7 +55,7 @@ module window { attribute [Replaceable] Navigator clientInformation; attribute [DoNotCheckDomainSecurity, JSCCustom, V8CustomSetter, V8DisallowShadowing] Location location; - attribute [Replaceable, CustomGetter] Event event; + attribute [Replaceable, CustomGetter, V8CustomSetter] Event event; readonly attribute [Custom] Crypto crypto; @@ -169,6 +169,9 @@ module window { readonly attribute Storage sessionStorage; readonly attribute Storage localStorage; #endif +#if defined(ENABLE_NOTIFICATIONS) && ENABLE_NOTIFICATIONS + readonly attribute NotificationCenter webkitNotifications; +#endif attribute [Replaceable] Console console; @@ -221,6 +224,7 @@ module window { attribute EventListener onended; attribute EventListener onerror; attribute EventListener onfocus; + attribute EventListener onhashchange; attribute EventListener oninput; attribute EventListener onkeydown; attribute EventListener onkeypress; @@ -454,6 +458,10 @@ module window { attribute RangeConstructor Range; attribute RangeExceptionConstructor RangeException; +#if ENABLE_EVENTSOURCE + attribute [JSCCustomGetter] EventSourceConstructor EventSource; // Usable with new the operator +#endif + // Mozilla has a separate XMLDocument object for XML documents. // We just use Document for this. attribute DocumentConstructor XMLDocument; diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index 41e859f..99ecce0 100644 --- a/WebCore/page/EventHandler.cpp +++ b/WebCore/page/EventHandler.cpp @@ -442,7 +442,7 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll // Otherwise, let the bridge handle it so the view can scroll itself. RenderObject* renderer = targetNode->renderer(); - while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) { + while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())) { if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) renderer = renderer->document()->ownerElement()->renderer(); else @@ -732,7 +732,7 @@ void EventHandler::updateAutoscrollRenderer() if (Node* nodeAtPoint = hitTest.innerNode()) m_autoscrollRenderer = nodeAtPoint->renderer(); - while (m_autoscrollRenderer && (!m_autoscrollRenderer->isBox() || !toRenderBox(m_autoscrollRenderer)->canBeProgramaticallyScrolled(false))) + while (m_autoscrollRenderer && (!m_autoscrollRenderer->isBox() || !toRenderBox(m_autoscrollRenderer)->canBeScrolledAndHasScrollableArea())) m_autoscrollRenderer = m_autoscrollRenderer->parent(); } @@ -1172,7 +1172,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) { RenderObject* renderer = mev.targetNode()->renderer(); - while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeProgramaticallyScrolled(false))) { + while (renderer && (!renderer->isBox() || !toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())) { if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) renderer = renderer->document()->ownerElement()->renderer(); else @@ -2339,7 +2339,7 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve } -#if !PLATFORM(MAC) && !PLATFORM(QT) +#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(HAIKU) bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const { return false; diff --git a/WebCore/page/EventSource.cpp b/WebCore/page/EventSource.cpp new file mode 100644 index 0000000..47243d9 --- /dev/null +++ b/WebCore/page/EventSource.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2009 Ericsson AB + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 "config.h" + +#if ENABLE(EVENTSOURCE) + +#include "EventSource.h" + +#include "Cache.h" +#include "DOMWindow.h" +#include "Event.h" +#include "EventException.h" +#include "PlatformString.h" +#include "MessageEvent.h" +#include "ResourceError.h" +#include "ResourceRequest.h" +#include "ResourceResponse.h" +#include "ScriptExecutionContext.h" +#include "TextResourceDecoder.h" +#include "ThreadableLoader.h" + +namespace WebCore { + +const unsigned long long EventSource::defaultReconnectDelay = 3000; + +EventSource::EventSource(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) + : ActiveDOMObject(context, this) + , m_state(CONNECTING) + , m_reconnectTimer(this, &EventSource::reconnectTimerFired) + , m_failSilently(false) + , m_requestInFlight(false) + , m_reconnectDelay(defaultReconnectDelay) +{ + if (url.isEmpty() || !(m_url = context->completeURL(url)).isValid()) { + ec = SYNTAX_ERR; + return; + } + // FIXME: should support cross-origin requests + if (!scriptExecutionContext()->securityOrigin()->canRequest(m_url)) { + ec = SECURITY_ERR; + return; + } + + m_origin = scriptExecutionContext()->securityOrigin()->toString(); + m_decoder = TextResourceDecoder::create("text/plain", "UTF-8"); + + setPendingActivity(this); + connect(); +} + +EventSource::~EventSource() +{ +} + +void EventSource::connect() +{ + ResourceRequest request(m_url); + request.setHTTPMethod("GET"); + request.setHTTPHeaderField("Accept", "text/event-stream"); + request.setHTTPHeaderField("Cache-Control", "no-cache"); + if (!m_lastEventId.isEmpty()) + request.setHTTPHeaderField("Last-Event-ID", m_lastEventId); + + ThreadableLoaderOptions options; + options.sendLoadCallbacks = true; + options.sniffContent = false; + options.allowCredentials = true; + + m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); + + m_requestInFlight = true; + + if (!scriptExecutionContext()->isWorkerContext()) + cache()->loader()->nonCacheRequestInFlight(m_url); +} + +void EventSource::endRequest() +{ + m_requestInFlight = false; + + if (!m_failSilently) + dispatchGenericEvent(eventNames().errorEvent); + + if (!scriptExecutionContext()->isWorkerContext()) + cache()->loader()->nonCacheRequestComplete(m_url); + + if (m_state != CLOSED) + scheduleReconnect(); + else + unsetPendingActivity(this); +} + +void EventSource::scheduleReconnect() +{ + m_state = CONNECTING; + m_reconnectTimer.startOneShot(m_reconnectDelay / 1000); +} + +void EventSource::reconnectTimerFired(Timer*) +{ + connect(); +} + +String EventSource::url() const +{ + return m_url.string(); +} + +EventSource::State EventSource::readyState() const +{ + return m_state; +} + +void EventSource::close() +{ + if (m_state == CLOSED) + return; + + if (m_reconnectTimer.isActive()) { + m_reconnectTimer.stop(); + unsetPendingActivity(this); + } + + m_state = CLOSED; + m_failSilently = true; + + if (m_requestInFlight) + m_loader->cancel(); +} + +ScriptExecutionContext* EventSource::scriptExecutionContext() const +{ + return ActiveDOMObject::scriptExecutionContext(); +} + +void EventSource::addEventListener(const AtomicString& eventType, PassRefPtr eventListener, bool) +{ + 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); + } +} + +void EventSource::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool) +{ + 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; + } + } +} + +bool EventSource::dispatchEvent(PassRefPtr event, ExceptionCode& ec) +{ + if (!event || event->type().isEmpty()) { + ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; + return true; + } + + EventListener* attributeListener = m_attributeListeners.get(event->type()).get(); + if (attributeListener) { + event->setTarget(this); + event->setCurrentTarget(this); + attributeListener->handleEvent(event.get(), false); + } + + 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); + } + + return !event->defaultPrevented(); +} + +void EventSource::didReceiveResponse(const ResourceResponse& response) +{ + int statusCode = response.httpStatusCode(); + if (statusCode == 200 && response.httpHeaderField("Content-Type") == "text/event-stream") { + m_state = OPEN; + dispatchGenericEvent(eventNames().openEvent); + } else { + if (statusCode <= 200 || statusCode > 299) + m_state = CLOSED; + m_loader->cancel(); + } +} + +void EventSource::didReceiveData(const char* data, int length) +{ + append(m_receiveBuf, m_decoder->decode(data, length)); + parseEventStream(); +} + +void EventSource::didFinishLoading(unsigned long) +{ + if (m_receiveBuf.size() > 0 || m_data.size() > 0) { + append(m_receiveBuf, "\n\n"); + parseEventStream(); + } + m_state = CONNECTING; + endRequest(); +} + +void EventSource::didFail(const ResourceError& error) +{ + int canceled = error.isCancellation(); + if (((m_state == CONNECTING) && !canceled) || ((m_state == OPEN) && canceled)) + m_state = CLOSED; + endRequest(); +} + +void EventSource::didFailRedirectCheck() +{ + m_state = CLOSED; + m_loader->cancel(); +} + +void EventSource::parseEventStream() +{ + unsigned int bufPos = 0; + unsigned int bufSize = m_receiveBuf.size(); + for (;;) { + int lineLength = -1; + int fieldLength = -1; + int carriageReturn = 0; + for (unsigned int i = bufPos; lineLength < 0 && i < bufSize; i++) { + switch (m_receiveBuf[i]) { + case ':': + if (fieldLength < 0) + fieldLength = i - bufPos; + break; + case '\n': + if (i > bufPos && m_receiveBuf[i - 1] == '\r') { + carriageReturn++; + i--; + } + lineLength = i - bufPos; + break; + } + } + + if (lineLength < 0) + break; + + parseEventStreamLine(bufPos, fieldLength, lineLength); + bufPos += lineLength + carriageReturn + 1; + } + + if (bufPos == bufSize) + m_receiveBuf.clear(); + else if (bufPos) + m_receiveBuf.remove(0, bufPos); +} + +void EventSource::parseEventStreamLine(unsigned int bufPos, int fieldLength, int lineLength) +{ + if (!lineLength) { + if (!m_data.isEmpty()) + dispatchMessageEvent(); + if (!m_eventName.isEmpty()) + m_eventName = ""; + } else if (fieldLength) { + bool noValue = fieldLength < 0; + + String field(&m_receiveBuf[bufPos], noValue ? lineLength : fieldLength); + int step; + if (noValue) + step = lineLength; + else if (m_receiveBuf[bufPos + fieldLength + 1] != ' ') + step = fieldLength + 1; + else + step = fieldLength + 2; + bufPos += step; + int valueLength = lineLength - step; + + if (field == "data") { + if (m_data.size() > 0) + m_data.append('\n'); + if (valueLength) + m_data.append(&m_receiveBuf[bufPos], valueLength); + } else if (field == "event") + m_eventName = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : ""; + else if (field == "id") + m_lastEventId = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : ""; + else if (field == "retry") { + if (!valueLength) + m_reconnectDelay = defaultReconnectDelay; + else { + String value(&m_receiveBuf[bufPos], valueLength); + bool ok; + unsigned long long retry = value.toUInt64(&ok); + if (ok) + m_reconnectDelay = retry; + } + } + } +} + +void EventSource::dispatchGenericEvent(const AtomicString& type) +{ + RefPtr evt = Event::create(type, false, false); + ExceptionCode ec = 0; + dispatchEvent(evt.release(), ec); + ASSERT(!ec); +} + +void EventSource::dispatchMessageEvent() +{ + RefPtr evt = MessageEvent::create(); + String eventName = m_eventName.isEmpty() ? eventNames().messageEvent.string() : m_eventName; + evt->initMessageEvent(eventName, false, false, String::adopt(m_data), m_origin, m_lastEventId, 0, 0); + ExceptionCode ec = 0; + dispatchEvent(evt.release(), ec); + ASSERT(!ec); +} + +void EventSource::stop() +{ + close(); +} + +} // namespace WebCore + +#endif // ENABLE(EVENTSOURCE) diff --git a/WebCore/page/EventSource.h b/WebCore/page/EventSource.h new file mode 100644 index 0000000..df55694 --- /dev/null +++ b/WebCore/page/EventSource.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2009 Ericsson AB + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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. + */ + +#ifndef EventSource_h +#define EventSource_h + +#if ENABLE(EVENTSOURCE) + +#include "ActiveDOMObject.h" +#include "AtomicStringHash.h" +#include "EventListener.h" +#include "EventNames.h" +#include "EventTarget.h" +#include "KURL.h" +#include "ThreadableLoaderClient.h" +#include "Timer.h" + +#include +#include +#include +#include + +namespace WebCore { + + class ResourceResponse; + class TextResourceDecoder; + class ThreadableLoader; + + class EventSource : public RefCounted, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject { + public: + static PassRefPtr create(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) { return adoptRef(new EventSource(url, context, ec)); } + virtual ~EventSource(); + + static const unsigned long long defaultReconnectDelay; + + String url() const; + + enum State { + CONNECTING = 0, + OPEN = 1, + CLOSED = 2, + }; + + State readyState() const; + + void setOnopen(PassRefPtr eventListener) { m_attributeListeners.set(eventNames().openEvent, eventListener); } + EventListener* onopen() const { return m_attributeListeners.get(eventNames().openEvent).get(); } + + void setOnmessage(PassRefPtr eventListener) { m_attributeListeners.set(eventNames().messageEvent, eventListener); } + EventListener* onmessage() const { return m_attributeListeners.get(eventNames().messageEvent).get(); } + + void setOnerror(PassRefPtr eventListener) { m_attributeListeners.set(eventNames().errorEvent, eventListener); } + EventListener* onerror() const { return m_attributeListeners.get(eventNames().errorEvent).get(); } + + void close(); + + using RefCounted::ref; + using RefCounted::deref; + + virtual EventSource* toEventSource() { return this; } + virtual ScriptExecutionContext* scriptExecutionContext() const; + + typedef Vector > ListenerVector; + typedef HashMap EventListenersMap; + + virtual void addEventListener(const AtomicString& eventType, PassRefPtr, bool useCapture); + virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture); + virtual bool dispatchEvent(PassRefPtr, ExceptionCode&); + EventListenersMap& eventListeners() { return m_eventListeners; } + + virtual void stop(); + + private: + EventSource(const String& url, ScriptExecutionContext* context, ExceptionCode& ec); + + virtual void refEventTarget() { ref(); } + virtual void derefEventTarget() { deref(); } + + virtual void didReceiveResponse(const ResourceResponse& response); + virtual void didReceiveData(const char* data, int length); + virtual void didFinishLoading(unsigned long); + virtual void didFail(const ResourceError& error); + virtual void didFailRedirectCheck(); + + void connect(); + void endRequest(); + void scheduleReconnect(); + void reconnectTimerFired(Timer*); + void parseEventStream(); + void parseEventStreamLine(unsigned int pos, int fieldLength, int lineLength); + void dispatchGenericEvent(const AtomicString& type); + void dispatchMessageEvent(); + + KURL m_url; + State m_state; + + HashMap > m_attributeListeners; + EventListenersMap m_eventListeners; + + RefPtr m_decoder; + RefPtr m_loader; + Timer m_reconnectTimer; + Vector m_receiveBuf; + bool m_failSilently; + bool m_requestInFlight; + + String m_eventName; + Vector m_data; + String m_lastEventId; + unsigned long long m_reconnectDelay; + String m_origin; + }; + +} // namespace WebCore + +#endif // ENABLE(EVENTSOURCE) + +#endif // EventSource_h diff --git a/WebCore/page/EventSource.idl b/WebCore/page/EventSource.idl new file mode 100644 index 0000000..c438e68 --- /dev/null +++ b/WebCore/page/EventSource.idl @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 Ericsson AB + * 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. + * 3. Neither the name of Ericsson nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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. + */ + +module window { + + interface [ + Conditional=EVENTSOURCE, + CustomMarkFunction, + NoStaticTables + ] EventSource { + + readonly attribute DOMString URL; + + // ready state + const unsigned short CONNECTING = 0; + const unsigned short OPEN = 1; + const unsigned short CLOSED = 2; + readonly attribute unsigned short readyState; + + // networking + attribute EventListener onopen; + attribute EventListener onmessage; + attribute EventListener onerror; + void close(); + + // EventTarget interface + [Custom] void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + [Custom] void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + boolean dispatchEvent(in Event evt) + raises(EventException); + + }; +} diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index e57a8b5..f8cc111 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -334,6 +334,7 @@ void Geolocation::requestPermission() void Geolocation::geolocationServicePositionChanged(GeolocationService*) { + ASSERT_UNUSED(service, service == m_service); ASSERT(m_service->lastPosition()); // Stop all currently running timers. diff --git a/WebCore/page/Navigator.cpp b/WebCore/page/Navigator.cpp index 3603b86..4922860 100644 --- a/WebCore/page/Navigator.cpp +++ b/WebCore/page/Navigator.cpp @@ -31,11 +31,13 @@ #include "Language.h" #include "MimeTypeArray.h" #include "Page.h" +#include "PageGroup.h" #include "PlatformString.h" #include "PluginArray.h" #include "PluginData.h" #include "ScriptController.h" #include "Settings.h" +#include "StorageNamespace.h" namespace WebCore { @@ -150,5 +152,21 @@ Geolocation* Navigator::geolocation() const m_geolocation = Geolocation::create(m_frame); return m_geolocation.get(); } - + +#if ENABLE(DOM_STORAGE) +void Navigator::getStorageUpdates() +{ + if (!m_frame) + return; + + Page* page = m_frame->page(); + if (!page) + return; + + StorageNamespace* localStorage = page->group().localStorage(); + if (localStorage) + localStorage->unlock(); +} +#endif + } // namespace WebCore diff --git a/WebCore/page/Navigator.h b/WebCore/page/Navigator.h index d50721e..4adebe1 100644 --- a/WebCore/page/Navigator.h +++ b/WebCore/page/Navigator.h @@ -55,6 +55,11 @@ namespace WebCore { // This is used for GC marking. Geolocation* optionalGeolocation() const { return m_geolocation.get(); } +#if ENABLE(DOM_STORAGE) + // Relinquishes the storage lock, if one exists. + void getStorageUpdates(); +#endif + private: Navigator(Frame*); Frame* m_frame; diff --git a/WebCore/page/Navigator.idl b/WebCore/page/Navigator.idl index 8048ff3..80ef4fb 100644 --- a/WebCore/page/Navigator.idl +++ b/WebCore/page/Navigator.idl @@ -42,6 +42,10 @@ module window { #if defined(ENABLE_GEOLOCATION) && ENABLE_GEOLOCATION readonly attribute Geolocation geolocation; #endif + +#if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE + void getStorageUpdates(); +#endif }; } diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h index 9d9af86..fb212a4 100644 --- a/WebCore/page/Page.h +++ b/WebCore/page/Page.h @@ -71,6 +71,9 @@ namespace WebCore { #if ENABLE(WML) class WMLPageState; #endif +#if ENABLE(NOTIFICATIONS) + class NotificationPresenter; +#endif enum FindDirection { FindDirectionForward, FindDirectionBackward }; @@ -272,6 +275,10 @@ namespace WebCore { #if ENABLE(WML) OwnPtr m_wmlPageState; #endif + +#if ENABLE(NOTIFICATIONS) + NotificationPresenter* m_notificationPresenter; +#endif }; } // namespace WebCore diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h index ee8530a..ed7074b 100644 --- a/WebCore/page/PositionOptions.h +++ b/WebCore/page/PositionOptions.h @@ -33,7 +33,7 @@ namespace WebCore { class PositionOptions : public RefCounted { public: - static PassRefPtr create() { return adoptRef(new PositionOptions); } + static PassRefPtr create() { return adoptRef(new PositionOptions()); } bool enableHighAccuracy() const { return m_highAccuracy; } void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; } diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index 14a1b59..8274e0e 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -32,15 +32,10 @@ #include "CString.h" #include "FrameLoader.h" #include "KURL.h" -#include "PlatformString.h" -#include "StringHash.h" -#include #include namespace WebCore { -typedef HashSet URLSchemesMap; - static URLSchemesMap& localSchemes() { DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ()); @@ -346,6 +341,28 @@ void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme) } // static +void SecurityOrigin::removeURLSchemeRegisteredAsLocal(const String& scheme) +{ + if (scheme == "file") + return; +#if PLATFORM(MAC) + if (scheme == "applewebdata") + return; +#endif +#if PLATFORM(QT) + if (scheme == "qrc") + return; +#endif + localSchemes().remove(scheme); +} + +// static +const URLSchemesMap& SecurityOrigin::localURLSchemes() +{ + return localSchemes(); +} + +// static bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) { // This avoids an allocation of another String and the HashSet contains() diff --git a/WebCore/page/SecurityOrigin.h b/WebCore/page/SecurityOrigin.h index ab92683..335ed28 100644 --- a/WebCore/page/SecurityOrigin.h +++ b/WebCore/page/SecurityOrigin.h @@ -29,14 +29,18 @@ #ifndef SecurityOrigin_h #define SecurityOrigin_h +#include #include #include #include #include "PlatformString.h" +#include "StringHash.h" namespace WebCore { + typedef HashSet URLSchemesMap; + class KURL; class SecurityOrigin : public ThreadSafeShared { @@ -129,6 +133,8 @@ namespace WebCore { bool isSameSchemeHostPort(const SecurityOrigin*) const; static void registerURLSchemeAsLocal(const String&); + static void removeURLSchemeRegisteredAsLocal(const String&); + static const URLSchemesMap& localURLSchemes(); static bool shouldTreatURLAsLocal(const String&); static bool shouldTreatURLSchemeAsLocal(const String&); diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 7503f0a..f85d8e4 100644 --- a/WebCore/page/animation/AnimationBase.cpp +++ b/WebCore/page/animation/AnimationBase.cpp @@ -302,11 +302,21 @@ public: { ShadowData* shadowA = (a->*m_getter)(); ShadowData* shadowB = (b->*m_getter)(); + + while (true) { + if (!shadowA && !shadowB) // end of both lists + return true; + + if (!shadowA || !shadowB) // end of just one of the lists + return false; + + if (*shadowA != *shadowB) + return false; + + shadowA = shadowA->next; + shadowB = shadowB->next; + } - if ((!shadowA && shadowB) || (shadowA && !shadowB)) - return false; - if (shadowA && shadowB && (*shadowA != *shadowB)) - return false; return true; } @@ -316,12 +326,22 @@ public: ShadowData* shadowB = (b->*m_getter)(); ShadowData defaultShadowData(0, 0, 0, 0, Normal, Color::transparent); - if (!shadowA) - shadowA = &defaultShadowData; - if (!shadowB) - shadowB = &defaultShadowData; + ShadowData* newShadowData = 0; + + while (shadowA || shadowB) { + ShadowData* srcShadow = shadowA ? shadowA : &defaultShadowData; + ShadowData* dstShadow = shadowB ? shadowB : &defaultShadowData; + + if (!newShadowData) + newShadowData = blendFunc(anim, srcShadow, dstShadow, progress); + else + newShadowData->next = blendFunc(anim, srcShadow, dstShadow, progress); - (dst->*m_setter)(blendFunc(anim, shadowA, shadowB, progress), false); + shadowA = shadowA ? shadowA->next : 0; + shadowB = shadowB ? shadowB->next : 0; + } + + (dst->*m_setter)(newShadowData, false); } private: @@ -365,6 +385,124 @@ private: void (RenderStyle::*m_setter)(const Color&); }; +// Wrapper base class for an animatable property in a FillLayer +class FillLayerPropertyWrapperBase { +public: + FillLayerPropertyWrapperBase() + { + } + + virtual ~FillLayerPropertyWrapperBase() { } + + virtual bool equals(const FillLayer* a, const FillLayer* b) const = 0; + virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const = 0; +}; + +template +class FillLayerPropertyWrapperGetter : public FillLayerPropertyWrapperBase { +public: + FillLayerPropertyWrapperGetter(T (FillLayer::*getter)() const) + : m_getter(getter) + { + } + + virtual bool equals(const FillLayer* a, const FillLayer* b) const + { + // If the style pointers are the same, don't bother doing the test. + // If either is null, return false. If both are null, return true. + if ((!a && !b) || a == b) + return true; + if (!a || !b) + return false; + return (a->*m_getter)() == (b->*m_getter)(); + } + +protected: + T (FillLayer::*m_getter)() const; +}; + +template +class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter { +public: + FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T)) + : FillLayerPropertyWrapperGetter(getter) + , m_setter(setter) + { + } + + virtual void blend(const AnimationBase* anim, FillLayer* dst, const FillLayer* a, const FillLayer* b, double progress) const + { + (dst->*m_setter)(blendFunc(anim, (a->*FillLayerPropertyWrapperGetter::m_getter)(), (b->*FillLayerPropertyWrapperGetter::m_getter)(), progress)); + } + +protected: + void (FillLayer::*m_setter)(T); +}; + + +class FillLayersPropertyWrapper : public PropertyWrapperBase { +public: + typedef const FillLayer* (RenderStyle::*LayersGetter)() const; + typedef FillLayer* (RenderStyle::*LayersAccessor)(); + + FillLayersPropertyWrapper(int prop, LayersGetter getter, LayersAccessor accessor) + : PropertyWrapperBase(prop) + , m_layersGetter(getter) + , m_layersAccessor(accessor) + { + switch (prop) { + case CSSPropertyBackgroundPositionX: + case CSSPropertyWebkitMaskPositionX: + m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper(&FillLayer::xPosition, &FillLayer::setXPosition); + break; + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: + m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper(&FillLayer::yPosition, &FillLayer::setYPosition); + break; + case CSSPropertyWebkitBackgroundSize: + case CSSPropertyWebkitMaskSize: + m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper(&FillLayer::size, &FillLayer::setSize); + break; + } + } + + virtual bool equals(const RenderStyle* a, const RenderStyle* b) const + { + const FillLayer* fromLayer = (a->*m_layersGetter)(); + const FillLayer* toLayer = (b->*m_layersGetter)(); + + while (fromLayer && toLayer) { + if (!m_fillLayerPropertyWrapper->equals(fromLayer, toLayer)) + return false; + + fromLayer = fromLayer->next(); + toLayer = toLayer->next(); + } + + return true; + } + + virtual void blend(const AnimationBase* anim, RenderStyle* dst, const RenderStyle* a, const RenderStyle* b, double progress) const + { + const FillLayer* aLayer = (a->*m_layersGetter)(); + const FillLayer* bLayer = (b->*m_layersGetter)(); + FillLayer* dstLayer = (dst->*m_layersAccessor)(); + + while (aLayer && bLayer && dstLayer) { + m_fillLayerPropertyWrapper->blend(anim, dstLayer, aLayer, bLayer, progress); + aLayer = aLayer->next(); + bLayer = bLayer->next(); + dstLayer = dstLayer->next(); + } + } + +private: + FillLayerPropertyWrapperBase* m_fillLayerPropertyWrapper; + + LayersGetter m_layersGetter; + LayersAccessor m_layersAccessor; +}; + class ShorthandPropertyWrapper : public PropertyWrapperBase { public: ShorthandPropertyWrapper(int property, const CSSPropertyLonghand& longhand) @@ -442,13 +580,14 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor)); gPropertyWrappers->append(new PropertyWrapper(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor)); - gPropertyWrappers->append(new PropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundXPosition, &RenderStyle::setBackgroundXPosition)); - gPropertyWrappers->append(new PropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundYPosition, &RenderStyle::setBackgroundYPosition)); - gPropertyWrappers->append(new PropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundSize, &RenderStyle::setBackgroundSize)); - gPropertyWrappers->append(new PropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskXPosition, &RenderStyle::setMaskXPosition)); - gPropertyWrappers->append(new PropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskYPosition, &RenderStyle::setMaskYPosition)); - gPropertyWrappers->append(new PropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskSize, &RenderStyle::setMaskSize)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundLayers, &RenderStyle::accessBackgroundLayers)); + + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); + gPropertyWrappers->append(new FillLayersPropertyWrapper(CSSPropertyWebkitMaskSize, &RenderStyle::maskLayers, &RenderStyle::accessMaskLayers)); gPropertyWrappers->append(new PropertyWrapper(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize)); gPropertyWrappers->append(new PropertyWrapper(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth)); diff --git a/WebCore/page/haiku/DragControllerHaiku.cpp b/WebCore/page/haiku/DragControllerHaiku.cpp index 0b95558..ef08ac2 100644 --- a/WebCore/page/haiku/DragControllerHaiku.cpp +++ b/WebCore/page/haiku/DragControllerHaiku.cpp @@ -32,10 +32,9 @@ #include -namespace WebCore -{ +namespace WebCore { -// FIXME: These values are straight out of DragControllerMac, so probably have +// FIXME: These values are straight out of DragControllerMac, so probably have // little correlation with Haiku standards... const int DragController::LinkDragBorderInset = 2; const int DragController::MaxOriginalImageArea = 1500 * 1500; diff --git a/WebCore/page/haiku/EventHandlerHaiku.cpp b/WebCore/page/haiku/EventHandlerHaiku.cpp index 64b8519..203344e 100644 --- a/WebCore/page/haiku/EventHandlerHaiku.cpp +++ b/WebCore/page/haiku/EventHandlerHaiku.cpp @@ -36,14 +36,13 @@ #include "HitTestResult.h" #include "KeyboardEvent.h" #include "MouseEventWithHitTestResults.h" +#include "NotImplemented.h" #include "Page.h" #include "PlatformKeyboardEvent.h" #include "PlatformScrollBar.h" #include "PlatformWheelEvent.h" #include "RenderWidget.h" -#include "NotImplemented.h" - #include @@ -117,13 +116,15 @@ bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& eve bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) { - notImplemented(); - return false; + if (!widget->isFrameView()) + return false; + + return static_cast(widget)->frame()->eventHandler()->handleWheelEvent(event); } PassRefPtr EventHandler::createDraggingClipboard() const { - return new ClipboardHaiku(ClipboardWritable, true); + return ClipboardHaiku::create(ClipboardWritable, true); } bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) -- cgit v1.1