diff options
Diffstat (limited to 'WebCore/page')
72 files changed, 3558 insertions, 1236 deletions
diff --git a/WebCore/page/Chrome.cpp b/WebCore/page/Chrome.cpp index 5a5670e..96f0fb7 100644 --- a/WebCore/page/Chrome.cpp +++ b/WebCore/page/Chrome.cpp @@ -87,9 +87,9 @@ IntRect Chrome::windowToScreen(const IntRect& rect) const return m_client->windowToScreen(rect); } -PlatformWidget Chrome::platformWindow() const +PlatformPageClient Chrome::platformPageClient() const { - return m_client->platformWindow(); + return m_client->platformPageClient(); } void Chrome::contentsSizeChanged(Frame* frame, const IntSize& size) const @@ -102,6 +102,11 @@ void Chrome::scrollRectIntoView(const IntRect& rect, const ScrollView* scrollVie m_client->scrollRectIntoView(rect, scrollView); } +void Chrome::scrollbarsModeDidChange() const +{ + m_client->scrollbarsModeDidChange(); +} + void Chrome::setWindowRect(const FloatRect& rect) const { m_client->setWindowRect(rect); @@ -311,8 +316,10 @@ void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modif } m_client->mouseDidMoveOverElement(result, modifierFlags); +#if ENABLE(INSPECTOR) if (InspectorController* inspector = m_page->inspectorController()) inspector->mouseDidMoveOverElement(result, modifierFlags); +#endif } void Chrome::setToolTip(const HitTestResult& result) @@ -403,6 +410,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..033311d 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; @@ -60,8 +63,9 @@ namespace WebCore { virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect); virtual IntPoint screenToWindow(const IntPoint&) const; virtual IntRect windowToScreen(const IntRect&) const; - virtual PlatformWidget platformWindow() const; + virtual PlatformPageClient platformPageClient() const; virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const; + virtual void scrollbarsModeDidChange() const; void contentsSizeChanged(Frame*, const IntSize&) const; @@ -128,6 +132,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..5231603 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; @@ -124,11 +128,12 @@ namespace WebCore { virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) = 0; virtual IntPoint screenToWindow(const IntPoint&) const = 0; virtual IntRect windowToScreen(const IntRect&) const = 0; - virtual PlatformWidget platformWindow() const = 0; + virtual PlatformPageClient platformPageClient() const = 0; virtual void contentsSizeChanged(Frame*, const IntSize&) const = 0; virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const = 0; // Currently only Mac has a non empty implementation. // End methods used by HostWindow. + virtual void scrollbarsModeDidChange() const = 0; virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) = 0; virtual void setToolTip(const String&, TextDirection) = 0; @@ -152,6 +157,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); @@ -166,7 +175,7 @@ namespace WebCore { float value, float proportion, ScrollbarControlPartMask); virtual bool paintCustomScrollCorner(GraphicsContext*, const FloatRect&); - // This is an asynchronous call. The ChromeClient can display UI asking the user for permission + // This can be either a synchronous or asynchronous call. The ChromeClient can display UI asking the user for permission // to use Geolococation. The ChromeClient must call Geolocation::setShouldClearCache() appropriately. virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) = 0; @@ -194,6 +203,10 @@ namespace WebCore { virtual void scheduleCompositingLayerSync() = 0; #endif + virtual bool supportsFullscreenForNode(const Node*) { return false; } + virtual void enterFullscreenForNode(Node*) { } + virtual void exitFullscreenForNode(Node*) { } + #if PLATFORM(MAC) virtual KeyboardUIMode keyboardUIMode() { return KeyboardAccessDefault; } diff --git a/WebCore/page/Console.cpp b/WebCore/page/Console.cpp index b5c9bb2..79613d3 100644 --- a/WebCore/page/Console.cpp +++ b/WebCore/page/Console.cpp @@ -129,6 +129,9 @@ static void printMessageSourceAndLevelPrefix(MessageSource source, MessageLevel case ErrorMessageLevel: levelString = "ERROR"; break; + case DebugMessageLevel: + levelString = "DEBUG"; + break; default: ASSERT_NOT_REACHED(); levelString = "UNKNOWN"; @@ -147,7 +150,9 @@ void Console::addMessage(MessageSource source, MessageType type, MessageLevel le if (source == JSMessageSource) page->chrome()->client()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL); +#if ENABLE(INSPECTOR) page->inspectorController()->addMessageToConsole(source, type, level, message, lineNumber, sourceURL); +#endif if (!Console::shouldPrintExceptions()) return; @@ -173,7 +178,9 @@ void Console::addMessage(MessageType type, MessageLevel level, ScriptCallStack* if (getFirstArgumentAsString(callStack->state(), lastCaller, message)) page->chrome()->client()->addMessageToConsole(JSMessageSource, type, level, message, lastCaller.lineNumber(), lastCaller.sourceURL().prettyURL()); +#if ENABLE(INSPECTOR) page->inspectorController()->addMessageToConsole(JSMessageSource, type, level, callStack); +#endif if (!Console::shouldPrintExceptions()) return; @@ -246,6 +253,7 @@ void Console::assertCondition(bool condition, ScriptCallStack* callStack) void Console::count(ScriptCallStack* callStack) { +#if ENABLE(INSPECTOR) Page* page = this->page(); if (!page) return; @@ -257,6 +265,9 @@ void Console::count(ScriptCallStack* callStack) getFirstArgumentAsString(callStack->state(), lastCaller, title); page->inspectorController()->count(title, lastCaller.lineNumber(), lastCaller.sourceURL().string()); +#else + UNUSED_PARAM(callStack); +#endif } #if ENABLE(WML) @@ -293,19 +304,27 @@ void Console::profile(const JSC::UString& title, ScriptCallStack* callStack) if (!page) return; +#if ENABLE(INSPECTOR) InspectorController* controller = page->inspectorController(); // FIXME: log a console message when profiling is disabled. if (!controller->profilerEnabled()) return; +#endif JSC::UString resolvedTitle = title; if (title.isNull()) // no title so give it the next user initiated profile title. +#if ENABLE(INSPECTOR) resolvedTitle = controller->getCurrentUserInitiatedProfileName(true); +#else + resolvedTitle = ""; +#endif JSC::Profiler::profiler()->startProfiling(callStack->state(), resolvedTitle); +#if ENABLE(INSPECTOR) const ScriptCallFrame& lastCaller = callStack->at(0); controller->addStartProfilingMessageToConsole(resolvedTitle, lastCaller.lineNumber(), lastCaller.sourceURL()); +#endif } void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) @@ -317,9 +336,11 @@ void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) if (!this->page()) return; +#if ENABLE(INSPECTOR) InspectorController* controller = page->inspectorController(); if (!controller->profilerEnabled()) return; +#endif RefPtr<JSC::Profile> profile = JSC::Profiler::profiler()->stopProfiling(callStack->state(), title); if (!profile) @@ -327,14 +348,17 @@ void Console::profileEnd(const JSC::UString& title, ScriptCallStack* callStack) m_profiles.append(profile); +#if ENABLE(INSPECTOR) const ScriptCallFrame& lastCaller = callStack->at(0); controller->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL()); +#endif } #endif void Console::time(const String& title) { +#if ENABLE(INSPECTOR) Page* page = this->page(); if (!page) return; @@ -345,10 +369,14 @@ void Console::time(const String& title) return; page->inspectorController()->startTiming(title); +#else + UNUSED_PARAM(title); +#endif } void Console::timeEnd(const String& title, ScriptCallStack* callStack) { +#if ENABLE(INSPECTOR) Page* page = this->page(); if (!page) return; @@ -366,24 +394,34 @@ void Console::timeEnd(const String& title, ScriptCallStack* callStack) const ScriptCallFrame& lastCaller = callStack->at(0); page->inspectorController()->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lastCaller.lineNumber(), lastCaller.sourceURL().string()); +#else + UNUSED_PARAM(title); + UNUSED_PARAM(callStack); +#endif } void Console::group(ScriptCallStack* callStack) { +#if ENABLE(INSPECTOR) Page* page = this->page(); if (!page) return; page->inspectorController()->startGroup(JSMessageSource, callStack); +#else + UNUSED_PARAM(callStack); +#endif } void Console::groupEnd() { +#if ENABLE(INSPECTOR) Page* page = this->page(); if (!page) return; page->inspectorController()->endGroup(JSMessageSource, 0, String()); +#endif } void Console::warn(ScriptCallStack* callStack) diff --git a/WebCore/page/Console.h b/WebCore/page/Console.h index 6d4dbce..08d43e3 100644 --- a/WebCore/page/Console.h +++ b/WebCore/page/Console.h @@ -71,7 +71,8 @@ namespace WebCore { TipMessageLevel, LogMessageLevel, WarningMessageLevel, - ErrorMessageLevel + ErrorMessageLevel, + DebugMessageLevel }; class Console : public RefCounted<Console> { diff --git a/WebCore/page/ContextMenuController.cpp b/WebCore/page/ContextMenuController.cpp index 0ec9d1c..1cf0014 100644 --- a/WebCore/page/ContextMenuController.cpp +++ b/WebCore/page/ContextMenuController.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "ContextMenuController.h" +#if ENABLE(CONTEXT_MENUS) + #include "Chrome.h" #include "ContextMenu.h" #include "ContextMenuClient.h" @@ -95,8 +97,10 @@ void ContextMenuController::handleContextMenuEvent(Event* event) m_contextMenu.set(new ContextMenu(result)); m_contextMenu->populate(); +#if ENABLE(INSPECTOR) if (m_page->inspectorController()->enabled()) m_contextMenu->addInspectElementItem(); +#endif PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get()); m_contextMenu->setPlatformDescription(customMenu); @@ -162,10 +166,12 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) frame->editor()->copy(); break; case ContextMenuItemTagGoBack: - frame->loader()->goBackOrForward(-1); + if (Page* page = frame->page()) + page->goBackOrForward(-1); break; case ContextMenuItemTagGoForward: - frame->loader()->goBackOrForward(1); + if (Page* page = frame->page()) + page->goBackOrForward(1); break; case ContextMenuItemTagStop: frame->loader()->stop(); @@ -325,13 +331,17 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) frame->editor()->changeBackToReplacedString(result.replacedString()); break; #endif +#if ENABLE(INSPECTOR) case ContextMenuItemTagInspectElement: if (Page* page = frame->page()) page->inspectorController()->inspect(result.innerNonSharedNode()); break; +#endif default: break; } } } // namespace WebCore + +#endif // ENABLE(CONTEXT_MENUS) diff --git a/WebCore/page/Coordinates.h b/WebCore/page/Coordinates.h index 43870a1..bd29d42 100644 --- a/WebCore/page/Coordinates.h +++ b/WebCore/page/Coordinates.h @@ -50,7 +50,11 @@ public: bool canProvideAltitudeAccuracy() const { return m_canProvideAltitudeAccuracy; } bool canProvideHeading() const { return m_canProvideHeading; } bool canProvideSpeed() const { return m_canProvideSpeed; } +<<<<<<< HEAD:WebCore/page/Coordinates.h +======= + +>>>>>>> webkit.org at 49305:WebCore/page/Coordinates.h private: Coordinates(double latitude, double longitude, bool providesAltitude, double altitude, double accuracy, bool providesAltitudeAccuracy, double altitudeAccuracy, bool providesHeading, double heading, bool providesSpeed, double speed) : m_latitude(latitude) diff --git a/WebCore/page/DOMTimer.cpp b/WebCore/page/DOMTimer.cpp index c42a0dc..dd1e842 100644 --- a/WebCore/page/DOMTimer.cpp +++ b/WebCore/page/DOMTimer.cpp @@ -47,6 +47,9 @@ DOMTimer::DOMTimer(ScriptExecutionContext* context, ScheduledAction* action, int , m_action(action) , m_nextFireInterval(0) , m_repeatInterval(0) +#if !ASSERT_DISABLED + , m_suspended(false) +#endif { static int lastUsedTimeoutId = 0; ++lastUsedTimeoutId; @@ -148,7 +151,10 @@ void DOMTimer::stop() void DOMTimer::suspend() { - ASSERT(!m_nextFireInterval && !m_repeatInterval); +#if !ASSERT_DISABLED + ASSERT(!m_suspended); + m_suspended = true; +#endif m_nextFireInterval = nextFireInterval(); m_repeatInterval = repeatInterval(); TimerBase::stop(); @@ -156,9 +162,11 @@ void DOMTimer::suspend() void DOMTimer::resume() { +#if !ASSERT_DISABLED + ASSERT(m_suspended); + m_suspended = false; +#endif start(m_nextFireInterval, m_repeatInterval); - m_nextFireInterval = 0; - m_repeatInterval = 0; } diff --git a/WebCore/page/DOMTimer.h b/WebCore/page/DOMTimer.h index 6d6271f..3c65258 100644 --- a/WebCore/page/DOMTimer.h +++ b/WebCore/page/DOMTimer.h @@ -66,6 +66,9 @@ namespace WebCore { OwnPtr<ScheduledAction> m_action; double m_nextFireInterval; double m_repeatInterval; +#if !ASSERT_DISABLED + bool m_suspended; +#endif static double s_minTimerInterval; }; diff --git a/WebCore/page/DOMWindow.cpp b/WebCore/page/DOMWindow.cpp index e50b488..e80ce87 100644 --- a/WebCore/page/DOMWindow.cpp +++ b/WebCore/page/DOMWindow.cpp @@ -34,8 +34,11 @@ #include "CString.h" #include "Chrome.h" #include "Console.h" +#include "Database.h" +#include "DOMApplicationCache.h" #include "DOMSelection.h" #include "DOMTimer.h" +#include "PageTransitionEvent.h" #include "Document.h" #include "Element.h" #include "EventException.h" @@ -54,32 +57,23 @@ #include "Media.h" #include "MessageEvent.h" #include "Navigator.h" +#include "NotificationCenter.h" #include "Page.h" #include "PageGroup.h" #include "PlatformScreen.h" #include "PlatformString.h" #include "Screen.h" #include "SecurityOrigin.h" +#include "SerializedScriptValue.h" #include "Settings.h" +#include "Storage.h" +#include "StorageArea.h" +#include "StorageNamespace.h" #include "SuddenTermination.h" #include "WebKitPoint.h" #include <algorithm> #include <wtf/MathExtras.h> -#if ENABLE(DATABASE) -#include "Database.h" -#endif - -#if ENABLE(DOM_STORAGE) -#include "Storage.h" -#include "StorageArea.h" -#include "StorageNamespace.h" -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "DOMApplicationCache.h" -#endif - using std::min; using std::max; @@ -87,24 +81,20 @@ namespace WebCore { class PostMessageTimer : public TimerBase { public: - PostMessageTimer(DOMWindow* window, const String& message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannel> channel, SecurityOrigin* targetOrigin) + PostMessageTimer(DOMWindow* window, PassRefPtr<SerializedScriptValue> message, const String& sourceOrigin, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortChannelArray> channels, SecurityOrigin* targetOrigin) : m_window(window) , m_message(message) , m_origin(sourceOrigin) , m_source(source) - , m_channel(channel) + , m_channels(channels) , m_targetOrigin(targetOrigin) { } PassRefPtr<MessageEvent> event(ScriptExecutionContext* context) { - RefPtr<MessagePort> messagePort; - if (m_channel) { - messagePort = MessagePort::create(*context); - messagePort->entangle(m_channel.release()); - } - return MessageEvent::create(m_message, m_origin, "", m_source, messagePort.release()); + OwnPtr<MessagePortArray> messagePorts = MessagePort::entanglePorts(*context, m_channels.release()); + return MessageEvent::create(messagePorts.release(), m_message, m_origin, "", m_source); } SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } @@ -115,90 +105,103 @@ private: } RefPtr<DOMWindow> m_window; - String m_message; + RefPtr<SerializedScriptValue> m_message; String m_origin; RefPtr<DOMWindow> m_source; - OwnPtr<MessagePortChannel> m_channel; + OwnPtr<MessagePortChannelArray> m_channels; RefPtr<SecurityOrigin> m_targetOrigin; }; -typedef HashMap<DOMWindow*, RegisteredEventListenerVector*> DOMWindowRegisteredEventListenerMap; +typedef HashCountedSet<DOMWindow*> DOMWindowSet; -static DOMWindowRegisteredEventListenerMap& pendingUnloadEventListenerMap() +static DOMWindowSet& windowsWithUnloadEventListeners() { - DEFINE_STATIC_LOCAL(DOMWindowRegisteredEventListenerMap, eventListenerMap, ()); - return eventListenerMap; + DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithUnloadEventListeners, ()); + return windowsWithUnloadEventListeners; } -static DOMWindowRegisteredEventListenerMap& pendingBeforeUnloadEventListenerMap() +static DOMWindowSet& windowsWithBeforeUnloadEventListeners() { - DEFINE_STATIC_LOCAL(DOMWindowRegisteredEventListenerMap, eventListenerMap, ()); - return eventListenerMap; + DEFINE_STATIC_LOCAL(DOMWindowSet, windowsWithBeforeUnloadEventListeners, ()); + return windowsWithBeforeUnloadEventListeners; } -static bool allowsPendingBeforeUnloadListeners(DOMWindow* window) +static void addUnloadEventListener(DOMWindow* domWindow) { - ASSERT_ARG(window, window); - Frame* frame = window->frame(); - Page* page = frame->page(); - return page && frame == page->mainFrame(); + DOMWindowSet& set = windowsWithUnloadEventListeners(); + if (set.isEmpty()) + disableSuddenTermination(); + set.add(domWindow); } -static void addPendingEventListener(DOMWindowRegisteredEventListenerMap& map, DOMWindow* window, RegisteredEventListener* listener) +static void removeUnloadEventListener(DOMWindow* domWindow) { - ASSERT_ARG(window, window); - ASSERT_ARG(listener, listener); - - if (map.isEmpty()) - disableSuddenTermination(); - - pair<DOMWindowRegisteredEventListenerMap::iterator, bool> result = map.add(window, 0); - if (result.second) - result.first->second = new RegisteredEventListenerVector; - result.first->second->append(listener); + DOMWindowSet& set = windowsWithUnloadEventListeners(); + DOMWindowSet::iterator it = set.find(domWindow); + if (it == set.end()) + return; + set.remove(it); + if (set.isEmpty()) + enableSuddenTermination(); } -static void removePendingEventListener(DOMWindowRegisteredEventListenerMap& map, DOMWindow* window, RegisteredEventListener* listener) +static void removeAllUnloadEventListeners(DOMWindow* domWindow) { - ASSERT_ARG(window, window); - ASSERT_ARG(listener, listener); - - DOMWindowRegisteredEventListenerMap::iterator it = map.find(window); - ASSERT(it != map.end()); - - RegisteredEventListenerVector* listeners = it->second; - size_t index = listeners->find(listener); - ASSERT(index != WTF::notFound); - listeners->remove(index); - - if (!listeners->isEmpty()) + DOMWindowSet& set = windowsWithUnloadEventListeners(); + DOMWindowSet::iterator it = set.find(domWindow); + if (it == set.end()) return; - - map.remove(it); - delete listeners; - - if (map.isEmpty()) + set.removeAll(it); + if (set.isEmpty()) enableSuddenTermination(); } -static void removePendingEventListeners(DOMWindowRegisteredEventListenerMap& map, DOMWindow* window) +static void addBeforeUnloadEventListener(DOMWindow* domWindow) { - ASSERT_ARG(window, window); + DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); + if (set.isEmpty()) + disableSuddenTermination(); + set.add(domWindow); +} - RegisteredEventListenerVector* listeners = map.take(window); - if (!listeners) +static void removeBeforeUnloadEventListener(DOMWindow* domWindow) +{ + DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); + DOMWindowSet::iterator it = set.find(domWindow); + if (it == set.end()) return; + set.remove(it); + if (set.isEmpty()) + enableSuddenTermination(); +} - delete listeners; - - if (map.isEmpty()) +static void removeAllBeforeUnloadEventListeners(DOMWindow* domWindow) +{ + DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); + DOMWindowSet::iterator it = set.find(domWindow); + if (it == set.end()) + return; + set.removeAll(it); + if (set.isEmpty()) enableSuddenTermination(); } +static bool allowsBeforeUnloadListeners(DOMWindow* window) +{ + ASSERT_ARG(window, window); + Frame* frame = window->frame(); + if (!frame) + return false; + Page* page = frame->page(); + if (!page) + return false; + return frame == page->mainFrame(); +} + bool DOMWindow::dispatchAllPendingBeforeUnloadEvents() { - DOMWindowRegisteredEventListenerMap& map = pendingBeforeUnloadEventListenerMap(); - if (map.isEmpty()) + DOMWindowSet& set = windowsWithBeforeUnloadEventListeners(); + if (set.isEmpty()) return true; static bool alreadyDispatched = false; @@ -207,20 +210,21 @@ bool DOMWindow::dispatchAllPendingBeforeUnloadEvents() return true; Vector<RefPtr<DOMWindow> > windows; - DOMWindowRegisteredEventListenerMap::iterator mapEnd = map.end(); - for (DOMWindowRegisteredEventListenerMap::iterator it = map.begin(); it != mapEnd; ++it) + DOMWindowSet::iterator end = set.end(); + for (DOMWindowSet::iterator it = set.begin(); it != end; ++it) windows.append(it->first); size_t size = windows.size(); for (size_t i = 0; i < size; ++i) { DOMWindow* window = windows[i].get(); - RegisteredEventListenerVector* listeners = map.get(window); - if (!listeners) + if (!set.contains(window)) continue; - RegisteredEventListenerVector listenersCopy = *listeners; Frame* frame = window->frame(); - if (!frame->shouldClose(&listenersCopy)) + if (!frame) + continue; + + if (!frame->shouldClose()) return false; } @@ -233,14 +237,13 @@ bool DOMWindow::dispatchAllPendingBeforeUnloadEvents() unsigned DOMWindow::pendingUnloadEventListeners() const { - RegisteredEventListenerVector* listeners = pendingUnloadEventListenerMap().get(const_cast<DOMWindow*>(this)); - return listeners ? listeners->size() : 0; + return windowsWithUnloadEventListeners().count(const_cast<DOMWindow*>(this)); } void DOMWindow::dispatchAllPendingUnloadEvents() { - DOMWindowRegisteredEventListenerMap& map = pendingUnloadEventListenerMap(); - if (map.isEmpty()) + DOMWindowSet& set = windowsWithUnloadEventListeners(); + if (set.isEmpty()) return; static bool alreadyDispatched = false; @@ -249,18 +252,18 @@ void DOMWindow::dispatchAllPendingUnloadEvents() return; Vector<RefPtr<DOMWindow> > windows; - DOMWindowRegisteredEventListenerMap::iterator mapEnd = map.end(); - for (DOMWindowRegisteredEventListenerMap::iterator it = map.begin(); it != mapEnd; ++it) + DOMWindowSet::iterator end = set.end(); + for (DOMWindowSet::iterator it = set.begin(); it != end; ++it) windows.append(it->first); size_t size = windows.size(); for (size_t i = 0; i < size; ++i) { DOMWindow* window = windows[i].get(); - RegisteredEventListenerVector* listeners = map.get(window); - if (!listeners) + if (!set.contains(window)) continue; - RegisteredEventListenerVector listenersCopy = *listeners; - window->dispatchUnloadEvent(&listenersCopy); + + window->dispatchEvent(PageTransitionEvent::create(EventNames().pagehideEvent, false), window->document()); + window->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), window->document()); } enableSuddenTermination(); @@ -374,8 +377,8 @@ DOMWindow::~DOMWindow() if (m_frame) m_frame->clearFormerDOMWindow(this); - removePendingEventListeners(pendingUnloadEventListenerMap(), this); - removePendingEventListeners(pendingBeforeUnloadEventListenerMap(), this); + removeAllUnloadEventListeners(this); + removeAllBeforeUnloadEventListeners(this); } ScriptExecutionContext* DOMWindow::scriptExecutionContext() const @@ -454,8 +457,22 @@ void DOMWindow::clear() m_applicationCache->disconnectFrame(); m_applicationCache = 0; #endif + +#if ENABLE(NOTIFICATIONS) + m_notifications = 0; +#endif } +#if ENABLE(ORIENTATION_EVENTS) +int DOMWindow::orientation() const +{ + if (!m_frame) + return 0; + + return m_frame->orientation(); +} +#endif + Screen* DOMWindow::screen() const { if (!m_screen) @@ -522,7 +539,7 @@ Console* DOMWindow::console() const #if ENABLE(OFFLINE_WEB_APPLICATIONS) DOMApplicationCache* DOMWindow::applicationCache() const { - if (!m_applicationCache && m_frame && m_frame->settings() && m_frame->settings()->offlineWebApplicationCacheEnabled()) + if (!m_applicationCache) m_applicationCache = DOMApplicationCache::create(m_frame); return m_applicationCache.get(); } @@ -560,7 +577,9 @@ Storage* DOMWindow::sessionStorage() const return 0; RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); +#if ENABLE(INSPECTOR) page->inspectorController()->didUseDOMStorage(storageArea.get(), false, m_frame); +#endif m_sessionStorage = Storage::create(m_frame, storageArea.release()); return m_sessionStorage.get(); @@ -582,18 +601,50 @@ Storage* DOMWindow::localStorage() const if (!page->settings()->localStorageEnabled()) return 0; - StorageNamespace* localStorage = page->group().localStorage(); - RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(document->securityOrigin()) : 0; - if (storageArea) { - page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame); - m_localStorage = Storage::create(m_frame, storageArea.release()); - } + RefPtr<StorageArea> storageArea = page->group().localStorage()->storageArea(document->securityOrigin()); +#if ENABLE(INSPECTOR) + page->inspectorController()->didUseDOMStorage(storageArea.get(), true, m_frame); +#endif + m_localStorage = Storage::create(m_frame, storageArea.release()); return m_localStorage.get(); } #endif -void DOMWindow::postMessage(const String& message, MessagePort* messagePort, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) +#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; + + if (!page->settings()->experimentalNotificationsEnabled()) + return 0; + + NotificationPresenter* provider = page->chrome()->notificationPresenter(); + if (provider) + m_notifications = NotificationCenter::create(document, provider); + + return m_notifications.get(); +} +#endif + +void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort* port, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) +{ + MessagePortArray ports; + if (port) + ports.append(port); + postMessage(message, &ports, targetOrigin, source, ec); +} + +void DOMWindow::postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray* ports, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) { if (!m_frame) return; @@ -609,9 +660,7 @@ void DOMWindow::postMessage(const String& message, MessagePort* messagePort, con } } - OwnPtr<MessagePortChannel> channel; - if (messagePort) - channel = messagePort->disentangle(ec); + OwnPtr<MessagePortChannelArray> channels = MessagePort::disentanglePorts(ports, ec); if (ec) return; @@ -623,7 +672,7 @@ void DOMWindow::postMessage(const String& message, MessagePort* messagePort, con String sourceOrigin = sourceDocument->securityOrigin()->toString(); // Schedule the message. - PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channel.release(), target.get()); + PostMessageTimer* timer = new PostMessageTimer(this, message, sourceOrigin, source, channels.release(), target.get()); timer->startOneShot(0); } @@ -644,8 +693,7 @@ void DOMWindow::postMessageTimerFired(PostMessageTimer* t) } } - ExceptionCode ec = 0; - dispatchEvent(timer->event(document()), ec); + dispatchEvent(timer->event(document())); } DOMSelection* DOMWindow::getSelection() @@ -692,12 +740,9 @@ void DOMWindow::close() return; Settings* settings = m_frame->settings(); - bool allowScriptsToCloseWindows = - settings && settings->allowScriptsToCloseWindows(); + bool allowScriptsToCloseWindows = settings && settings->allowScriptsToCloseWindows(); - if (m_frame->loader()->openedByDOM() - || m_frame->loader()->getHistoryLength() <= 1 - || allowScriptsToCloseWindows) + if (page->openedByDOM() || page->getHistoryLength() <= 1 || allowScriptsToCloseWindows) m_frame->scheduleClose(); } @@ -1214,104 +1259,38 @@ void DOMWindow::clearInterval(int timeoutId) DOMTimer::removeById(scriptExecutionContext(), timeoutId); } -void DOMWindow::handleEvent(Event* event, bool useCapture, RegisteredEventListenerVector* alternateListeners) +bool DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) { - RegisteredEventListenerVector& listeners = (alternateListeners ? *alternateListeners : m_eventListeners); - if (listeners.isEmpty()) - return; - - // If any HTML event listeners are registered on the window, dispatch them here. - RegisteredEventListenerVector listenersCopy = listeners; - size_t size = listenersCopy.size(); - for (size_t i = 0; i < size; ++i) { - RegisteredEventListener& r = *listenersCopy[i]; - if (r.eventType() == event->type() && r.useCapture() == useCapture && !r.removed()) - r.listener()->handleEvent(event, true); - } -} + if (!EventTarget::addEventListener(eventType, listener, useCapture)) + return false; -void DOMWindow::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) -{ - // Remove existing identical listener set with identical arguments. - // The DOM 2 spec says that "duplicate instances are discarded" in this case. - removeEventListener(eventType, listener.get(), useCapture); if (Document* document = this->document()) document->addListenerTypeIfNeeded(eventType); - RefPtr<RegisteredEventListener> registeredListener = RegisteredEventListener::create(eventType, listener, useCapture); - m_eventListeners.append(registeredListener); - if (eventType == eventNames().unloadEvent) - addPendingEventListener(pendingUnloadEventListenerMap(), this, registeredListener.get()); - else if (eventType == eventNames().beforeunloadEvent && allowsPendingBeforeUnloadListeners(this)) - addPendingEventListener(pendingBeforeUnloadEventListenerMap(), this, registeredListener.get()); -} + addUnloadEventListener(this); + else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) + addBeforeUnloadEventListener(this); -void DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) -{ - size_t size = m_eventListeners.size(); - for (size_t i = 0; i < size; ++i) { - RegisteredEventListener& r = *m_eventListeners[i]; - if (r.eventType() == eventType && r.listener() == listener && r.useCapture() == useCapture) { - if (eventType == eventNames().unloadEvent) - removePendingEventListener(pendingUnloadEventListenerMap(), this, &r); - else if (eventType == eventNames().beforeunloadEvent && allowsPendingBeforeUnloadListeners(this)) - removePendingEventListener(pendingBeforeUnloadEventListenerMap(), this, &r); - r.setRemoved(true); - m_eventListeners.remove(i); - return; - } - } -} - -bool DOMWindow::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec) -{ - ASSERT(!eventDispatchForbidden()); - - RefPtr<Event> event = e; - if (!event || event->type().isEmpty()) { - ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; - return true; - } - - RefPtr<DOMWindow> protect(this); - - event->setTarget(this); - event->setCurrentTarget(this); - - handleEvent(event.get(), true); - handleEvent(event.get(), false); - - return !event->defaultPrevented(); -} - -void DOMWindow::dispatchEvent(const AtomicString& eventType, bool canBubble, bool cancelable) -{ - ASSERT(!eventDispatchForbidden()); - ExceptionCode ec = 0; - dispatchEvent(Event::create(eventType, canBubble, cancelable), ec); + return true; } -// This function accommodates the Firefox quirk of dispatching the load, unload and -// beforeunload events on the window, but setting event.target to be the Document. -inline void DOMWindow::dispatchEventWithDocumentAsTarget(PassRefPtr<Event> e, RegisteredEventListenerVector* alternateEventListeners) +bool DOMWindow::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) { - ASSERT(!eventDispatchForbidden()); - - RefPtr<Event> event = e; - RefPtr<DOMWindow> protect(this); - RefPtr<Document> document = this->document(); + if (!EventTarget::removeEventListener(eventType, listener, useCapture)) + return false; - event->setTarget(document); - event->setCurrentTarget(this); + if (eventType == eventNames().unloadEvent) + removeUnloadEventListener(this); + else if (eventType == eventNames().beforeunloadEvent && allowsBeforeUnloadListeners(this)) + removeBeforeUnloadEventListener(this); - handleEvent(event.get(), true, alternateEventListeners); - handleEvent(event.get(), false, alternateEventListeners); + return true; } void DOMWindow::dispatchLoadEvent() { - dispatchEventWithDocumentAsTarget(Event::create(eventNames().loadEvent, false, false)); + dispatchEvent(Event::create(eventNames().loadEvent, false, false), document()); // For load events, send a separate load event to the enclosing frame only. // This is a DOM extension and is independent of bubbling/capturing rules of @@ -1322,704 +1301,54 @@ void DOMWindow::dispatchLoadEvent() ownerEvent->setTarget(ownerElement); ownerElement->dispatchGenericEvent(ownerEvent.release()); } -} - -void DOMWindow::dispatchUnloadEvent(RegisteredEventListenerVector* alternateEventListeners) -{ - dispatchEventWithDocumentAsTarget(Event::create(eventNames().unloadEvent, false, false), alternateEventListeners); -} -PassRefPtr<BeforeUnloadEvent> DOMWindow::dispatchBeforeUnloadEvent(RegisteredEventListenerVector* alternateEventListeners) -{ - RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); - dispatchEventWithDocumentAsTarget(beforeUnloadEvent.get(), alternateEventListeners); - return beforeUnloadEvent.release(); -} - -void DOMWindow::removeAllEventListeners() -{ - size_t size = m_eventListeners.size(); - for (size_t i = 0; i < size; ++i) - m_eventListeners[i]->setRemoved(true); - m_eventListeners.clear(); - - removePendingEventListeners(pendingUnloadEventListenerMap(), this); - removePendingEventListeners(pendingBeforeUnloadEventListenerMap(), this); -} - -bool DOMWindow::hasEventListener(const AtomicString& eventType) -{ - size_t size = m_eventListeners.size(); - for (size_t i = 0; i < size; ++i) { - if (m_eventListeners[i]->eventType() == eventType) - return true; - } - return false; -} - -void DOMWindow::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener) -{ - clearAttributeEventListener(eventType); - if (listener) - addEventListener(eventType, listener, false); -} - -void DOMWindow::clearAttributeEventListener(const AtomicString& eventType) -{ - size_t size = m_eventListeners.size(); - for (size_t i = 0; i < size; ++i) { - RegisteredEventListener& r = *m_eventListeners[i]; - if (r.eventType() == eventType && r.listener()->isAttribute()) { - if (eventType == eventNames().unloadEvent) - removePendingEventListener(pendingUnloadEventListenerMap(), this, &r); - else if (eventType == eventNames().beforeunloadEvent && allowsPendingBeforeUnloadListeners(this)) - removePendingEventListener(pendingBeforeUnloadEventListenerMap(), this, &r); - r.setRemoved(true); - m_eventListeners.remove(i); - return; - } - } -} - -EventListener* DOMWindow::getAttributeEventListener(const AtomicString& eventType) const -{ - size_t size = m_eventListeners.size(); - for (size_t i = 0; i < size; ++i) { - RegisteredEventListener& r = *m_eventListeners[i]; - if (r.eventType() == eventType && r.listener()->isAttribute()) - return r.listener(); - } - return 0; -} - -EventListener* DOMWindow::onabort() const -{ - return getAttributeEventListener(eventNames().abortEvent); -} - -void DOMWindow::setOnabort(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().abortEvent, eventListener); -} - -EventListener* DOMWindow::onblur() const -{ - return getAttributeEventListener(eventNames().blurEvent); -} - -void DOMWindow::setOnblur(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().blurEvent, eventListener); -} - -EventListener* DOMWindow::onchange() const -{ - return getAttributeEventListener(eventNames().changeEvent); -} - -void DOMWindow::setOnchange(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().changeEvent, eventListener); -} - -EventListener* DOMWindow::onclick() const -{ - return getAttributeEventListener(eventNames().clickEvent); -} - -void DOMWindow::setOnclick(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().clickEvent, eventListener); -} - -EventListener* DOMWindow::ondblclick() const -{ - return getAttributeEventListener(eventNames().dblclickEvent); -} - -void DOMWindow::setOndblclick(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dblclickEvent, eventListener); -} - -EventListener* DOMWindow::ondrag() const -{ - return getAttributeEventListener(eventNames().dragEvent); -} - -void DOMWindow::setOndrag(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dragEvent, eventListener); -} - -EventListener* DOMWindow::ondragend() const -{ - return getAttributeEventListener(eventNames().dragendEvent); -} - -void DOMWindow::setOndragend(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dragendEvent, eventListener); -} - -EventListener* DOMWindow::ondragenter() const -{ - return getAttributeEventListener(eventNames().dragenterEvent); -} - -void DOMWindow::setOndragenter(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dragenterEvent, eventListener); -} - -EventListener* DOMWindow::ondragleave() const -{ - return getAttributeEventListener(eventNames().dragleaveEvent); -} - -void DOMWindow::setOndragleave(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dragleaveEvent, eventListener); -} - -EventListener* DOMWindow::ondragover() const -{ - return getAttributeEventListener(eventNames().dragoverEvent); -} - -void DOMWindow::setOndragover(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dragoverEvent, eventListener); -} - -EventListener* DOMWindow::ondragstart() const -{ - return getAttributeEventListener(eventNames().dragstartEvent); -} - -void DOMWindow::setOndragstart(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dragstartEvent, eventListener); -} - -EventListener* DOMWindow::ondrop() const -{ - return getAttributeEventListener(eventNames().dropEvent); -} - -void DOMWindow::setOndrop(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().dropEvent, eventListener); -} - -EventListener* DOMWindow::onerror() const -{ - return getAttributeEventListener(eventNames().errorEvent); -} - -void DOMWindow::setOnerror(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().errorEvent, eventListener); -} - -EventListener* DOMWindow::onfocus() const -{ - return getAttributeEventListener(eventNames().focusEvent); -} - -void DOMWindow::setOnfocus(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().focusEvent, eventListener); -} - -EventListener* DOMWindow::onkeydown() const -{ - return getAttributeEventListener(eventNames().keydownEvent); -} - -void DOMWindow::setOnkeydown(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().keydownEvent, eventListener); -} - -EventListener* DOMWindow::onkeypress() const -{ - return getAttributeEventListener(eventNames().keypressEvent); -} - -void DOMWindow::setOnkeypress(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().keypressEvent, eventListener); -} - -EventListener* DOMWindow::onkeyup() const -{ - return getAttributeEventListener(eventNames().keyupEvent); -} - -void DOMWindow::setOnkeyup(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().keyupEvent, eventListener); -} - -EventListener* DOMWindow::onload() const -{ - return getAttributeEventListener(eventNames().loadEvent); -} - -void DOMWindow::setOnload(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().loadEvent, eventListener); -} - -EventListener* DOMWindow::onmousedown() const -{ - return getAttributeEventListener(eventNames().mousedownEvent); -} - -void DOMWindow::setOnmousedown(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().mousedownEvent, eventListener); -} - -EventListener* DOMWindow::onmousemove() const -{ - return getAttributeEventListener(eventNames().mousemoveEvent); -} - -void DOMWindow::setOnmousemove(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().mousemoveEvent, eventListener); -} - -EventListener* DOMWindow::onmouseout() const -{ - return getAttributeEventListener(eventNames().mouseoutEvent); -} - -void DOMWindow::setOnmouseout(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().mouseoutEvent, eventListener); -} - -EventListener* DOMWindow::onmouseover() const -{ - return getAttributeEventListener(eventNames().mouseoverEvent); -} - -void DOMWindow::setOnmouseover(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().mouseoverEvent, eventListener); -} - -EventListener* DOMWindow::onmouseup() const -{ - return getAttributeEventListener(eventNames().mouseupEvent); -} - -void DOMWindow::setOnmouseup(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().mouseupEvent, eventListener); -} - -EventListener* DOMWindow::onmousewheel() const -{ - return getAttributeEventListener(eventNames().mousewheelEvent); -} - -void DOMWindow::setOnmousewheel(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().mousewheelEvent, eventListener); -} - -EventListener* DOMWindow::onoffline() const -{ - return getAttributeEventListener(eventNames().offlineEvent); -} - -void DOMWindow::setOnoffline(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().offlineEvent, eventListener); -} - -EventListener* DOMWindow::ononline() const -{ - return getAttributeEventListener(eventNames().onlineEvent); -} - -void DOMWindow::setOnonline(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().onlineEvent, eventListener); -} - -EventListener* DOMWindow::onreset() const -{ - return getAttributeEventListener(eventNames().resetEvent); -} - -void DOMWindow::setOnreset(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().resetEvent, eventListener); -} - -EventListener* DOMWindow::onresize() const -{ - return getAttributeEventListener(eventNames().resizeEvent); -} - -void DOMWindow::setOnresize(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().resizeEvent, eventListener); -} - -EventListener* DOMWindow::onscroll() const -{ - return getAttributeEventListener(eventNames().scrollEvent); -} - -void DOMWindow::setOnscroll(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().scrollEvent, eventListener); -} - -EventListener* DOMWindow::onsearch() const -{ - return getAttributeEventListener(eventNames().searchEvent); -} - -void DOMWindow::setOnsearch(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().searchEvent, eventListener); -} - -EventListener* DOMWindow::onselect() const -{ - return getAttributeEventListener(eventNames().selectEvent); -} - -void DOMWindow::setOnselect(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().selectEvent, eventListener); -} - -EventListener* DOMWindow::onstorage() const -{ - return getAttributeEventListener(eventNames().storageEvent); -} - -void DOMWindow::setOnstorage(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().storageEvent, eventListener); -} - -EventListener* DOMWindow::onsubmit() const -{ - return getAttributeEventListener(eventNames().submitEvent); -} - -void DOMWindow::setOnsubmit(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().submitEvent, eventListener); -} - -EventListener* DOMWindow::onunload() const -{ - return getAttributeEventListener(eventNames().unloadEvent); -} - -void DOMWindow::setOnunload(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().unloadEvent, eventListener); -} - -EventListener* DOMWindow::onbeforeunload() const -{ - return getAttributeEventListener(eventNames().beforeunloadEvent); -} - -void DOMWindow::setOnbeforeunload(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().beforeunloadEvent, eventListener); -} - -EventListener* DOMWindow::onwebkitanimationstart() const -{ - return getAttributeEventListener(eventNames().webkitAnimationStartEvent); -} - -void DOMWindow::setOnwebkitanimationstart(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().webkitAnimationStartEvent, eventListener); -} - -EventListener* DOMWindow::onwebkitanimationiteration() const -{ - return getAttributeEventListener(eventNames().webkitAnimationIterationEvent); -} - -void DOMWindow::setOnwebkitanimationiteration(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().webkitAnimationIterationEvent, eventListener); -} - -EventListener* DOMWindow::onwebkitanimationend() const -{ - return getAttributeEventListener(eventNames().webkitAnimationEndEvent); -} - -void DOMWindow::setOnwebkitanimationend(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().webkitAnimationEndEvent, eventListener); -} - -EventListener* DOMWindow::onwebkittransitionend() const -{ - return getAttributeEventListener(eventNames().webkitTransitionEndEvent); -} - -void DOMWindow::setOnwebkittransitionend(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().webkitTransitionEndEvent, eventListener); -} - -EventListener* DOMWindow::oncanplay() const -{ - return getAttributeEventListener(eventNames().canplayEvent); -} - -void DOMWindow::setOncanplay(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().canplayEvent, eventListener); -} - -EventListener* DOMWindow::oncanplaythrough() const -{ - return getAttributeEventListener(eventNames().canplaythroughEvent); -} - -void DOMWindow::setOncanplaythrough(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().canplaythroughEvent, eventListener); -} - -EventListener* DOMWindow::ondurationchange() const -{ - return getAttributeEventListener(eventNames().durationchangeEvent); -} - -void DOMWindow::setOndurationchange(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().durationchangeEvent, eventListener); -} - -EventListener* DOMWindow::onemptied() const -{ - return getAttributeEventListener(eventNames().emptiedEvent); -} - -void DOMWindow::setOnemptied(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().emptiedEvent, eventListener); -} - -EventListener* DOMWindow::onended() const -{ - return getAttributeEventListener(eventNames().endedEvent); -} - -void DOMWindow::setOnended(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().endedEvent, eventListener); -} - -EventListener* DOMWindow::onloadeddata() const -{ - return getAttributeEventListener(eventNames().loadeddataEvent); -} - -void DOMWindow::setOnloadeddata(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().loadeddataEvent, eventListener); -} - -EventListener* DOMWindow::onloadedmetadata() const -{ - return getAttributeEventListener(eventNames().loadedmetadataEvent); -} - -void DOMWindow::setOnloadedmetadata(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().loadedmetadataEvent, eventListener); -} - -EventListener* DOMWindow::onpause() const -{ - return getAttributeEventListener(eventNames().pauseEvent); -} - -void DOMWindow::setOnpause(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().pauseEvent, eventListener); -} - -EventListener* DOMWindow::onplay() const -{ - return getAttributeEventListener(eventNames().playEvent); -} - -void DOMWindow::setOnplay(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().playEvent, eventListener); -} - -EventListener* DOMWindow::onplaying() const -{ - return getAttributeEventListener(eventNames().playingEvent); -} - -void DOMWindow::setOnplaying(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().playingEvent, eventListener); -} - -EventListener* DOMWindow::onratechange() const -{ - return getAttributeEventListener(eventNames().ratechangeEvent); -} - -void DOMWindow::setOnratechange(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().ratechangeEvent, eventListener); -} - -EventListener* DOMWindow::onseeked() const -{ - return getAttributeEventListener(eventNames().seekedEvent); -} - -void DOMWindow::setOnseeked(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().seekedEvent, eventListener); -} - -EventListener* DOMWindow::onseeking() const -{ - return getAttributeEventListener(eventNames().seekingEvent); -} - -void DOMWindow::setOnseeking(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().seekingEvent, eventListener); -} - -EventListener* DOMWindow::ontimeupdate() const -{ - return getAttributeEventListener(eventNames().timeupdateEvent); -} - -void DOMWindow::setOntimeupdate(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().timeupdateEvent, eventListener); -} - -EventListener* DOMWindow::onvolumechange() const -{ - return getAttributeEventListener(eventNames().volumechangeEvent); -} - -void DOMWindow::setOnvolumechange(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().volumechangeEvent, eventListener); -} - -EventListener* DOMWindow::onwaiting() const -{ - return getAttributeEventListener(eventNames().waitingEvent); -} - -void DOMWindow::setOnwaiting(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().waitingEvent, eventListener); -} - -EventListener* DOMWindow::onloadstart() const -{ - return getAttributeEventListener(eventNames().loadstartEvent); -} - -void DOMWindow::setOnloadstart(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().loadstartEvent, eventListener); -} - -EventListener* DOMWindow::onprogress() const -{ - return getAttributeEventListener(eventNames().progressEvent); -} - -void DOMWindow::setOnprogress(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().progressEvent, eventListener); -} - -EventListener* DOMWindow::onstalled() const -{ - return getAttributeEventListener(eventNames().stalledEvent); -} - -void DOMWindow::setOnstalled(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().stalledEvent, eventListener); -} +#if ENABLE(INSPECTOR) + if (!frame() || !frame()->page()) + return; -EventListener* DOMWindow::onsuspend() const -{ - return getAttributeEventListener(eventNames().suspendEvent); + if (InspectorController* controller = frame()->page()->inspectorController()) + controller->mainResourceFiredLoadEvent(frame()->loader()->documentLoader(), url()); +#endif } -void DOMWindow::setOnsuspend(PassRefPtr<EventListener> eventListener) +bool DOMWindow::dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget) { - setAttributeEventListener(eventNames().suspendEvent, eventListener); -} + RefPtr<EventTarget> protect = this; + RefPtr<Event> event = prpEvent; -EventListener* DOMWindow::oninput() const -{ - return getAttributeEventListener(eventNames().inputEvent); -} + event->setTarget(prpTarget ? prpTarget : this); + event->setCurrentTarget(this); + event->setEventPhase(Event::AT_TARGET); -void DOMWindow::setOninput(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().inputEvent, eventListener); + return fireEventListeners(event.get()); } -EventListener* DOMWindow::onmessage() const +void DOMWindow::removeAllEventListeners() { - return getAttributeEventListener(eventNames().messageEvent); -} + EventTarget::removeAllEventListeners(); -void DOMWindow::setOnmessage(PassRefPtr<EventListener> eventListener) -{ - setAttributeEventListener(eventNames().messageEvent, eventListener); + removeAllUnloadEventListeners(this); + removeAllBeforeUnloadEventListeners(this); } -EventListener* DOMWindow::oncontextmenu() const +void DOMWindow::captureEvents() { - return getAttributeEventListener(eventNames().contextmenuEvent); + // Not implemented. } -void DOMWindow::setOncontextmenu(PassRefPtr<EventListener> eventListener) +void DOMWindow::releaseEvents() { - setAttributeEventListener(eventNames().contextmenuEvent, eventListener); + // Not implemented. } -void DOMWindow::captureEvents() +EventTargetData* DOMWindow::eventTargetData() { - // Not implemented. + return &m_eventTargetData; } -void DOMWindow::releaseEvents() +EventTargetData* DOMWindow::ensureEventTargetData() { - // Not implemented. + return &m_eventTargetData; } #if ENABLE(TOUCH_EVENTS) // Android diff --git a/WebCore/page/DOMWindow.h b/WebCore/page/DOMWindow.h index 12caf7e..3e3cbb4 100644 --- a/WebCore/page/DOMWindow.h +++ b/WebCore/page/DOMWindow.h @@ -28,6 +28,7 @@ #include "EventTarget.h" #include "KURL.h" +#include "MessagePort.h" #include "PlatformString.h" #include "RegisteredEventListener.h" #include "SecurityOrigin.h" @@ -53,11 +54,12 @@ namespace WebCore { class History; class Location; class Media; - class MessagePort; class Navigator; class Node; + class NotificationCenter; class PostMessageTimer; class ScheduledAction; + class SerializedScriptValue; class Screen; class WebKitPoint; @@ -84,6 +86,13 @@ namespace WebCore { void clear(); +#if ENABLE(ORIENTATION_EVENTS) + // This is the interface orientation in degrees. Some examples are: + // 0 is straight up; -90 is when the device is rotated 90 clockwise; + // 90 is when rotated counter clockwise. + int orientation() const; +#endif + void setSecurityOrigin(SecurityOrigin* securityOrigin) { m_securityOrigin = securityOrigin; } SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); } @@ -205,7 +214,13 @@ namespace WebCore { DOMApplicationCache* applicationCache() const; #endif - void postMessage(const String& message, MessagePort*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); +#if ENABLE(NOTIFICATIONS) + NotificationCenter* webkitNotifications() const; +#endif + + void postMessage(PassRefPtr<SerializedScriptValue> message, const MessagePortArray*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); + // FIXME: remove this when we update the ObjC bindings (bug #28774). + void postMessage(PassRefPtr<SerializedScriptValue> message, MessagePort*, const String& targetOrigin, DOMWindow* source, ExceptionCode&); void postMessageTimerFired(PostMessageTimer*); void scrollBy(int x, int y) const; @@ -226,17 +241,20 @@ namespace WebCore { // Events // EventTarget API - virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture); - virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture); - virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&); + virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture); + virtual bool removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture); + virtual void removeAllEventListeners(); - void handleEvent(Event*, bool useCapture, RegisteredEventListenerVector* = 0); - - void dispatchEvent(const AtomicString& eventType, bool canBubble, bool cancelable); + using EventTarget::dispatchEvent; + bool dispatchEvent(PassRefPtr<Event> prpEvent, PassRefPtr<EventTarget> prpTarget); void dispatchLoadEvent(); +<<<<<<< HEAD:WebCore/page/DOMWindow.h void dispatchUnloadEvent(RegisteredEventListenerVector* = 0); PassRefPtr<BeforeUnloadEvent> dispatchBeforeUnloadEvent(RegisteredEventListenerVector* = 0); +======= +>>>>>>> webkit.org at 49305:WebCore/page/DOMWindow.h +<<<<<<< HEAD:WebCore/page/DOMWindow.h // Used for legacy "onEvent" property APIs. void setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener>); void clearAttributeEventListener(const AtomicString& eventType); @@ -333,7 +351,74 @@ namespace WebCore { void setOntouchmove(PassRefPtr<EventListener>); EventListener* ontouchcancel() const; void setOntouchcancel(PassRefPtr<EventListener>); +======= + DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); + DEFINE_ATTRIBUTE_EVENT_LISTENER(blur); + DEFINE_ATTRIBUTE_EVENT_LISTENER(change); + DEFINE_ATTRIBUTE_EVENT_LISTENER(click); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick); + DEFINE_ATTRIBUTE_EVENT_LISTENER(drag); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragenter); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragleave); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover); + DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(drop); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(focus); + DEFINE_ATTRIBUTE_EVENT_LISTENER(hashchange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress); + DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup); + DEFINE_ATTRIBUTE_EVENT_LISTENER(load); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup); + DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel); + DEFINE_ATTRIBUTE_EVENT_LISTENER(offline); + DEFINE_ATTRIBUTE_EVENT_LISTENER(online); + DEFINE_ATTRIBUTE_EVENT_LISTENER(pagehide); + DEFINE_ATTRIBUTE_EVENT_LISTENER(pageshow); + DEFINE_ATTRIBUTE_EVENT_LISTENER(reset); + DEFINE_ATTRIBUTE_EVENT_LISTENER(resize); + DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll); + DEFINE_ATTRIBUTE_EVENT_LISTENER(search); + DEFINE_ATTRIBUTE_EVENT_LISTENER(select); + DEFINE_ATTRIBUTE_EVENT_LISTENER(storage); + DEFINE_ATTRIBUTE_EVENT_LISTENER(submit); + DEFINE_ATTRIBUTE_EVENT_LISTENER(unload); + DEFINE_ATTRIBUTE_EVENT_LISTENER(beforeunload); + DEFINE_ATTRIBUTE_EVENT_LISTENER(canplay); + DEFINE_ATTRIBUTE_EVENT_LISTENER(canplaythrough); + DEFINE_ATTRIBUTE_EVENT_LISTENER(durationchange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(emptied); + DEFINE_ATTRIBUTE_EVENT_LISTENER(ended); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadeddata); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadedmetadata); + DEFINE_ATTRIBUTE_EVENT_LISTENER(pause); + DEFINE_ATTRIBUTE_EVENT_LISTENER(play); + DEFINE_ATTRIBUTE_EVENT_LISTENER(playing); + DEFINE_ATTRIBUTE_EVENT_LISTENER(ratechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(seeked); + DEFINE_ATTRIBUTE_EVENT_LISTENER(seeking); + DEFINE_ATTRIBUTE_EVENT_LISTENER(timeupdate); + DEFINE_ATTRIBUTE_EVENT_LISTENER(volumechange); + DEFINE_ATTRIBUTE_EVENT_LISTENER(waiting); + DEFINE_ATTRIBUTE_EVENT_LISTENER(loadstart); + DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); + DEFINE_ATTRIBUTE_EVENT_LISTENER(stalled); + DEFINE_ATTRIBUTE_EVENT_LISTENER(suspend); + DEFINE_ATTRIBUTE_EVENT_LISTENER(input); + DEFINE_ATTRIBUTE_EVENT_LISTENER(message); + DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu); + DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid); +#if ENABLE(ORIENTATION_EVENTS) + DEFINE_ATTRIBUTE_EVENT_LISTENER(orientationchange); +>>>>>>> webkit.org at 49305:WebCore/page/DOMWindow.h #endif +<<<<<<< HEAD:WebCore/page/DOMWindow.h EventListener* oncanplay() const; void setOncanplay(PassRefPtr<EventListener>); @@ -381,6 +466,13 @@ namespace WebCore { void setOnmessage(PassRefPtr<EventListener>); EventListener* oncontextmenu() const; void setOncontextmenu(PassRefPtr<EventListener>); +======= + + DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationstart, webkitAnimationStart); + DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationiteration, webkitAnimationIteration); + DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkitanimationend, webkitAnimationEnd); + DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(webkittransitionend, webkitTransitionEnd); +>>>>>>> webkit.org at 49305:WebCore/page/DOMWindow.h void captureEvents(); void releaseEvents(); @@ -415,8 +507,8 @@ namespace WebCore { virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } - - void dispatchEventWithDocumentAsTarget(PassRefPtr<Event>, RegisteredEventListenerVector* = 0); + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); RefPtr<SecurityOrigin> m_securityOrigin; KURL m_url; @@ -441,8 +533,11 @@ namespace WebCore { #if ENABLE(OFFLINE_WEB_APPLICATIONS) mutable RefPtr<DOMApplicationCache> m_applicationCache; #endif +#if ENABLE(NOTIFICATIONS) + mutable RefPtr<NotificationCenter> m_notifications; +#endif - RegisteredEventListenerVector m_eventListeners; + EventTargetData m_eventTargetData; }; } // namespace WebCore diff --git a/WebCore/page/DOMWindow.idl b/WebCore/page/DOMWindow.idl index aba92f0..c8eafe6 100644 --- a/WebCore/page/DOMWindow.idl +++ b/WebCore/page/DOMWindow.idl @@ -39,6 +39,7 @@ module window { CustomNativeConverter, CustomPutFunction, ExtendsDOMGlobalObject, + EventTarget, GenerateNativeConverter, LegacyParent=JSDOMWindowBase ] DOMWindow { @@ -55,7 +56,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; @@ -74,7 +75,7 @@ module window { in DOMString name, in [Optional] DOMString options); - [Custom] DOMObject showModalDialog(in DOMString url, + [Custom] DOMObject showModalDialog(in DOMString url, in [Optional] DOMObject dialogArgs, in [Optional] DOMString featureArgs); @@ -169,12 +170,28 @@ module window { readonly attribute Storage sessionStorage; readonly attribute Storage localStorage; #endif +#if defined(ENABLE_NOTIFICATIONS) && ENABLE_NOTIFICATIONS + readonly attribute NotificationCenter webkitNotifications; +#endif + +#if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS + // This is the interface orientation in degrees. Some examples are: + // 0 is straight up; -90 is when the device is rotated 90 clockwise; + // 90 is when rotated counter clockwise. + readonly attribute long orientation; +#endif attribute [Replaceable] Console console; // cross-document messaging - [DoNotCheckDomainSecurity, Custom] void postMessage(in DOMString message, in [Optional] MessagePort messagePort, in DOMString targetOrigin) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT + [DoNotCheckDomainSecurity, Custom] void postMessage(in SerializedScriptValue message, in [Optional] Array messagePorts, in DOMString targetOrigin) raises(DOMException); +#else + // There's no good way to expose an array via the ObjC bindings, so for now just allow passing in a single port. + [DoNotCheckDomainSecurity, Custom] void postMessage(in SerializedScriptValue message, in [Optional] MessagePort messagePort, in DOMString targetOrigin) + raises(DOMException); +#endif // Timers [Custom] long setTimeout(in TimeoutHandler handler, in long timeout); @@ -221,7 +238,9 @@ module window { attribute EventListener onended; attribute EventListener onerror; attribute EventListener onfocus; + attribute EventListener onhashchange; attribute EventListener oninput; + attribute EventListener oninvalid; attribute EventListener onkeydown; attribute EventListener onkeypress; attribute EventListener onkeyup; @@ -238,6 +257,8 @@ module window { attribute EventListener onmousewheel; attribute EventListener onoffline; attribute EventListener ononline; + attribute EventListener onpagehide; + attribute EventListener onpageshow; attribute EventListener onpause; attribute EventListener onplay; attribute EventListener onplaying; @@ -262,8 +283,6 @@ module window { // attribute EventListener onbeforeprint; // attribute EventListener onformchange; // attribute EventListener onforminput; - // attribute EventListener onhashchange; - // attribute EventListener oninvalid; // attribute EventListener onpopstate; // attribute EventListener onreadystatechange; // attribute EventListener onredo; @@ -277,6 +296,9 @@ module window { attribute EventListener onwebkitanimationiteration; attribute EventListener onwebkitanimationstart; attribute EventListener onwebkittransitionend; +#if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS + attribute EventListener onorientationchange; +#endif // EventTarget interface [Custom] void addEventListener(in DOMString type, @@ -419,13 +441,25 @@ module window { attribute [CustomGetter] HTMLOptionElementConstructor Option; // Usable with new operator attribute CanvasRenderingContext2DConstructor CanvasRenderingContext2D; + attribute [Conditional=3D_CANVAS] CanvasRenderingContext3DConstructor CanvasRenderingContext3D; attribute TextMetricsConstructor TextMetrics; + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasArrayBufferConstructor CanvasArrayBuffer; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasByteArrayConstructor CanvasByteArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasUnsignedByteArrayConstructor CanvasUnsignedByteArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasShortArrayConstructor CanvasShortArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasUnsignedShortArrayConstructor CanvasUnsignedShortArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasIntArrayConstructor CanvasIntArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasUnsignedIntArrayConstructor CanvasUnsignedIntArray; // Usable with new operator + attribute [JSCCustomGetter,Conditional=3D_CANVAS] CanvasFloatArrayConstructor CanvasFloatArray; // Usable with new operator + attribute EventConstructor Event; + attribute BeforeLoadEventConstructor BeforeLoadEvent; attribute KeyboardEventConstructor KeyboardEvent; attribute MouseEventConstructor MouseEvent; attribute MutationEventConstructor MutationEvent; attribute OverflowEventConstructor OverflowEvent; + attribute PageTransitionEventConstructor PageTransitionEvent; attribute ProgressEventConstructor ProgressEvent; attribute TextEventConstructor TextEvent; attribute UIEventConstructor UIEvent; @@ -454,6 +488,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; @@ -465,9 +503,7 @@ module window { attribute XMLHttpRequestUploadConstructor XMLHttpRequestUpload; attribute XMLHttpRequestExceptionConstructor XMLHttpRequestException; -#if defined(ENABLE_XSLT) && ENABLE_XSLT - attribute [JSCCustomGetter] XSLTProcessorConstructor XSLTProcessor; // Usable with the new operator -#endif + attribute [JSCCustomGetter,Conditional=XSLT] XSLTProcessorConstructor XSLTProcessor; // Usable with the new operator #if defined(ENABLE_CHANNEL_MESSAGING) && ENABLE_CHANNEL_MESSAGING attribute MessagePortConstructor MessagePort; @@ -482,6 +518,10 @@ module window { attribute [JSCCustomGetter] SharedWorkerConstructor SharedWorker; // Usable with the new operator #endif +#if defined(ENABLE_WEB_SOCKETS) && ENABLE_WEB_SOCKETS + attribute [JSCCustomGetter] WebSocketConstructor WebSocket; // Usable with the new operator +#endif + attribute PluginConstructor Plugin; attribute PluginArrayConstructor PluginArray; diff --git a/WebCore/page/DragController.cpp b/WebCore/page/DragController.cpp index 08fb872..634595a 100644 --- a/WebCore/page/DragController.cpp +++ b/WebCore/page/DragController.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "DragController.h" +#if ENABLE(DRAG_SUPPORT) #include "CSSStyleDeclaration.h" #include "Clipboard.h" #include "ClipboardAccessPolicy.h" @@ -46,6 +47,7 @@ #include "HTMLAnchorElement.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include "HitTestRequest.h" #include "HitTestResult.h" #include "Image.h" #include "MoveSelectionCommand.h" @@ -53,6 +55,7 @@ #include "Page.h" #include "RenderFileUploadControl.h" #include "RenderImage.h" +#include "RenderView.h" #include "ReplaceSelectionCommand.h" #include "ResourceRequest.h" #include "SelectionController.h" @@ -107,7 +110,7 @@ static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragD String title; String url = dragData->asURL(&title); if (!url.isEmpty()) { - RefPtr<HTMLAnchorElement> anchor = new HTMLAnchorElement(document); + RefPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(document); anchor->setHref(url); ExceptionCode ec; RefPtr<Node> anchorText = document->createTextNode(title); @@ -253,6 +256,25 @@ static HTMLInputElement* asFileInput(Node* node) return 0; } +static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint& p) +{ + float zoomFactor = documentUnderMouse->frame()->pageZoomFactor(); + IntPoint point = roundedIntPoint(FloatPoint(p.x() * zoomFactor, p.y() * zoomFactor)); + + HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); + HitTestResult result(point); + documentUnderMouse->renderView()->layer()->hitTest(request, result); + + Node* n = result.innerNode(); + while (n && !n->isElementNode()) + n = n->parentNode(); + if (n) + n = n->shadowAncestorNode(); + + ASSERT(n); + return static_cast<Element*>(n); +} + bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask, DragOperation& operation) { ASSERT(dragData); @@ -287,10 +309,8 @@ bool DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction a return true; } - IntPoint dragPos = dragData->clientPosition(); - IntPoint point = frameView->windowToContents(dragPos); - Element* element = m_documentUnderMouse->elementFromPoint(point.x(), point.y()); - ASSERT(element); + IntPoint point = frameView->windowToContents(dragData->clientPosition()); + Element* element = elementUnderMouse(m_documentUnderMouse, point); if (!asFileInput(element)) { VisibleSelection dragCaret = m_documentUnderMouse->frame()->visiblePositionForPoint(point); m_page->dragCaretController()->setSelection(dragCaret); @@ -340,8 +360,7 @@ bool DragController::concludeEditDrag(DragData* dragData) return false; IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition()); - Element* element = m_documentUnderMouse->elementFromPoint(point.x(), point.y()); - ASSERT(element); + Element* element = elementUnderMouse(m_documentUnderMouse, point); Frame* innerFrame = element->ownerDocument()->frame(); ASSERT(innerFrame); @@ -630,6 +649,12 @@ bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation s if (isDHTMLDrag) dragImage = clipboard->createDragImage(dragImageOffset); + else { + // This drag operation is not a DHTML drag and may go outside the WebView. + // We provide a default set of allowed drag operations that follows from: + // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430 + m_sourceDragOperation = (DragOperation)(DragOperationGeneric | DragOperationCopy); + } // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. @@ -785,3 +810,5 @@ void DragController::placeDragCaret(const IntPoint& windowPoint) } } // namespace WebCore + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp index 937f08f..6b4031e 100644 --- a/WebCore/page/EventHandler.cpp +++ b/WebCore/page/EventHandler.cpp @@ -87,6 +87,7 @@ namespace WebCore { using namespace HTMLNames; +#if ENABLE(DRAG_SUPPORT) // The link drag hysteresis is much larger than the others because there // needs to be enough space to cancel the link press without starting a link drag, // and because dragging links is rare. @@ -94,6 +95,7 @@ const int LinkDragHysteresis = 40; const int ImageDragHysteresis = 5; const int TextDragHysteresis = 3; const int GeneralDragHysteresis = 3; +#endif // ENABLE(DRAG_SUPPORT) // Match key code of composition keydown event on windows. // IE sends VK_PROCESSKEY which has value 229; @@ -106,10 +108,9 @@ using namespace SVGNames; // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth const double autoscrollInterval = 0.05; -static Frame* subframeForTargetNode(Node*); static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&); -static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node) +static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node, Node** stopNode) { if (!delta) return; @@ -118,12 +119,13 @@ static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDir RenderBox* enclosingBox = node->renderer()->enclosingBox(); if (e.granularity() == ScrollByPageWheelEvent) { - if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1)) + if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1, stopNode)) e.accept(); return; - } + } + float pixelsToScroll = delta > 0 ? delta : -delta; - if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll)) + if (enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll, stopNode)) e.accept(); } @@ -146,7 +148,9 @@ EventHandler::EventHandler(Frame* frame) , m_mousePressed(false) , m_capturesDragging(false) , m_mouseDownMayStartSelect(false) +#if ENABLE(DRAG_SUPPORT) , m_mouseDownMayStartDrag(false) +#endif , m_mouseDownWasSingleClickInSelection(false) , m_beganSelectingText(false) , m_panScrollInProgress(false) @@ -179,11 +183,13 @@ EventHandler::~EventHandler() { } +#if ENABLE(DRAG_SUPPORT) EventHandler::EventHandlerDragState& EventHandler::dragState() { DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ()); return state; } +#endif // ENABLE(DRAG_SUPPORT) void EventHandler::clear() { @@ -203,13 +209,16 @@ void EventHandler::clear() m_touch = 0; #endif m_frameSetBeingResized = 0; +#if ENABLE(DRAG_SUPPORT) m_dragTarget = 0; +#endif m_currentMousePosition = IntPoint(); m_mousePressNode = 0; m_mousePressed = false; m_capturesDragging = false; m_capturingMouseEventsNode = 0; m_latchedWheelEventNode = 0; + m_previousWheelScrolledNode = 0; } void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) @@ -357,8 +366,10 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) { +#if ENABLE(DRAG_SUPPORT) // Reset drag state. dragState().m_dragSrc = 0; +#endif if (ScrollView* scrollView = m_frame->view()) { if (scrollView->isPointInScrollbarCorner(event.event().pos())) @@ -371,8 +382,10 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve // so it's allowed to start a drag or selection. m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()); +#if ENABLE(DRAG_SUPPORT) // Careful that the drag starting logic stays in sync with eventMayStartDrag() m_mouseDownMayStartDrag = singleClick; +#endif m_mouseDownWasSingleClickInSelection = false; @@ -400,7 +413,9 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve Node* innerNode = event.targetNode(); m_mousePressNode = innerNode; +#if ENABLE(DRAG_SUPPORT) m_dragStartPos = event.event().pos(); +#endif bool swallowEvent = false; m_frame->selection()->setCaretBlinkingSuspended(true); @@ -420,6 +435,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve return swallowEvent; } +#if ENABLE(DRAG_SUPPORT) bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) { if (handleDrag(event)) @@ -442,7 +458,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 @@ -559,6 +575,7 @@ void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& m_frame->selection()->setSelection(newSelection); } } +#endif // ENABLE(DRAG_SUPPORT) bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) { @@ -586,7 +603,9 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e m_frame->selection()->setCaretBlinkingSuspended(false); m_mousePressed = false; m_capturesDragging = false; +#if ENABLE(DRAG_SUPPORT) m_mouseDownMayStartDrag = false; +#endif m_mouseDownMayStartSelect = false; m_mouseDownMayStartAutoscroll = false; m_mouseDownWasInSubframe = false; @@ -598,7 +617,9 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e // on the selection, the selection goes away. However, if we are // editing, place the caret. if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText +#if ENABLE(DRAG_SUPPORT) && m_dragStartPos == event.event().pos() +#endif && m_frame->selection()->isRange() && event.event().button() != RightButton) { VisibleSelection newSelection; @@ -732,7 +753,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(); } @@ -741,6 +762,7 @@ void EventHandler::setAutoscrollRenderer(RenderObject* renderer) m_autoscrollRenderer = renderer; } +#if ENABLE(DRAG_SUPPORT) void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const { flagDHTML = false; @@ -761,6 +783,7 @@ void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone; flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection)); } +#endif // ENABLE(DRAG_SUPPORT) HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars) { @@ -883,8 +906,10 @@ bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity g if (node) { RenderObject* r = node->renderer(); - if (r && !r->isListBox()) - return r->enclosingBox()->scroll(direction, granularity); + if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) { + setFrameWasScrolledByUser(); + return true; + } } return false; @@ -914,10 +939,10 @@ Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResul { if (!hitTestResult.isOverWidget()) return 0; - return subframeForTargetNode(hitTestResult.targetNode()); + return EventHandler::subframeForTargetNode(hitTestResult.targetNode()); } -Frame* subframeForTargetNode(Node* node) +Frame* EventHandler::subframeForTargetNode(Node* node) { if (!node) return 0; @@ -1117,7 +1142,9 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) m_capturesDragging = true; m_currentMousePosition = mouseEvent.pos(); m_mouseDownTimestamp = mouseEvent.timestamp(); +#if ENABLE(DRAG_SUPPORT) m_mouseDownMayStartDrag = false; +#endif m_mouseDownMayStartSelect = false; m_mouseDownMayStartAutoscroll = false; if (FrameView* view = m_frame->view()) @@ -1141,6 +1168,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) m_mousePressNode = mev.targetNode(); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) { InspectorController* inspector = page->inspectorController(); if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) { @@ -1149,6 +1177,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) return true; } } +#endif Frame* subframe = subframeForHitTestResult(mev); if (subframe && passMousePressEventToSubframe(mev, subframe)) { @@ -1172,7 +1201,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 @@ -1393,8 +1422,10 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi return true; swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true); +#if ENABLE(DRAG_SUPPORT) if (!swallowEvent) swallowEvent = handleMouseDraggedEvent(mev); +#endif // ENABLE(DRAG_SUPPORT) return swallowEvent; } @@ -1464,6 +1495,7 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; } +#if ENABLE(DRAG_SUPPORT) bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard) { FrameView* view = m_frame->view(); @@ -1508,15 +1540,15 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* // it is sometimes incorrect when dragging within subframes, as seen with // LayoutTests/fast/events/drag-in-frames.html. if (newTarget) { - if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) - accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); + Frame* frame = (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) ? static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame() : 0; + if (frame) + accept = frame->eventHandler()->updateDragAndDrop(event, clipboard); else accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard); } if (m_dragTarget) { - Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) - ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; + Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; if (frame) accept = frame->eventHandler()->updateDragAndDrop(event, clipboard); else @@ -1524,8 +1556,9 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* } } else { if (newTarget) { - if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) - accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); + Frame* frame = (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) ? static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame() : 0; + if (frame) + accept = frame->eventHandler()->updateDragAndDrop(event, clipboard); else accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard); } @@ -1571,6 +1604,7 @@ void EventHandler::clearDragState() m_sendingEventToSubview = false; #endif } +#endif // ENABLE(DRAG_SUPPORT) void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n) { @@ -1692,12 +1726,15 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount); if (!swallowEvent && eventType == eventNames().mousedownEvent) { + // The layout needs to be up to date to determine if an element is focusable. + m_frame->document()->updateLayoutIgnorePendingStylesheets(); + // Blur current focus node when a link/button is clicked; this // is expected by some sites that rely on onChange handlers running // from form fields before the button click is processed. Node* node = m_nodeUnderMouse.get(); RenderObject* renderer = node ? node->renderer() : 0; - + // Walk up the render tree to search for a node to focus. // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields. while (renderer) { @@ -1736,6 +1773,13 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe return swallowEvent; } +#if !PLATFORM(GTK) +bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const +{ + return false; +} +#endif + bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) { Document* doc = m_frame->document(); @@ -1749,35 +1793,39 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) FrameView* view = m_frame->view(); if (!view) return false; + setFrameWasScrolledByUser(); IntPoint vPoint = view->windowToContents(e.pos()); Node* node; bool isOverWidget; bool didSetLatchedNode = false; - + + HitTestRequest request(HitTestRequest::ReadOnly); + HitTestResult result(vPoint); + doc->renderView()->layer()->hitTest(request, result); + if (m_useLatchedWheelEventNode) { if (!m_latchedWheelEventNode) { - HitTestRequest request(HitTestRequest::ReadOnly); - HitTestResult result(vPoint); - doc->renderView()->layer()->hitTest(request, result); m_latchedWheelEventNode = result.innerNode(); m_widgetIsLatched = result.isOverWidget(); didSetLatchedNode = true; } - + node = m_latchedWheelEventNode.get(); isOverWidget = m_widgetIsLatched; } else { if (m_latchedWheelEventNode) m_latchedWheelEventNode = 0; - - HitTestRequest request(HitTestRequest::ReadOnly); - HitTestResult result(vPoint); - doc->renderView()->layer()->hitTest(request, result); + if (m_previousWheelScrolledNode) + m_previousWheelScrolledNode = 0; + node = result.innerNode(); isOverWidget = result.isOverWidget(); } - + + if (shouldTurnVerticalTicksIntoHorizontal(result)) + e.turnVerticalTicksIntoHorizontal(); + if (node) { // Figure out which view to send the event to. RenderObject* target = node->renderer(); @@ -1794,17 +1842,20 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) node->dispatchWheelEvent(e); if (e.isAccepted()) return true; - + // If we don't have a renderer, send the wheel event to the first node we find with a renderer. // This is needed for <option> and <optgroup> elements so that <select>s get a wheel scroll. while (node && !node->renderer()) node = node->parent(); - + if (node && node->renderer()) { // Just break up into two scrolls if we need to. Diagonal movement on // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). - scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node); - scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node); + Node* stopNode = m_previousWheelScrolledNode.get(); + scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node, &stopNode); + scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node, &stopNode); + if (!m_useLatchedWheelEventNode) + m_previousWheelScrolledNode = stopNode; } } @@ -1819,6 +1870,7 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) return e.isAccepted(); } +#if ENABLE(CONTEXT_MENUS) bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) { Document* doc = m_frame->document(); @@ -1849,6 +1901,7 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) return swallowEvent; } +#endif // ENABLE(CONTEXT_MENUS) void EventHandler::scheduleHoverStateUpdate() { @@ -1868,12 +1921,13 @@ bool EventHandler::canMouseDownStartSelect(Node* node) for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) { if (Node* node = curr->node()) - return node->dispatchEvent(eventNames().selectstartEvent, true, true); + return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)); } return true; } +#if ENABLE(DRAG_SUPPORT) bool EventHandler::canMouseDragExtendSelect(Node* node) { if (!node || !node->renderer()) @@ -1881,11 +1935,12 @@ bool EventHandler::canMouseDragExtendSelect(Node* node) for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) { if (Node* node = curr->node()) - return node->dispatchEvent(eventNames().selectstartEvent, true, true); + return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true)); } return true; } +#endif // ENABLE(DRAG_SUPPORT) void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet) { @@ -2109,6 +2164,7 @@ void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) } } +#if ENABLE(DRAG_SUPPORT) bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const { IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y()); @@ -2142,7 +2198,7 @@ void EventHandler::freeClipboard() bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const { - if (!node || node->hasChildNodes() || !m_frame->view()) + if (!node || !m_frame->view()) return false; Page* page = m_frame->page(); return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point); @@ -2308,6 +2364,7 @@ cleanupDrag: // No more default handling (like selection), whether we're past the hysteresis bounds or not return true; } +#endif // ENABLE(DRAG_SUPPORT) bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, bool isLineBreak, bool isBackTab) { @@ -2339,7 +2396,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; @@ -2440,22 +2497,28 @@ void EventHandler::capsLockStateMayHaveChanged() void EventHandler::sendResizeEvent() { - m_frame->document()->dispatchWindowEvent(eventNames().resizeEvent, false, false); + m_frame->document()->dispatchWindowEvent(Event::create(eventNames().resizeEvent, false, false)); } void EventHandler::sendScrollEvent() { + setFrameWasScrolledByUser(); + if (m_frame->view()) + m_frame->document()->dispatchEvent(Event::create(eventNames().scrollEvent, true, false)); +} + +void EventHandler::setFrameWasScrolledByUser() +{ FrameView* v = m_frame->view(); - if (!v) - return; - v->setWasScrolledByUser(true); - m_frame->document()->dispatchEvent(eventNames().scrollEvent, true, false); + if (v) + v->setWasScrolledByUser(true); } bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar) { if (!scrollbar || !scrollbar->enabled()) return false; + setFrameWasScrolledByUser(); return scrollbar->mouseDown(mev.event()); } diff --git a/WebCore/page/EventHandler.h b/WebCore/page/EventHandler.h index 7fe64ad..3348366 100644 --- a/WebCore/page/EventHandler.h +++ b/WebCore/page/EventHandler.h @@ -66,10 +66,12 @@ class PlatformTouchEvent; class Touch; #endif +#if ENABLE(DRAG_SUPPORT) extern const int LinkDragHysteresis; extern const int ImageDragHysteresis; extern const int TextDragHysteresis; extern const int GeneralDragHysteresis; +#endif // ENABLE(DRAG_SUPPORT) enum HitTestScrollbars { ShouldHitTestScrollbars, DontHitTestScrollbars }; @@ -80,7 +82,9 @@ public: void clear(); +#if ENABLE(DRAG_SUPPORT) void updateSelectionForMouseDrag(); +#endif Node* mousePressNode() const; void setMousePressNode(PassRefPtr<Node>); @@ -99,9 +103,11 @@ public: void setCapturingMouseEventsNode(PassRefPtr<Node>); +#if ENABLE(DRAG_SUPPORT) bool updateDragAndDrop(const PlatformMouseEvent&, Clipboard*); void cancelDragAndDrop(const PlatformMouseEvent&, Clipboard*); bool performDragAndDrop(const PlatformMouseEvent&, Clipboard*); +#endif void scheduleHoverStateUpdate(); @@ -113,11 +119,17 @@ public: void setIgnoreWheelEvents(bool); + static Frame* subframeForTargetNode(Node*); + bool scrollOverflow(ScrollDirection, ScrollGranularity); bool scrollRecursively(ScrollDirection, ScrollGranularity); +#if ENABLE(DRAG_SUPPORT) bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto +#endif + + bool shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const; bool tabsToLinks(KeyboardEvent*) const; bool tabsToAllControls(KeyboardEvent*) const; @@ -131,11 +143,16 @@ public: bool handleMouseReleaseEvent(const PlatformMouseEvent&); bool handleWheelEvent(PlatformWheelEvent&); +<<<<<<< HEAD:WebCore/page/EventHandler.h #if ENABLE(TOUCH_EVENTS) // Android bool handleTouchEvent(const PlatformTouchEvent&); #endif +======= +#if ENABLE(CONTEXT_MENUS) +>>>>>>> webkit.org at 49305:WebCore/page/EventHandler.h bool sendContextMenuEvent(const PlatformMouseEvent&); +#endif void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; } @@ -150,10 +167,12 @@ public: bool isLineBreak = false, bool isBackTab = false); void defaultTextInputEventHandler(TextEvent*); +#if ENABLE(DRAG_SUPPORT) bool eventMayStartDrag(const PlatformMouseEvent&) const; void dragSourceMovedTo(const PlatformMouseEvent&); void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation); +#endif void focusDocumentView(); @@ -172,7 +191,9 @@ public: bool keyEvent(NSEvent *); bool wheelEvent(NSEvent *); +#if ENABLE(CONTEXT_MENUS) bool sendContextMenuEvent(NSEvent *); +#endif bool eventMayStartDrag(NSEvent *); void sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent); @@ -183,6 +204,7 @@ public: #endif private: +#if ENABLE(DRAG_SUPPORT) struct EventHandlerDragState { RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture bool m_dragSrcIsLink; @@ -197,6 +219,7 @@ private: static const double TextDragDelay; PassRefPtr<Clipboard> createDraggingClipboard() const; +#endif // ENABLE(DRAG_SUPPORT) bool eventActivatedView(const PlatformMouseEvent&) const; void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&); @@ -208,7 +231,9 @@ private: bool handleMousePressEventSingleClick(const MouseEventWithHitTestResults&); bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&); bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&); +#if ENABLE(DRAG_SUPPORT) bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&); +#endif bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&); void handleKeyboardSelectionMovement(KeyboardEvent*); @@ -221,7 +246,9 @@ private: void hoverTimerFired(Timer<EventHandler>*); static bool canMouseDownStartSelect(Node*); +#if ENABLE(DRAG_SUPPORT) static bool canMouseDragExtendSelect(Node*); +#endif void handleAutoscroll(RenderObject*); void startAutoscrollTimer(); @@ -238,18 +265,22 @@ private: MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&); bool dispatchMouseEvent(const AtomicString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder); +#if ENABLE(DRAG_SUPPORT) bool dispatchDragEvent(const AtomicString& eventType, Node* target, const PlatformMouseEvent&, Clipboard*); void freeClipboard(); bool handleDrag(const MouseEventWithHitTestResults&); +#endif bool handleMouseUp(const MouseEventWithHitTestResults&); +#if ENABLE(DRAG_SUPPORT) void clearDragState(); bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&); bool dragHysteresisExceeded(const FloatPoint&) const; bool dragHysteresisExceeded(const IntPoint&) const; +#endif // ENABLE(DRAG_SUPPORT) bool passMousePressEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe); bool passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0); @@ -268,18 +299,26 @@ private: void defaultSpaceEventHandler(KeyboardEvent*); void defaultTabEventHandler(KeyboardEvent*); +#if ENABLE(DRAG_SUPPORT) void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const; +#endif // The following are called at the beginning of handleMouseUp and handleDrag. // If they return true it indicates that they have consumed the event. bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&); +#if ENABLE(DRAG_SUPPORT) bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&); +#endif bool invertSenseOfTabsToLinks(KeyboardEvent*) const; +#if ENABLE(DRAG_SUPPORT) void updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint); +#endif void updateLastScrollbarUnderMouse(Scrollbar*, bool); + + void setFrameWasScrolledByUser(); bool capturesDragging() const { return m_capturesDragging; } @@ -296,11 +335,15 @@ private: RefPtr<Node> m_mousePressNode; bool m_mouseDownMayStartSelect; +#if ENABLE(DRAG_SUPPORT) bool m_mouseDownMayStartDrag; +#endif bool m_mouseDownWasSingleClickInSelection; bool m_beganSelectingText; +#if ENABLE(DRAG_SUPPORT) IntPoint m_dragStartPos; +#endif IntPoint m_panScrollStartPos; bool m_panScrollInProgress; @@ -337,7 +380,9 @@ private: RefPtr<Touch> m_touch; #endif +#if ENABLE(DRAG_SUPPORT) RefPtr<Node> m_dragTarget; +#endif RefPtr<HTMLFrameSetElement> m_frameSetBeingResized; @@ -351,7 +396,9 @@ private: bool m_useLatchedWheelEventNode; RefPtr<Node> m_latchedWheelEventNode; bool m_widgetIsLatched; - + + RefPtr<Node> m_previousWheelScrolledNode; + #if PLATFORM(MAC) NSView *m_mouseDownView; bool m_sendingEventToSubview; diff --git a/WebCore/page/EventSource.cpp b/WebCore/page/EventSource.cpp new file mode 100644 index 0000000..2c9a343 --- /dev/null +++ b/WebCore/page/EventSource.cpp @@ -0,0 +1,314 @@ +/* + * 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 "SerializedScriptValue.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) + dispatchEvent(Event::create(eventNames().errorEvent, false, false)); + + 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<EventSource>*) +{ + 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::didReceiveResponse(const ResourceResponse& response) +{ + int statusCode = response.httpStatusCode(); + if (statusCode == 200 && response.httpHeaderField("Content-Type") == "text/event-stream") { + m_state = OPEN; + dispatchEvent(Event::create(eventNames().openEvent, false, false)); + } 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()) + dispatchEvent(createMessageEvent()); + 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::stop() +{ + close(); +} + +PassRefPtr<MessageEvent> EventSource::createMessageEvent() +{ + RefPtr<MessageEvent> event = MessageEvent::create(); + event->initMessageEvent(m_eventName.isEmpty() ? eventNames().messageEvent : AtomicString(m_eventName), false, false, SerializedScriptValue::create(String::adopt(m_data)), m_origin, m_lastEventId, 0, 0); + return event.release(); +} + +EventTargetData* EventSource::eventTargetData() +{ + return &m_eventTargetData; +} + +EventTargetData* EventSource::ensureEventTargetData() +{ + return &m_eventTargetData; +} + +} // namespace WebCore + +#endif // ENABLE(EVENTSOURCE) diff --git a/WebCore/page/EventSource.h b/WebCore/page/EventSource.h new file mode 100644 index 0000000..5b037a4 --- /dev/null +++ b/WebCore/page/EventSource.h @@ -0,0 +1,134 @@ +/* + * 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 <wtf/HashMap.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class MessageEvent; + class ResourceResponse; + class TextResourceDecoder; + class ThreadableLoader; + + class EventSource : public RefCounted<EventSource>, public EventTarget, private ThreadableLoaderClient, public ActiveDOMObject { + public: + static PassRefPtr<EventSource> 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; + + DEFINE_ATTRIBUTE_EVENT_LISTENER(open); + DEFINE_ATTRIBUTE_EVENT_LISTENER(message); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + + void close(); + + using RefCounted<EventSource>::ref; + using RefCounted<EventSource>::deref; + + virtual EventSource* toEventSource() { return this; } + virtual ScriptExecutionContext* scriptExecutionContext() const; + + virtual void stop(); + + private: + EventSource(const String& url, ScriptExecutionContext* context, ExceptionCode& ec); + + virtual void refEventTarget() { ref(); } + virtual void derefEventTarget() { deref(); } + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); + + 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<EventSource>*); + void parseEventStream(); + void parseEventStreamLine(unsigned int pos, int fieldLength, int lineLength); + PassRefPtr<MessageEvent> createMessageEvent(); + + KURL m_url; + State m_state; + + RefPtr<TextResourceDecoder> m_decoder; + RefPtr<ThreadableLoader> m_loader; + Timer<EventSource> m_reconnectTimer; + Vector<UChar> m_receiveBuf; + bool m_failSilently; + bool m_requestInFlight; + + String m_eventName; + Vector<UChar> m_data; + String m_lastEventId; + unsigned long long m_reconnectDelay; + String m_origin; + + EventTargetData m_eventTargetData; + }; + +} // 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..561bd68 --- /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, + EventTarget, + 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/FocusController.cpp b/WebCore/page/FocusController.cpp index 817801c..5e78c7d 100644 --- a/WebCore/page/FocusController.cpp +++ b/WebCore/page/FocusController.cpp @@ -36,6 +36,7 @@ #include "Event.h" #include "EventHandler.h" #include "EventNames.h" +#include "ExceptionCode.h" #include "Frame.h" #include "FrameView.h" #include "FrameTree.h" @@ -55,6 +56,18 @@ namespace WebCore { using namespace HTMLNames; +static inline void dispatchEventsOnWindowAndFocusedNode(Document* document, bool focused) +{ + // If we have a focused node we should dispatch blur on it before we blur the window. + // If we have a focused node we should dispatch focus on it after we focus the window. + // https://bugs.webkit.org/show_bug.cgi?id=27105 + if (!focused && document->focusedNode()) + document->focusedNode()->dispatchBlurEvent(); + document->dispatchWindowEvent(Event::create(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false)); + if (focused && document->focusedNode()) + document->focusedNode()->dispatchFocusEvent(); +} + FocusController::FocusController(Page* page) : m_page(page) , m_isActive(false) @@ -75,12 +88,12 @@ void FocusController::setFocusedFrame(PassRefPtr<Frame> frame) // Now that the frame is updated, fire events and update the selection focused states of both frames. if (oldFrame && oldFrame->view()) { oldFrame->selection()->setFocused(false); - oldFrame->document()->dispatchWindowEvent(eventNames().blurEvent, false, false); + oldFrame->document()->dispatchWindowEvent(Event::create(eventNames().blurEvent, false, false)); } if (newFrame && newFrame->view() && isFocused()) { newFrame->selection()->setFocused(true); - newFrame->document()->dispatchWindowEvent(eventNames().focusEvent, false, false); + newFrame->document()->dispatchWindowEvent(Event::create(eventNames().focusEvent, false, false)); } } @@ -100,7 +113,7 @@ void FocusController::setFocused(bool focused) if (m_focusedFrame && m_focusedFrame->view()) { m_focusedFrame->selection()->setFocused(focused); - m_focusedFrame->document()->dispatchWindowEvent(focused ? eventNames().focusEvent : eventNames().blurEvent, false, false); + dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), focused); } } @@ -146,6 +159,8 @@ bool FocusController::advanceFocus(FocusDirection direction, KeyboardEvent* even if (caretBrowsing && !currentNode) currentNode = frame->selection()->start().node(); + document->updateLayoutIgnorePendingStylesheets(); + Node* node = (direction == FocusDirectionForward) ? document->nextFocusableNode(currentNode, event) : document->previousFocusableNode(currentNode, event); @@ -341,7 +356,7 @@ void FocusController::setActive(bool active) focusedOrMainFrame()->selection()->pageActivationChanged(); if (m_focusedFrame && isFocused()) - m_focusedFrame->document()->dispatchWindowEvent(active ? eventNames().focusEvent : eventNames().blurEvent, false, false); + dispatchEventsOnWindowAndFocusedNode(m_focusedFrame->document(), active); } } // namespace WebCore diff --git a/WebCore/page/Frame.cpp b/WebCore/page/Frame.cpp index 78cc25c..c03efb0 100644 --- a/WebCore/page/Frame.cpp +++ b/WebCore/page/Frame.cpp @@ -59,6 +59,7 @@ #include "Navigator.h" #include "NodeList.h" #include "Page.h" +#include "PageGroup.h" #include "RegularExpression.h" #include "RenderPart.h" #include "RenderTableCell.h" @@ -66,9 +67,12 @@ #include "RenderTheme.h" #include "RenderView.h" #include "ScriptController.h" +#include "ScriptSourceCode.h" +#include "ScriptValue.h" #include "Settings.h" #include "TextIterator.h" #include "TextResourceDecoder.h" +#include "UserContentURLPattern.h" #include "XMLNames.h" #include "htmlediting.h" #include "markup.h" @@ -82,10 +86,6 @@ #include "runtime_root.h" #endif -#if FRAME_LOADS_USER_STYLESHEET -#include "UserStyleSheetLoader.h" -#endif - #if ENABLE(SVG) #include "SVGDocument.h" #include "SVGDocumentExtensions.h" @@ -101,6 +101,10 @@ #include "WMLNames.h" #endif +#if ENABLE(MATHML) +#include "MathMLNames.h" +#endif + using namespace std; namespace WebCore { @@ -122,6 +126,7 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* : m_page(page) , m_treeNode(this, parentFromOwnerElement(ownerElement)) , m_loader(this, frameLoaderClient) + , m_redirectScheduler(this) , m_ownerElement(ownerElement) , m_script(this) , m_selectionGranularity(CharacterGranularity) @@ -131,6 +136,9 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* , m_eventHandler(this) , m_animationController(this) , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired) +#if ENABLE(ORIENTATION_EVENTS) + , m_orientation(0) +#endif , m_caretVisible(false) , m_caretPaint(true) , m_highlightTextMatches(false) @@ -138,9 +146,6 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* , m_needsReapplyStyles(false) , m_isDisconnected(false) , m_excludeFromTextSearch(false) -#if FRAME_LOADS_USER_STYLESHEET - , m_userStyleSheetLoader(0) -#endif { Frame* parent = parentFromOwnerElement(ownerElement); m_zoomFactor = parent ? parent->m_zoomFactor : 1.0f; @@ -159,6 +164,10 @@ Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* WMLNames::init(); #endif +#if ENABLE(MATHML) + MathMLNames::init(); +#endif + XMLNames::init(); if (!ownerElement) @@ -203,10 +212,6 @@ Frame::~Frame() } ASSERT(!m_lifeSupportTimer.isActive()); - -#if FRAME_LOADS_USER_STYLESHEET - delete m_userStyleSheetLoader; -#endif } void Frame::init() @@ -219,6 +224,11 @@ FrameLoader* Frame::loader() const return &m_loader; } +RedirectScheduler* Frame::redirectScheduler() const +{ + return &m_redirectScheduler; +} + FrameView* Frame::view() const { return m_view.get(); @@ -226,6 +236,12 @@ FrameView* Frame::view() const void Frame::setView(PassRefPtr<FrameView> view) { + // We the custom scroll bars as early as possible to prevent m_doc->detach() + // from messing with the view such that its scroll bars won't be torn down. + // FIXME: We should revisit this. + if (m_view) + m_view->detachCustomScrollbars(); + // Detach the document now, so any onUnload handlers get run - if // we wait until the view is destroyed, then things won't be // hooked up enough for some JavaScript calls to work. @@ -273,6 +289,15 @@ void Frame::setDocument(PassRefPtr<Document> newDoc) m_script.updateDocument(); } +#if ENABLE(ORIENTATION_EVENTS) +void Frame::sendOrientationChangeEvent(int orientation) +{ + m_orientation = orientation; + if (Document* doc = document()) + doc->dispatchWindowEvent(eventNames().orientationchangeEvent, false, false); +} +#endif // ENABLE(ORIENTATION_EVENTS) + Settings* Frame::settings() const { return m_page ? m_page->settings() : 0; @@ -829,14 +854,6 @@ void Frame::reapplyStyles() // We should probably eventually move it into its own function. m_doc->docLoader()->setAutoLoadImages(m_page && m_page->settings()->loadsImagesAutomatically()); -#if FRAME_LOADS_USER_STYLESHEET - const KURL userStyleSheetLocation = m_page ? m_page->settings()->userStyleSheetLocation() : KURL(); - if (!userStyleSheetLocation.isEmpty()) - setUserStyleSheetLocation(userStyleSheetLocation); - else - setUserStyleSheet(String()); -#endif - // FIXME: It's not entirely clear why the following is needed. // The document automatically does this as required when you set the style sheet. // But we had problems when this code was removed. Details are in @@ -844,6 +861,39 @@ void Frame::reapplyStyles() m_doc->updateStyleSelector(); } +void Frame::injectUserScripts(UserScriptInjectionTime injectionTime) +{ + if (!m_page) + return; + + // Walk the hashtable. Inject by world. + const UserScriptMap* userScripts = m_page->group().userScripts(); + if (!userScripts) + return; + UserScriptMap::const_iterator end = userScripts->end(); + for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it) + injectUserScriptsForWorld(it->first, *it->second, injectionTime); +} + +void Frame::injectUserScriptsForWorld(unsigned worldID, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime) +{ + if (userScripts.isEmpty()) + return; + + Document* doc = document(); + if (!doc) + return; + + Vector<ScriptSourceCode> sourceCode; + unsigned count = userScripts.size(); + for (unsigned i = 0; i < count; ++i) { + UserScript* script = userScripts[i].get(); + if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist())) + sourceCode.append(ScriptSourceCode(script->source(), script->url())); + } + script()->evaluateInIsolatedWorld(worldID, sourceCode); +} + bool Frame::shouldChangeSelection(const VisibleSelection& newSelection) const { return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false); @@ -1559,6 +1609,11 @@ Page* Frame::page() const return m_page; } +void Frame::detachFromPage() +{ + m_page = 0; +} + EventHandler* Frame::eventHandler() const { return &m_eventHandler; @@ -1579,7 +1634,7 @@ void Frame::pageDestroyed() script()->clearScriptObjects(); script()->updatePlatformScriptObjects(); - m_page = 0; + detachFromPage(); } void Frame::disconnectOwnerElement() @@ -1624,7 +1679,7 @@ void Frame::unfocusWindow() page()->chrome()->unfocus(); } -bool Frame::shouldClose(RegisteredEventListenerVector* alternateEventListeners) +bool Frame::shouldClose() { Chrome* chrome = page() ? page()->chrome() : 0; if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel()) @@ -1638,7 +1693,8 @@ bool Frame::shouldClose(RegisteredEventListenerVector* alternateEventListeners) if (!body) return true; - RefPtr<BeforeUnloadEvent> beforeUnloadEvent = m_domWindow->dispatchBeforeUnloadEvent(alternateEventListeners); + RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); + m_domWindow->dispatchEvent(beforeUnloadEvent.get(), m_domWindow->document()); if (!beforeUnloadEvent->defaultPrevented()) doc->defaultEventHandler(beforeUnloadEvent.get()); @@ -1759,7 +1815,6 @@ void Frame::createView(const IntSize& viewportSize, frameView = FrameView::create(this); frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode); - frameView->updateDefaultScrollbarState(); setView(frameView); diff --git a/WebCore/page/Frame.h b/WebCore/page/Frame.h index 652269a..6208bbd 100644 --- a/WebCore/page/Frame.h +++ b/WebCore/page/Frame.h @@ -41,6 +41,7 @@ #include "ScrollBehavior.h" #include "SelectionController.h" #include "TextGranularity.h" +#include "UserScriptTypes.h" #if PLATFORM(WIN) #include "FrameWin.h" @@ -66,6 +67,7 @@ namespace WebCore { class Editor; class EventHandler; class FrameLoader; + class RedirectScheduler; class FrameLoaderClient; class FrameTree; class FrameView; @@ -79,10 +81,6 @@ namespace WebCore { class VisibleSelection; class Widget; -#if FRAME_LOADS_USER_STYLESHEET - class UserStyleSheetLoader; -#endif - template <typename T> class Timer; class Frame : public RefCounted<Frame> { @@ -97,6 +95,7 @@ namespace WebCore { void init(); Page* page() const; + void detachFromPage(); HTMLFrameOwnerElement* ownerElement() const; void pageDestroyed(); @@ -112,6 +111,7 @@ namespace WebCore { Editor* editor() const; EventHandler* eventHandler() const; FrameLoader* loader() const; + RedirectScheduler* redirectScheduler() const; SelectionController* selection() const; FrameTree* tree() const; AnimationController* animation() const; @@ -128,6 +128,10 @@ namespace WebCore { void createView(const IntSize&, const Color&, bool, const IntSize &, bool, ScrollbarMode = ScrollbarAuto, ScrollbarMode = ScrollbarAuto); + void injectUserScripts(UserScriptInjectionTime); + + private: + void injectUserScriptsForWorld(unsigned worldID, const UserScriptVector&, UserScriptInjectionTime); private: Frame(Page*, HTMLFrameOwnerElement*, FrameLoaderClient*); @@ -139,11 +143,6 @@ namespace WebCore { Settings* settings() const; // can be NULL - #if FRAME_LOADS_USER_STYLESHEET - void setUserStyleSheetLocation(const KURL&); - void setUserStyleSheet(const String& styleSheetData); - #endif - void setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize); bool inViewSourceMode() const; @@ -156,6 +155,14 @@ namespace WebCore { void setDocument(PassRefPtr<Document>); +#if ENABLE(ORIENTATION_EVENTS) + // Orientation is the interface orientation in degrees. Some examples are: + // 0 is straight up; -90 is when the device is rotated 90 clockwise; + // 90 is when rotated counter clockwise. + void sendOrientationChangeEvent(int orientation); + int orientation() const { return m_orientation; } +#endif + void clearTimers(); static void clearTimers(FrameView*, Document*); @@ -193,7 +200,7 @@ namespace WebCore { public: void focusWindow(); void unfocusWindow(); - bool shouldClose(RegisteredEventListenerVector* alternateEventListeners = 0); + bool shouldClose(); void scheduleClose(); void setJSStatusBarText(const String&); @@ -329,6 +336,7 @@ namespace WebCore { Page* m_page; mutable FrameTree m_treeNode; mutable FrameLoader m_loader; + mutable RedirectScheduler m_redirectScheduler; mutable RefPtr<DOMWindow> m_domWindow; HashSet<DOMWindow*> m_liveFormerWindows; @@ -357,6 +365,10 @@ namespace WebCore { Timer<Frame> m_lifeSupportTimer; +#if ENABLE(ORIENTATION_EVENTS) + int m_orientation; +#endif + bool m_caretVisible; bool m_caretPaint; @@ -365,11 +377,6 @@ namespace WebCore { bool m_needsReapplyStyles; bool m_isDisconnected; bool m_excludeFromTextSearch; - - #if FRAME_LOADS_USER_STYLESHEET - UserStyleSheetLoader* m_userStyleSheetLoader; - #endif - }; } // namespace WebCore diff --git a/WebCore/page/FrameTree.cpp b/WebCore/page/FrameTree.cpp index 24f125d..41caa9c 100644 --- a/WebCore/page/FrameTree.cpp +++ b/WebCore/page/FrameTree.cpp @@ -91,7 +91,7 @@ void FrameTree::removeChild(Frame* child) RefPtr<Frame>& newLocationForNext = m_firstChild == child ? m_firstChild : child->tree()->m_previousSibling->tree()->m_nextSibling; Frame*& newLocationForPrevious = m_lastChild == child ? m_lastChild : child->tree()->m_nextSibling->tree()->m_previousSibling; swap(newLocationForNext, child->tree()->m_nextSibling); - // For some inexplicable reason, the following line does not compile without the explicit std:: namepsace + // For some inexplicable reason, the following line does not compile without the explicit std:: namespace std::swap(newLocationForPrevious, child->tree()->m_previousSibling); child->tree()->m_previousSibling = 0; diff --git a/WebCore/page/FrameView.cpp b/WebCore/page/FrameView.cpp index ed91587..e7006ed 100644 --- a/WebCore/page/FrameView.cpp +++ b/WebCore/page/FrameView.cpp @@ -42,11 +42,12 @@ #include "HTMLFrameElement.h" #include "HTMLFrameSetElement.h" #include "HTMLNames.h" +#include "InspectorTimelineAgent.h" #include "OverflowEvent.h" -#include "Page.h" #include "RenderPart.h" #include "RenderPartObject.h" #include "RenderScrollbar.h" +#include "RenderScrollbarPart.h" #include "RenderTheme.h" #include "RenderView.h" #include "Settings.h" @@ -96,13 +97,10 @@ struct ScheduledEvent { FrameView::FrameView(Frame* frame) : m_frame(frame) - , m_vmode(ScrollbarAuto) - , m_hmode(ScrollbarAuto) , m_slowRepaintObjectCount(0) , m_layoutTimer(this, &FrameView::layoutTimerFired) , m_layoutRoot(0) , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired) - , m_needToInitScrollbars(true) , m_isTransparent(false) , m_baseBackgroundColor(Color::white) , m_mediaType("screen") @@ -115,6 +113,7 @@ FrameView::FrameView(Frame* frame) , m_shouldUpdateWhileOffscreen(true) , m_deferSetNeedsLayouts(0) , m_setNeedsLayoutWasDeferred(false) + , m_scrollCorner(0) { init(); } @@ -143,9 +142,15 @@ FrameView::~FrameView() } resetScrollbars(); + + // Custom scrollbars should already be destroyed at this point + ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar()); + ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar()); + setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow. setHasVerticalScrollbar(false); + ASSERT(!m_scrollCorner); ASSERT(m_scheduledEvents.isEmpty()); ASSERT(!m_enqueueEvents); @@ -206,7 +211,7 @@ void FrameView::resetScrollbars() // Reset the document's scrollbars back to our defaults before we yield the floor. m_firstLayout = true; setScrollbarsSuppressed(true); - setScrollbarModes(m_hmode, m_vmode); + setScrollbarModes(ScrollbarAuto, ScrollbarAuto); setScrollbarsSuppressed(false); } @@ -237,23 +242,18 @@ void FrameView::detachCustomScrollbars() if (!m_frame) return; - Document* document = m_frame->document(); - if (!document) - return; - - Element* body = document->body(); - if (!body) - return; - - RenderBox* renderBox = body->renderBox(); - Scrollbar* horizontalBar = horizontalScrollbar(); - if (horizontalBar && horizontalBar->isCustomScrollbar() && toRenderScrollbar(horizontalBar)->owningRenderer() == renderBox) + if (horizontalBar && horizontalBar->isCustomScrollbar() && !toRenderScrollbar(horizontalBar)->owningRenderer()->isRenderPart()) setHasHorizontalScrollbar(false); Scrollbar* verticalBar = verticalScrollbar(); - if (verticalBar && verticalBar->isCustomScrollbar() && toRenderScrollbar(verticalBar)->owningRenderer() == renderBox) + if (verticalBar && verticalBar->isCustomScrollbar() && !toRenderScrollbar(verticalBar)->owningRenderer()->isRenderPart()) setHasVerticalScrollbar(false); + + if (m_scrollCorner) { + m_scrollCorner->destroy(); + m_scrollCorner = 0; + } } void FrameView::clear() @@ -275,21 +275,6 @@ bool FrameView::didFirstLayout() const return !m_firstLayout; } -void FrameView::initScrollbars() -{ - if (!m_needToInitScrollbars) - return; - m_needToInitScrollbars = false; - updateDefaultScrollbarState(); -} - -void FrameView::updateDefaultScrollbarState() -{ - m_hmode = horizontalScrollbarMode(); - m_vmode = verticalScrollbarMode(); - setScrollbarModes(m_hmode, m_vmode); -} - void FrameView::invalidateRect(const IntRect& rect) { if (!parent()) { @@ -323,12 +308,6 @@ void FrameView::setMarginHeight(int h) m_margins.setHeight(h); } -void FrameView::setCanHaveScrollbars(bool canScroll) -{ - ScrollView::setCanHaveScrollbars(canScroll); - scrollbarModes(m_hmode, m_vmode); -} - PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation) { // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles). @@ -377,7 +356,7 @@ void FrameView::adjustViewSize() RenderView* root = m_frame->contentRenderer(); if (!root) return; - setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight())); + setContentsSize(IntSize(root->rightLayoutOverflow(), root->bottomLayoutOverflow())); } void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode) @@ -517,6 +496,12 @@ void FrameView::layout(bool allowSubtree) if (isPainting()) return; +#if ENABLE(INSPECTOR) + InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(); + if (timelineAgent) + timelineAgent->willLayout(); +#endif + if (!allowSubtree && m_layoutRoot) { m_layoutRoot->markContainingBlocksForLayout(false); m_layoutRoot = 0; @@ -573,8 +558,9 @@ void FrameView::layout(bool allowSubtree) m_nestedLayoutCount++; - ScrollbarMode hMode = m_hmode; - ScrollbarMode vMode = m_vmode; + ScrollbarMode hMode; + ScrollbarMode vMode; + scrollbarModes(hMode, vMode); if (!subtree) { RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0; @@ -674,7 +660,7 @@ void FrameView::layout(bool allowSubtree) #if PLATFORM(MAC) if (AXObjectCache::accessibilityEnabled()) - root->document()->axObjectCache()->postNotification(root, "AXLayoutComplete", true); + root->document()->axObjectCache()->postNotification(root, AXObjectCache::AXLayoutComplete, true); #endif #if ENABLE(DASHBOARD_SUPPORT) updateDashboardRegions(); @@ -709,6 +695,11 @@ void FrameView::layout(bool allowSubtree) ASSERT(m_enqueueEvents); } +#if ENABLE(INSPECTOR) + if (timelineAgent) + timelineAgent->didLayout(); +#endif + m_nestedLayoutCount--; } @@ -825,6 +816,22 @@ void FrameView::setScrollPosition(const IntPoint& scrollPoint) m_inProgrammaticScroll = wasInProgrammaticScroll; } +void FrameView::scrollPositionChanged() +{ + frame()->eventHandler()->sendScrollEvent(); + +#if USE(ACCELERATED_COMPOSITING) + // We need to update layer positions after scrolling to account for position:fixed layers. + Document* document = m_frame->document(); + if (!document) + return; + + RenderLayer* layer = document->renderer() ? document->renderer()->enclosingLayer() : 0; + if (layer) + layer->updateLayerPositions(RenderLayer::UpdateCompositingLayers); +#endif +} + HostWindow* FrameView::hostWindow() const { Page* page = frame() ? frame()->page() : 0; @@ -857,9 +864,9 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate) m_repaintRects.append(unionedRect); } if (m_repaintCount < cRepaintRectUnionThreshold) - m_repaintRects.append(r); + m_repaintRects.append(visibleContent); else - m_repaintRects[0].unite(r); + m_repaintRects[0].unite(visibleContent); m_repaintCount++; if (!m_deferringRepaints && !m_deferredRepaintTimer.isActive()) @@ -997,7 +1004,8 @@ void FrameView::layoutTimerFired(Timer<FrameView>*) void FrameView::scheduleRelayout() { - ASSERT(!m_frame->document()->inPageCache()); + // FIXME: We should assert the page is not in the page cache, but that is causing + // too many false assertions. See <rdar://problem/7218118>. ASSERT(m_frame->view() == this); if (m_layoutRoot) { @@ -1221,6 +1229,9 @@ void FrameView::scrollToAnchor() // Align to the top and to the closest side (this matches other browsers). anchorNode->renderer()->enclosingLayer()->scrollRectToVisible(rect, true, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways); + if (AXObjectCache::accessibilityEnabled()) + m_frame->document()->axObjectCache()->handleScrolledToAnchor(anchorNode.get()); + // scrollRectToVisible can call into scrollRectIntoViewRecursively(), which resets m_maintainScrollPositionAnchor. m_maintainScrollPositionAnchor = anchorNode; } @@ -1427,6 +1438,86 @@ void FrameView::updateDashboardRegions() } #endif +void FrameView::invalidateScrollCorner() +{ + invalidateRect(scrollCornerRect()); +} + +void FrameView::updateScrollCorner() +{ + RenderObject* renderer = 0; + RefPtr<RenderStyle> cornerStyle; + + if (!scrollCornerRect().isEmpty()) { + // Try the <body> element first as a scroll corner source. + Document* doc = m_frame->document(); + Element* body = doc ? doc->body() : 0; + if (body && body->renderer()) { + renderer = body->renderer(); + cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + } + + if (!cornerStyle) { + // If the <body> didn't have a custom style, then the root element might. + Element* docElement = doc ? doc->documentElement() : 0; + if (docElement && docElement->renderer()) { + renderer = docElement->renderer(); + cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + } + } + + if (!cornerStyle) { + // If we have an owning iframe/frame element, then it can set the custom scrollbar also. + if (RenderPart* renderer = m_frame->ownerRenderer()) + cornerStyle = renderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, renderer->style()); + } + } + + if (cornerStyle) { + if (!m_scrollCorner) + m_scrollCorner = new (renderer->renderArena()) RenderScrollbarPart(renderer->document()); + m_scrollCorner->setStyle(cornerStyle.release()); + invalidateRect(scrollCornerRect()); + } else if (m_scrollCorner) { + m_scrollCorner->destroy(); + m_scrollCorner = 0; + } +} + +void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) +{ + if (context->updatingControlTints()) { + updateScrollCorner(); + return; + } + + if (m_scrollCorner) { + m_scrollCorner->paintIntoRect(context, cornerRect.x(), cornerRect.y(), cornerRect); + return; + } + + ScrollView::paintScrollCorner(context, cornerRect); +} + +bool FrameView::hasCustomScrollbars() const +{ + const HashSet<RefPtr<Widget> >* viewChildren = children(); + HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end(); + for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) { + Widget* widget = current->get(); + if (widget->isFrameView()) { + if (static_cast<FrameView*>(widget)->hasCustomScrollbars()) + return true; + } else if (widget->isScrollbar()) { + Scrollbar* scrollbar = static_cast<Scrollbar*>(widget); + if (scrollbar->isCustomScrollbar()) + return true; + } + } + + return false; +} + void FrameView::updateControlTints() { // This is called when control tints are changed from aqua/graphite to clear and vice versa. @@ -1438,7 +1529,7 @@ void FrameView::updateControlTints() if (!m_frame || m_frame->loader()->url().isEmpty()) return; - if (m_frame->contentRenderer() && m_frame->contentRenderer()->theme()->supportsControlTints()) { + if ((m_frame->contentRenderer() && m_frame->contentRenderer()->theme()->supportsControlTints()) || hasCustomScrollbars()) { if (needsLayout()) layout(); PlatformGraphicsContext* const noContext = 0; @@ -1468,7 +1559,13 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) { if (!frame()) return; - + +#if ENABLE(INSPECTOR) + InspectorTimelineAgent* timelineAgent = inspectorTimelineAgent(); + if (timelineAgent) + timelineAgent->willPaint(); +#endif + Document* document = frame()->document(); #ifndef NDEBUG @@ -1532,6 +1629,11 @@ void FrameView::paintContents(GraphicsContext* p, const IntRect& rect) if (isTopLevelPainter) sCurrentPaintTimeStamp = 0; + +#if ENABLE(INSPECTOR) + if (timelineAgent) + timelineAgent->didPaint(); +#endif } void FrameView::setPaintRestriction(PaintRestriction pr) @@ -1573,10 +1675,15 @@ void FrameView::layoutIfNeededRecursive() // layoutIfNeededRecursive is called when we need to make sure layout is up-to-date before // painting, so we need to flush out any deferred repaints too. - if (m_deferredRepaintTimer.isActive()) { - m_deferredRepaintTimer.stop(); - doDeferredRepaints(); - } + flushDeferredRepaints(); +} + +void FrameView::flushDeferredRepaints() +{ + if (!m_deferredRepaintTimer.isActive()) + return; + m_deferredRepaintTimer.stop(); + doDeferredRepaints(); } void FrameView::forceLayout(bool allowSubtree) @@ -1626,7 +1733,7 @@ void FrameView::adjustPageHeight(float *newBottom, float oldTop, float oldBottom // Use a context with painting disabled. GraphicsContext context((PlatformGraphicsContext*)0); root->setTruncatedAt((int)floorf(oldBottom)); - IntRect dirtyRect(0, (int)floorf(oldTop), root->overflowWidth(), (int)ceilf(oldBottom - oldTop)); + IntRect dirtyRect(0, (int)floorf(oldTop), root->rightLayoutOverflow(), (int)ceilf(oldBottom - oldTop)); root->layer()->paint(&context, dirtyRect); *newBottom = root->bestTruncatedAt(); if (*newBottom == 0) diff --git a/WebCore/page/FrameView.h b/WebCore/page/FrameView.h index 1bdcfb3..4c900ae 100644 --- a/WebCore/page/FrameView.h +++ b/WebCore/page/FrameView.h @@ -25,7 +25,9 @@ #ifndef FrameView_h #define FrameView_h +#include "Frame.h" #include "IntSize.h" +#include "Page.h" #include "RenderLayer.h" #include "ScrollView.h" #include <wtf/Forward.h> @@ -37,6 +39,7 @@ class Color; class Event; class Frame; class FrameViewPrivate; +class InspectorTimelineAgent; class IntRect; class Node; class PlatformMouseEvent; @@ -69,8 +72,6 @@ public: void setMarginWidth(int); void setMarginHeight(int); - virtual void setCanHaveScrollbars(bool); - virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); virtual void setContentsSize(const IntSize&); @@ -122,8 +123,6 @@ public: void setShouldUpdateWhileOffscreen(bool); void adjustViewSize(); - void initScrollbars(); - void updateDefaultScrollbarState(); virtual IntRect windowClipRect(bool clipToContents = true) const; IntRect windowClipRectForLayer(const RenderLayer*, bool clipToLayerContents) const; @@ -132,6 +131,7 @@ public: virtual void scrollRectIntoViewRecursively(const IntRect&); virtual void setScrollPosition(const IntPoint&); + void scrollPositionChanged(); String mediaType() const; void setMediaType(const String&); @@ -174,6 +174,7 @@ public: static double currentPaintTimeStamp() { return sCurrentPaintTimeStamp; } // returns 0 if not painting void layoutIfNeededRecursive(); + void flushDeferredRepaints(); void setIsVisuallyNonEmpty() { m_isVisuallyNonEmpty = true; } @@ -190,6 +191,9 @@ public: virtual IntPoint convertFromRenderer(const RenderObject*, const IntPoint&) const; virtual IntPoint convertToRenderer(const RenderObject*, const IntPoint&) const; + bool isFrameViewScrollCorner(RenderScrollbarPart* scrollCorner) const { return m_scrollCorner == scrollCorner; } + void invalidateScrollCorner(); + private: FrameView(Frame*); @@ -232,7 +236,16 @@ private: bool updateWidgets(); void scrollToAnchor(); + +#if ENABLE(INSPECTOR) + InspectorTimelineAgent* inspectorTimelineAgent() const; +#endif + bool hasCustomScrollbars() const; + + virtual void updateScrollCorner(); + virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect); + static double sCurrentPaintTimeStamp; // used for detecting decoded resource thrash in the cache IntSize m_size; @@ -242,8 +255,6 @@ private: bool m_doFullRepaint; - ScrollbarMode m_vmode; - ScrollbarMode m_hmode; bool m_useSlowRepaints; bool m_isOverlapped; bool m_contentIsOpaque; @@ -263,7 +274,6 @@ private: bool m_firstLayoutCallbackPending; bool m_firstLayout; - bool m_needToInitScrollbars; bool m_isTransparent; Color m_baseBackgroundColor; IntSize m_lastLayoutSize; @@ -302,8 +312,18 @@ private: bool m_firstVisuallyNonEmptyLayoutCallbackPending; RefPtr<Node> m_maintainScrollPositionAnchor; + + // Renderer to hold our custom scroll corner. + RenderScrollbarPart* m_scrollCorner; }; +#if ENABLE(INSPECTOR) +inline InspectorTimelineAgent* FrameView::inspectorTimelineAgent() const +{ + return m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0; +} +#endif + } // namespace WebCore #endif // FrameView_h diff --git a/WebCore/page/Geolocation.cpp b/WebCore/page/Geolocation.cpp index bf877e6..1ded2af 100644 --- a/WebCore/page/Geolocation.cpp +++ b/WebCore/page/Geolocation.cpp @@ -41,8 +41,11 @@ namespace WebCore { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp static const char* permissionDeniedErrorMessage = "User denied Geolocation"; +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) : m_geolocation(geolocation) , m_successCallback(successCallback) @@ -60,15 +63,30 @@ Geolocation::GeoNotifier::GeoNotifier(Geolocation* geolocation, PassRefPtr<Posit void Geolocation::GeoNotifier::setFatalError(PassRefPtr<PositionError> error) { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp m_fatalError = error; m_timer.startOneShot(0); +======= + ASSERT(m_successCallback); + // If no options were supplied from JS, we should have created a default set + // of options in JSGeolocationCustom.cpp. + ASSERT(m_options); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp } +<<<<<<< HEAD:WebCore/page/Geolocation.cpp void Geolocation::GeoNotifier::setCachedPosition(Geoposition* cachedPosition) +======= +bool Geolocation::GeoNotifier::hasZeroTimeout() const +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp // We do not take owenership from the caller, but add our own ref count. m_cachedPosition = cachedPosition; m_timer.startOneShot(0); +======= + return m_options->hasTimeout() && m_options->timeout() == 0; +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp } void Geolocation::GeoNotifier::startTimerIfNeeded() @@ -81,6 +99,7 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) { m_timer.stop(); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp if (m_fatalError) { if (m_errorCallback) m_errorCallback->handleEvent(m_fatalError.get()); @@ -95,8 +114,14 @@ void Geolocation::GeoNotifier::timerFired(Timer<GeoNotifier>*) return; } +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp if (m_errorCallback) { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timed out"); +======= + RefPtr<PositionError> error = PositionError::create(PositionError::TIMEOUT, "Timeout expired"); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp m_errorCallback->handleEvent(error.get()); } m_geolocation->requestTimedOut(this); @@ -274,23 +299,55 @@ void Geolocation::disconnectFrame() void Geolocation::getCurrentPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp RefPtr<GeoNotifier> notifier = makeRequest(successCallback, errorCallback, options); ASSERT(notifier); +======= + RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options); + + if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get())) + notifier->startTimerIfNeeded(); + else { + if (notifier->m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); + notifier->m_errorCallback->handleEvent(error.get()); + } + return; + } +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp m_oneShots.add(notifier); } int Geolocation::watchPosition(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp RefPtr<GeoNotifier> notifier = makeRequest(successCallback, errorCallback, options); ASSERT(notifier); +======= + RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + if (notifier->hasZeroTimeout() || m_service->startUpdating(notifier->m_options.get())) + notifier->startTimerIfNeeded(); + else { + if (notifier->m_errorCallback) { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "Unable to Start"); + notifier->m_errorCallback->handleEvent(error.get()); + } + return 0; + } + +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp static int sIdentifier = 0; m_watchers.set(++sIdentifier, notifier); return sIdentifier; } +<<<<<<< HEAD:WebCore/page/Geolocation.cpp PassRefPtr<Geolocation::GeoNotifier> Geolocation::makeRequest(PassRefPtr<PositionCallback> successCallback, PassRefPtr<PositionErrorCallback> errorCallback, PassRefPtr<PositionOptions> options) { RefPtr<GeoNotifier> notifier = GeoNotifier::create(this, successCallback, errorCallback, options); @@ -334,6 +391,8 @@ void Geolocation::fatalErrorOccurred(Geolocation::GeoNotifier* notifier) m_service->stopUpdating(); } +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp void Geolocation::requestTimedOut(GeoNotifier* notifier) { // If this is a one-shot request, stop it. @@ -343,6 +402,7 @@ void Geolocation::requestTimedOut(GeoNotifier* notifier) m_service->stopUpdating(); } +<<<<<<< HEAD:WebCore/page/Geolocation.cpp void Geolocation::requestReturnedCachedPosition(GeoNotifier* notifier) { // If this is a one-shot request, stop it. @@ -372,6 +432,8 @@ bool Geolocation::haveSuitableCachedPosition(PositionOptions* options) return m_cachedPositionManager->cachedPosition()->timestamp() > currentTimeMillis - options->maximumAge(); } +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp void Geolocation::clearWatch(int watchId) { m_watchers.remove(watchId); @@ -397,9 +459,17 @@ void Geolocation::setIsAllowed(bool allowed) // This may be due to either a new position from the service, or a cached // position. m_allowGeolocation = allowed ? Yes : No; +<<<<<<< HEAD:WebCore/page/Geolocation.cpp if (!isAllowed()) { RefPtr<WebCore::PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, permissionDeniedErrorMessage); +======= + + if (isAllowed()) + makeSuccessCallbacks(); + else { + RefPtr<PositionError> error = PositionError::create(PositionError::PERMISSION_DENIED, "User disallowed Geolocation"); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp error->setIsFatal(true); handleError(error.get()); return; @@ -436,7 +506,10 @@ void Geolocation::sendPosition(Vector<RefPtr<GeoNotifier> >& notifiers, Geoposit RefPtr<GeoNotifier> notifier = *it; ASSERT(notifier->m_successCallback); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp notifier->m_timer.stop(); +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp notifier->m_successCallback->handleEvent(position); } } @@ -475,15 +548,29 @@ void Geolocation::stopTimers() void Geolocation::handleError(PositionError* error) { ASSERT(error); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + + Vector<RefPtr<GeoNotifier> > oneShotsCopy; + copyToVector(m_oneShots, oneShotsCopy); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp +<<<<<<< HEAD:WebCore/page/Geolocation.cpp Vector<RefPtr<GeoNotifier> > oneShotsCopy; copyToVector(m_oneShots, oneShotsCopy); +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp Vector<RefPtr<GeoNotifier> > watchersCopy; copyValuesToVector(m_watchers, watchersCopy); // Clear the lists before we make the callbacks, to avoid clearing notifiers +<<<<<<< HEAD:WebCore/page/Geolocation.cpp // added by calls to Geolocation methods from the callbacks. +======= + // added by calls to Geolocation methods from the callbacks, and to prevent + // further callbacks to these notifiers. +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp m_oneShots.clear(); if (error->isFatal()) m_watchers.clear(); @@ -515,17 +602,32 @@ void Geolocation::requestPermission() void Geolocation::geolocationServicePositionChanged(GeolocationService*) { +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + ASSERT_UNUSED(service, service == m_service); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp ASSERT(m_service->lastPosition()); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp m_cachedPositionManager->setCachedPosition(m_service->lastPosition()); +======= +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp // Stop all currently running timers. stopTimers(); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp if (!isAllowed()) { // requestPermission() will ask the chrome for permission. This may be // implemented synchronously or asynchronously. In both cases, +<<<<<<< HEAD:WebCore/page/Geolocation.cpp // makeSucessCallbacks() will be called if permission is granted, so +======= + // makeSuccessCallbacks() will be called if permission is granted, so +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp // there's nothing more to do here. requestPermission(); return; @@ -538,15 +640,32 @@ void Geolocation::makeSuccessCallbacks() { ASSERT(m_service->lastPosition()); ASSERT(isAllowed()); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp Vector<RefPtr<GeoNotifier> > oneShotsCopy; copyToVector(m_oneShots, oneShotsCopy); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp Vector<RefPtr<GeoNotifier> > watchersCopy; copyValuesToVector(m_watchers, watchersCopy); +<<<<<<< HEAD:WebCore/page/Geolocation.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp // Clear the lists before we make the callbacks, to avoid clearing notifiers +<<<<<<< HEAD:WebCore/page/Geolocation.cpp // added by calls to Geolocation methods from the callbacks. +======= + // added by calls to Geolocation methods from the callbacks, and to prevent + // further callbacks to these notifiers. +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.cpp m_oneShots.clear(); sendPosition(oneShotsCopy, m_service->lastPosition()); diff --git a/WebCore/page/Geolocation.h b/WebCore/page/Geolocation.h index 9b3b43f..5b3d156 100644 --- a/WebCore/page/Geolocation.h +++ b/WebCore/page/Geolocation.h @@ -82,8 +82,12 @@ private: public: static PassRefPtr<GeoNotifier> create(Geolocation* geolocation, PassRefPtr<PositionCallback> positionCallback, PassRefPtr<PositionErrorCallback> positionErrorCallback, PassRefPtr<PositionOptions> options) { return adoptRef(new GeoNotifier(geolocation, positionCallback, positionErrorCallback, options)); } +<<<<<<< HEAD:WebCore/page/Geolocation.h void setFatalError(PassRefPtr<PositionError> error); void setCachedPosition(Geoposition* cachedPosition); +======= + bool hasZeroTimeout() const; +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.h void startTimerIfNeeded(); void timerFired(Timer<GeoNotifier>*); @@ -96,14 +100,22 @@ private: RefPtr<Geoposition> m_cachedPosition; private: +<<<<<<< HEAD:WebCore/page/Geolocation.h GeoNotifier(Geolocation* geolocation, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); +======= + GeoNotifier(Geolocation*, PassRefPtr<PositionCallback>, PassRefPtr<PositionErrorCallback>, PassRefPtr<PositionOptions>); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.h }; bool hasListeners() const { return !m_oneShots.isEmpty() || !m_watchers.isEmpty(); } void sendError(Vector<RefPtr<GeoNotifier> >&, PositionError*); void sendPosition(Vector<RefPtr<GeoNotifier> >&, Geoposition*); +<<<<<<< HEAD:WebCore/page/Geolocation.h +======= + +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.h static void stopTimer(Vector<RefPtr<GeoNotifier> >&); void stopTimersForOneShots(); void stopTimersForWatchers(); @@ -119,13 +131,20 @@ private: virtual void geolocationServicePositionChanged(GeolocationService*); virtual void geolocationServiceErrorOccurred(GeolocationService*); +<<<<<<< HEAD:WebCore/page/Geolocation.h // EventListener virtual void handleEvent(Event*, bool isWindowEvent); +======= +<<<<<<< HEAD:WebCore/page/Geolocation.h +>>>>>>> Merge webkit.org at R49305 : Automatic merge by git.:WebCore/page/Geolocation.h void fatalErrorOccurred(GeoNotifier* notifier); void requestTimedOut(GeoNotifier* notifier); void requestReturnedCachedPosition(GeoNotifier* notifier); bool haveSuitableCachedPosition(PositionOptions*); +======= + void requestTimedOut(GeoNotifier*); +>>>>>>> webkit.org at 49305:WebCore/page/Geolocation.h typedef HashSet<RefPtr<GeoNotifier> > GeoNotifierSet; typedef HashMap<int, RefPtr<GeoNotifier> > GeoNotifierMap; diff --git a/WebCore/page/HaltablePlugin.h b/WebCore/page/HaltablePlugin.h new file mode 100644 index 0000000..a5fe0f4 --- /dev/null +++ b/WebCore/page/HaltablePlugin.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 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 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 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. + */ + +#ifndef HaltablePlugin_h +#define HaltablePlugin_h + +namespace WebCore { + +class Node; + +class HaltablePlugin { +public: + virtual ~HaltablePlugin() { } + + virtual void halt() = 0; + virtual void restart() = 0; + virtual Node* node() const = 0; +}; + +} // namespace WebCore + +#endif // HaltablePlugin_h diff --git a/WebCore/page/History.cpp b/WebCore/page/History.cpp index 2527132..9a27f1c 100644 --- a/WebCore/page/History.cpp +++ b/WebCore/page/History.cpp @@ -50,28 +50,30 @@ unsigned History::length() const { if (!m_frame) return 0; - return m_frame->loader()->getHistoryLength(); + if (!m_frame->page()) + return 0; + return m_frame->page()->getHistoryLength(); } void History::back() { if (!m_frame) return; - m_frame->loader()->scheduleHistoryNavigation(-1); + m_frame->redirectScheduler()->scheduleHistoryNavigation(-1); } void History::forward() { if (!m_frame) return; - m_frame->loader()->scheduleHistoryNavigation(1); + m_frame->redirectScheduler()->scheduleHistoryNavigation(1); } void History::go(int distance) { if (!m_frame) return; - m_frame->loader()->scheduleHistoryNavigation(distance); + m_frame->redirectScheduler()->scheduleHistoryNavigation(distance); } } // namespace WebCore 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/OriginAccessEntry.cpp b/WebCore/page/OriginAccessEntry.cpp new file mode 100644 index 0000000..98c280c --- /dev/null +++ b/WebCore/page/OriginAccessEntry.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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" +#include "OriginAccessEntry.h" + +#include "SecurityOrigin.h" + +namespace WebCore { + +OriginAccessEntry::OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting subdomainSetting) + : m_protocol(protocol.lower()) + , m_host(host.lower()) + , m_subdomainSettings(subdomainSetting) +{ + ASSERT(m_protocol == "http" || m_protocol == "https"); + ASSERT(subdomainSetting == AllowSubdomains || subdomainSetting == DisallowSubdomains); + + // Assume that any host that ends with a digit is trying to be an IP address. + m_hostIsIPAddress = !m_host.isEmpty() && isASCIIDigit(m_host[m_host.length() - 1]); +} + +bool OriginAccessEntry::matchesOrigin(const SecurityOrigin& origin) const +{ + ASSERT(origin.host() == origin.host().lower()); + ASSERT(origin.protocol() == origin.protocol().lower()); + + if (m_protocol != origin.protocol()) + return false; + + // Special case: Include subdomains and empty host means "all hosts, including ip addresses". + if (m_subdomainSettings == AllowSubdomains && m_host.isEmpty()) + return true; + + // Exact match. + if (m_host == origin.host()) + return true; + + // Otherwise we can only match if we're matching subdomains. + if (m_subdomainSettings == DisallowSubdomains) + return false; + + // Don't try to do subdomain matching on IP addresses. + if (m_hostIsIPAddress) + return false; + + // Match subdomains. + if (origin.host().length() > m_host.length() && origin.host()[origin.host().length() - m_host.length() - 1] == '.' && origin.host().endsWith(m_host)) + return true; + + return false; +} + +} // namespace WebCore diff --git a/WebCore/page/OriginAccessEntry.h b/WebCore/page/OriginAccessEntry.h new file mode 100644 index 0000000..767d75f --- /dev/null +++ b/WebCore/page/OriginAccessEntry.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 CrossOriginAccess_h +#define CrossOriginAccess_h + +#include "PlatformString.h" + +namespace WebCore { + +class SecurityOrigin; + +class OriginAccessEntry { +public: + enum SubdomainSetting { + AllowSubdomains, + DisallowSubdomains + }; + + // If host is empty string and SubdomainSetting is AllowSubdomains, the entry will match all domains in the specified protocol. + OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting); + bool matchesOrigin(const SecurityOrigin&) const; + +private: + String m_protocol; + String m_host; + SubdomainSetting m_subdomainSettings; + bool m_hostIsIPAddress; + +}; + +} // namespace WebCore + +#endif // CrossOriginAccess_h diff --git a/WebCore/page/Page.cpp b/WebCore/page/Page.cpp index a13496b..397cb72 100644 --- a/WebCore/page/Page.cpp +++ b/WebCore/page/Page.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "Page.h" +#include "Base64.h" #include "CSSStyleSelector.h" #include "Chrome.h" #include "ChromeClient.h" @@ -28,8 +29,10 @@ #include "ContextMenuController.h" #include "DOMWindow.h" #include "DragController.h" +#include "ExceptionCode.h" #include "EditorClient.h" #include "EventNames.h" +#include "Event.h" #include "FileSystem.h" #include "FocusController.h" #include "Frame.h" @@ -40,11 +43,13 @@ #include "HTMLElement.h" #include "HistoryItem.h" #include "InspectorController.h" +#include "InspectorTimelineAgent.h" #include "Logging.h" #include "Navigator.h" #include "NetworkStateNotifier.h" #include "PageGroup.h" #include "PluginData.h" +#include "PluginHalter.h" #include "ProgressTracker.h" #include "RenderWidget.h" #include "RenderTheme.h" @@ -92,22 +97,29 @@ static void networkStateChanged() AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent; for (unsigned i = 0; i < frames.size(); i++) - frames[i]->document()->dispatchWindowEvent(eventName, false, false); + frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false)); } -Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient) +Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient, PluginHalterClient* pluginHalterClient) : m_chrome(new Chrome(this, chromeClient)) , m_dragCaretController(new SelectionController(0, true)) +#if ENABLE(DRAG_SUPPORT) , m_dragController(new DragController(this, dragClient)) +#endif , m_focusController(new FocusController(this)) +#if ENABLE(CONTEXT_MENUS) , m_contextMenuController(new ContextMenuController(this, contextMenuClient)) +#endif +#if ENABLE(INSPECTOR) , m_inspectorController(new InspectorController(this, inspectorClient)) +#endif , m_settings(new Settings(this)) , m_progress(new ProgressTracker) , m_backForwardList(BackForwardList::create(this)) , m_theme(RenderTheme::themeForPage(this)) , m_editorClient(editorClient) , m_frameCount(0) + , m_openedByDOM(false) , m_tabKeyCyclesThroughElements(true) , m_defersLoading(false) , m_inLowQualityInterpolationMode(false) @@ -115,7 +127,9 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_areMemoryCacheClientCallsEnabled(true) , m_mediaVolume(1) , m_javaScriptURLsAreAllowed(true) +#if ENABLE(INSPECTOR) , m_parentInspectorController(0) +#endif , m_didLoadUserStyleSheet(false) , m_userStyleSheetModificationTime(0) , m_group(0) @@ -123,7 +137,17 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi , m_customHTMLTokenizerTimeDelay(-1) , m_customHTMLTokenizerChunkSize(-1) , m_canStartPlugins(true) + , m_pluginHalterClient(pluginHalterClient) { +#if !ENABLE(CONTEXT_MENUS) + UNUSED_PARAM(contextMenuClient); +#endif +#if !ENABLE(DRAG_SUPPORT) + UNUSED_PARAM(dragClient); +#endif +#if !ENABLE(INSPECTOR) + UNUSED_PARAM(inspectorClient); +#endif if (!allPages) { allPages = new HashSet<Page*>; @@ -133,6 +157,8 @@ Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, Edi ASSERT(!allPages->contains(this)); allPages->add(this); + pluginHalterEnabledStateChanged(); + #if ENABLE(JAVASCRIPT_DEBUGGER) JavaScriptDebugServer::shared().pageCreated(this); #endif @@ -152,9 +178,11 @@ Page::~Page() frame->pageDestroyed(); m_editorClient->pageDestroyed(); +#if ENABLE(INSPECTOR) if (m_parentInspectorController) m_parentInspectorController->pageDestroyed(); m_inspectorController->inspectedPageDestroyed(); +#endif m_backForwardList->close(); @@ -174,6 +202,16 @@ void Page::setMainFrame(PassRefPtr<Frame> mainFrame) m_mainFrame = mainFrame; } +bool Page::openedByDOM() const +{ + return m_openedByDOM; +} + +void Page::setOpenedByDOM() +{ + m_openedByDOM = true; +} + BackForwardList* Page::backForwardList() { return m_backForwardList.get(); @@ -201,6 +239,40 @@ bool Page::goForward() return false; } +bool Page::canGoBackOrForward(int distance) const +{ + if (distance == 0) + return true; + if (distance > 0 && distance <= m_backForwardList->forwardListCount()) + return true; + if (distance < 0 && -distance <= m_backForwardList->backListCount()) + return true; + return false; +} + +void Page::goBackOrForward(int distance) +{ + if (distance == 0) + return; + + HistoryItem* item = m_backForwardList->itemAtIndex(distance); + if (!item) { + if (distance > 0) { + int forwardListCount = m_backForwardList->forwardListCount(); + if (forwardListCount > 0) + item = m_backForwardList->itemAtIndex(forwardListCount); + } else { + int backListCount = m_backForwardList->backListCount(); + if (backListCount > 0) + item = m_backForwardList->itemAtIndex(-backListCount); + } + } + + ASSERT(item); // we should not reach this line with an empty back/forward list + if (item) + goToItem(item, FrameLoadTypeIndexedBackForward); +} + void Page::goToItem(HistoryItem* item, FrameLoadType type) { // Abort any current load if we're going to a history item @@ -220,6 +292,11 @@ void Page::goToItem(HistoryItem* item, FrameLoadType type) m_mainFrame->loader()->goToItem(item, type); } +int Page::getHistoryLength() +{ + return m_backForwardList->backListCount() + 1; +} + void Page::setGlobalHistoryItem(HistoryItem* item) { m_globalHistoryItem = item; @@ -439,26 +516,43 @@ void Page::willMoveOffscreen() void Page::userStyleSheetLocationChanged() { -#if !FRAME_LOADS_USER_STYLESHEET - // FIXME: We should provide a way to load other types of URLs than just - // file: (e.g., http:, data:). - if (m_settings->userStyleSheetLocation().isLocalFile()) - m_userStyleSheetPath = m_settings->userStyleSheetLocation().fileSystemPath(); + // FIXME: Eventually we will move to a model of just being handed the sheet + // text instead of loading the URL ourselves. + KURL url = m_settings->userStyleSheetLocation(); + if (url.isLocalFile()) + m_userStyleSheetPath = url.fileSystemPath(); else m_userStyleSheetPath = String(); m_didLoadUserStyleSheet = false; m_userStyleSheet = String(); m_userStyleSheetModificationTime = 0; -#endif + + // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them + // synchronously and avoid using a loader. + if (url.protocolIs("data") && url.string().startsWith("data:text/css;charset=utf-8;base64,")) { + m_didLoadUserStyleSheet = true; + + const unsigned prefixLength = 35; + Vector<char> encodedData(url.string().length() - prefixLength); + for (unsigned i = prefixLength; i < url.string().length(); ++i) + encodedData[i - prefixLength] = static_cast<char>(url.string()[i]); + + Vector<char> styleSheetAsUTF8; + if (base64Decode(encodedData, styleSheetAsUTF8)) + m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data()); + } + + for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { + if (frame->document()) + frame->document()->clearPageUserSheet(); + } } const String& Page::userStyleSheet() const { - if (m_userStyleSheetPath.isEmpty()) { - ASSERT(m_userStyleSheet.isEmpty()); + if (m_userStyleSheetPath.isEmpty()) return m_userStyleSheet; - } time_t modTime; if (!getFileModificationTime(m_userStyleSheetPath, modTime)) { @@ -632,4 +726,39 @@ bool Page::javaScriptURLsAreAllowed() const return m_javaScriptURLsAreAllowed; } +#if ENABLE(INSPECTOR) +InspectorTimelineAgent* Page::inspectorTimelineAgent() const +{ + return m_inspectorController->timelineAgent(); +} +#endif + +void Page::pluginHalterEnabledStateChanged() +{ + if (m_settings->pluginHalterEnabled()) { + ASSERT(!m_pluginHalter); + m_pluginHalter.set(new PluginHalter(m_pluginHalterClient)); + m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); + } else + m_pluginHalter = 0; +} + +void Page::pluginAllowedRunTimeChanged() +{ + if (m_pluginHalter) + m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); +} + +void Page::didStartPlugin(HaltablePlugin* obj) +{ + if (m_pluginHalter) + m_pluginHalter->didStartPlugin(obj); +} + +void Page::didStopPlugin(HaltablePlugin* obj) +{ + if (m_pluginHalter) + m_pluginHalter->didStopPlugin(obj); +} + } // namespace WebCore diff --git a/WebCore/page/Page.h b/WebCore/page/Page.h index 9d9af86..cab075e 100644 --- a/WebCore/page/Page.h +++ b/WebCore/page/Page.h @@ -54,11 +54,15 @@ namespace WebCore { class EditorClient; class FocusController; class Frame; + class HaltablePlugin; class InspectorClient; class InspectorController; + class InspectorTimelineAgent; class Node; class PageGroup; class PluginData; + class PluginHalter; + class PluginHalterClient; class PluginView; class ProgressTracker; class RenderTheme; @@ -71,6 +75,9 @@ namespace WebCore { #if ENABLE(WML) class WMLPageState; #endif +#if ENABLE(NOTIFICATIONS) + class NotificationPresenter; +#endif enum FindDirection { FindDirectionForward, FindDirectionBackward }; @@ -78,7 +85,7 @@ namespace WebCore { public: static void setNeedsReapplyStyles(); - Page(ChromeClient*, ContextMenuClient*, EditorClient*, DragClient*, InspectorClient*); + Page(ChromeClient*, ContextMenuClient*, EditorClient*, DragClient*, InspectorClient*, PluginHalterClient*); ~Page(); RenderTheme* theme() const { return m_theme.get(); }; @@ -96,6 +103,9 @@ namespace WebCore { void setMainFrame(PassRefPtr<Frame>); Frame* mainFrame() const { return m_mainFrame.get(); } + bool openedByDOM() const; + void setOpenedByDOM(); + BackForwardList* backForwardList(); // FIXME: The following three methods don't fall under the responsibilities of the Page object @@ -104,7 +114,10 @@ namespace WebCore { // makes more sense when that class exists. bool goBack(); bool goForward(); + bool canGoBackOrForward(int distance) const; + void goBackOrForward(int distance); void goToItem(HistoryItem*, FrameLoadType); + int getHistoryLength(); HistoryItem* globalHistoryItem() const { return m_globalHistoryItem.get(); } void setGlobalHistoryItem(HistoryItem*); @@ -121,15 +134,23 @@ namespace WebCore { Chrome* chrome() const { return m_chrome.get(); } SelectionController* dragCaretController() const { return m_dragCaretController.get(); } +#if ENABLE(DRAG_SUPPORT) DragController* dragController() const { return m_dragController.get(); } +#endif FocusController* focusController() const { return m_focusController.get(); } +#if ENABLE(CONTEXT_MENUS) ContextMenuController* contextMenuController() const { return m_contextMenuController.get(); } +#endif +#if ENABLE(INSPECTOR) InspectorController* inspectorController() const { return m_inspectorController.get(); } +#endif Settings* settings() const { return m_settings.get(); } ProgressTracker* progress() const { return m_progress.get(); } +#if ENABLE(INSPECTOR) void setParentInspectorController(InspectorController* controller) { m_parentInspectorController = controller; } InspectorController* parentInspectorController() const { return m_parentInspectorController; } +#endif void setTabKeyCyclesThroughElements(bool b) { m_tabKeyCyclesThroughElements = b; } bool tabKeyCyclesThroughElements() const { return m_tabKeyCyclesThroughElements; } @@ -169,6 +190,11 @@ namespace WebCore { void userStyleSheetLocationChanged(); const String& userStyleSheet() const; + void didStartPlugin(HaltablePlugin*); + void didStopPlugin(HaltablePlugin*); + void pluginAllowedRunTimeChanged(); + void pluginHalterEnabledStateChanged(); + static void setDebuggerForAllPages(JSC::Debugger*); void setDebugger(JSC::Debugger*); JSC::Debugger* debugger() const { return m_debugger; } @@ -207,15 +233,24 @@ namespace WebCore { void setJavaScriptURLsAreAllowed(bool); bool javaScriptURLsAreAllowed() const; +#if ENABLE(INSPECTOR) + InspectorTimelineAgent* inspectorTimelineAgent() const; +#endif private: void initGroup(); OwnPtr<Chrome> m_chrome; OwnPtr<SelectionController> m_dragCaretController; +#if ENABLE(DRAG_SUPPORT) OwnPtr<DragController> m_dragController; +#endif OwnPtr<FocusController> m_focusController; +#if ENABLE(CONTEXT_MENUS) OwnPtr<ContextMenuController> m_contextMenuController; +#endif +#if ENABLE(INSPECTOR) OwnPtr<InspectorController> m_inspectorController; +#endif OwnPtr<Settings> m_settings; OwnPtr<ProgressTracker> m_progress; @@ -232,6 +267,7 @@ namespace WebCore { int m_frameCount; String m_groupName; + bool m_openedByDOM; bool m_tabKeyCyclesThroughElements; bool m_defersLoading; @@ -243,7 +279,9 @@ namespace WebCore { bool m_javaScriptURLsAreAllowed; +#if ENABLE(INSPECTOR) InspectorController* m_parentInspectorController; +#endif String m_userStyleSheetPath; mutable String m_userStyleSheet; @@ -261,6 +299,9 @@ namespace WebCore { bool m_canStartPlugins; HashSet<PluginView*> m_unstartedPlugins; + OwnPtr<PluginHalter> m_pluginHalter; + PluginHalterClient* m_pluginHalterClient; + #if ENABLE(DOM_STORAGE) RefPtr<StorageNamespace> m_sessionStorage; #endif @@ -272,6 +313,10 @@ namespace WebCore { #if ENABLE(WML) OwnPtr<WMLPageState> m_wmlPageState; #endif + +#if ENABLE(NOTIFICATIONS) + NotificationPresenter* m_notificationPresenter; +#endif }; } // namespace WebCore diff --git a/WebCore/page/PageGroup.cpp b/WebCore/page/PageGroup.cpp index 5155be1..cf6ba37 100644 --- a/WebCore/page/PageGroup.cpp +++ b/WebCore/page/PageGroup.cpp @@ -28,6 +28,7 @@ #include "ChromeClient.h" #include "Document.h" +#include "Frame.h" #include "Page.h" #include "Settings.h" @@ -66,6 +67,11 @@ PageGroup::PageGroup(Page* page) addPage(page); } +PageGroup::~PageGroup() +{ + removeAllUserContent(); +} + typedef HashMap<String, PageGroup*> PageGroupMap; static PageGroupMap* pageGroups = 0; @@ -185,12 +191,139 @@ StorageNamespace* PageGroup::localStorage() if (!m_localStorage) { // Need a page in this page group to query the settings for the local storage database path. Page* page = *m_pages.begin(); - ASSERT(page); - m_localStorage = StorageNamespace::localStorageNamespace(page->settings()->localStorageDatabasePath()); + const String& path = page->settings()->localStorageDatabasePath(); + unsigned quota = page->settings()->localStorageQuota(); + m_localStorage = StorageNamespace::localStorageNamespace(path, quota); } return m_localStorage.get(); } #endif +void PageGroup::addUserScript(const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, + PassOwnPtr<Vector<String> > blacklist, unsigned worldID, UserScriptInjectionTime injectionTime) +{ + if (worldID == UINT_MAX) + return; + OwnPtr<UserScript> userScript(new UserScript(source, url, whitelist, blacklist, worldID, injectionTime)); + if (!m_userScripts) + m_userScripts.set(new UserScriptMap); + UserScriptVector*& scriptsInWorld = m_userScripts->add(worldID, 0).first->second; + if (!scriptsInWorld) + scriptsInWorld = new UserScriptVector; + scriptsInWorld->append(userScript.release()); +} + +void PageGroup::addUserStyleSheet(const String& source, const KURL& url, PassOwnPtr<Vector<String> > whitelist, + PassOwnPtr<Vector<String> > blacklist, unsigned worldID) +{ + if (worldID == UINT_MAX) + return; + OwnPtr<UserStyleSheet> userStyleSheet(new UserStyleSheet(source, url, whitelist, blacklist, worldID)); + if (!m_userStyleSheets) + m_userStyleSheets.set(new UserStyleSheetMap); + UserStyleSheetVector*& styleSheetsInWorld = m_userStyleSheets->add(worldID, 0).first->second; + if (!styleSheetsInWorld) + styleSheetsInWorld = new UserStyleSheetVector; + styleSheetsInWorld->append(userStyleSheet.release()); + + // Clear our cached sheets and have them just reparse. + HashSet<Page*>::const_iterator end = m_pages.end(); + for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { + for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->clearPageGroupUserSheets(); + } +} + +void PageGroup::removeUserContentWithURLForWorld(const KURL& url, unsigned worldID) +{ + if (m_userScripts) { + UserScriptMap::iterator it = m_userScripts->find(worldID); + if (it != m_userScripts->end()) { + UserScriptVector* scripts = it->second; + for (int i = scripts->size() - 1; i >= 0; --i) { + if (scripts->at(i)->url() == url) + scripts->remove(i); + } + + if (scripts->isEmpty()) { + delete it->second; + m_userScripts->remove(it); + } + } + } + + if (m_userStyleSheets) { + UserStyleSheetMap::iterator it = m_userStyleSheets->find(worldID); + bool sheetsChanged = false; + if (it != m_userStyleSheets->end()) { + UserStyleSheetVector* stylesheets = it->second; + for (int i = stylesheets->size() - 1; i >= 0; --i) { + if (stylesheets->at(i)->url() == url) { + stylesheets->remove(i); + sheetsChanged = true; + } + } + + if (stylesheets->isEmpty()) { + delete it->second; + m_userStyleSheets->remove(it); + } + } + + // Clear our cached sheets and have them just reparse. + if (sheetsChanged) { + HashSet<Page*>::const_iterator end = m_pages.end(); + for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { + for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->clearPageGroupUserSheets(); + } + } + } +} + +void PageGroup::removeUserContentForWorld(unsigned worldID) +{ + if (m_userScripts) { + UserScriptMap::iterator it = m_userScripts->find(worldID); + if (it != m_userScripts->end()) { + delete it->second; + m_userScripts->remove(it); + } + } + + if (m_userStyleSheets) { + bool sheetsChanged = false; + UserStyleSheetMap::iterator it = m_userStyleSheets->find(worldID); + if (it != m_userStyleSheets->end()) { + delete it->second; + m_userStyleSheets->remove(it); + sheetsChanged = true; + } + + if (sheetsChanged) { + // Clear our cached sheets and have them just reparse. + HashSet<Page*>::const_iterator end = m_pages.end(); + for (HashSet<Page*>::const_iterator it = m_pages.begin(); it != end; ++it) { + for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) + frame->document()->clearPageGroupUserSheets(); + } + } + } +} + +void PageGroup::removeAllUserContent() +{ + if (m_userScripts) { + deleteAllValues(*m_userScripts); + m_userScripts.clear(); + } + + + if (m_userStyleSheets) { + deleteAllValues(*m_userStyleSheets); + m_userStyleSheets.clear(); + } +} + } // namespace WebCore diff --git a/WebCore/page/PageGroup.h b/WebCore/page/PageGroup.h index f92c2e6..7ea2967 100644 --- a/WebCore/page/PageGroup.h +++ b/WebCore/page/PageGroup.h @@ -30,6 +30,8 @@ #include <wtf/Noncopyable.h> #include "LinkHash.h" #include "StringHash.h" +#include "UserScript.h" +#include "UserStyleSheet.h" namespace WebCore { @@ -41,6 +43,7 @@ namespace WebCore { public: PageGroup(const String& name); PageGroup(Page*); + ~PageGroup(); static PageGroup* pageGroup(const String& groupName); static void closeLocalStorage(); @@ -64,13 +67,26 @@ namespace WebCore { #if ENABLE(DOM_STORAGE) StorageNamespace* localStorage(); + bool hasLocalStorage() { return m_localStorage; } #endif + void addUserScript(const String& source, const KURL&, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, + unsigned worldID, UserScriptInjectionTime); + const UserScriptMap* userScripts() const { return m_userScripts.get(); } + + void addUserStyleSheet(const String& source, const KURL&, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, + unsigned worldID); + const UserStyleSheetMap* userStyleSheets() const { return m_userStyleSheets.get(); } + + void removeUserContentForWorld(unsigned); + void removeUserContentWithURLForWorld(const KURL&, unsigned); + void removeAllUserContent(); + private: void addVisitedLink(LinkHash stringHash); -#if ENABLE(DOM_STORAGE) - bool hasLocalStorage() { return m_localStorage; } -#endif + String m_name; HashSet<Page*> m_pages; @@ -82,6 +98,9 @@ namespace WebCore { #if ENABLE(DOM_STORAGE) RefPtr<StorageNamespace> m_localStorage; #endif + + OwnPtr<UserScriptMap> m_userScripts; + OwnPtr<UserStyleSheetMap> m_userStyleSheets; }; } // namespace WebCore diff --git a/WebCore/page/PageGroupLoadDeferrer.cpp b/WebCore/page/PageGroupLoadDeferrer.cpp index f274de3..122658b 100644 --- a/WebCore/page/PageGroupLoadDeferrer.cpp +++ b/WebCore/page/PageGroupLoadDeferrer.cpp @@ -41,10 +41,10 @@ PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf) if (!otherPage->defersLoading()) m_deferredFrames.append(otherPage->mainFrame()); -#if !PLATFORM(MAC) + // This code is not logically part of load deferring, but we do not want JS code executed beneath modal + // windows or sheets, which is exactly when PageGroupLoadDeferrer is used. for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) frame->document()->suspendActiveDOMObjects(); -#endif } } @@ -60,10 +60,8 @@ PageGroupLoadDeferrer::~PageGroupLoadDeferrer() if (Page* page = m_deferredFrames[i]->page()) { page->setDefersLoading(false); -#if !PLATFORM(MAC) for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) frame->document()->resumeActiveDOMObjects(); -#endif } } } diff --git a/WebCore/page/PluginHalter.cpp b/WebCore/page/PluginHalter.cpp new file mode 100644 index 0000000..8025337 --- /dev/null +++ b/WebCore/page/PluginHalter.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2009 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 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 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 "config.h" + +#include "PluginHalter.h" + +#include "HaltablePlugin.h" +#include "PluginHalterClient.h" +#include <wtf/CurrentTime.h> +#include <wtf/Vector.h> + +using namespace std; + +namespace WebCore { + +PluginHalter::PluginHalter(PluginHalterClient* client) + : m_client(client) + , m_timer(this, &PluginHalter::timerFired) + , m_pluginAllowedRunTime(numeric_limits<unsigned>::max()) +{ + ASSERT_ARG(client, client); +} + +void PluginHalter::didStartPlugin(HaltablePlugin* obj) +{ + ASSERT_ARG(obj, obj); + ASSERT_ARG(obj, !m_plugins.contains(obj)); + + double currentTime = WTF::currentTime(); + + m_plugins.add(obj, currentTime); + + if (m_plugins.size() == 1) + m_oldestStartTime = currentTime; + + startTimerIfNecessary(); +} + +void PluginHalter::didStopPlugin(HaltablePlugin* obj) +{ + m_plugins.remove(obj); +} + +void PluginHalter::timerFired(Timer<PluginHalter>*) +{ + if (m_plugins.isEmpty()) + return; + + Vector<HaltablePlugin*> plugins; + copyKeysToVector(m_plugins, plugins); + + // Plug-ins older than this are candidates to be halted. + double pluginCutOffTime = WTF::currentTime() - m_pluginAllowedRunTime; + + m_oldestStartTime = numeric_limits<double>::max(); + + for (size_t i = 0; i < plugins.size(); ++i) { + double thisStartTime = m_plugins.get(plugins[i]); + if (thisStartTime > pluginCutOffTime) { + // This plug-in is too young to be halted. We find the oldest + // plug-in that is not old enough to be halted and use it to set + // the timer's next fire time. + if (thisStartTime < m_oldestStartTime) + m_oldestStartTime = thisStartTime; + continue; + } + + if (m_client->shouldHaltPlugin(plugins[i]->node())) + plugins[i]->halt(); + + m_plugins.remove(plugins[i]); + } + + startTimerIfNecessary(); +} + +void PluginHalter::startTimerIfNecessary() +{ + if (m_timer.isActive()) + return; + + if (m_plugins.isEmpty()) + return; + + double nextFireInterval = static_cast<double>(m_pluginAllowedRunTime) - (currentTime() - m_oldestStartTime); + m_timer.startOneShot(nextFireInterval < 0 ? 0 : nextFireInterval); +} + +} // namespace WebCore diff --git a/WebCore/page/PluginHalter.h b/WebCore/page/PluginHalter.h new file mode 100644 index 0000000..26f5101 --- /dev/null +++ b/WebCore/page/PluginHalter.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 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 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 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. + */ + +#ifndef PluginHalter_h +#define PluginHalter_h + +#include "Timer.h" +#include <wtf/HashMap.h> + +namespace WebCore { + +class HaltablePlugin; +class PluginHalterClient; + +class PluginHalter { +public: + PluginHalter(PluginHalterClient*); + + void didStartPlugin(HaltablePlugin*); + void didStopPlugin(HaltablePlugin*); + + void setPluginAllowedRunTime(unsigned runTime) { m_pluginAllowedRunTime = runTime; } + +private: + void timerFired(Timer<PluginHalter>*); + void startTimerIfNecessary(); + + PluginHalterClient* m_client; + Timer<PluginHalter> m_timer; + unsigned m_pluginAllowedRunTime; + double m_oldestStartTime; + HashMap<HaltablePlugin*, double> m_plugins; +}; + +} // namespace WebCore + +#endif // PluginHalter_h diff --git a/WebCore/page/PluginHalterClient.h b/WebCore/page/PluginHalterClient.h new file mode 100644 index 0000000..7ea460a --- /dev/null +++ b/WebCore/page/PluginHalterClient.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 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 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 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. + */ + +#ifndef PluginHalterClient_h +#define PluginHalterClient_h + +namespace WebCore { + +class Node; + +class PluginHalterClient { +public: + virtual ~PluginHalterClient() { } + + virtual bool shouldHaltPlugin(Node*) const = 0; +}; + +} // namespace WebCore + +#endif // PluginHalterClient_h diff --git a/WebCore/page/PositionCallback.h b/WebCore/page/PositionCallback.h index f6bf139..30da2c1 100644 --- a/WebCore/page/PositionCallback.h +++ b/WebCore/page/PositionCallback.h @@ -36,7 +36,11 @@ namespace WebCore { class PositionCallback : public RefCounted<PositionCallback> { public: virtual ~PositionCallback() { } +<<<<<<< HEAD:WebCore/page/PositionCallback.h virtual void handleEvent(Geoposition* position) = 0; +======= + virtual void handleEvent(Geoposition*) = 0; +>>>>>>> webkit.org at 49305:WebCore/page/PositionCallback.h }; } // namespace WebCore diff --git a/WebCore/page/PositionError.h b/WebCore/page/PositionError.h index c309061..5c26fcc 100644 --- a/WebCore/page/PositionError.h +++ b/WebCore/page/PositionError.h @@ -46,7 +46,11 @@ public: ErrorCode code() const { return m_code; } const String& message() const { return m_message; } void setIsFatal(bool isFatal) { m_isFatal = isFatal; } +<<<<<<< HEAD:WebCore/page/PositionError.h bool isFatal() { return m_isFatal; } +======= + bool isFatal() const { return m_isFatal; } +>>>>>>> webkit.org at 49305:WebCore/page/PositionError.h private: PositionError(ErrorCode code, const String& message) diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h index 5900998..b1746a8 100644 --- a/WebCore/page/PositionOptions.h +++ b/WebCore/page/PositionOptions.h @@ -33,7 +33,11 @@ namespace WebCore { class PositionOptions : public RefCounted<PositionOptions> { public: +<<<<<<< HEAD:WebCore/page/PositionOptions.h static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions); } +======= + static PassRefPtr<PositionOptions> create() { return adoptRef(new PositionOptions()); } +>>>>>>> webkit.org at 49305:WebCore/page/PositionOptions.h bool enableHighAccuracy() const { return m_highAccuracy; } void setEnableHighAccuracy(bool enable) { m_highAccuracy = enable; } diff --git a/WebCore/page/PrintContext.cpp b/WebCore/page/PrintContext.cpp index b855ca5..4d3a839 100644 --- a/WebCore/page/PrintContext.cpp +++ b/WebCore/page/PrintContext.cpp @@ -67,7 +67,7 @@ void PrintContext::computePageRects(const FloatRect& printRect, float headerHeig float ratio = printRect.height() / printRect.width(); - float pageWidth = (float)root->overflowWidth(); + float pageWidth = (float)root->rightLayoutOverflow(); float pageHeight = pageWidth * ratio; outPageHeight = pageHeight; // this is the height of the page adjusted by margins pageHeight -= headerHeight + footerHeight; diff --git a/WebCore/page/SecurityOrigin.cpp b/WebCore/page/SecurityOrigin.cpp index 14a1b59..338bf9f 100644 --- a/WebCore/page/SecurityOrigin.cpp +++ b/WebCore/page/SecurityOrigin.cpp @@ -30,16 +30,23 @@ #include "SecurityOrigin.h" #include "CString.h" -#include "FrameLoader.h" +#include "Document.h" #include "KURL.h" -#include "PlatformString.h" -#include "StringHash.h" -#include <wtf/HashSet.h> +#include "OriginAccessEntry.h" #include <wtf/StdLibExtras.h> namespace WebCore { -typedef HashSet<String, CaseFoldingHash> URLSchemesMap; +static SecurityOrigin::LocalLoadPolicy localLoadPolicy = SecurityOrigin::AllowLocalLoadsForLocalOnly; + +typedef Vector<OriginAccessEntry> OriginAccessWhiteList; +typedef HashMap<String, OriginAccessWhiteList*> OriginAccessMap; + +static OriginAccessMap& originAccessMap() +{ + DEFINE_STATIC_LOCAL(OriginAccessMap, originAccessMap, ()); + return originAccessMap; +} static URLSchemesMap& localSchemes() { @@ -68,7 +75,7 @@ static URLSchemesMap& noAccessSchemes() return noAccessSchemes; } -static bool isDefaultPortForProtocol(unsigned short port, const String& protocol) +bool SecurityOrigin::isDefaultPortForProtocol(unsigned short port, const String& protocol) { if (protocol.isEmpty()) return false; @@ -111,9 +118,9 @@ SecurityOrigin::SecurityOrigin(const KURL& url) } SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) - : m_protocol(other->m_protocol.copy()) - , m_host(other->m_host.copy()) - , m_domain(other->m_domain.copy()) + : m_protocol(other->m_protocol.threadsafeCopy()) + , m_host(other->m_host.threadsafeCopy()) + , m_domain(other->m_domain.threadsafeCopy()) , m_port(other->m_port) , m_noAccess(other->m_noAccess) , m_universalAccess(other->m_universalAccess) @@ -139,7 +146,7 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createEmpty() return create(KURL()); } -PassRefPtr<SecurityOrigin> SecurityOrigin::copy() +PassRefPtr<SecurityOrigin> SecurityOrigin::threadsafeCopy() { return adoptRef(new SecurityOrigin(this)); } @@ -203,7 +210,47 @@ bool SecurityOrigin::canRequest(const KURL& url) const // We call isSameSchemeHostPort here instead of canAccess because we want // to ignore document.domain effects. - return isSameSchemeHostPort(targetOrigin.get()); + if (isSameSchemeHostPort(targetOrigin.get())) + return true; + + if (OriginAccessWhiteList* list = originAccessMap().get(toString())) { + for (size_t i = 0; i < list->size(); ++i) { + if (list->at(i).matchesOrigin(*targetOrigin)) + return true; + } + } + + return false; +} + +bool SecurityOrigin::taintsCanvas(const KURL& url) const +{ + if (canRequest(url)) + return false; + + // This method exists because we treat data URLs as noAccess, contrary + // to the current (9/19/2009) draft of the HTML5 specification. We still + // want to let folks paint data URLs onto untainted canvases, so we special + // case data URLs below. If we change to match HTML5 w.r.t. data URL + // security, then we can remove this method in favor of !canRequest. + if (url.protocolIs("data")) + return false; + + return true; +} + +bool SecurityOrigin::canLoad(const KURL& url, const String& referrer, Document* document) +{ + if (!shouldTreatURLAsLocal(url.string())) + return true; + + // If we were provided a document, we let its local file policy dictate the result, + // otherwise we allow local loads only if the supplied referrer is also local. + if (document) + return document->securityOrigin()->canLoadLocalResources(); + if (!referrer.isEmpty()) + return shouldTreatURLAsLocal(referrer); + return false; } void SecurityOrigin::grantLoadLocalResources() @@ -213,7 +260,7 @@ void SecurityOrigin::grantLoadLocalResources() // in a SecurityOrigin is a security hazard because the documents without // the privilege can obtain the privilege by injecting script into the // documents that have been granted the privilege. - ASSERT(FrameLoader::allowSubstituteDataAccessToLocal()); + ASSERT(allowSubstituteDataAccessToLocal()); m_canLoadLocalResources = true; } @@ -339,13 +386,31 @@ bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const return true; } -// static void SecurityOrigin::registerURLSchemeAsLocal(const String& scheme) { localSchemes().add(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); +} + +const URLSchemesMap& SecurityOrigin::localURLSchemes() +{ + return localSchemes(); +} + bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) { // This avoids an allocation of another String and the HashSet contains() @@ -366,7 +431,6 @@ bool SecurityOrigin::shouldTreatURLAsLocal(const String& url) return localSchemes().contains(scheme); } -// static bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme) { // This avoids an allocation of another String and the HashSet contains() @@ -385,16 +449,69 @@ bool SecurityOrigin::shouldTreatURLSchemeAsLocal(const String& scheme) return localSchemes().contains(scheme); } -// static void SecurityOrigin::registerURLSchemeAsNoAccess(const String& scheme) { noAccessSchemes().add(scheme); } -// static bool SecurityOrigin::shouldTreatURLSchemeAsNoAccess(const String& scheme) { return noAccessSchemes().contains(scheme); } +bool SecurityOrigin::shouldHideReferrer(const KURL& url, const String& referrer) +{ + bool referrerIsSecureURL = protocolIs(referrer, "https"); + bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); + + if (!referrerIsWebURL) + return true; + + if (!referrerIsSecureURL) + return false; + + bool URLIsSecureURL = url.protocolIs("https"); + + return !URLIsSecureURL; +} + +void SecurityOrigin::setLocalLoadPolicy(LocalLoadPolicy policy) +{ + localLoadPolicy = policy; +} + +bool SecurityOrigin::restrictAccessToLocal() +{ + return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForAll; +} + +bool SecurityOrigin::allowSubstituteDataAccessToLocal() +{ + return localLoadPolicy != SecurityOrigin::AllowLocalLoadsForLocalOnly; +} + +void SecurityOrigin::whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains) +{ + ASSERT(isMainThread()); + ASSERT(!sourceOrigin.isEmpty()); + if (sourceOrigin.isEmpty()) + return; + + String sourceString = sourceOrigin.toString(); + OriginAccessWhiteList* list = originAccessMap().get(sourceString); + if (!list) { + list = new OriginAccessWhiteList; + originAccessMap().set(sourceString, list); + } + list->append(OriginAccessEntry(destinationProtocol, destinationDomains, allowDestinationSubdomains ? OriginAccessEntry::AllowSubdomains : OriginAccessEntry::DisallowSubdomains)); +} + +void SecurityOrigin::resetOriginAccessWhiteLists() +{ + ASSERT(isMainThread()); + OriginAccessMap& map = originAccessMap(); + deleteAllValues(map); + map.clear(); +} + } // namespace WebCore diff --git a/WebCore/page/SecurityOrigin.h b/WebCore/page/SecurityOrigin.h index ab92683..46e6fad 100644 --- a/WebCore/page/SecurityOrigin.h +++ b/WebCore/page/SecurityOrigin.h @@ -29,14 +29,19 @@ #ifndef SecurityOrigin_h #define SecurityOrigin_h +#include <wtf/HashSet.h> #include <wtf/RefCounted.h> #include <wtf/PassRefPtr.h> #include <wtf/Threading.h> #include "PlatformString.h" +#include "StringHash.h" namespace WebCore { + typedef HashSet<String, CaseFoldingHash> URLSchemesMap; + + class Document; class KURL; class SecurityOrigin : public ThreadSafeShared<SecurityOrigin> { @@ -48,7 +53,7 @@ namespace WebCore { // Create a deep copy of this SecurityOrigin. This method is useful // when marshalling a SecurityOrigin to another thread. - PassRefPtr<SecurityOrigin> copy(); + PassRefPtr<SecurityOrigin> threadsafeCopy(); // Set the domain property of this security origin to newDomain. This // function does not check whether newDomain is a suffix of the current @@ -72,6 +77,16 @@ namespace WebCore { // XMLHttpRequests. bool canRequest(const KURL&) const; + // Returns true if drawing an image from this URL taints a canvas from + // this security origin. For example, call this function before + // drawing an image onto an HTML canvas element with the drawImage API. + bool taintsCanvas(const KURL&) const; + + // Returns true for any non-local URL. If document parameter is supplied, + // its local load policy dictates, otherwise if referrer is non-empty and + // represents a local file, then the local load is allowed. + static bool canLoad(const KURL&, const String& referrer, Document* document); + // Returns true if this SecurityOrigin can load local resources, such // as images, iframes, and style sheets, and can link to local URLs. // For example, call this function before creating an iframe to a @@ -129,12 +144,30 @@ 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&); + static bool shouldHideReferrer(const KURL&, const String& referrer); + + enum LocalLoadPolicy { + AllowLocalLoadsForAll, // No restriction on local loads. + AllowLocalLoadsForLocalAndSubstituteData, + AllowLocalLoadsForLocalOnly, + }; + static void setLocalLoadPolicy(LocalLoadPolicy); + static bool restrictAccessToLocal(); + static bool allowSubstituteDataAccessToLocal(); + static void registerURLSchemeAsNoAccess(const String&); static bool shouldTreatURLSchemeAsNoAccess(const String&); + static void whiteListAccessFromOrigin(const SecurityOrigin& sourceOrigin, const String& destinationProtocol, const String& destinationDomains, bool allowDestinationSubdomains); + static void resetOriginAccessWhiteLists(); + + static bool isDefaultPortForProtocol(unsigned short port, const String& protocol); + private: explicit SecurityOrigin(const KURL&); explicit SecurityOrigin(const SecurityOrigin*); diff --git a/WebCore/page/Settings.cpp b/WebCore/page/Settings.cpp index 9692707..98d08d2 100644 --- a/WebCore/page/Settings.cpp +++ b/WebCore/page/Settings.cpp @@ -48,6 +48,10 @@ static void setNeedsReapplyStylesInAllFrames(Page* page) bool Settings::gShouldPaintNativeControls = true; #endif +#if PLATFORM(WIN) || (PLATFORM(WIN_OS) && PLATFORM(WX)) +bool Settings::gShouldUseHighResolutionTimers = true; +#endif + Settings::Settings(Page* page) : m_page(page) #ifdef ANDROID_LAYOUT @@ -69,6 +73,8 @@ Settings::Settings(Page* page) , m_blockNetworkImage(false) #endif , m_maximumDecodedImageSize(numeric_limits<size_t>::max()) + , m_localStorageQuota(5 * 1024 * 1024) // Suggested by the HTML5 spec. + , m_pluginAllowedRunTime(numeric_limits<unsigned>::max()) , m_isJavaEnabled(false) , m_loadsImagesAutomatically(false) , m_privateBrowsingEnabled(false) @@ -110,7 +116,8 @@ Settings::Settings(Page* page) , m_usesEncodingDetector(false) , m_allowScriptsToCloseWindows(false) , m_editingBehavior( -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) + // (PLATFORM(MAC) is always false in Chromium, hence the extra condition.) EditingMacBehavior #else EditingWindowsBehavior @@ -121,6 +128,12 @@ Settings::Settings(Page* page) , m_downloadableBinaryFontsEnabled(true) , m_xssAuditorEnabled(false) , m_acceleratedCompositingEnabled(true) + , m_experimentalNotificationsEnabled(false) + , m_pluginHalterEnabled(false) + , m_webGLEnabled(false) +#if ENABLE(WEB_SOCKETS) + , m_experimentalWebSocketsEnabled(false) +#endif { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. @@ -272,6 +285,11 @@ void Settings::setSessionStorageEnabled(bool sessionStorageEnabled) m_sessionStorageEnabled = sessionStorageEnabled; } +void Settings::setLocalStorageQuota(unsigned localStorageQuota) +{ + m_localStorageQuota = localStorageQuota; +} + void Settings::setPrivateBrowsingEnabled(bool privateBrowsingEnabled) { m_privateBrowsingEnabled = privateBrowsingEnabled; @@ -295,7 +313,6 @@ void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation) m_userStyleSheetLocation = userStyleSheetLocation; m_page->userStyleSheetLocationChanged(); - setNeedsReapplyStylesInAllFrames(m_page); } void Settings::setShouldPrintBackgrounds(bool shouldPrintBackgrounds) @@ -620,4 +637,44 @@ void Settings::setAcceleratedCompositingEnabled(bool enabled) setNeedsReapplyStylesInAllFrames(m_page); } +void Settings::setExperimentalNotificationsEnabled(bool enabled) +{ + m_experimentalNotificationsEnabled = enabled; +} + +void Settings::setPluginHalterEnabled(bool enabled) +{ + if (m_pluginHalterEnabled == enabled) + return; + + m_pluginHalterEnabled = enabled; + + m_page->pluginHalterEnabledStateChanged(); +} + +void Settings::setPluginAllowedRunTime(unsigned runTime) +{ + m_pluginAllowedRunTime = runTime; + m_page->pluginAllowedRunTimeChanged(); +} + +#if PLATFORM(WIN) || (PLATFORM(WIN_OS) && PLATFORM(WX)) +void Settings::setShouldUseHighResolutionTimers(bool shouldUseHighResolutionTimers) +{ + gShouldUseHighResolutionTimers = shouldUseHighResolutionTimers; +} +#endif + +void Settings::setWebGLEnabled(bool enabled) +{ + m_webGLEnabled = enabled; +} + +#if ENABLE(WEB_SOCKETS) +void Settings::setExperimentalWebSocketsEnabled(bool enabled) +{ + m_experimentalWebSocketsEnabled = enabled; +} +#endif + } // namespace WebCore diff --git a/WebCore/page/Settings.h b/WebCore/page/Settings.h index 162b21d..344746f 100644 --- a/WebCore/page/Settings.h +++ b/WebCore/page/Settings.h @@ -151,6 +151,9 @@ namespace WebCore { void setSessionStorageEnabled(bool); bool sessionStorageEnabled() const { return m_sessionStorageEnabled; } + void setLocalStorageQuota(unsigned); + unsigned localStorageQuota() const { return m_localStorageQuota; } + void setPrivateBrowsingEnabled(bool); bool privateBrowsingEnabled() const { return m_privateBrowsingEnabled; } @@ -295,6 +298,28 @@ namespace WebCore { void setAcceleratedCompositingEnabled(bool); bool acceleratedCompositingEnabled() const { return m_acceleratedCompositingEnabled; } + void setExperimentalNotificationsEnabled(bool); + bool experimentalNotificationsEnabled() const { return m_experimentalNotificationsEnabled; } + +#if PLATFORM(WIN) || (PLATFORM(WIN_OS) && PLATFORM(WX)) + static void setShouldUseHighResolutionTimers(bool); + static bool shouldUseHighResolutionTimers() { return gShouldUseHighResolutionTimers; } +#endif + + void setPluginHalterEnabled(bool); + bool pluginHalterEnabled() const { return m_pluginHalterEnabled; } + + void setPluginAllowedRunTime(unsigned); + unsigned pluginAllowedRunTime() const { return m_pluginAllowedRunTime; } + + void setWebGLEnabled(bool); + bool webGLEnabled() const { return m_webGLEnabled; } + +#if ENABLE(WEB_SOCKETS) + void setExperimentalWebSocketsEnabled(bool); + bool experimentalWebSocketsEnabled() const { return m_experimentalWebSocketsEnabled; } +#endif + private: Page* m_page; @@ -352,6 +377,8 @@ namespace WebCore { bool m_blockNetworkImage : 1; #endif size_t m_maximumDecodedImageSize; + unsigned m_localStorageQuota; + unsigned m_pluginAllowedRunTime; bool m_isJavaEnabled : 1; bool m_loadsImagesAutomatically : 1; bool m_privateBrowsingEnabled : 1; @@ -396,10 +423,20 @@ namespace WebCore { bool m_downloadableBinaryFontsEnabled : 1; bool m_xssAuditorEnabled : 1; bool m_acceleratedCompositingEnabled : 1; + bool m_experimentalNotificationsEnabled : 1; + bool m_pluginHalterEnabled : 1; + bool m_webGLEnabled : 1; + +#if ENABLE(WEB_SOCKETS) + bool m_experimentalWebSocketsEnabled : 1; +#endif #if USE(SAFARI_THEME) static bool gShouldPaintNativeControls; #endif +#if PLATFORM(WIN) || (PLATFORM(WIN_OS) && PLATFORM(WX)) + static bool gShouldUseHighResolutionTimers; +#endif }; } // namespace WebCore diff --git a/WebCore/page/UserContentURLPattern.cpp b/WebCore/page/UserContentURLPattern.cpp new file mode 100644 index 0000000..5f0a311 --- /dev/null +++ b/WebCore/page/UserContentURLPattern.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2009 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 "config.h" +#include "UserContentURLPattern.h" +#include "KURL.h" +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +bool UserContentURLPattern::matchesPatterns(const KURL& url, const Vector<String>* whitelist, const Vector<String>* blacklist) +{ + // In order for a URL to be a match it has to be present in the whitelist and not present in the blacklist. + // If there is no whitelist at all, then all URLs are assumed to be in the whitelist. + bool matchesWhitelist = !whitelist || whitelist->isEmpty(); + if (!matchesWhitelist) { + for (unsigned i = 0; i < whitelist->size(); ++i) { + UserContentURLPattern contentPattern(whitelist->at(i)); + if (contentPattern.matches(url)) { + matchesWhitelist = true; + break; + } + } + } + + bool matchesBlacklist = false; + if (blacklist) { + for (unsigned i = 0; i < blacklist->size(); ++i) { + UserContentURLPattern contentPattern(blacklist->at(i)); + if (contentPattern.matches(url)) { + matchesBlacklist = true; + break; + } + } + } + + return matchesWhitelist && !matchesBlacklist; +} + +bool UserContentURLPattern::parse(const String& pattern) +{ + DEFINE_STATIC_LOCAL(const String, schemeSeparator, ("://")); + + int schemeEndPos = pattern.find(schemeSeparator); + if (schemeEndPos == -1) + return false; + + m_scheme = pattern.left(schemeEndPos); + + int hostStartPos = schemeEndPos + schemeSeparator.length(); + if (hostStartPos >= static_cast<int>(pattern.length())) + return false; + + int pathStartPos = 0; + + if (m_scheme == "file") + pathStartPos = hostStartPos; + else { + int hostEndPos = pattern.find("/", hostStartPos); + if (hostEndPos == -1) + return false; + + m_host = pattern.substring(hostStartPos, hostEndPos - hostStartPos); + + // The first component can be '*', which means to match all subdomains. + Vector<String> hostComponents; + m_host.split(".", hostComponents); + if (hostComponents[0] == "*") { + m_matchSubdomains = true; + m_host = ""; + for (unsigned i = 1; i < hostComponents.size(); ++i) { + m_host = m_host + hostComponents[i]; + if (i < hostComponents.size() - 1) + m_host = m_host + "."; + } + } + + // No other '*' can occur in the host. + if (m_host.find("*") != -1) + return false; + + pathStartPos = hostEndPos; + } + + m_path = pattern.right(pattern.length() - pathStartPos); + + return true; +} + +bool UserContentURLPattern::matches(const KURL& test) const +{ + if (m_invalid) + return false; + + if (test.protocol() != m_scheme) + return false; + + if (!matchesHost(test)) + return false; + + return matchesPath(test); +} + +bool UserContentURLPattern::matchesHost(const KURL& test) const +{ + if (test.host() == m_host) + return true; + + if (!m_matchSubdomains) + return false; + + // If we're matching subdomains, and we have no host, that means the pattern + // was <scheme>://*/<whatever>, so we match anything. + if (!m_host.length()) + return true; + + // Check if the test host is a subdomain of our host. + return test.host().endsWith(m_host, false); +} + +struct MatchTester +{ + const String m_pattern; + unsigned m_patternIndex; + + const String m_test; + unsigned m_testIndex; + + MatchTester(const String& pattern, const String& test) + : m_pattern(pattern) + , m_patternIndex(0) + , m_test(test) + , m_testIndex(0) + { + } + + bool testStringFinished() const { return m_testIndex >= m_test.length(); } + bool patternStringFinished() const { return m_patternIndex >= m_pattern.length(); } + + void eatWildcard() + { + while (!patternStringFinished()) { + if (m_pattern[m_patternIndex] != '*') + return; + m_patternIndex++; + } + } + + void eatSameChars() + { + while (!patternStringFinished() && !testStringFinished()) { + if (m_pattern[m_patternIndex] == '*') + return; + if (m_pattern[m_patternIndex] != m_test[m_testIndex]) + return; + m_patternIndex++; + m_testIndex++; + } + } + + bool test() + { + // Eat all the matching chars. + eatSameChars(); + + // If the string is finished, then the pattern must be empty too, or contains + // only wildcards. + if (testStringFinished()) { + eatWildcard(); + if (patternStringFinished()) + return true; + return false; + } + + // Pattern is empty but not string, this is not a match. + if (patternStringFinished()) + return false; + + // If we don't encounter a *, then we're hosed. + if (m_pattern[m_patternIndex] != '*') + return false; + + while (!testStringFinished()) { + MatchTester nextMatch(*this); + nextMatch.m_patternIndex++; + if (nextMatch.test()) + return true; + m_testIndex++; + } + + // We reached the end of the string. Let's see if the pattern contains only + // wildcards. + eatWildcard(); + return patternStringFinished(); + } +}; + +bool UserContentURLPattern::matchesPath(const KURL& test) const +{ + MatchTester match(m_path, test.path()); + return match.test(); +} + +} // namespace WebCore diff --git a/WebCore/page/UserContentURLPattern.h b/WebCore/page/UserContentURLPattern.h new file mode 100644 index 0000000..0b1a248 --- /dev/null +++ b/WebCore/page/UserContentURLPattern.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef UserContentURLPattern_h +#define UserContentURLPattern_h + +#include "PlatformString.h" +#include <wtf/Vector.h> + +namespace WebCore { + +class KURL; + +class UserContentURLPattern { +public: + UserContentURLPattern(const String& pattern) + : m_matchSubdomains(false) + { + m_invalid = !parse(pattern); + } + + bool matches(const KURL&) const; + + const String& scheme() const { return m_scheme; } + const String& host() const { return m_host; } + const String& path() const { return m_path; } + + bool matchSubdomains() const { return m_matchSubdomains; } + + static bool matchesPatterns(const KURL&, const Vector<String>* whitelist, const Vector<String>* blacklist); + +private: + bool parse(const String& pattern); + + bool matchesHost(const KURL&) const; + bool matchesPath(const KURL&) const; + + bool m_invalid; + + String m_scheme; + String m_host; + String m_path; + + bool m_matchSubdomains; +}; + + +} // namespace WebCore + +#endif // UserContentURLPattern_h diff --git a/WebCore/page/UserScript.h b/WebCore/page/UserScript.h new file mode 100644 index 0000000..dbbb879 --- /dev/null +++ b/WebCore/page/UserScript.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef UserScript_h +#define UserScript_h + +#include "KURL.h" +#include "UserScriptTypes.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class UserScript { +public: + UserScript(const String& source, const KURL& url, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, + unsigned worldID, UserScriptInjectionTime injectionTime) + : m_source(source) + , m_url(url) + , m_whitelist(whitelist) + , m_blacklist(blacklist) + , m_worldID(worldID) + , m_injectionTime(injectionTime) + { + } + + const String& source() const { return m_source; } + const KURL& url() const { return m_url; } + const Vector<String>* whitelist() const { return m_whitelist.get(); } + const Vector<String>* blacklist() const { return m_blacklist.get(); } + unsigned worldID() const { return m_worldID; } + UserScriptInjectionTime injectionTime() const { return m_injectionTime; } + +private: + String m_source; + KURL m_url; + OwnPtr<Vector<String> > m_whitelist; + OwnPtr<Vector<String> > m_blacklist; + unsigned m_worldID; + UserScriptInjectionTime m_injectionTime; +}; + +} // namespace WebCore + +#endif // UserScript_h diff --git a/WebCore/page/UserScriptTypes.h b/WebCore/page/UserScriptTypes.h new file mode 100644 index 0000000..ac37662 --- /dev/null +++ b/WebCore/page/UserScriptTypes.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef UserScriptTypes_h +#define UserScriptTypes_h + +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +namespace WebCore { + +enum UserScriptInjectionTime { InjectAtDocumentStart, InjectAtDocumentEnd }; + +class UserScript; + +typedef Vector<OwnPtr<UserScript> > UserScriptVector; +typedef HashMap<unsigned, UserScriptVector*> UserScriptMap; + +} // namespace WebCore + +#endif // UserScriptTypes_h diff --git a/WebCore/page/UserStyleSheet.h b/WebCore/page/UserStyleSheet.h new file mode 100644 index 0000000..56bec40 --- /dev/null +++ b/WebCore/page/UserStyleSheet.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef UserStyleSheet_h +#define UserStyleSheet_h + +#include "KURL.h" +#include "UserStyleSheetTypes.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class UserStyleSheet { +public: + UserStyleSheet(const String& source, const KURL& url, + PassOwnPtr<Vector<String> > whitelist, PassOwnPtr<Vector<String> > blacklist, + unsigned worldID) + : m_source(source) + , m_url(url) + , m_whitelist(whitelist) + , m_blacklist(blacklist) + , m_worldID(worldID) + { + } + + const String& source() const { return m_source; } + const KURL& url() const { return m_url; } + const Vector<String>* whitelist() const { return m_whitelist.get(); } + const Vector<String>* blacklist() const { return m_blacklist.get(); } + unsigned worldID() const { return m_worldID; } + +private: + String m_source; + KURL m_url; + OwnPtr<Vector<String> > m_whitelist; + OwnPtr<Vector<String> > m_blacklist; + unsigned m_worldID; +}; + +} // namespace WebCore + +#endif // UserStyleSheet_h diff --git a/WebCore/page/UserStyleSheetTypes.h b/WebCore/page/UserStyleSheetTypes.h new file mode 100644 index 0000000..094b2cf --- /dev/null +++ b/WebCore/page/UserStyleSheetTypes.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2009 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. + */ + +#ifndef UserStyleSheetTypes_h +#define UserStyleSheetTypes_h + +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class UserStyleSheet; + +typedef Vector<OwnPtr<UserStyleSheet> > UserStyleSheetVector; +typedef HashMap<unsigned, UserStyleSheetVector*> UserStyleSheetMap; + +} // namespace WebCore + +#endif // UserStyleSheetTypes_h diff --git a/WebCore/page/XSSAuditor.cpp b/WebCore/page/XSSAuditor.cpp index 70b691b..92ed896 100644 --- a/WebCore/page/XSSAuditor.cpp +++ b/WebCore/page/XSSAuditor.cpp @@ -48,12 +48,38 @@ namespace WebCore { static bool isNonCanonicalCharacter(UChar c) { + // We remove all non-ASCII characters, including non-printable ASCII characters. + // // Note, we don't remove backslashes like PHP stripslashes(), which among other things converts "\\0" to the \0 character. // Instead, we remove backslashes and zeros (since the string "\\0" =(remove backslashes)=> "0"). However, this has the // adverse effect that we remove any legitimate zeros from a string. // // For instance: new String("http://localhost:8000") => new String("http://localhost:8"). - return (c == '\\' || c == '0' || c < ' ' || c == 127); + return (c == '\\' || c == '0' || c < ' ' || c >= 127); +} + +static bool isIllegalURICharacter(UChar c) +{ + // The characters described in section 2.4.3 of RFC 2396 <http://www.faqs.org/rfcs/rfc2396.html> in addition to the + // single quote character "'" are considered illegal URI characters. That is, the following characters cannot appear + // in a valid URI: ', ", <, > + // + // If the request does not contain these characters then we can assume that no inline scripts have been injected + // into response page, because it is impossible to write an inline script of the form <script>...</script> + // without "<", ">". + return (c == '\'' || c == '"' || c == '<' || c == '>'); +} + +String XSSAuditor::CachingURLCanonicalizer::canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities) +{ + if (decodeEntities == m_decodeEntities && encoding == m_encoding && url == m_inputURL) + return m_cachedCanonicalizedURL; + + m_cachedCanonicalizedURL = canonicalize(decodeURL(url, encoding, decodeEntities)); + m_inputURL = url; + m_encoding = encoding; + m_decodeEntities = decodeEntities; + return m_cachedCanonicalizedURL; } XSSAuditor::XSSAuditor(Frame* frame) @@ -76,7 +102,7 @@ bool XSSAuditor::canEvaluate(const String& code) const if (!isEnabled()) return true; - if (findInRequest(code, false)) { + if (findInRequest(code, false, true)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -102,7 +128,7 @@ bool XSSAuditor::canCreateInlineEventListener(const String&, const String& code) if (!isEnabled()) return true; - if (findInRequest(code)) { + if (findInRequest(code, true, true)) { DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n")); m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); return false; @@ -156,22 +182,23 @@ String XSSAuditor::canonicalize(const String& string) return result.removeCharacters(&isNonCanonicalCharacter); } -String XSSAuditor::decodeURL(const String& string, const TextEncoding& encoding, bool decodeHTMLentities) +String XSSAuditor::decodeURL(const String& string, const TextEncoding& encoding, bool decodeEntities) { String result; String url = string; url.replace('+', ' '); result = decodeURLEscapeSequences(url); - String decodedResult = encoding.decode(result.utf8().data(), result.length()); + CString utf8Url = result.utf8(); + String decodedResult = encoding.decode(utf8Url.data(), utf8Url.length()); if (!decodedResult.isEmpty()) result = decodedResult; - if (decodeHTMLentities) + if (decodeEntities) result = decodeHTMLEntities(result); return result; } -String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodableHTMLEntitiesUntouched) +String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodableEntitiesUntouched) { SegmentedString source(string); SegmentedString sourceShadow; @@ -186,7 +213,7 @@ String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodabl continue; } - if (leaveUndecodableHTMLEntitiesUntouched) + if (leaveUndecodableEntitiesUntouched) sourceShadow = source; bool notEnoughCharacters = false; unsigned entity = PreloadScanner::consumeEntity(source, notEnoughCharacters); @@ -196,11 +223,11 @@ String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodabl if (entity > 0xFFFF) { result.append(U16_LEAD(entity)); result.append(U16_TRAIL(entity)); - } else if (entity && (!leaveUndecodableHTMLEntitiesUntouched || entity != 0xFFFD)){ + } else if (entity && (!leaveUndecodableEntitiesUntouched || entity != 0xFFFD)){ result.append(entity); } else { result.append('&'); - if (leaveUndecodableHTMLEntitiesUntouched) + if (leaveUndecodableEntitiesUntouched) source = sourceShadow; } } @@ -208,31 +235,48 @@ String XSSAuditor::decodeHTMLEntities(const String& string, bool leaveUndecodabl return String::adopt(result); } -bool XSSAuditor::findInRequest(const String& string, bool decodeHTMLentities) const +bool XSSAuditor::findInRequest(const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters) const { bool result = false; Frame* parentFrame = m_frame->tree()->parent(); if (parentFrame && m_frame->document()->url() == blankURL()) - result = findInRequest(parentFrame, string, decodeHTMLentities); + result = findInRequest(parentFrame, string, decodeEntities, allowRequestIfNoIllegalURICharacters); if (!result) - result = findInRequest(m_frame, string, decodeHTMLentities); + result = findInRequest(m_frame, string, decodeEntities, allowRequestIfNoIllegalURICharacters); return result; } -bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeHTMLentities) const +bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters) const { ASSERT(frame->document()); - String pageURL = frame->document()->url().string(); if (!frame->document()->decoder()) { // Note, JavaScript URLs do not have a charset. return false; } - if (protocolIs(pageURL, "data")) + if (string.isEmpty()) return false; - if (string.isEmpty()) + FormData* formDataObj = frame->loader()->documentLoader()->originalRequest().httpBody(); + String pageURL = frame->document()->url().string(); + + if (!formDataObj && string.length() >= 2 * pageURL.length()) { + // Q: Why do we bother to do this check at all? + // A: Canonicalizing large inline scripts can be expensive. We want to + // bail out before the call to canonicalize below, which could + // result in an unneeded allocation and memcpy. + // + // Q: Why do we multiply by two here? + // A: We attempt to detect reflected XSS even when the server + // transforms the attacker's input with addSlashes. The best the + // attacker can do get the server to inflate his/her input by a + // factor of two by sending " characters, which the server + // transforms to \". + return false; + } + + if (frame->document()->url().protocolIs("data")) return false; String canonicalizedString = canonicalize(string); @@ -241,12 +285,16 @@ bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeHT if (string.length() < pageURL.length()) { // The string can actually fit inside the pageURL. - String decodedPageURL = canonicalize(decodeURL(pageURL, frame->document()->decoder()->encoding(), decodeHTMLentities)); + String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), decodeEntities); + + if (allowRequestIfNoIllegalURICharacters && (!formDataObj || formDataObj->isEmpty()) + && decodedPageURL.find(&isIllegalURICharacter, 0) == -1) + return false; // Injection is impossible because the request does not contain any illegal URI characters. + if (decodedPageURL.find(canonicalizedString, 0, false) != -1) - return true; // We've found the smoking gun. + return true; // We've found the smoking gun. } - FormData* formDataObj = frame->loader()->documentLoader()->originalRequest().httpBody(); if (formDataObj && !formDataObj->isEmpty()) { String formData = formDataObj->flattenToString(); if (string.length() < formData.length()) { @@ -254,7 +302,7 @@ bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeHT // the url-encoded POST data because the length of the url-decoded // code is less than or equal to the length of the url-encoded // string. - String decodedFormData = canonicalize(decodeURL(formData, frame->document()->decoder()->encoding(), decodeHTMLentities)); + String decodedFormData = m_cache.canonicalizeURL(formData, frame->document()->decoder()->encoding(), decodeEntities); if (decodedFormData.find(canonicalizedString, 0, false) != -1) return true; // We found the string in the POST data. } diff --git a/WebCore/page/XSSAuditor.h b/WebCore/page/XSSAuditor.h index 26f10ab..d3d1ec9 100644 --- a/WebCore/page/XSSAuditor.h +++ b/WebCore/page/XSSAuditor.h @@ -99,18 +99,34 @@ namespace WebCore { bool canSetBaseElementURL(const String& url) const; private: - static String canonicalize(const String&); - - static String decodeURL(const String& url, const TextEncoding& encoding = UTF8Encoding(), bool decodeHTMLentities = true); - - static String decodeHTMLEntities(const String&, bool leaveUndecodableHTMLEntitiesUntouched = true); + class CachingURLCanonicalizer + { + public: + CachingURLCanonicalizer() : m_decodeEntities(false) { } + String canonicalizeURL(const String& url, const TextEncoding& encoding, bool decodeEntities); + + private: + // The parameters we were called with last. + String m_inputURL; + TextEncoding m_encoding; + bool m_decodeEntities; + + // The cached result. + String m_cachedCanonicalizedURL; + }; - bool findInRequest(const String&, bool decodeHTMLentities = true) const; + static String canonicalize(const String&); + static String decodeURL(const String& url, const TextEncoding& encoding, bool decodeEntities); + static String decodeHTMLEntities(const String&, bool leaveUndecodableEntitiesUntouched = true); - bool findInRequest(Frame*, const String&, bool decodeHTMLentities = true) const; + bool findInRequest(const String&, bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false) const; + bool findInRequest(Frame*, const String&, bool decodeEntities = true, bool allowRequestIfNoIllegalURICharacters = false) const; // The frame to audit. Frame* m_frame; + + // A state store to help us avoid canonicalizing the same URL repeated. + mutable CachingURLCanonicalizer m_cache; }; } // namespace WebCore diff --git a/WebCore/page/animation/AnimationBase.cpp b/WebCore/page/animation/AnimationBase.cpp index 7503f0a..ec0e284 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: @@ -341,6 +361,10 @@ public: { Color fromColor = (a->*m_getter)(); Color toColor = (b->*m_getter)(); + + if (!fromColor.isValid() && !toColor.isValid()) + return true; + if (!fromColor.isValid()) fromColor = a->color(); if (!toColor.isValid()) @@ -353,6 +377,10 @@ public: { Color fromColor = (a->*m_getter)(); Color toColor = (b->*m_getter)(); + + if (!fromColor.isValid() && !toColor.isValid()) + return; + if (!fromColor.isValid()) fromColor = a->color(); if (!toColor.isValid()) @@ -365,6 +393,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 <typename T> +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 <typename T> +class FillLayerPropertyWrapper : public FillLayerPropertyWrapperGetter<T> { +public: + FillLayerPropertyWrapper(T (FillLayer::*getter)() const, void (FillLayer::*setter)(T)) + : FillLayerPropertyWrapperGetter<T>(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<T>::m_getter)(), (b->*FillLayerPropertyWrapperGetter<T>::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<Length>(&FillLayer::xPosition, &FillLayer::setXPosition); + break; + case CSSPropertyBackgroundPositionY: + case CSSPropertyWebkitMaskPositionY: + m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<Length>(&FillLayer::yPosition, &FillLayer::setYPosition); + break; + case CSSPropertyBackgroundSize: + case CSSPropertyWebkitMaskSize: + m_fillLayerPropertyWrapper = new FillLayerPropertyWrapper<LengthSize>(&FillLayer::sizeLength, &FillLayer::setSizeLength); + 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 +588,14 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyColor, &RenderStyle::color, &RenderStyle::setColor)); gPropertyWrappers->append(new PropertyWrapper<const Color&>(CSSPropertyBackgroundColor, &RenderStyle::backgroundColor, &RenderStyle::setBackgroundColor)); - gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBackgroundPositionX, &RenderStyle::backgroundXPosition, &RenderStyle::setBackgroundXPosition)); - gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyBackgroundPositionY, &RenderStyle::backgroundYPosition, &RenderStyle::setBackgroundYPosition)); - gPropertyWrappers->append(new PropertyWrapper<LengthSize>(CSSPropertyWebkitBackgroundSize, &RenderStyle::backgroundSize, &RenderStyle::setBackgroundSize)); - gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitMaskPositionX, &RenderStyle::maskXPosition, &RenderStyle::setMaskXPosition)); - gPropertyWrappers->append(new PropertyWrapper<Length>(CSSPropertyWebkitMaskPositionY, &RenderStyle::maskYPosition, &RenderStyle::setMaskYPosition)); - gPropertyWrappers->append(new PropertyWrapper<LengthSize>(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(CSSPropertyBackgroundSize, &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<int>(CSSPropertyFontSize, &RenderStyle::fontSize, &RenderStyle::setBlendedFontSize)); gPropertyWrappers->append(new PropertyWrapper<unsigned short>(CSSPropertyWebkitColumnRuleWidth, &RenderStyle::columnRuleWidth, &RenderStyle::setColumnRuleWidth)); @@ -496,7 +643,7 @@ static void ensurePropertyMap() gPropertyWrappers->append(new PropertyWrapperMaybeInvalidColor(CSSPropertyOutlineColor, &RenderStyle::outlineColor, &RenderStyle::setOutlineColor)); // These are for shadows - gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); + gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyWebkitBoxShadow, &RenderStyle::boxShadow, &RenderStyle::setBoxShadow)); gPropertyWrappers->append(new PropertyWrapperShadow(CSSPropertyTextShadow, &RenderStyle::textShadow, &RenderStyle::setTextShadow)); #if ENABLE(SVG) @@ -685,7 +832,7 @@ void AnimationBase::setNeedsStyleRecalc(Node* node) { ASSERT(!node || (node->document() && !node->document()->inPageCache())); if (node) - node->setNeedsStyleRecalc(AnimationStyleChange); + node->setNeedsStyleRecalc(SyntheticStyleChange); } double AnimationBase::duration() const diff --git a/WebCore/page/animation/AnimationController.cpp b/WebCore/page/animation/AnimationController.cpp index ed241e1..691932e 100644 --- a/WebCore/page/animation/AnimationController.cpp +++ b/WebCore/page/animation/AnimationController.cpp @@ -36,6 +36,8 @@ #include "EventNames.h" #include "Frame.h" #include "RenderView.h" +#include "WebKitAnimationEvent.h" +#include "WebKitTransitionEvent.h" #include <wtf/CurrentTime.h> #include <wtf/UnusedParam.h> @@ -98,7 +100,7 @@ void AnimationControllerPrivate::updateAnimationTimer(bool callSetChanged/* = fa if (callSetChanged) { Node* node = it->first->node(); ASSERT(!node || (node->document() && !node->document()->inPageCache())); - node->setNeedsStyleRecalc(AnimationStyleChange); + node->setNeedsStyleRecalc(SyntheticStyleChange); calledSetChanged = true; } else @@ -136,9 +138,9 @@ void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<Animat Vector<EventToDispatch>::const_iterator eventsToDispatchEnd = m_eventsToDispatch.end(); for (Vector<EventToDispatch>::const_iterator it = m_eventsToDispatch.begin(); it != eventsToDispatchEnd; ++it) { if (it->eventType == eventNames().webkitTransitionEndEvent) - it->element->dispatchWebKitTransitionEvent(it->eventType, it->name, it->elapsedTime); + it->element->dispatchEvent(WebKitTransitionEvent::create(it->eventType, it->name, it->elapsedTime)); else - it->element->dispatchWebKitAnimationEvent(it->eventType, it->name, it->elapsedTime); + it->element->dispatchEvent(WebKitAnimationEvent::create(it->eventType, it->name, it->elapsedTime)); } m_eventsToDispatch.clear(); @@ -146,7 +148,7 @@ void AnimationControllerPrivate::updateStyleIfNeededDispatcherFired(Timer<Animat // call setChanged on all the elements Vector<RefPtr<Node> >::const_iterator nodeChangesToDispatchEnd = m_nodeChangesToDispatch.end(); for (Vector<RefPtr<Node> >::const_iterator it = m_nodeChangesToDispatch.begin(); it != nodeChangesToDispatchEnd; ++it) - (*it)->setNeedsStyleRecalc(AnimationStyleChange); + (*it)->setNeedsStyleRecalc(SyntheticStyleChange); m_nodeChangesToDispatch.clear(); @@ -244,7 +246,7 @@ bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, co return false; if (compAnim->pauseAnimationAtTime(name, t)) { - renderer->node()->setNeedsStyleRecalc(AnimationStyleChange); + renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); startUpdateStyleIfNeededDispatcher(); return true; } @@ -262,7 +264,7 @@ bool AnimationControllerPrivate::pauseTransitionAtTime(RenderObject* renderer, c return false; if (compAnim->pauseTransitionAtTime(cssPropertyID(property), t)) { - renderer->node()->setNeedsStyleRecalc(AnimationStyleChange); + renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange); startUpdateStyleIfNeededDispatcher(); return true; } @@ -438,7 +440,7 @@ void AnimationController::cancelAnimations(RenderObject* renderer) if (m_data->clear(renderer)) { Node* node = renderer->node(); ASSERT(!node || (node->document() && !node->document()->inPageCache())); - node->setNeedsStyleRecalc(AnimationStyleChange); + node->setNeedsStyleRecalc(SyntheticStyleChange); } } diff --git a/WebCore/page/chromium/FrameChromium.cpp b/WebCore/page/chromium/FrameChromium.cpp index 1372cd9..d79ae68 100644 --- a/WebCore/page/chromium/FrameChromium.cpp +++ b/WebCore/page/chromium/FrameChromium.cpp @@ -60,7 +60,7 @@ void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float head float ratio = static_cast<float>(printRect.height()) / static_cast<float>(printRect.width()); - float pageWidth = static_cast<float>(root->overflowWidth()); + float pageWidth = static_cast<float>(root->rightLayoutOverflow()); float pageHeight = pageWidth * ratio; outPageHeight = static_cast<int>(pageHeight); // this is the height of the page adjusted by margins pageHeight -= (headerHeight + footerHeight); diff --git a/WebCore/page/gtk/EventHandlerGtk.cpp b/WebCore/page/gtk/EventHandlerGtk.cpp index d12cdcc..7051391 100644 --- a/WebCore/page/gtk/EventHandlerGtk.cpp +++ b/WebCore/page/gtk/EventHandlerGtk.cpp @@ -122,4 +122,13 @@ unsigned EventHandler::accessKeyModifiers() return PlatformKeyboardEvent::AltKey; } +// GTK+ must scroll horizontally if the mouse pointer is on top of the +// horizontal scrollbar while scrolling with the wheel; we need to +// add the deltas and ticks here so that this behavior is consistent +// for styled scrollbars. +bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult& result) const +{ + return result.scrollbar() && result.scrollbar()->orientation() == HorizontalScrollbar; +} + } 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 <InterfaceDefs.h> -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 <interface/View.h> @@ -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<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); } PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const { - return new ClipboardHaiku(ClipboardWritable, true); + return ClipboardHaiku::create(ClipboardWritable, true); } bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) diff --git a/WebCore/page/mac/DragControllerMac.mm b/WebCore/page/mac/DragControllerMac.mm index c476df7..8a04809 100644 --- a/WebCore/page/mac/DragControllerMac.mm +++ b/WebCore/page/mac/DragControllerMac.mm @@ -26,6 +26,7 @@ #import "config.h" #import "DragController.h" +#if ENABLE(DRAG_SUPPORT) #import "DragData.h" #import "Frame.h" #import "FrameView.h" @@ -75,4 +76,6 @@ void DragController::cleanupAfterSystemDrag() dragEnded(); } -} +} // namespace WebCore + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/WebCore/page/mac/EventHandlerMac.mm b/WebCore/page/mac/EventHandlerMac.mm index 54bdff9..7da1d36 100644 --- a/WebCore/page/mac/EventHandlerMac.mm +++ b/WebCore/page/mac/EventHandlerMac.mm @@ -60,7 +60,9 @@ static inline IMP method_setImplementation(Method m, IMP i) namespace WebCore { +#if ENABLE(DRAG_SUPPORT) const double EventHandler::TextDragDelay = 0.15; +#endif static RetainPtr<NSEvent>& currentNSEventSlot() { @@ -110,7 +112,7 @@ bool EventHandler::wheelEvent(NSEvent *event) m_useLatchedWheelEventNode = wkIsLatchingWheelEvent(event); - PlatformWheelEvent wheelEvent(event, page->chrome()->platformWindow()); + PlatformWheelEvent wheelEvent(event, page->chrome()->platformPageClient()); handleWheelEvent(wheelEvent); return wheelEvent.isAccepted(); @@ -372,6 +374,7 @@ bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const return m_activationEventNumber == event.eventNumber(); } +#if ENABLE(DRAG_SUPPORT) bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&) { NSView *view = mouseDownViewIfStillGood(); @@ -399,6 +402,7 @@ PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const [pasteboard declareTypes:[NSArray array] owner:nil]; return ClipboardMac::create(true, pasteboard, ClipboardWritable, m_frame); } +#endif // ENABLE(DRAG_SUPPORT) bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&) { @@ -430,8 +434,10 @@ bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& eve // layout tests. if (!m_mouseDownWasInSubframe) return false; +#if ENABLE(DRAG_SUPPORT) if (subframe->page()->dragController()->didInitiateDrag()) return false; +#endif case NSMouseMoved: // Since we're passing in currentNSEvent() here, we can call // handleMouseMoveEvent() directly, since the save/restore of @@ -706,24 +712,28 @@ PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const { NSView *windowView = nil; if (Page* page = m_frame->page()) - windowView = page->chrome()->platformWindow(); + windowView = page->chrome()->platformPageClient(); return PlatformMouseEvent(currentNSEvent(), windowView); } +#if ENABLE(CONTEXT_MENUS) bool EventHandler::sendContextMenuEvent(NSEvent *event) { Page* page = m_frame->page(); if (!page) return false; - return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformWindow())); + return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformPageClient())); } +#endif // ENABLE(CONTEXT_MENUS) +#if ENABLE(DRAG_SUPPORT) bool EventHandler::eventMayStartDrag(NSEvent *event) { Page* page = m_frame->page(); if (!page) return false; - return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformWindow())); + return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformPageClient())); } +#endif // ENABLE(DRAG_SUPPORT) } diff --git a/WebCore/page/mac/FrameMac.mm b/WebCore/page/mac/FrameMac.mm index c656624..d9faa8b 100644 --- a/WebCore/page/mac/FrameMac.mm +++ b/WebCore/page/mac/FrameMac.mm @@ -28,7 +28,6 @@ #import "config.h" #import "Frame.h" -#import "Base64.h" #import "BlockExceptions.h" #import "ColorMac.h" #import "Cursor.h" @@ -53,7 +52,6 @@ #import "RenderTableCell.h" #import "Scrollbar.h" #import "SimpleFontData.h" -#import "UserStyleSheetLoader.h" #import "WebCoreViewFactory.h" #import "visible_units.h" @@ -533,35 +531,4 @@ DragImageRef Frame::dragImageForSelection() return selectionImage(); } -void Frame::setUserStyleSheetLocation(const KURL& url) -{ - delete m_userStyleSheetLoader; - m_userStyleSheetLoader = 0; - - // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them - // synchronously and avoid using a loader. - if (url.protocolIs("data") && url.string().startsWith("data:text/css;charset=utf-8;base64,")) { - const unsigned prefixLength = 35; - Vector<char> encodedData(url.string().length() - prefixLength); - for (unsigned i = prefixLength; i < url.string().length(); ++i) - encodedData[i - prefixLength] = static_cast<char>(url.string()[i]); - - Vector<char> styleSheetAsUTF8; - if (base64Decode(encodedData, styleSheetAsUTF8)) { - m_doc->setUserStyleSheet(String::fromUTF8(styleSheetAsUTF8.data())); - return; - } - } - - if (m_doc->docLoader()) - m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); -} - -void Frame::setUserStyleSheet(const String& styleSheet) -{ - delete m_userStyleSheetLoader; - m_userStyleSheetLoader = 0; - m_doc->setUserStyleSheet(styleSheet); -} - } // namespace WebCore diff --git a/WebCore/page/mac/WebCoreViewFactory.h b/WebCore/page/mac/WebCoreViewFactory.h index d4dc821..249d696 100644 --- a/WebCore/page/mac/WebCoreViewFactory.h +++ b/WebCore/page/mac/WebCoreViewFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2005 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2005, 2009 Apple Computer, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -39,6 +39,7 @@ - (NSString *)fileButtonNoFileSelectedLabel; - (NSString *)copyImageUnknownFileLabel; +#if ENABLE(CONTEXT_MENUS) // Context menu item titles - (NSString *)contextMenuItemTagOpenLinkInNewWindow; - (NSString *)contextMenuItemTagDownloadLinkToDisk; @@ -97,6 +98,7 @@ - (NSString *)contextMenuItemTagCapitalize; - (NSString *)contextMenuItemTagChangeBack:(NSString *)replacedString; - (NSString *)contextMenuItemTagInspectElement; +#endif // ENABLE(CONTEXT_MENUS) - (NSString *)searchMenuNoRecentSearchesText; - (NSString *)searchMenuRecentSearchesText; @@ -129,6 +131,7 @@ - (NSString *)AXHeadingText; - (NSString *)AXDefinitionListTermText; - (NSString *)AXDefinitionListDefinitionText; +- (NSString *)AXARIAContentGroupText:(NSString *)ariaType; - (NSString *)AXButtonActionVerb; - (NSString *)AXRadioButtonActionVerb; @@ -143,6 +146,10 @@ - (NSString *)mediaElementLoadingStateText; - (NSString *)mediaElementLiveBroadcastStateText; +- (NSString*)localizedMediaControlElementString:(NSString*)name; +- (NSString*)localizedMediaControlElementHelpText:(NSString*)name; +- (NSString*)localizedMediaTimeDescription:(float)time; + @end diff --git a/WebCore/page/qt/FrameQt.cpp b/WebCore/page/qt/FrameQt.cpp index 388bf66..493e60d 100644 --- a/WebCore/page/qt/FrameQt.cpp +++ b/WebCore/page/qt/FrameQt.cpp @@ -24,8 +24,6 @@ #include "config.h" #include "Frame.h" -#include "UserStyleSheetLoader.h" - namespace WebCore { DragImageRef Frame::dragImageForSelection() @@ -33,21 +31,5 @@ DragImageRef Frame::dragImageForSelection() return 0; } -void Frame::setUserStyleSheetLocation(const KURL& url) -{ - delete m_userStyleSheetLoader; - m_userStyleSheetLoader = 0; - if (m_doc && m_doc->docLoader()) - m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); -} - -void Frame::setUserStyleSheet(const String& styleSheet) -{ - delete m_userStyleSheetLoader; - m_userStyleSheetLoader = 0; - if (m_doc) - m_doc->setUserStyleSheet(styleSheet); -} - } // vim: ts=4 sw=4 et diff --git a/WebCore/page/win/FrameWin.cpp b/WebCore/page/win/FrameWin.cpp index 1e480fb..b15d195 100644 --- a/WebCore/page/win/FrameWin.cpp +++ b/WebCore/page/win/FrameWin.cpp @@ -61,7 +61,7 @@ void computePageRectsForFrame(Frame* frame, const IntRect& printRect, float head float ratio = static_cast<float>(printRect.height()) / static_cast<float>(printRect.width()); - float pageWidth = static_cast<float>(root->overflowWidth()); + float pageWidth = static_cast<float>(root->rightLayoutOverflow()); float pageHeight = pageWidth * ratio; outPageHeight = static_cast<int>(pageHeight); // this is the height of the page adjusted by margins pageHeight -= (headerHeight + footerHeight); diff --git a/WebCore/page/wince/FrameWince.cpp b/WebCore/page/wince/FrameWince.cpp index 480a103..5ecb579 100644 --- a/WebCore/page/wince/FrameWince.cpp +++ b/WebCore/page/wince/FrameWince.cpp @@ -50,7 +50,6 @@ #include "runtime_root.h" #include "Settings.h" #include "TextResourceDecoder.h" -#include "UserStyleSheetLoader.h" #include <windows.h> @@ -166,20 +165,4 @@ DragImageRef Frame::dragImageForSelection() return 0; } -void Frame::setUserStyleSheetLocation(const KURL& url) -{ - delete m_userStyleSheetLoader; - m_userStyleSheetLoader = 0; - if (m_doc && m_doc->docLoader()) - m_userStyleSheetLoader = new UserStyleSheetLoader(m_doc, url.string()); -} - -void Frame::setUserStyleSheet(const String& styleSheet) -{ - delete m_userStyleSheetLoader; - m_userStyleSheetLoader = 0; - if (m_doc) - m_doc->setUserStyleSheet(styleSheet); -} - } // namespace WebCore diff --git a/WebCore/page/wx/EventHandlerWx.cpp b/WebCore/page/wx/EventHandlerWx.cpp index 65a743c..f4f6914 100644 --- a/WebCore/page/wx/EventHandlerWx.cpp +++ b/WebCore/page/wx/EventHandlerWx.cpp @@ -32,6 +32,7 @@ #include "FrameView.h" #include "KeyboardEvent.h" #include "MouseEventWithHitTestResults.h" +#include "NotImplemented.h" #include "Page.h" #include "PlatformKeyboardEvent.h" #include "RenderWidget.h" @@ -43,17 +44,20 @@ const double EventHandler::TextDragDelay = 0.0; bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) { - return passSubframeEventToSubframe(mev, subframe); + subframe->eventHandler()->handleMousePressEvent(mev.event()); + return true; } bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, WebCore::HitTestResult* hittest) { - return passSubframeEventToSubframe(mev, subframe); + subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hittest); + return true; } bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe) { - return passSubframeEventToSubframe(mev, subframe); + subframe->eventHandler()->handleMouseReleaseEvent(mev.event()); + return true; } bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event) @@ -70,6 +74,32 @@ bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget) return passMouseDownEventToWidget(renderWidget->widget()); } +bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& event, Widget* widget) +{ + if (!widget || !widget->isFrameView()) + return false; + + return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(event); +} + +bool EventHandler::tabsToAllControls(KeyboardEvent* event) const +{ + notImplemented(); + return false; +} + +bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult*) +{ + notImplemented(); + return false; +} + +bool EventHandler::passMouseDownEventToWidget(Widget*) +{ + notImplemented(); + return false; +} + void EventHandler::focusDocumentView() { if (Page* page = m_frame->page()) diff --git a/WebCore/page/wx/FrameWx.cpp b/WebCore/page/wx/FrameWx.cpp new file mode 100644 index 0000000..b220694 --- /dev/null +++ b/WebCore/page/wx/FrameWx.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 Kevin Ollivier <kevino@theolliviers.com>. 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 "config.h" +#include "Frame.h" +#include "NotImplemented.h" + +namespace WebCore { + +DragImageRef Frame::dragImageForSelection() +{ + notImplemented(); + return 0; +} + +} |